Browse Source

Merge branch 'feature/event' of xuyiping/kpt-pasture into develop

xuyiping 3 months ago
parent
commit
3068bdec7d
100 changed files with 7071 additions and 1350 deletions
  1. 1 1
      .drone.yml
  2. 9 6
      Dockerfile
  3. 13 1
      README.md
  4. 2 15
      cmd/consumer.go
  5. 19 0
      cmd/mqtt.go
  6. 2 3
      cmd/root.go
  7. 26 7
      config/app.develop.yaml
  8. 30 9
      config/app.go
  9. 26 7
      config/app.test.yaml
  10. 7 2
      dep/dep.go
  11. 8 4
      dep/di_asynq.go
  12. 23 2
      dep/di_crontab.go
  13. 40 0
      dep/di_mqtt.go
  14. 25 10
      docker-compose.yml
  15. 17 10
      go.mod
  16. 27 31
      go.sum
  17. 277 0
      http/handler/analysis/analysis.go
  18. 24 4
      http/handler/config/config.go
  19. 13 11
      http/handler/event/event_base.go
  20. 131 37
      http/handler/event/event_breed.go
  21. 199 0
      http/handler/event/event_health.go
  22. 0 1
      http/handler/event/event_vet.go
  23. 47 0
      http/handler/goods/drugs.go
  24. 158 0
      http/handler/goods/outbound.go
  25. 0 2
      http/handler/pasture/prescription.go
  26. 204 0
      http/handler/work/calendar.go
  27. 5 0
      http/middleware/bus.go
  28. 1 34
      http/middleware/cors.go
  29. 0 11
      http/middleware/hub.go
  30. 37 6
      http/middleware/log.go
  31. 58 0
      http/middleware/rate_limit.go
  32. 11 0
      http/middleware/sso.go
  33. 11 0
      http/route/analysis_api.go
  34. 1 0
      http/route/config_api.go
  35. 25 6
      http/route/event_api.go
  36. 15 0
      http/route/goods_api.go
  37. 36 0
      http/route/work.go
  38. 0 21
      http/route/work_order.go
  39. 2 3
      main.go
  40. 64 0
      model/calendar.go
  41. 5 2
      model/calving_calf.go
  42. 15 1
      model/config_disease_type.go
  43. 250 93
      model/cow.go
  44. 58 0
      model/cow_active_habit.go
  45. 45 0
      model/cow_pregnant.go
  46. 35 0
      model/cow_same_time.go
  47. 0 38
      model/cow_weight.go
  48. 22 0
      model/crontab_log.go
  49. 13 12
      model/disease.go
  50. 28 23
      model/drugs.go
  51. 74 0
      model/event_abortion.go
  52. 15 11
      model/event_body_score.go
  53. 92 44
      model/event_calving.go
  54. 82 0
      model/event_cow_disease.go
  55. 61 0
      model/event_cow_log.go
  56. 141 0
      model/event_cow_same_time.go
  57. 93 0
      model/event_cow_treatment.go
  58. 62 39
      model/event_enter.go
  59. 28 34
      model/event_estrus.go
  60. 0 22
      model/event_frozen_semen_log.go
  61. 99 0
      model/event_immunization_plan.go
  62. 77 0
      model/event_item.go
  63. 205 38
      model/event_mating.go
  64. 134 48
      model/event_pregnant_check.go
  65. 25 0
      model/event_sale.go
  66. 20 0
      model/event_sale_vehicle.go
  67. 0 46
      model/event_same_time.go
  68. 31 10
      model/event_transfer_group.go
  69. 46 0
      model/event_weaning.go
  70. 44 0
      model/event_weight.go
  71. 7 7
      model/frozen_semen.go
  72. 32 0
      model/frozen_semen_log.go
  73. 35 35
      model/immunization_plan.go
  74. 34 0
      model/neck_ring_error.go
  75. 63 0
      model/neck_ring_log.go
  76. 37 0
      model/neck_ring_original.go
  77. 32 0
      model/neck_ring_unregist.go
  78. 81 0
      model/outbound.go
  79. 64 0
      model/outbound_log.go
  80. 48 6
      model/pen.go
  81. 34 30
      model/prescription.go
  82. 3 3
      model/prescription_drugs.go
  83. 14 0
      model/sale_dealer.go
  84. 15 15
      model/same_time.go
  85. 0 27
      model/same_time_cow.go
  86. 44 0
      model/system_basic.go
  87. 1 0
      model/system_role.go
  88. 0 32
      model/work_order_calendar.go
  89. 0 45
      model/work_order_list.go
  90. 8 5
      model/work_order_master.go
  91. 6 6
      module/asynq/consumer.go
  92. 2 4
      module/asynq/interface.go
  93. 441 3
      module/backend/analysis.go
  94. 706 0
      module/backend/analysis_breed.go
  95. 436 0
      module/backend/analysis_other.go
  96. 508 0
      module/backend/calendar.go
  97. 123 427
      module/backend/config_data.go
  98. 461 0
      module/backend/config_data_breed.go
  99. 41 0
      module/backend/config_data_extend.go
  100. 401 0
      module/backend/config_data_other.go

+ 1 - 1
.drone.yml

@@ -1,6 +1,6 @@
 kind: pipeline
 type: docker
-name: kptTmrGroup
+name: kptPasture
 
 #clone:
 #  depth: 1

+ 9 - 6
Dockerfile

@@ -6,11 +6,11 @@ COPY . .
 RUN mkdir -p ./bin
 
 RUN go env -w GO111MODULE=on && \
-    go env -w GOPROXY=https://goproxy.cn,direct && \
+    go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/,direct && \
     go env -w CGO_ENABLED=0 && \
     go env -w GOARCH=amd64 && \
     go env -w GOOS=linux && \
-    go build -o ./bin/kptTmrGroup -ldflags "-X kpt.kptyun.cn:3000/kpt-event/kpt-pasture/pod.appVersion=beef" main.go
+    go build -o ./kptPasture -ldflags "-X kpt.kptyun.cn:3000/kpt-event/kpt-pasture/pod.appVersion=beef" main.go
 
 
 FROM alpine:latest
@@ -20,11 +20,14 @@ owner="yiping.xu"
 
 WORKDIR /app/kpt-pasture
 
+RUN rm -f /etc/localtime \
+&& ln -sv /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
+&& echo "Asia/Shanghai" > /etc/timezone
 
-COPY --from=0 /app/kpt-pasture/config/ /app/kpt-pasture/bin/config/
-COPY --from=0  /app/kpt-pasture/bin/kptPasture /app/kpt-pasture/bin/kptPasture
+COPY --from=0 /app/kpt-pasture/config/ /app/kpt-pasture/config/
+COPY --from=0  /app/kpt-pasture/kptPasture /app/kpt-pasture/kptPasture
 
 EXPOSE 8090
-VOLUME ["/app/kpt-pasture/logger","/app/kpt-pasture/bin/config","/app/kpt-pasture/files"]
+VOLUME ["/app/kpt-pasture/logger","/app/kpt-pasture/config","/app/kpt-pasture/files"]
 
-CMD ["/app/kpt-pasture/bin/kptPasture","http"]
+CMD ["/app/kpt-pasture/kptPasture","http"]

+ 13 - 1
README.md

@@ -32,4 +32,16 @@ lint:
 - make generate
 
 todo列表:
-- module/crontab/crontab.go 中119行[Limit(100)] 待优化,case为产后日期类型待测试
+- [x] module/crontab/crontab.go 中119行[Limit(100)] 待优化,case为产后日期类型待测试
+- [ ] 后台添加配种数据时候,不知道该牛只是同期还是自然发情还是人工揭发?
+- [ ] 青年牛转后备牛事件(到达主动停配期主动转?)
+- [ ] 后备牛到达主动停配期后的牛只放在哪个模块(配种清单,发情清单)
+- [ ] 发情清单和配种清单更新机制
+- [ ] 前后端部署架构【k8s,docker-compose,docker-swarm】namespace隔离,需要考虑的问题【1.一次性任务,2. 定时任务 3. 数据收集,4. 日志收集 5. 报警介入】
+- [x] 所有事件录入梳理【批量录入,excel导入,信息人员与操作人员统一规范】
+- [ ] 药品优化成药品名称关联生产商
+- [x] 框架logrus日志优化【未按照指定天数的日志自动删除,待验证】
+- [ ] 犊牛的牛只品种是根据母牛的品种来确定,还是根据公牛来确定?【目前是根据母牛品种来确定】
+
+脖环发情算法梳理:
+- [ ] 处理异常上报数据(frameid > 12)

+ 2 - 15
cmd/consumer.go

@@ -4,31 +4,18 @@ import (
 	"kpt-pasture/dep"
 
 	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
-	"go.uber.org/zap"
-
 	"github.com/spf13/cobra"
+	"go.uber.org/zap"
 )
 
 // ConsumerCmd represents the consumer command
 var ConsumerCmd = &cobra.Command{
 	Use:   "consumer",
 	Short: "start consumer",
-	PersistentPreRun: func(cmd *cobra.Command, args []string) {
-
-	},
-}
-
-func init() {
-	ConsumerCmd.AddCommand(workOrder)
-}
-
-var workOrder = &cobra.Command{
-	Use:   "workOrder",
-	Short: "kpt pasture work order",
 	Run: func(cmd *cobra.Command, args []string) {
 		srv := dep.DIAsynqWorkOrder()
 		if err := srv.Server.Run(srv.Mux); err != nil {
-			zaplog.Error("eventWorkflow", zap.Any("err", err))
+			zaplog.Error("consumer", zap.Any("err", err))
 		}
 	},
 }

+ 19 - 0
cmd/mqtt.go

@@ -0,0 +1,19 @@
+package cmd
+
+import (
+	"kpt-pasture/config"
+	"kpt-pasture/dep"
+
+	"github.com/spf13/cobra"
+)
+
+var MqttCmd = &cobra.Command{
+	Use:   "mqtt",
+	Short: "mqtt server",
+	Run: func(cmd *cobra.Command, args []string) {
+		conf := config.Options().Mqtt
+		dataEvent := dep.DIMqtt()
+		mqttClient := dataEvent.DataEventEntry.NewMqtt(conf)
+		dataEvent.DataEventEntry.SubMsg(conf, mqttClient)
+	},
+}

+ 2 - 3
cmd/root.go

@@ -7,12 +7,10 @@ import (
 )
 
 var RootCmd = &cobra.Command{
-	Use:   "kpt-pasture",
+	Use:   "kptPasture",
 	Short: "科湃腾牛群系统",
 }
 
-// Execute adds all child commands to the root command and sets flags appropriately.
-// This is called by main.main(). It only needs to happen once to the rootCmd.
 func Execute() {
 	err := RootCmd.Execute()
 	if err != nil {
@@ -25,4 +23,5 @@ func init() {
 	RootCmd.AddCommand(JobCmd)
 	RootCmd.AddCommand(CrontabCmd)
 	RootCmd.AddCommand(ConsumerCmd)
+	RootCmd.AddCommand(MqttCmd)
 }

+ 26 - 7
config/app.develop.yaml

@@ -5,6 +5,7 @@ debug: true
 http_server_addr: ':8090'
 http_metrics_addr: ':23332'
 jwt_expire_time: 172800
+neck_ring_limit: 10000
 
 store:
   show_sql: true
@@ -16,11 +17,10 @@ redis_setting:
   cache_redis:
     addr: '47.92.95.119:6389'
     db: 11
-    requirepass: ""
+    requirepass: "root"
     expiry: 120
 
 jwt_secret: "sUd7j%UfJMt59ywh"
-cache_key_suffix: "gmym"
 
 side_work_setting:
   asynq_setting:
@@ -28,14 +28,33 @@ side_work_setting:
       addr: '47.92.95.119:6389'
       db: 0
       pool_size: 10
+      password: "root"
     concurrency: 5
     queues:
-      workflow: 20
+      work: 20
       low: 10
       default: 5
 cron:
   crontab_start_run: false
-  update_cow_info: "0 * * * * ?"
-  generate_work_order: "0 0 22 * * ?"
-  immunization_plan: "0 * * * * ?"
-  same_Time_plan: "0 */1 * * * ?"
+  update_cow_info: "0 01 1 * * ?"
+  generate_work_order: "0 05 1 * * ?"
+  immunization_plan: "0 10 1 * * ?"
+  same_time_plan: "0 15 1 * * ?"
+  update_same_time: "0 20 1 * * ?"
+  system_basic_crontab: "0 25 1 * * ?"
+  cow_pregnant: "0 00 15 * * ?"
+  neck_ring: "0 30 * * * ?"
+mqtt:
+  broker: "47.92.95.119"
+  port: 1883
+  username: ""
+  password: ""
+  client_id: "ping"
+  topic: "a"
+  qos: 0
+  retain: false
+  keep_alive: 60
+  connect_timeout: 10
+  auto_reconnect: true
+  reconnect_interval: 10
+  work_number: 1

+ 30 - 9
config/app.go

@@ -21,11 +21,12 @@ var (
 
 // AppConfig store all configuration options
 type AppConfig struct {
-	FarmName       string `json:"farm_name"`
+	FarmName       string `yaml:"farm_name"`
 	AppName        string `yaml:"app_name"`
 	AppEnv         string `yaml:"app_environment"`
-	Debug          bool   `yaml:"debug" env:"APP_DEBUG"`
-	HTTPServerAddr string `yaml:"http_server_addr" env:"HTTP_SERVER_ADDR"`
+	Debug          bool   `yaml:"debug"`
+	HTTPServerAddr string `yaml:"http_server_addr"`
+	NeckRingLimit  int32  `yaml:"neck_ring_limit"`
 
 	// 数据库配置 额外加载文件部分 database.yaml
 	StoreSetting StoreSetting `json:"storeSetting" yaml:"store"`
@@ -41,18 +42,22 @@ type AppConfig struct {
 
 	// asynq 相关配置
 	SideWorkSetting SideWorkSetting `yaml:"side_work_setting"`
-
-	CronSetting CronSetting `json:"cron_setting" yaml:"cron"`
+	CronSetting     CronSetting     `json:"cron_setting" yaml:"cron"`
+	Mqtt            MqttSetting     `json:"mqtt"`
 }
 
 type CronSetting struct {
 	// 是否启动任务时先跑一次
 	CrontabStartRun bool `yaml:"crontab_start_run"`
 	// CRONTAB 表达式
-	UpdateCowInfo     string `yaml:"update_cow_info"`
-	GenerateWorkOrder string `yaml:"generate_work_order"`
-	ImmunizationPlan  string `yaml:"immunization_plan"`
-	SameTimePlan      string `yaml:"same_time_plan"`
+	UpdateCowInfo      string `yaml:"update_cow_info"`      //  更新牛只信息
+	GenerateWorkOrder  string `yaml:"generate_work_order"`  //  生成工作单
+	ImmunizationPlan   string `yaml:"immunization_plan"`    //  免疫计划
+	SameTimePlan       string `yaml:"same_time_plan"`       //  同期
+	UpdateSameTime     string `yaml:"update_same_time"`     //  更新同期
+	SystemBasicCrontab string `yaml:"system_basic_crontab"` //  系统基础定时任务
+	CowPregnant        string `yaml:"cow_pregnant"`         //  月度牛只怀孕清单
+	NeckRing           string `yaml:"neck_ring"`            //  脖环数据更新
 }
 
 type JwtTokenKeyConfig struct {
@@ -152,6 +157,22 @@ type AsynqRedisSetting struct {
 	TLSConfig *tls.Config `json:"tlsConfig,omitempty" yaml:"tls_config"`
 }
 
+type MqttSetting struct {
+	Broker            string `json:"broker" yaml:"broker"`
+	Port              int    `json:"port" yaml:"port"`
+	UserName          string `json:"username" yaml:"username"`
+	Password          string `json:"password" yaml:"password"`
+	ClientId          string `json:"client" yaml:"client_id"`
+	Topic             string `json:"topic"  yaml:"topic"`
+	Retain            bool   `json:"retain" yaml:"retain"`
+	Qos               int    `json:"qos" yaml:"qos"`
+	KeepAlive         int    `json:"keepAlive" yaml:"keep_alive"`
+	ConnectTimeout    int    `json:"connectTimeout" yaml:"connect_timeout"`
+	AutoReconnect     bool   `json:"autoReconnect" yaml:"auto_reconnect"`
+	ReconnectInterval int    `json:"reconnectInterval" yaml:"reconnect_interval"`
+	WorkNumber        int    `json:"workNumber" yaml:"work_number"`
+}
+
 func (a *AppConfig) Name() string {
 	return fmt.Sprintf("%s-%s", a.AppName, a.AppEnv)
 }

+ 26 - 7
config/app.test.yaml

@@ -4,6 +4,7 @@ debug: true
 http_server_addr: ':8090'
 http_metrics_addr: ':23332'
 jwt_expire_time: 172800
+neck_ring_limit: 10000
 
 store:
   show_sql: true
@@ -15,7 +16,7 @@ redis_setting:
   cache_redis:
     addr: 47.92.95.119:6389'
     db: 0
-    requirepass: ""
+    requirepass: "root"
     expiry: 120
 
 jwt_secret: "sUd7j%UfJMt59ywh"
@@ -25,16 +26,34 @@ side_work_setting:
   asynq_setting:
     redis:
       addr: '47.92.95.119:6389'
-      db: 16
+      db: 0
       pool_size: 10
     concurrency: 5
     queues:
-      workflow: 20
+      work: 20
       low: 10
       default: 5
 cron:
   crontab_start_run: false
-  update_cow_info: "0 */1 * * * ?"
-  generate_work_order: "0 0 22 * * ?"
-  immunization_plan: "0 * * * * ?"
-  same_Time_plan: "0 */1 * * * ?"
+  update_cow_info: "0 01 1 * * ?"
+  generate_work_order: "0 05 1 * * ?"
+  immunization_plan: "0 10 1 * * ?"
+  same_time_plan: "0 15 1 * * ?"
+  update_same_time: "0 20 1 * * ?"
+  system_basic_crontab: "0 25 1 * * ?"
+  cow_pregnant: "0 00 15 * * ?"
+  neck_ring: "0 30 * * * ?"
+mqtt:
+  broker: "47.92.95.119"
+  port: 1883
+  username: ""
+  password: ""
+  client_id: "ping"
+  topic: "a"
+  qos: 0
+  retain: false
+  keep_alive: 60
+  connect_timeout: 10
+  auto_reconnect: true
+  reconnect_interval: 10
+  work_number: 1

+ 7 - 2
dep/dep.go

@@ -2,10 +2,12 @@ package dep
 
 import (
 	"kpt-pasture/config"
+	"kpt-pasture/module/asynq"
 	"kpt-pasture/module/backend"
-	"kpt-pasture/module/consumer"
 	"kpt-pasture/module/crontab"
+	moduleMqtt "kpt-pasture/module/mqtt"
 	"kpt-pasture/service/asynqsvc"
+	"kpt-pasture/service/mqtt"
 	"kpt-pasture/service/redis"
 	"kpt-pasture/service/sso"
 	"kpt-pasture/service/wechat"
@@ -33,8 +35,11 @@ func Options() []di.HubOption {
 		sso.Module,
 		wechat.Module,
 		asynqsvc.Module,
-		consumer.Module,
+		asynq.Module,
 		redis.Module,
 		crontab.Module,
+		mqtt.Module,
+		//mqtt2.Module,
+		moduleMqtt.Module,
 	}
 }

+ 8 - 4
dep/di_asynq.go

@@ -1,9 +1,10 @@
 package dep
 
 import (
+	"fmt"
 	"kpt-pasture/config"
 	"kpt-pasture/model"
-	"kpt-pasture/module/consumer"
+	"kpt-pasture/module/asynq"
 	"kpt-pasture/service/asynqsvc"
 
 	"go.uber.org/dig"
@@ -22,8 +23,11 @@ func DIAsynqWorkOrder() (out *asynqsvc.Server) {
 
 // AsynqWorkOrder 相关消费
 func AsynqWorkOrder(dep AsyncDependency) *asynqsvc.Server {
-	srv := asynqsvc.NewServer(config.Options())
-	srv.Mux.HandleFunc(model.TaskWorkOrder, dep.WorkOrder.DayWorkOrder) // 工单
+	cfg := config.Options()
+	srv := asynqsvc.NewServer(cfg)
+	pref := cfg.FarmName
+	pattern := fmt.Sprintf("%s:%s", pref, model.TaskWorkOrder)
+	srv.Mux.HandleFunc(pattern, dep.WorkOrder.DayWorkOrder) // 工单
 	return srv
 }
 
@@ -31,5 +35,5 @@ func AsynqWorkOrder(dep AsyncDependency) *asynqsvc.Server {
 type AsyncDependency struct {
 	dig.In
 
-	WorkOrder consumer.BizExec // BizExec 工单
+	WorkOrder asynq.BizExec // BizExec 工单
 }

+ 23 - 2
dep/di_crontab.go

@@ -40,16 +40,17 @@ type CrontabDependency struct {
 func EntryCrontab(dependency CrontabDependency) *cron.Crontab {
 	cfg := config.Options()
 	cs := cfg.CronSetting
+
 	newCrontab := cron.NewCrontab(DataCenterCrontabCounterVec)
 	err := newCrontab.Bind("UpdateCowInfo", cs.UpdateCowInfo, dependency.CrontabHub.UpdateCowInfo)
 	if err != nil {
 		panic(err)
 	}
 
-	err = newCrontab.Bind("GenerateWorkOrder", cs.GenerateWorkOrder, dependency.CrontabHub.GenerateAsynqWorkOrder)
+	/*err = newCrontab.Bind("GenerateWorkOrder", cs.GenerateWorkOrder, dependency.CrontabHub.GenerateAsynqWorkOrder)
 	if err != nil {
 		panic(err)
-	}
+	}*/
 
 	err = newCrontab.Bind("ImmunizationPlan", cs.ImmunizationPlan, dependency.CrontabHub.ImmunizationPlan)
 	if err != nil {
@@ -60,5 +61,25 @@ func EntryCrontab(dependency CrontabDependency) *cron.Crontab {
 	if err != nil {
 		panic(err)
 	}
+
+	err = newCrontab.Bind("UpdateSameTime", cs.UpdateSameTime, dependency.CrontabHub.UpdateSameTime)
+	if err != nil {
+		panic(err)
+	}
+
+	err = newCrontab.Bind("SystemBasicCrontab", cs.SystemBasicCrontab, dependency.CrontabHub.SystemBasicCrontab)
+	if err != nil {
+		panic(err)
+	}
+
+	err = newCrontab.Bind("CowPregnant", cs.CowPregnant, dependency.CrontabHub.CowPregnant)
+	if err != nil {
+		panic(err)
+	}
+
+	err = newCrontab.Bind("NeckRing", cs.NeckRing, dependency.CrontabHub.NeckRingMergeData)
+	if err != nil {
+		panic(err)
+	}
 	return newCrontab
 }

+ 40 - 0
dep/di_mqtt.go

@@ -0,0 +1,40 @@
+package dep
+
+import (
+	"kpt-pasture/service/mqtt"
+
+	"go.uber.org/dig"
+)
+
+func DIMqtt() (out MqttDependency) {
+	container := DI()
+	if err := container.Invoke(func(c MqttDependency) { out = c }); err != nil {
+		panic(err)
+	}
+	return
+}
+
+type MqttDependency struct {
+	dig.In
+
+	DataEventEntry mqtt.DataEvent
+}
+
+/*func DIMqtt() (out MqttDependency) {
+	container := DI()
+	if err := container.Provide(MqttDependency); err != nil {
+		panic(err)
+	}
+	if err := container.Invoke(func(c *mqtt2.MqttServer) { out = c }); err != nil {
+		panic(err)
+	}
+	return
+}
+
+type MqttDependency struct {
+	dig.In
+
+	//DataEventEntry mqtt.DataEvent
+	MqttClient mqtt2.MqttServer
+}
+*/

+ 25 - 10
docker-compose.yml

@@ -1,29 +1,44 @@
 version : '3'
 services:
-  kpt-dtm-crontab:
+  kpt-pasture-crontab:
     privileged: true
     container_name: xdmy001_kpt_pasture_crontab
     restart: always
     image: registry.cn-hangzhou.aliyuncs.com/kpt-event/kpt-pasture:test
     volumes:
-      - /var/logger/kpt-dtm/:/app/kpt-dtm/logger
+      - /var/logger/kpt-pasture/:/app/kpt-pasture/logger
       - /etc/localtime:/etc/localtime
       - /data/docker-compose/kpt-pasture/config:/app/kpt-pasture/config
     environment:
       - APP_ENVIRONMENT=production
-      - DTM_WORK_DIR=/app/kpt-pasture/bin
-    command: [ "/app/kpt-pasture/bin/kptPasture","crontab" ]
-  kpt-dtm-http:
+      - PASTURE_WORK_DIR=/app/kpt-pasture
+    command: [ "/app/kpt-pasture/kptPasture","crontab" ]
+  kpt-pasture-http:
     privileged: true
     container_name: xdmy001_kpt_pasture_http
     restart: always
-    image: registry.cn-hangzhou.aliyuncs.com/kpt-event/kpt-dtm:test
+    image: registry.cn-hangzhou.aliyuncs.com/kpt-event/kpt-pasture:test
     volumes:
-      - /var/logger/kpt-dtm/:/app/kpt-dtm/logger
+      - /var/logger/kpt-pasture/:/app/kpt-pasture/logger
       - /etc/localtime:/etc/localtime
-      - /data/docker-compose/kpt-dtm/config:/app/kpt-dtm/config
+      - /data/docker-compose/kpt-pasture/config:/app/kpt-pasture/config
       - /data/docker-compose/kpt-pasture/files:/app/kpt-pasture/files
+    ports:
+      - "8091:8090"
     environment:
       - APP_ENVIRONMENT=production
-      - DTM_WORK_DIR=/app/kpt-pasture/bin
-    command: [ "/app/kpt-pasture/bin/kptPasture","http" ]
+      - PASTURE_WORK_DIR=/app/kpt-pasture
+    command: [ "/app/kpt-pasture/kptPasture","http" ]
+  #kpt-pasture-consumer:
+    #privileged: true
+    #container_name: xdmy001_kpt_pasture_consumer
+    #restart: always
+    #image: registry.cn-hangzhou.aliyuncs.com/kpt-event/kpt-pasture:test
+      #volumes:
+      #- /var/logger/kpt-pasture/:/app/kpt-pasture/logger
+      #- /etc/localtime:/etc/localtime
+      #- /data/docker-compose/kpt-pasture/config:/app/kpt-pasture/config
+      #environment:
+      #- APP_ENVIRONMENT=production
+      #- PASTURE_WORK_DIR=/app/kpt-pasture
+    #command: [ "/app/kpt-pasture/kptPasture","consumer" ]

+ 17 - 10
go.mod

@@ -3,9 +3,10 @@ module kpt-pasture
 go 1.17
 
 require (
-	gitee.com/xuyiping_admin/go_proto v0.0.0-20240909083429-fbc0524f090a
-	gitee.com/xuyiping_admin/pkg v0.0.0-20231218082641-aac597b8a015
+	gitee.com/xuyiping_admin/go_proto v0.0.0-20241203073346-ba8687d6c8de
+	gitee.com/xuyiping_admin/pkg v0.0.0-20241108060137-caea58c59f5b
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
+	github.com/eclipse/paho.mqtt.golang v1.4.3
 	github.com/eko/gocache v1.1.0
 	github.com/getsentry/sentry-go v0.23.0
 	github.com/gin-contrib/cors v1.4.0
@@ -19,17 +20,24 @@ require (
 	github.com/hibiken/asynq v0.23.0
 	github.com/mitchellh/mapstructure v1.5.0
 	github.com/prometheus/client_golang v1.16.0
-	github.com/spf13/cobra v1.7.0
+	github.com/spf13/cobra v1.8.1
 	github.com/spf13/viper v1.16.0
 	github.com/stretchr/testify v1.8.4
 	github.com/xuri/excelize/v2 v2.8.0
+	github.com/yangxikun/gin-limit-by-key v0.0.0-20190512072151-520697354d5f
 	go.uber.org/dig v1.15.0
 	go.uber.org/zap v1.24.0
-	golang.org/x/sync v0.6.0
+	golang.org/x/sync v0.7.0
 	gorm.io/driver/mysql v1.5.1
 	gorm.io/gorm v1.25.2
 )
 
+require (
+	github.com/gorilla/websocket v1.5.3 // indirect
+	github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
+	golang.org/x/arch v0.3.0 // indirect
+)
+
 require (
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect
@@ -72,7 +80,7 @@ require (
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/prometheus/client_model v0.3.0 // indirect
-	github.com/prometheus/common v0.42.0 // indirect
+	github.com/prometheus/common v0.42.0 // indirect; indirec
 	github.com/prometheus/procfs v0.10.1 // indirect
 	github.com/richardlehane/mscfb v1.0.4 // indirect
 	github.com/richardlehane/msoleps v1.0.3 // indirect
@@ -92,12 +100,11 @@ require (
 	github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 // indirect
 	go.uber.org/atomic v1.9.0 // indirect
 	go.uber.org/multierr v1.8.0 // indirect
-	golang.org/x/arch v0.5.0 // indirect
-	golang.org/x/crypto v0.21.0 // indirect
-	golang.org/x/net v0.22.0 // indirect
-	golang.org/x/sys v0.18.0 // indirect
+	golang.org/x/crypto v0.23.0 // indirect
+	golang.org/x/net v0.25.0 // indirect
+	golang.org/x/sys v0.20.0 // indirect
 	golang.org/x/text v0.15.0 // indirect
-	golang.org/x/time v0.3.0 // indirect
+	golang.org/x/time v0.3.0
 	google.golang.org/appengine v1.6.8 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 // indirect
 	google.golang.org/grpc v1.64.0 // indirect

+ 27 - 31
go.sum

@@ -36,24 +36,12 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
 cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
 cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-gitee.com/xuyiping_admin/go_proto v0.0.0-20240905100333-97e1bcf51bd3 h1:hNO95yUSYiSGfDKRper22iC+UdZFlgfLuwPigAy1WM0=
-gitee.com/xuyiping_admin/go_proto v0.0.0-20240905100333-97e1bcf51bd3/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
-gitee.com/xuyiping_admin/go_proto v0.0.0-20240906022358-d28cc0317fcc h1:q5QHNfCRLFiQnWReEweKch01/2wopT03QBlRN4DQT/4=
-gitee.com/xuyiping_admin/go_proto v0.0.0-20240906022358-d28cc0317fcc/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
-gitee.com/xuyiping_admin/go_proto v0.0.0-20240906085821-e407cf34db4d h1:vUz+UjLU0FgtH0EWdm2B7DWImbY/KF5R0DaCRY1B5Ao=
-gitee.com/xuyiping_admin/go_proto v0.0.0-20240906085821-e407cf34db4d/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
-gitee.com/xuyiping_admin/go_proto v0.0.0-20240909032240-4bb8d1ae9a74 h1:EiIqP3VKAgfxAfTcYb0pahRDF8HTJszMS+6FT69kx5o=
-gitee.com/xuyiping_admin/go_proto v0.0.0-20240909032240-4bb8d1ae9a74/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
-gitee.com/xuyiping_admin/go_proto v0.0.0-20240909053609-bc77419ef76f h1:oRK0jUyGYwyF2hnMPskhWLvlMqlTkUeNwuI/HlTROZ0=
-gitee.com/xuyiping_admin/go_proto v0.0.0-20240909053609-bc77419ef76f/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
-gitee.com/xuyiping_admin/go_proto v0.0.0-20240909054215-306813604abd h1:j34BDfJy91vtzhhEYHU0k5cANdMerKj7Ctjg+n1XwBg=
-gitee.com/xuyiping_admin/go_proto v0.0.0-20240909054215-306813604abd/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
-gitee.com/xuyiping_admin/go_proto v0.0.0-20240909070422-d8e24115eea0 h1:WlkXLe5NFBAg57PLasrp3XvO/TB25+UqKGSXnWrbFBI=
-gitee.com/xuyiping_admin/go_proto v0.0.0-20240909070422-d8e24115eea0/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
-gitee.com/xuyiping_admin/go_proto v0.0.0-20240909083429-fbc0524f090a h1:Vz40n7q51ZKrI2P5BCT0eY1I2Du5ApRaaFkkzqDO1bg=
-gitee.com/xuyiping_admin/go_proto v0.0.0-20240909083429-fbc0524f090a/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
-gitee.com/xuyiping_admin/pkg v0.0.0-20231218082641-aac597b8a015 h1:dfb5dRd57L2HKjdwLT93UFmPYFPOmEl56gtZmqcNnaE=
-gitee.com/xuyiping_admin/pkg v0.0.0-20231218082641-aac597b8a015/go.mod h1:Fk4GYI/v0IK3XFrm1Gn+VkgCz5Y7mfswD5hsTJYOG6A=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241128102506-727966a0f004 h1:0kHmrqRNqiJuzIGIk+dkAsTd/7iAlPRKPYN5h2aaeTo=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241128102506-727966a0f004/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241203073346-ba8687d6c8de h1:dIATo9IIIOfcQaSISrclzRF0piVoy7bydeG0psN1Lt0=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241203073346-ba8687d6c8de/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/pkg v0.0.0-20241108060137-caea58c59f5b h1:w05MxH7yqveRlaRbxHhbif5YjPrJFodRPfOjYhXn7Zk=
+gitee.com/xuyiping_admin/pkg v0.0.0-20241108060137-caea58c59f5b/go.mod h1:8tF25X6pE9WkFCczlNAC0K2mrjwKvhhp02I7o0HtDxY=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
@@ -122,7 +110,7 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
 github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
-github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
 github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -139,6 +127,8 @@ github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:Htrtb
 github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
 github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
 github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
+github.com/eclipse/paho.mqtt.golang v1.4.3 h1:2kwcUGn8seMUfWndX0hGbvH8r7crgcJguQNCyp70xik=
+github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE=
 github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
 github.com/eko/gocache v1.1.0 h1:FeER4gxA+lneYNeg/56obO6itD903LhPI0fT38J01WI=
 github.com/eko/gocache v1.1.0/go.mod h1:Q/KMUBMhv7CO4VahJStlTzMfFzP5dxTqs7D34NmJmVM=
@@ -291,6 +281,8 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51
 github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
 github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
 github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
+github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
@@ -452,6 +444,8 @@ github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnh
 github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
 github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
+github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
 github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
 github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
 github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
@@ -538,8 +532,8 @@ github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
 github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
 github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
 github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
-github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
-github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
+github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
+github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
 github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
 github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
 github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
@@ -590,6 +584,8 @@ github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05 h1:qhbILQo1K3mphbwKh1vNm4
 github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
 github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 h1:zzrxE1FKn5ryBNl9eKOeqQ58Y/Qpo3Q9QNxKHX5uzzQ=
 github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2/go.mod h1:hzfGeIUDq/j97IG+FhNqkowIyEcD88LrW6fyU3K3WqY=
+github.com/yangxikun/gin-limit-by-key v0.0.0-20190512072151-520697354d5f h1:ERcGMTmr8QfJ2KPgKGnyKG5QEEK+YxraUch0I0gN8uc=
+github.com/yangxikun/gin-limit-by-key v0.0.0-20190512072151-520697354d5f/go.mod h1:ysnqe7upAAVOSwxQZHAMPXbO80SFzg/ArkjnIJIcuGE=
 github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -629,8 +625,8 @@ go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
 go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
 go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
 golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
-golang.org/x/arch v0.5.0 h1:jpGode6huXQxcskEIpOCvrU+tzo81b6+oFLUYXWtH/Y=
-golang.org/x/arch v0.5.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
+golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -644,8 +640,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
-golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
-golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
+golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
+golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -732,8 +728,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
 golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
 golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
-golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
-golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
+golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
+golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
 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-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -756,8 +752,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
-golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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=
@@ -825,8 +821,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
-golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=

+ 277 - 0
http/handler/analysis/analysis.go

@@ -4,6 +4,8 @@ import (
 	"kpt-pasture/http/middleware"
 	"net/http"
 
+	"gitee.com/xuyiping_admin/pkg/valid"
+
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 	"gitee.com/xuyiping_admin/pkg/apierr"
 	"gitee.com/xuyiping_admin/pkg/ginutil"
@@ -22,5 +24,280 @@ func GrowthCurve(c *gin.Context) {
 		apierr.ClassifiedAbort(c, err)
 		return
 	}
+
+	ginutil.JSONResp(c, res)
+}
+
+func WeightRange(c *gin.Context) {
+	var req pasturePb.WeightRangeRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.MaxWeight, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.WeightRange(c, &req)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	ginutil.JSONResp(c, res)
+}
+
+func MatingTimeLy(c *gin.Context) {
+	var req pasturePb.MatingTimelyRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.StartDayAt, valid.Required),
+		valid.Field(&req.EndDayAt, valid.Required),
+		valid.Field(&req.CowType, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.MatingTimely(c, &req)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	c.JSON(http.StatusOK, res)
+}
+
+func PenWeight(c *gin.Context) {
+	var req pasturePb.PenWeightRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	pagination := &pasturePb.PaginationModel{
+		Page:       int32(c.GetInt(middleware.Page)),
+		PageSize:   int32(c.GetInt(middleware.PageSize)),
+		PageOffset: int32(c.GetInt(middleware.PageOffset)),
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.PenWeight(c, &req, pagination)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}
+
+func TwentyOnePregnantRate(c *gin.Context) {
+	var req pasturePb.TwentyOnePregnantRateRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.StartDate, valid.Required),
+		valid.Field(&req.EndDate, valid.Required),
+		valid.Field(&req.CowType, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.TwentyOnePregnantRate(c, &req)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}
+
+func AbortionRate(c *gin.Context) {
+	var req pasturePb.AbortionRateRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.StartDayTime, valid.Required),
+		valid.Field(&req.EndDayTime, valid.Required),
+		valid.Field(&req.CowType, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.AbortionRate(c, &req)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}
+
+func PregnancyReport(c *gin.Context) {
+	var req pasturePb.PregnancyReportRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.StartDayTime, valid.Required),
+		valid.Field(&req.EndDayTime, valid.Required),
+		valid.Field(&req.CowType, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	pagination := &pasturePb.PaginationModel{
+		Page:       int32(c.GetInt(middleware.Page)),
+		PageSize:   int32(c.GetInt(middleware.PageSize)),
+		PageOffset: int32(c.GetInt(middleware.PageOffset)),
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.PregnancyReport(c, &req, pagination)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}
+
+func CalvingReport(c *gin.Context) {
+	var req pasturePb.CalvingReportRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.StartDayTime, valid.Required),
+		valid.Field(&req.EndDayTime, valid.Required),
+		valid.Field(&req.LateLabor, valid.Required),
+		valid.Field(&req.PrematureLabor, valid.Required),
+		valid.Field(&req.AnalysisMethod, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.CalvingReport(c, &req)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}
+
+func DiseaseCureReport(c *gin.Context) {
+	var req pasturePb.DiseaseCureRateRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.StartDayTime, valid.Required),
+		valid.Field(&req.EndDayTime, valid.Required),
+		valid.Field(&req.AnalysisMethod, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.DiseaseCureReport(c, &req)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}
+
+func SaleCowReport(c *gin.Context) {
+	var req pasturePb.SaleCowReportRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.StartDay, valid.Required),
+		valid.Field(&req.EndDay, valid.Required),
+		valid.Field(&req.AnalysisMethod, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.SaleCowReport(c, &req)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}
+
+func SingleFactorInfantSurvivalRate(c *gin.Context) {
+	var req pasturePb.SingleFactorPregnancyRateRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.StartDayTime, valid.Required),
+		valid.Field(&req.EndDayTime, valid.Required),
+		valid.Field(&req.AnalysisMethod, valid.Required),
+		valid.Field(&req.CowType, valid.Required),
+		valid.Field(&req.LactInterval, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.SingleFactorInfantSurvivalRateAnalysis(c, &req)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}
+
+func MultiFactorInfantSurvivalRate(c *gin.Context) {
+	var req pasturePb.MultiFactorPregnancyRateRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.StartDayTime, valid.Required),
+		valid.Field(&req.EndDayTime, valid.Required),
+		valid.Field(&req.CowType, valid.Required),
+		valid.Field(&req.XAxle, valid.Required),
+		valid.Field(&req.YAxle, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.MultipleFactorAnalysis(c, &req)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
 	c.JSON(http.StatusOK, res)
 }

+ 24 - 4
http/handler/config/config.go

@@ -23,11 +23,12 @@ func BarnTypeOptions(c *gin.Context) {
 func BarnListOptions(c *gin.Context) {
 	penTypeStr := c.Query("pen_type")
 	penTypeId, _ := strconv.Atoi(penTypeStr)
+	isAll := c.Query("is_all")
 	if err := valid.Validate(penTypeId, valid.Required, valid.Min(-1)); err != nil {
 		apierr.ClassifiedAbort(c, err)
 		return
 	}
-	res, err := middleware.Dependency(c).StoreEventHub.OpsService.BarnListOptions(c, penTypeId)
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.BarnListOptions(c, penTypeId, isAll)
 	if err != nil {
 		apierr.ClassifiedAbort(c, err)
 		return
@@ -36,7 +37,8 @@ func BarnListOptions(c *gin.Context) {
 }
 
 func DiseaseTypeOptions(c *gin.Context) {
-	res, err := middleware.Dependency(c).StoreEventHub.OpsService.DiseaseTypeOptions(c)
+	isChildren := c.Query("is_children")
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.DiseaseTypeOptions(c, isChildren)
 	if err != nil {
 		apierr.ClassifiedAbort(c, err)
 		return
@@ -51,6 +53,16 @@ func DiseaseOptions(c *gin.Context) {
 	}
 	ginutil.JSONResp(c, res)
 }
+
+func PrescriptionOptions(c *gin.Context) {
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.PrescriptionOptions(c)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}
+
 func BreedStatusOptions(c *gin.Context) {
 	res, err := middleware.Dependency(c).StoreEventHub.OpsService.BreedStatusOptions(c)
 	if err != nil {
@@ -79,7 +91,14 @@ func CowSourceOptions(c *gin.Context) {
 }
 
 func CowTypeOptions(c *gin.Context) {
-	res, err := middleware.Dependency(c).StoreEventHub.OpsService.CowTypeOptions(c)
+	optionName := c.Query("option_name")
+	isAll := c.Query("is_all")
+	if err := valid.Validate(optionName, valid.Required, valid.Length(1, 50)); err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.CowTypeOptions(c, optionName, isAll)
 	if err != nil {
 		apierr.ClassifiedAbort(c, err)
 		return
@@ -122,11 +141,12 @@ func BullListOptions(c *gin.Context) {
 
 func SystemBaseConfigOptions(c *gin.Context) {
 	optionName := c.Query("option_name")
+	isAll := c.Query("is_all")
 	if err := valid.Validate(optionName, valid.Required, valid.Length(1, 50)); err != nil {
 		apierr.ClassifiedAbort(c, err)
 		return
 	}
-	res, err := middleware.Dependency(c).StoreEventHub.OpsService.SystemBaseConfigOptions(c, optionName)
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.SystemBaseConfigOptions(c, optionName, isAll)
 	if err != nil {
 		apierr.ClassifiedAbort(c, err)
 		return

+ 13 - 11
http/handler/event/event_base.go

@@ -35,7 +35,7 @@ func EnterEventList(c *gin.Context) {
 }
 
 func EnterEventCreate(c *gin.Context) {
-	var req pasturePb.EventEnterData
+	var req pasturePb.EventEnterRequest
 	if err := ginutil.BindProto(c, &req); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
 		return
@@ -45,11 +45,13 @@ func EnterEventCreate(c *gin.Context) {
 		valid.Field(&req.EarNumber, valid.Required),
 		valid.Field(&req.BirthAt, valid.Required),
 		valid.Field(&req.Sex, valid.Required),
-		valid.Field(&req.CowTypeId, valid.Required),
-		valid.Field(&req.CowKindId, valid.Required),
-		valid.Field(&req.CowSourceId, valid.Required),
+		valid.Field(&req.CowType, valid.Required),
+		valid.Field(&req.CowKind, valid.Required),
+		valid.Field(&req.CowSource, valid.Required),
 		valid.Field(&req.Lact, valid.Required),
 		valid.Field(&req.EnterAt, valid.Required),
+		valid.Field(&req.CowSource, valid.Required),
+		valid.Field(&req.OperationId, valid.Required),
 	); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
 		return
@@ -103,7 +105,7 @@ func GroupTransferEventCreate(c *gin.Context) {
 				valid.Field(&s.TransferDate, valid.Required),
 				valid.Field(&s.TransferInPenId, valid.Required),
 				valid.Field(&s.TransferReasonId, valid.Required),
-				valid.Field(&s.StaffMemberId, valid.Required),
+				valid.Field(&s.OperationId, valid.Required),
 			)
 		}))),
 	); err != nil {
@@ -154,7 +156,7 @@ func BodyScoreEventCreate(c *gin.Context) {
 		valid.Field(&req.CowId, valid.Required),
 		valid.Field(&req.ScoreAt, valid.Required),
 		valid.Field(&req.Score, valid.Required),
-		valid.Field(&req.StaffMemberId, valid.Required),
+		valid.Field(&req.OperationId, valid.Required),
 	); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
 		return
@@ -172,7 +174,7 @@ func BodyScoreEventCreate(c *gin.Context) {
 	})
 }
 
-func WeightEventList(c *gin.Context) {
+func WeightList(c *gin.Context) {
 	var req pasturePb.SearchEventRequest
 	if err := ginutil.BindProto(c, &req); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
@@ -193,7 +195,7 @@ func WeightEventList(c *gin.Context) {
 	ginutil.JSONResp(c, res)
 }
 
-func WeightEventCreate(c *gin.Context) {
+func WeightBatch(c *gin.Context) {
 	var req pasturePb.EventWeight
 	if err := ginutil.BindProto(c, &req); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
@@ -201,13 +203,13 @@ func WeightEventCreate(c *gin.Context) {
 	}
 
 	if err := valid.ValidateStruct(&req,
-		valid.Field(&req.CowId, valid.Required),
 		valid.Field(&req.WeightAt, valid.Required),
-		valid.Field(&req.StaffMemberId, valid.Required),
+		valid.Field(&req.OperationId, valid.Required),
 		valid.Field(&req.WeightItems, valid.Required, valid.Each(valid.By(func(value interface{}) error {
 			s := value.(pasturePb.WeightItem)
 			return valid.ValidateStruct(&s,
 				valid.Field(&s.Weight, valid.Required),
+				valid.Field(&s.CowId, valid.Required),
 			)
 		}))),
 	); err != nil {
@@ -215,7 +217,7 @@ func WeightEventCreate(c *gin.Context) {
 		return
 	}
 
-	if err := middleware.BackendOperation(c).OpsService.WeightCreate(c, &req); err != nil {
+	if err := middleware.BackendOperation(c).OpsService.WeightBatch(c, &req); err != nil {
 		apierr.ClassifiedAbort(c, err)
 		return
 	}

+ 131 - 37
http/handler/event/event_breed.go

@@ -54,7 +54,7 @@ func CalvingEventCreate(c *gin.Context) {
 				valid.Field(&s.IsAdoption, valid.Required),
 			)
 		}))),
-		valid.Field(&req.StaffMemberId, valid.Required),
+		valid.Field(&req.OperationId, valid.Required),
 	); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
 		return
@@ -93,25 +93,30 @@ func PregnantCheckEventList(c *gin.Context) {
 	ginutil.JSONResp(c, res)
 }
 
-func PregnantCheckEventCreate(c *gin.Context) {
-	var req pasturePb.EventPregnantCheck
+func PregnantCheckEventCreateBatch(c *gin.Context) {
+	var req pasturePb.EventPregnantCheckBatch
 	if err := ginutil.BindProto(c, &req); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
 		return
 	}
 
 	if err := valid.ValidateStruct(&req,
-		valid.Field(&req.CowId, valid.Required),
-		valid.Field(&req.PregnantCheckAt, valid.Required),
-		valid.Field(&req.PregnantCheckResult, valid.Required),
-		valid.Field(&req.PregnantCheckAt, valid.Required),
-		valid.Field(&req.StaffMemberId, valid.Required),
+		valid.Field(&req.Item, valid.Required, valid.Each(valid.By(func(value interface{}) error {
+			item := value.(pasturePb.EventPregnantCheckRequest)
+			return valid.ValidateStruct(&item,
+				valid.Field(&item.CowId, valid.Required),
+				valid.Field(&item.PregnantCheckAt, valid.Required),
+				valid.Field(&item.PregnantCheckResult, valid.Required),
+				valid.Field(&item.PregnantCheckMethod, valid.Required),
+				valid.Field(&item.OperationId, valid.Required),
+			)
+		}))),
 	); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
 		return
 	}
 
-	if err := middleware.BackendOperation(c).OpsService.PregnantCheckCreate(c, &req); err != nil {
+	if err := middleware.BackendOperation(c).OpsService.PregnantCheckCreateBatch(c, &req); err != nil {
 		apierr.ClassifiedAbort(c, err)
 		return
 	}
@@ -152,11 +157,11 @@ func MatingCreate(c *gin.Context) {
 	}
 
 	if err := valid.ValidateStruct(&req,
-		valid.Field(&req.CowId, valid.Required),
-		valid.Field(&req.StaffMemberId, valid.Required),
-		valid.Field(&req.ExposeEstrusType, valid.Required),
-		valid.Field(&req.BullId, valid.Required),
+		valid.Field(&req.CowIds, valid.Required),
+		valid.Field(&req.OperationId, valid.Required),
+		valid.Field(&req.FrozenSemenNumber, valid.Required),
 		valid.Field(&req.MatingAt, valid.Required),
+		valid.Field(&req.FrozenSemenCount, valid.Required, valid.Min(1)),
 	); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
 		return
@@ -204,7 +209,7 @@ func EstrusCreate(c *gin.Context) {
 
 	if err := valid.ValidateStruct(&req,
 		valid.Field(&req.CowId, valid.Required),
-		valid.Field(&req.StaffMemberId, valid.Required),
+		valid.Field(&req.OperationId, valid.Required),
 		valid.Field(&req.EstrusAt, valid.Required),
 	); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
@@ -222,9 +227,71 @@ func EstrusCreate(c *gin.Context) {
 		Data: &operationPb.Success{Success: true},
 	})
 }
+func SameTimeCreate(c *gin.Context) {
+	var req pasturePb.EventSameTime
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.Id, valid.Required),
+		valid.Field(&req.DrugsId, valid.Required),
+		valid.Field(&req.OperationId, valid.Required),
+		valid.Field(&req.SameTimeAt, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := middleware.BackendOperation(c).OpsService.SameTimeCreate(c, &req); err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	ginutil.JSONResp(c, &operationPb.CommonOK{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &operationPb.Success{Success: true},
+	})
+}
+
+func SameTimeBatch(c *gin.Context) {
+	var req pasturePb.EventSameTimeBatch
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.OperationId, valid.Required),
+		valid.Field(&req.DrugsId, valid.Required),
+		valid.Field(&req.SameTimeAt, valid.Required),
+		valid.Field(&req.Item, valid.Required, valid.Each(valid.By(func(value interface{}) error {
+			item := value.(pasturePb.EventSameTimeItem)
+			return valid.ValidateStruct(&item,
+				valid.Field(&item.CowId, valid.Required),
+			)
+		}))),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := middleware.BackendOperation(c).OpsService.SameTimeBatch(c, &req); err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	ginutil.JSONResp(c, &operationPb.CommonOK{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &operationPb.Success{Success: true},
+	})
+}
 
-func FrozenSemeList(c *gin.Context) {
-	var req pasturePb.FrozenSemenRequest
+func SameTimeList(c *gin.Context) {
+	var req pasturePb.SearchEventRequest
 	if err := ginutil.BindProto(c, &req); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
 		return
@@ -236,7 +303,7 @@ func FrozenSemeList(c *gin.Context) {
 		PageOffset: int32(c.GetInt(middleware.PageOffset)),
 	}
 
-	res, err := middleware.Dependency(c).StoreEventHub.OpsService.FrozenSemenList(c, &req, pagination)
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.SameTimeList(c, &req, pagination)
 	if err != nil {
 		apierr.ClassifiedAbort(c, err)
 		return
@@ -244,26 +311,30 @@ func FrozenSemeList(c *gin.Context) {
 	ginutil.JSONResp(c, res)
 }
 
-// FrozenSemeCreate 冻精
-func FrozenSemeCreate(c *gin.Context) {
-	var req pasturePb.SearchFrozenSemenList
+func AbortionCreateBatch(c *gin.Context) {
+	var req pasturePb.EventAbortionBatch
 	if err := ginutil.BindProto(c, &req); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
 		return
 	}
 
 	if err := valid.ValidateStruct(&req,
-		valid.Field(&req.BullId, valid.Required),
-		valid.Field(&req.Producer, valid.Required),
-		valid.Field(&req.Quantity, valid.Required),
-		valid.Field(&req.Unit, valid.Required),
-		valid.Field(&req.FrozenSemenType, valid.Required),
+		valid.Field(&req.Item, valid.Required, valid.Each(valid.By(func(value interface{}) error {
+			item := value.(pasturePb.EventAbortionRequest)
+			return valid.ValidateStruct(&item,
+				valid.Field(&item.CowId, valid.Required),
+				valid.Field(&item.IsAfterbirth, valid.Required),
+				valid.Field(&item.AbortionReasons, valid.Required),
+				valid.Field(&item.AbortionAt, valid.Required),
+				valid.Field(&item.OperationId, valid.Required),
+			)
+		}))),
 	); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
 		return
 	}
 
-	if err := middleware.BackendOperation(c).OpsService.FrozenSemenCreate(c, &req); err != nil {
+	if err := middleware.BackendOperation(c).OpsService.AbortionCreateBatch(c, &req); err != nil {
 		apierr.ClassifiedAbort(c, err)
 		return
 	}
@@ -275,23 +346,51 @@ func FrozenSemeCreate(c *gin.Context) {
 	})
 }
 
-func SameTimeCreate(c *gin.Context) {
-	var req pasturePb.EventSameTime
+func AbortionList(c *gin.Context) {
+	var req pasturePb.SearchEventRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	pagination := &pasturePb.PaginationModel{
+		Page:       int32(c.GetInt(middleware.Page)),
+		PageSize:   int32(c.GetInt(middleware.PageSize)),
+		PageOffset: int32(c.GetInt(middleware.PageOffset)),
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.AbortionList(c, &req, pagination)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}
+
+func WeaningCreateBatch(c *gin.Context) {
+	var req pasturePb.EventWeaningBatchRequest
 	if err := ginutil.BindProto(c, &req); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
 		return
 	}
 
 	if err := valid.ValidateStruct(&req,
-		valid.Field(&req.SameTimeId, valid.Required),
-		valid.Field(&req.SameTimeType, valid.Required),
-		valid.Field(&req.SameTimeAt, valid.Required),
+		valid.Field(req.WeaningAt, valid.Required),
+		valid.Field(req.OperationId, valid.Required),
+		valid.Field(req.PenId, valid.Required),
+		valid.Field(&req.Item, valid.Required, valid.Each(valid.By(func(value interface{}) error {
+			item := value.(pasturePb.WeaningBatch)
+			return valid.ValidateStruct(&item,
+				valid.Field(&item.CowId, valid.Required),
+				valid.Field(&item.Weight, valid.Required),
+			)
+		}))),
 	); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
 		return
 	}
 
-	if err := middleware.BackendOperation(c).OpsService.SameTimeCreate(c, &req); err != nil {
+	if err := middleware.BackendOperation(c).OpsService.WeaningBatch(c, &req); err != nil {
 		apierr.ClassifiedAbort(c, err)
 		return
 	}
@@ -301,9 +400,4 @@ func SameTimeCreate(c *gin.Context) {
 		Msg:  "ok",
 		Data: &operationPb.Success{Success: true},
 	})
-
-}
-
-func SameTimeList(c *gin.Context) {
-
 }

+ 199 - 0
http/handler/event/event_health.go

@@ -0,0 +1,199 @@
+package event
+
+import (
+	"kpt-pasture/http/middleware"
+	"net/http"
+	"strconv"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+	operationPb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/operation"
+	"gitee.com/xuyiping_admin/pkg/apierr"
+	"gitee.com/xuyiping_admin/pkg/ginutil"
+	"gitee.com/xuyiping_admin/pkg/valid"
+	"github.com/gin-gonic/gin"
+)
+
+func CowDiseaseCreate(c *gin.Context) {
+	var req pasturePb.EventCowDiseaseRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.CowId, valid.Required),
+		valid.Field(&req.DiseaseAt, valid.Required),
+		valid.Field(&req.DiseaseId, valid.Required),
+		valid.Field(&req.OperationId, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := middleware.BackendOperation(c).OpsService.CowDiseaseCreate(c, &req); err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	ginutil.JSONResp(c, &operationPb.CommonOK{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &operationPb.Success{Success: true},
+	})
+}
+
+func CowDiseaseList(c *gin.Context) {
+	var req pasturePb.SearchEventCowTreatmentRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	pagination := &pasturePb.PaginationModel{
+		Page:       int32(c.GetInt(middleware.Page)),
+		PageSize:   int32(c.GetInt(middleware.PageSize)),
+		PageOffset: int32(c.GetInt(middleware.PageOffset)),
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.CowDiseaseList(c, &req, pagination)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+
+}
+
+func CowDiseaseDiagnose(c *gin.Context) {
+	var req pasturePb.CowDiagnosedRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.Id, valid.Required),
+		valid.Field(&req.CowId, valid.Required),
+		valid.Field(&req.DiagnosedResult, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := middleware.BackendOperation(c).OpsService.CowDiseaseDiagnose(c, &req); err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	ginutil.JSONResp(c, &operationPb.CommonOK{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &operationPb.Success{Success: true},
+	})
+}
+
+func DiseaseSuggestPrescription(c *gin.Context) {
+	diseaseIdStr := c.Param("id")
+	diseaseId, _ := strconv.Atoi(diseaseIdStr)
+
+	if err := valid.Validate(diseaseId, valid.Required, valid.Min(1)); err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	res, err := middleware.BackendOperation(c).OpsService.DiseaseSuggestPrescription(c, int64(diseaseId))
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	ginutil.JSONResp(c, res)
+}
+
+func CowDiseaseTreatment(c *gin.Context) {
+	var req pasturePb.CowTreatmentRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.Id, valid.Required),
+		valid.Field(&req.CowId, valid.Required),
+		valid.Field(&req.DiseaseId, valid.Required),
+		valid.Field(&req.PrescriptionId, valid.Required),
+		valid.Field(&req.TreatmentAt, valid.Required),
+		valid.Field(&req.OperationId, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := middleware.BackendOperation(c).OpsService.CowDiseaseTreatment(c, &req); err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	ginutil.JSONResp(c, &operationPb.CommonOK{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &operationPb.Success{Success: true},
+	})
+}
+
+func CowDiseaseTreatmentDetail(c *gin.Context) {
+	var req pasturePb.EventCowTreatmentDetailRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.CowId, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	pagination := &pasturePb.PaginationModel{
+		Page:       int32(c.GetInt(middleware.Page)),
+		PageSize:   int32(c.GetInt(middleware.PageSize)),
+		PageOffset: int32(c.GetInt(middleware.PageOffset)),
+	}
+
+	res, err := middleware.BackendOperation(c).OpsService.CowDiseaseTreatmentDetail(c, &req, pagination)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	ginutil.JSONResp(c, res)
+}
+
+func CowDiseaseCurable(c *gin.Context) {
+	var req pasturePb.EventCowCurableRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.Ids, valid.Required),
+		valid.Field(&req.OperationId, valid.Required),
+		valid.Field(&req.CurableAt, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := middleware.BackendOperation(c).OpsService.CowDiseaseCurable(c, &req); err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	ginutil.JSONResp(c, &operationPb.CommonOK{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &operationPb.Success{Success: true},
+	})
+}

+ 0 - 1
http/handler/event/event_vet.go

@@ -1 +0,0 @@
-package event

+ 47 - 0
http/handler/goods/drugs.go

@@ -119,3 +119,50 @@ func MedicalEquipmentCreateOrUpdate(c *gin.Context) {
 		Data: &operationPb.Success{Success: true},
 	})
 }
+
+func NeckRingList(c *gin.Context) {
+	var req pasturePb.SearchNeckRingRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	pagination := &pasturePb.PaginationModel{
+		Page:       int32(c.GetInt(middleware.Page)),
+		PageSize:   int32(c.GetInt(middleware.PageSize)),
+		PageOffset: int32(c.GetInt(middleware.PageOffset)),
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.NeckRingLogList(c, &req, pagination)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}
+
+func NeckRingCreateOrUpdate(c *gin.Context) {
+	var req pasturePb.NeckRingCreateRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.Items, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := middleware.BackendOperation(c).OpsService.NeckRingLogCreateOrUpdate(c, &req); err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	ginutil.JSONResp(c, &operationPb.CommonOK{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &operationPb.Success{Success: true},
+	})
+}

+ 158 - 0
http/handler/goods/outbound.go

@@ -0,0 +1,158 @@
+package goods
+
+import (
+	"kpt-pasture/http/middleware"
+	"net/http"
+	"strconv"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+	operationPb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/operation"
+	"gitee.com/xuyiping_admin/pkg/apierr"
+	"gitee.com/xuyiping_admin/pkg/ginutil"
+	"gitee.com/xuyiping_admin/pkg/valid"
+	"github.com/gin-gonic/gin"
+)
+
+func OutboundApply(c *gin.Context) {
+	var req pasturePb.OutboundApplyItem
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.OutType, valid.Required),
+		valid.Field(&req.Goods, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := middleware.BackendOperation(c).OpsService.OutboundApply(c, &req); err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	ginutil.JSONResp(c, &operationPb.CommonOK{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &operationPb.Success{Success: true},
+	})
+}
+
+func OutboundList(c *gin.Context) {
+	var req pasturePb.SearchOutboundApplyRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	pagination := &pasturePb.PaginationModel{
+		Page:       int32(c.GetInt(middleware.Page)),
+		PageSize:   int32(c.GetInt(middleware.PageSize)),
+		PageOffset: int32(c.GetInt(middleware.PageOffset)),
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.OutboundList(c, &req, pagination)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}
+
+func OutboundAudit(c *gin.Context) {
+	var req pasturePb.OutboundApplyAuditRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.Id, valid.Required),
+		valid.Field(&req.AuditStatus, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := middleware.BackendOperation(c).OpsService.OutboundAudit(c, &req); err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	ginutil.JSONResp(c, &operationPb.CommonOK{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &operationPb.Success{Success: true},
+	})
+}
+
+func OutboundDetail(c *gin.Context) {
+	idStr := c.Query("id")
+	id, _ := strconv.ParseInt(idStr, 10, 64)
+	if err := valid.Validate(id, valid.Required); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	res, err := middleware.BackendOperation(c).OpsService.OutboundDetail(c, id)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	ginutil.JSONResp(c, res)
+}
+
+func FrozenSemeList(c *gin.Context) {
+	var req pasturePb.FrozenSemenRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	pagination := &pasturePb.PaginationModel{
+		Page:       int32(c.GetInt(middleware.Page)),
+		PageSize:   int32(c.GetInt(middleware.PageSize)),
+		PageOffset: int32(c.GetInt(middleware.PageOffset)),
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.FrozenSemenList(c, &req, pagination)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}
+
+// FrozenSemeCreate 冻精
+func FrozenSemeCreate(c *gin.Context) {
+	var req pasturePb.SearchFrozenSemenList
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.BullId, valid.Required),
+		valid.Field(&req.Producer, valid.Required),
+		valid.Field(&req.Quantity, valid.Required),
+		valid.Field(&req.Unit, valid.Required),
+		valid.Field(&req.FrozenSemenType, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := middleware.BackendOperation(c).OpsService.FrozenSemenCreate(c, &req); err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	ginutil.JSONResp(c, &operationPb.CommonOK{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &operationPb.Success{Success: true},
+	})
+}

+ 0 - 2
http/handler/pasture/prescription.go

@@ -186,10 +186,8 @@ func CreatedOrUpdateImmunization(c *gin.Context) {
 
 	if err := valid.ValidateStruct(&req,
 		valid.Field(&req.Name, valid.Required),
-		valid.Field(&req.CowType, valid.Required),
 		valid.Field(&req.Conditions, valid.Required),
 		valid.Field(&req.Value, valid.Required),
-		valid.Field(&req.Value2, valid.Required),
 	); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
 		return

+ 204 - 0
http/handler/work/calendar.go

@@ -0,0 +1,204 @@
+package work
+
+import (
+	"kpt-pasture/http/middleware"
+	"net/http"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+	"gitee.com/xuyiping_admin/pkg/apierr"
+	"gitee.com/xuyiping_admin/pkg/ginutil"
+	"gitee.com/xuyiping_admin/pkg/valid"
+	"github.com/gin-gonic/gin"
+)
+
+func CalendarList(c *gin.Context) {
+	var req pasturePb.CalendarRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.ShowStartDay, valid.Required),
+		valid.Field(&req.ShowEndDay, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.CalendarList(c, &req)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}
+
+func CalendarTableDetail(c *gin.Context) {
+	var req pasturePb.CalendarTableRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.CalendarType, valid.Required),
+		valid.Field(&req.Start, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	pagination := &pasturePb.PaginationModel{
+		Page:       int32(c.GetInt(middleware.Page)),
+		PageSize:   int32(c.GetInt(middleware.PageSize)),
+		PageOffset: int32(c.GetInt(middleware.PageOffset)),
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.CalendarTableDetail(c, &req, pagination)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	c.JSON(http.StatusOK, res)
+}
+
+func CalendarToDoList(c *gin.Context) {
+	var req pasturePb.CalendarToDoRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+	pagination := &pasturePb.PaginationModel{
+		Page:       int32(c.GetInt(middleware.Page)),
+		PageSize:   int32(c.GetInt(middleware.PageSize)),
+		PageOffset: int32(c.GetInt(middleware.PageOffset)),
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.CalendarToDoList(c, &req, pagination)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	c.JSON(http.StatusOK, res)
+}
+
+func ImmunizationItems(c *gin.Context) {
+	var req pasturePb.ItemsRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+	pagination := &pasturePb.PaginationModel{
+		Page:       int32(c.GetInt(middleware.Page)),
+		PageSize:   int32(c.GetInt(middleware.PageSize)),
+		PageOffset: int32(c.GetInt(middleware.PageOffset)),
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.ImmunisationCowList(c, &req, pagination)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}
+
+func SameTimeCowList(c *gin.Context) {
+	var req pasturePb.ItemsRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+	pagination := &pasturePb.PaginationModel{
+		Page:       int32(c.GetInt(middleware.Page)),
+		PageSize:   int32(c.GetInt(middleware.PageSize)),
+		PageOffset: int32(c.GetInt(middleware.PageOffset)),
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.SameTimeCowList(c, &req, pagination)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}
+
+func PregnancyCheckCowList(c *gin.Context) {
+	var req pasturePb.ItemsRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+	pagination := &pasturePb.PaginationModel{
+		Page:       int32(c.GetInt(middleware.Page)),
+		PageSize:   int32(c.GetInt(middleware.PageSize)),
+		PageOffset: int32(c.GetInt(middleware.PageOffset)),
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.PregnancyCheckCowList(c, &req, pagination)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}
+
+func WeaningCowList(c *gin.Context) {
+	var req pasturePb.ItemsRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+	pagination := &pasturePb.PaginationModel{
+		Page:       int32(c.GetInt(middleware.Page)),
+		PageSize:   int32(c.GetInt(middleware.PageSize)),
+		PageOffset: int32(c.GetInt(middleware.PageOffset)),
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.WeaningCowList(c, &req, pagination)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}
+
+func MatingCowList(c *gin.Context) {
+	var req pasturePb.ItemsRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+	pagination := &pasturePb.PaginationModel{
+		Page:       int32(c.GetInt(middleware.Page)),
+		PageSize:   int32(c.GetInt(middleware.PageSize)),
+		PageOffset: int32(c.GetInt(middleware.PageOffset)),
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.MatingCowList(c, &req, pagination)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}
+
+func CalvingList(c *gin.Context) {
+	var req pasturePb.ItemsRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+	pagination := &pasturePb.PaginationModel{
+		Page:       int32(c.GetInt(middleware.Page)),
+		PageSize:   int32(c.GetInt(middleware.PageSize)),
+		PageOffset: int32(c.GetInt(middleware.PageOffset)),
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.CalvingCowList(c, &req, pagination)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}

+ 5 - 0
http/middleware/bus.go

@@ -2,6 +2,7 @@ package middleware
 
 import (
 	"kpt-pasture/dep"
+	"kpt-pasture/module/backend"
 
 	"github.com/gin-gonic/gin"
 )
@@ -18,3 +19,7 @@ func WithDependency(s *dep.HttpDependency) gin.HandlerFunc {
 func Dependency(c *gin.Context) *dep.HttpDependency {
 	return c.MustGet(KeyDep).(*dep.HttpDependency)
 }
+
+func BackendOperation(c *gin.Context) *backend.Hub {
+	return &(Dependency(c).StoreEventHub)
+}

+ 1 - 34
http/middleware/cors.go

@@ -1,14 +1,7 @@
 package middleware
 
 import (
-	"io/ioutil"
 	"net/http"
-	"path/filepath"
-	"runtime"
-
-	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
-
-	"go.uber.org/zap"
 
 	"github.com/gin-contrib/cors"
 	"github.com/gin-gonic/gin"
@@ -28,7 +21,7 @@ func CORS(configs ...cors.Config) gin.HandlerFunc {
 			//服务器支持的所有跨域请求的方法
 			c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
 			//允许跨域设置可以返回其他子段,可以自定义字段
-			c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session")
+			c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length")
 			// 允许浏览器(客户端)可以解析的头部 (重要)
 			c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers")
 			//设置缓存时间
@@ -42,32 +35,6 @@ func CORS(configs ...cors.Config) gin.HandlerFunc {
 			c.JSON(http.StatusOK, "ok!")
 			return
 		}
-
-		defer func() {
-			if err := recover(); err != nil {
-				body, _ := ioutil.ReadAll(c.Request.Body)
-
-				// 获取 panic 发生的位置
-				pc, file, line, ok := runtime.Caller(1)
-				funcName := ""
-				if ok {
-					funcName := runtime.FuncForPC(pc).Name()
-					// 去除包路径,只保留函数名
-					funcName = filepath.Base(funcName)
-					file = filepath.Base(file)
-				}
-				zaplog.Error("cors",
-					zap.Any("recover", err),
-					zap.Any("url", c.Request.URL),
-					zap.Any("method", method),
-					zap.Any("file", file),
-					zap.Any("line", line),
-					zap.Any("func", funcName),
-					zap.Any("request", string(body)),
-				)
-			}
-		}()
-
 		c.Next()
 	}
 }

+ 0 - 11
http/middleware/hub.go

@@ -1,11 +0,0 @@
-package middleware
-
-import (
-	"kpt-pasture/module/backend"
-
-	"github.com/gin-gonic/gin"
-)
-
-func BackendOperation(c *gin.Context) *backend.Hub {
-	return &(Dependency(c).StoreEventHub)
-}

+ 37 - 6
http/middleware/log.go

@@ -2,11 +2,10 @@ package middleware
 
 import (
 	"bytes"
+	"io"
 	"io/ioutil"
-	"net"
 	"net/http"
-	"net/http/httputil"
-	"os"
+	"runtime"
 	"runtime/debug"
 	"strings"
 	"time"
@@ -56,7 +55,6 @@ func GinLogger() gin.HandlerFunc {
 			zap.String("query", c.Request.URL.RawQuery),
 			zap.String("ip", c.ClientIP()),
 			zap.String("user-agent", c.Request.UserAgent()),
-			//zap.String("errors", c.Errors.ByType(gin.ErrorTypePrivate).String()),
 			zap.String("time", cost.String()),
 			zap.String("Request body", string(requestBody)),
 			zap.String("Response body", w.body.String()),
@@ -76,7 +74,7 @@ func GinRecovery(stack bool) gin.HandlerFunc {
 	return func(c *gin.Context) {
 		defer func() {
 			if err := recover(); err != nil {
-				// Check for a broken connection, as it is not really a
+				/*// Check for a broken connection, as it is not really a
 				// condition that warrants a panic stack trace.
 				var brokenPipe bool
 				if ne, ok := err.(*net.OpError); ok {
@@ -110,7 +108,40 @@ func GinRecovery(stack bool) gin.HandlerFunc {
 						zap.Any("error", err),
 						zap.String("request", string(httpRequest)),
 					)
-				}
+				}*/
+				defer func() {
+					if err = recover(); err != nil {
+						body, _ := ioutil.ReadAll(c.Request.Body)
+
+						// 获取 panic 发生的位置
+						pc, file, line, ok := runtime.Caller(2)
+						funcName := ""
+						if ok {
+							fn := runtime.FuncForPC(pc).Name()
+							// 去除包路径,只保留函数名
+							/*funcName = filepath.Base(fn)
+							file = filepath.Base(file)*/
+							parts := strings.Split(fn, "/")
+							if len(parts) > 0 {
+								lastPart := parts[len(parts)-1]
+								parts = strings.Split(lastPart, ".")
+								if len(parts) > 0 {
+									funcName = parts[len(parts)-1]
+								}
+							}
+							file = strings.TrimPrefix(file, c.Request.Context().Value(gin.ContextKey).(string)+"/") // 尝试去除项目路径前缀(可选)
+						}
+						zaplog.Error("cors",
+							zap.Any("recover", err),
+							zap.Any("url", c.Request.URL),
+							zap.Any("file", file),
+							zap.Any("line", line),
+							zap.Any("func", funcName),
+							zap.Any("request", string(body)),
+						)
+						c.Request.Body = io.NopCloser(bytes.NewBuffer(body))
+					}
+				}()
 				c.AbortWithStatus(http.StatusInternalServerError)
 			}
 		}()

+ 58 - 0
http/middleware/rate_limit.go

@@ -0,0 +1,58 @@
+package middleware
+
+import (
+	"fmt"
+	"time"
+
+	"gitee.com/xuyiping_admin/pkg/apierr"
+	"gitee.com/xuyiping_admin/pkg/xerr"
+	"github.com/gin-gonic/gin"
+	limit "github.com/yangxikun/gin-limit-by-key"
+	"golang.org/x/time/rate"
+)
+
+// RateLimit limit rate by client ip
+// limit 10 qps/client_ip and permit bursts of at most 10 tokens, and the limiter live time duration is 3 minutes
+// handle exceed rate limit request
+func RateLimit(opts ...*RateLimitOption) gin.HandlerFunc {
+	var opt *RateLimitOption
+	if len(opts) == 0 {
+		opt = defaultRateLimitOption
+	} else {
+		opt = opts[0]
+	}
+
+	return limit.NewRateLimiter(func(c *gin.Context) string {
+		return fmt.Sprintf("%s-%s", c.ClientIP(), authorization(c))
+	}, func(c *gin.Context) (*rate.Limiter, time.Duration) {
+		return rate.NewLimiter(rate.Every(opt.Interval), opt.Tokens), opt.LiveTime
+	}, func(c *gin.Context) {
+		apierr.AbortBadRequest(c, 429, xerr.Customf("request too many %s", c.ClientIP()))
+	})
+}
+
+type RateLimitOption struct {
+	Interval time.Duration
+	Tokens   int
+	LiveTime time.Duration
+}
+
+var defaultRateLimitOption = &RateLimitOption{
+	Interval: 100 * time.Millisecond,
+	Tokens:   10,
+	LiveTime: 3 * time.Minute,
+}
+
+var testRateLimitOption = &RateLimitOption{
+	Interval: 10 * time.Millisecond,
+	Tokens:   1000,
+	LiveTime: 1 * time.Minute,
+}
+
+func RateLimitOptionLow() *RateLimitOption {
+	return &RateLimitOption{
+		Interval: 1 * time.Second,
+		Tokens:   10,
+		LiveTime: 3 * time.Minute,
+	}
+}

+ 11 - 0
http/middleware/sso.go

@@ -37,6 +37,17 @@ func unauthorized(c *gin.Context) {
 	c.AbortWithStatusJSON(http.StatusUnauthorized, apierr.WithContext(c, commonPb.Error_UNAUTHORIZED))
 }
 
+func authorization(c *gin.Context) string {
+	if v := c.GetHeader("Authorization"); v != "" {
+		return v
+	}
+	if v := c.GetHeader("authorization"); v != "" {
+		return v
+	}
+
+	return ""
+}
+
 // RequireAdmin ...
 func RequireAdmin() gin.HandlerFunc {
 	return func(c *gin.Context) {

+ 11 - 0
http/route/analysis_api.go

@@ -14,5 +14,16 @@ func AnalysisAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		// pasture API 组  牧场管理
 		pastureRoute := authRouteGroup(s, "/api/v1/analysis/")
 		pastureRoute.POST("/growth/curve", analysis.GrowthCurve)
+		pastureRoute.POST("/weight/range", analysis.WeightRange)
+		pastureRoute.POST("/mating/timely", analysis.MatingTimeLy)
+		pastureRoute.POST("/pen/weight", analysis.PenWeight)
+		pastureRoute.POST("/abortion/rate", analysis.AbortionRate)
+		pastureRoute.POST("/twenty/one/pregnant/rate", analysis.TwentyOnePregnantRate)
+		pastureRoute.POST("/pregnancy/report", analysis.PregnancyReport)
+		pastureRoute.POST("/calving/report", analysis.CalvingReport)
+		pastureRoute.POST("/disease/cure/report", analysis.DiseaseCureReport)
+		pastureRoute.POST("/sale/cow/report", analysis.SaleCowReport)
+		pastureRoute.POST("/single/factor/pregnant/report", analysis.SingleFactorInfantSurvivalRate)
+		pastureRoute.POST("/multi/factor/pregnant/report", analysis.MultiFactorInfantSurvivalRate)
 	}
 }

+ 1 - 0
http/route/config_api.go

@@ -25,5 +25,6 @@ func ConfigAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		pastureRoute.GET("/system/base/config/options", config.SystemBaseConfigOptions)
 		pastureRoute.GET("/disease/type/options", config.DiseaseTypeOptions)
 		pastureRoute.GET("/disease/options", config.DiseaseOptions)
+		pastureRoute.GET("/prescription/options", config.PrescriptionOptions)
 	}
 }

+ 25 - 6
http/route/event_api.go

@@ -19,31 +19,50 @@ func EventAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		// 转群
 		eventRoute.POST("/group/transfer/list", event.GroupTransferEventList)
 		eventRoute.POST("/group/transfer/create", event.GroupTransferEventCreate)
+
 		// 体况评分
 		eventRoute.POST("/body/score/list", event.BodyScoreEventList)
 		eventRoute.POST("/body/score/create", event.BodyScoreEventCreate)
+
 		// 称重
-		eventRoute.POST("/weight/list", event.WeightEventList)
-		eventRoute.POST("/weight/create", event.WeightEventCreate)
+		eventRoute.POST("/weight/list", event.WeightList)
+		eventRoute.POST("/weight/batch", event.WeightBatch)
 
 		// 产犊
 		eventRoute.POST("/calving/list", event.CalvingEventList)
 		eventRoute.POST("/calving/create", event.CalvingEventCreate)
 		// 孕检
 		eventRoute.POST("/pregnant/check/list", event.PregnantCheckEventList)
-		eventRoute.POST("/pregnant/check/create", event.PregnantCheckEventCreate)
+		eventRoute.POST("/pregnant/check/batch", event.PregnantCheckEventCreateBatch)
 		// 配种
 		eventRoute.POST("/mating/list", event.MatingEventList)
 		eventRoute.POST("/mating/create", event.MatingCreate)
 		// 发情
 		eventRoute.POST("/estrus/list", event.EstrusEventList)
 		eventRoute.POST("/estrus/create", event.EstrusCreate)
-		// 冻精
-		eventRoute.POST("/frozen/seme/list", event.FrozenSemeList)
-		eventRoute.POST("/frozen/seme/create", event.FrozenSemeCreate)
 		// 同期
 		eventRoute.POST("/same/time/list", event.SameTimeList)
 		eventRoute.POST("/same/time/create", event.SameTimeCreate)
+		eventRoute.POST("/same/time/batch", event.SameTimeBatch)
+
+		// 流产
+		eventRoute.POST("/abortion/list", event.AbortionList)
+		eventRoute.POST("/abortion/batch", event.AbortionCreateBatch)
+
+		// 断奶
+		eventRoute.POST("/weaning/batch", event.WeaningCreateBatch)
+
+		// 发病
+		eventRoute.POST("/disease/create", event.CowDiseaseCreate)
 
+		// 疾病诊断
+		eventRoute.POST("/disease/diagnose", event.CowDiseaseDiagnose)
+		// 疾病治疗
+		eventRoute.POST("/disease/treatment", event.CowDiseaseTreatment)
+		eventRoute.GET("/disease/suggest/prescription/:id", event.DiseaseSuggestPrescription)
+		// 治疗详情
+		eventRoute.POST("/disease/treatment/details", event.CowDiseaseTreatmentDetail)
+		// 批量治愈
+		eventRoute.POST("/disease/curable/batch", event.CowDiseaseCurable)
 	}
 }

+ 15 - 0
http/route/goods_api.go

@@ -13,9 +13,24 @@ func GoodsManageAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		}
 		// goods API 组  物品管理
 		goodsRoute := authRouteGroup(s, "/api/v1/goods/")
+		// 药品相关
 		goodsRoute.POST("/drugs/list", goods.DrugsList)
 		goodsRoute.POST("/drugs/createOrUpdate", goods.DrugsCreateOrUpdate)
+		// 医疗器械相关
 		goodsRoute.POST("/medical/equipment/list", goods.MedicalEquipmentList)
 		goodsRoute.POST("/medical/equipment/createOrUpdate", goods.MedicalEquipmentCreateOrUpdate)
+		// 脖环相关
+		goodsRoute.POST("/neck/ring/list", goods.NeckRingList)
+		goodsRoute.POST("/neck/ring/createOrUpdate", goods.NeckRingCreateOrUpdate)
+		// 出库相关
+		goodsRoute.POST("/outbound/apply", goods.OutboundApply)
+		goodsRoute.POST("/outbound/list", goods.OutboundList)
+		goodsRoute.POST("/outbound/audit", goods.OutboundAudit)
+		goodsRoute.POST("/outbound/cancel", goods.OutboundAudit)
+		goodsRoute.GET("/outbound/detail/:id", goods.OutboundDetail)
+
+		// 冻精
+		goodsRoute.POST("/frozen/seme/list", goods.FrozenSemeList)
+		goodsRoute.POST("/frozen/seme/create", goods.FrozenSemeCreate)
 	}
 }

+ 36 - 0
http/route/work.go

@@ -0,0 +1,36 @@
+package route
+
+import (
+	"kpt-pasture/http/handler/event"
+	"kpt-pasture/http/handler/work"
+
+	"github.com/gin-gonic/gin"
+)
+
+func WorkOrderAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
+	return func(s *gin.Engine) {
+		for _, opt := range opts {
+			opt(s)
+		}
+		// work API 组  工作清单
+		workRoute := authRouteGroup(s, "/api/v1/work/")
+		workRoute.POST("/order/list", work.OrderList)
+		workRoute.POST("/order/createOrUpdate", work.OrderCreateOrUpdate)
+		workRoute.PUT("/order/is_show/:id", work.OrderIsShow)
+		workRoute.GET("/user/order/list/:status", work.UserOrderList)
+
+		workRoute.POST("/calendar/list", work.CalendarList)
+		workRoute.POST("/calendar/detail", work.CalendarTableDetail)
+		workRoute.POST("/calendar/todo/list", work.CalendarToDoList)
+
+		// 清单相关接口
+		workRoute.POST("/same/time/items", work.SameTimeCowList)
+		workRoute.POST("/immunization/items", work.ImmunizationItems)
+		workRoute.POST("/pregnancy/check/items", work.PregnancyCheckCowList)
+		workRoute.POST("/weaning/items", work.WeaningCowList)
+		workRoute.POST("/mating/items", work.MatingCowList)
+		workRoute.POST("/calving/items", work.CalvingList)
+		workRoute.POST("/disease/items", event.CowDiseaseList)
+
+	}
+}

+ 0 - 21
http/route/work_order.go

@@ -1,21 +0,0 @@
-package route
-
-import (
-	"kpt-pasture/http/handler/work"
-
-	"github.com/gin-gonic/gin"
-)
-
-func WorkOrderAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
-	return func(s *gin.Engine) {
-		for _, opt := range opts {
-			opt(s)
-		}
-		// goods API 组  物品管理
-		workRoute := authRouteGroup(s, "/api/v1/work/")
-		workRoute.POST("/order/list", work.OrderList)
-		workRoute.POST("/order/createOrUpdate", work.OrderCreateOrUpdate)
-		workRoute.PUT("/order/is_show/:id", work.OrderIsShow)
-		workRoute.GET("/user/order/list/:status", work.UserOrderList)
-	}
-}

+ 2 - 3
main.go

@@ -1,16 +1,15 @@
 /*
 Copyright © 2022 NAME HERE <EMAIL ADDRESS>
-
 */
 package main
 
 import (
-	"gitee.com/xuyiping_admin/pkg/logger/logrus"
 	"kpt-pasture/cmd"
+
+	"gitee.com/xuyiping_admin/pkg/logger/logrus"
 )
 
 func main() {
-	logrus.Info("kpt-pasture: is starting")
 	cmd.Execute()
 	logrus.Error("kpt-pasture: is shut down")
 }

+ 64 - 0
model/calendar.go

@@ -0,0 +1,64 @@
+package model
+
+import (
+	"fmt"
+	"time"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
+
+type Calendar struct {
+	Id           int64                       `json:"id"`
+	Name         string                      `json:"name"`
+	CalendarType pasturePb.CalendarType_Kind `json:"calendarType"`
+	Count        int32                       `json:"count"`
+	ShowDay      string                      `json:"showDay"`
+	IsShow       pasturePb.IsShow_Kind       `json:"isShow"`
+	Backup       string                      `json:"backup"`
+	CreatedAt    int64                       `json:"createdAt"`
+	UpdatedAt    int64                       `json:"updatedAt"`
+}
+
+func (w *Calendar) TableName() string {
+	return "calendar"
+}
+
+func NewCalendar(name string, calendarType pasturePb.CalendarType_Kind, count int32) *Calendar {
+	return &Calendar{
+		Name:         name,
+		Count:        count,
+		CalendarType: calendarType,
+		ShowDay:      time.Now().Format(LayoutDate2),
+		IsShow:       pasturePb.IsShow_Ok,
+	}
+}
+
+var CalendarTypeColorMap = map[pasturePb.CalendarType_Kind]string{
+	pasturePb.CalendarType_Immunisation:    "#85c1e9",
+	pasturePb.CalendarType_PG:              "#48C9B0",
+	pasturePb.CalendarType_RnGH:            "#d35400",
+	pasturePb.CalendarType_Pregnancy_Check: "#8E44AD",
+	pasturePb.CalendarType_WorkOrder:       "#5d6d7e",
+	pasturePb.CalendarType_Treatment:       "#c0392b",
+}
+
+type CalendarSlice []*Calendar
+
+func (c CalendarSlice) ToPB() []*pasturePb.Calendar {
+	res := make([]*pasturePb.Calendar, len(c))
+	for i, v := range c {
+		res[i] = &pasturePb.Calendar{
+			Id:      int32(v.Id),
+			Title:   fmt.Sprintf("%s - %d", v.Name, v.Count),
+			GroupId: v.CalendarType,
+			Count:   v.Count,
+			Start:   v.ShowDay,
+			Color:   CalendarTypeColorMap[v.CalendarType],
+			ExtendedProps: &pasturePb.ExtendedProps{
+				StartDay: v.ShowDay,
+				Backup:   v.Backup,
+			},
+		}
+	}
+	return res
+}

+ 5 - 2
model/calving_calf.go

@@ -6,11 +6,12 @@ type CalvingCalf struct {
 	Id            int64                  `json:"id"`
 	CalvingId     int64                  `json:"calvingId"`
 	CowId         int64                  `json:"cow_id"`
+	BirthAt       int64                  `json:"birthAt"`
 	MotherId      int64                  `json:"motherId"`
 	EarNumber     string                 `json:"earNumber"`
 	Sex           pasturePb.Genders_Kind `json:"sex"`
 	CowKind       pasturePb.CowKind_Kind `json:"cowKind"`
-	BrithWeight   int64                  `json:"brithWeight"`
+	BirthWeight   int64                  `json:"birthWeight"`
 	IsLive        pasturePb.IsShow_Kind  `json:"isLive"`
 	IsAdoption    pasturePb.IsShow_Kind  `json:"isAdoption"`
 	PenId         int32                  `json:"penId"`
@@ -35,8 +36,10 @@ func NewEventCalvingCalf(motherId, calvingId int64, req *pasturePb.EventCalving)
 		calvingCalfList = append(calvingCalfList, &CalvingCalf{
 			EarNumber:     v.EarNumber,
 			CalvingId:     calvingId,
+			CowId:         int64(v.CowId),
+			BirthAt:       int64(req.CalvingAt),
 			PenId:         v.PenId,
-			BrithWeight:   int64(v.Weight * 1000),
+			BirthWeight:   int64(v.Weight * 1000),
 			CurrentWeight: int64(v.Weight * 1000),
 			Sex:           v.Sex,
 			MotherId:      motherId,

+ 15 - 1
model/config_disease_type.go

@@ -34,13 +34,27 @@ func (c ConfigDiseaseTypeSlice) ToPB() []*pasturePb.SearchBaseConfigList {
 	return res
 }
 
-func (c ConfigDiseaseTypeSlice) ToPB2() []*pasturePb.ConfigOptionsList {
+func (c ConfigDiseaseTypeSlice) ToPB2(diseaseList []*Disease) []*pasturePb.ConfigOptionsList {
 	res := make([]*pasturePb.ConfigOptionsList, len(c))
 	for i, d := range c {
+		children := make([]*pasturePb.ConfigOptionsList, 0)
+		if len(diseaseList) > 0 {
+			for _, v := range diseaseList {
+				if int64(v.DiseaseType) != d.Id {
+					continue
+				}
+				children = append(children, &pasturePb.ConfigOptionsList{
+					Value:    int32(v.Id),
+					Label:    v.Name,
+					Disabled: true,
+				})
+			}
+		}
 		res[i] = &pasturePb.ConfigOptionsList{
 			Value:    int32(d.Id),
 			Label:    d.Name,
 			Disabled: true,
+			Children: children,
 		}
 	}
 	return res

+ 250 - 93
model/cow.go

@@ -2,6 +2,7 @@ package model
 
 import (
 	"fmt"
+	"kpt-pasture/util"
 	"math"
 	"time"
 
@@ -9,43 +10,47 @@ import (
 )
 
 type Cow struct {
-	Id                  int64                      `json:"id"`
-	Sex                 pasturePb.Genders_Kind     `json:"sex"`
-	NeckRingNumber      string                     `json:"neck_ring_number"`
-	EarNumber           string                     `json:"ear_number"`
-	EarOldNumber        string                     `json:"ear_old_number"`
-	PenId               int64                      `json:"pen_id"`
-	Lact                int32                      `json:"lact"`
-	DayAge              int32                      `json:"day_age"`
-	CalvingAge          int64                      `json:"calving_age"`
-	PregnancyAge        int64                      `json:"pregnancy_age"` // 怀孕天数 孕检结果有阳性更新,产犊后至0
-	AdmissionAge        int64                      `json:"admission_age"`
-	CowType             pasturePb.CowType_Kind     `json:"cow_type"`
-	BreedStatus         pasturePb.BreedStatus_Kind `json:"breed_status"`
-	CowKind             pasturePb.CowKind_Kind     `json:"cow_kind"`
-	BirthWeight         int64                      `json:"birth_weight"`
-	CurrentWeight       int64                      `json:"current_weight"`
-	SourceId            pasturePb.CowSource_Kind   `json:"source_id"`
-	FatherId            int64                      `json:"father_id"`
-	MotherId            int64                      `json:"mother_id"`
-	IsRemove            pasturePb.IsShow_Kind      `json:"is_remove"`
-	IsPregnant          pasturePb.IsShow_Kind      `json:"is_pregnant"`
-	WeaningAt           int64                      `json:"weaning_at"`
-	CalvingAt           int64                      `json:"calving_at"`
-	BirthAt             int64                      `json:"birth_at"`
-	AdmissionAt         int64                      `json:"admission_at"`
-	FirstMatingAt       int64                      `json:"first_mating_at"`
-	LastEstrusAt        int64                      `json:"last_estrus_at"`
-	LastCalvingAt       int64                      `json:"last_calving_at"`
-	LastMatingAt        int64                      `json:"last_mating_at"`
-	LastBullId          int64                      `json:"last_bull_id"`
-	LastPregnantCheckAt int64                      `json:"last_pregnant_check_at"`
-	LastDryMilkAt       int64                      `json:"last_dry_milk_at"`
-	LastSecondWeight    int64                      `json:"last_second_weight"`
-	LastSecondWeightAt  int64                      `json:"last_second_weight_at"`
-	LastWeightAt        int64                      `json:"last_weight_at"`
-	CreatedAt           int64                      `json:"created_at"`
-	UpdatedAt           int64                      `json:"updated_at"`
+	Id                  int64                          `json:"id"`
+	Sex                 pasturePb.Genders_Kind         `json:"sex"`
+	NeckRingNumber      string                         `json:"neckRingNumber"`
+	EarNumber           string                         `json:"earNumber"`
+	EarOldNumber        string                         `json:"earOldNumber"`
+	PenId               int32                          `json:"penId"`
+	Lact                int32                          `json:"lact"`
+	DayAge              int32                          `json:"dayAge"`
+	CalvingAge          int64                          `json:"calvingAge"`
+	PregnancyAge        int32                          `json:"pregnancyAge"` // 怀孕天数 孕检结果有阳性更新,产犊后至0
+	AdmissionAge        int32                          `json:"admissionAge"`
+	AbortionAge         int64                          `json:"abortionAge"` // 流产天数
+	CowType             pasturePb.CowType_Kind         `json:"cowType"`
+	BreedStatus         pasturePb.BreedStatus_Kind     `json:"breedStatus"`
+	CowKind             pasturePb.CowKind_Kind         `json:"cowKind"`
+	BirthWeight         int64                          `json:"birthWeight"`
+	CurrentWeight       int64                          `json:"currentWeight"`
+	AdmissionWeight     int64                          `json:"admissionWeight"`
+	SourceId            pasturePb.CowSource_Kind       `json:"sourceId"`
+	FatherNumber        string                         `json:"fatherNumber"`
+	MotherNumber        string                         `json:"motherNumber"`
+	AdmissionStatus     pasturePb.AdmissionStatus_Kind `json:"admissionStatus"`
+	IsPregnant          pasturePb.IsShow_Kind          `json:"isPregnant"`
+	HealthStatus        pasturePb.HealthStatus_Kind    `json:"healthStatus"`
+	WeaningAt           int64                          `json:"weaningAt"`
+	BirthAt             int64                          `json:"birthAt"`
+	AdmissionAt         int64                          `json:"admissionAt"`
+	FirstMatingAt       int64                          `json:"firstMatingAt"`
+	MatingTimes         int32                          `json:"matingTimes"`
+	LastEstrusAt        int64                          `json:"lastEstrusAt"`
+	LastCalvingAt       int64                          `json:"lastCalvingAt"`
+	LastMatingAt        int64                          `json:"lastMatingAt"`
+	LastBullNumber      string                         `json:"lastBullNumber"`
+	LastPregnantCheckAt int64                          `json:"lastPregnantCheckAt"`
+	LastDryMilkAt       int64                          `json:"lastDryMilkAt"`
+	LastSecondWeight    int64                          `json:"lastSecondWeight"`
+	LastSecondWeightAt  int64                          `json:"lastSecondWeightAt"`
+	LastAbortionAt      int64                          `json:"lastAbortionAt"`
+	LastWeightAt        int64                          `json:"lastWeightAt"`
+	CreatedAt           int64                          `json:"createdAt"`
+	UpdatedAt           int64                          `json:"updatedAt"`
 }
 
 func (c *Cow) TableName() string {
@@ -55,84 +60,196 @@ func (c *Cow) TableName() string {
 type CowSlice []*Cow
 
 func (c CowSlice) ToPB(
-	penList []*Pen,
+	penMap map[int32]*Pen,
 	cowTypeMap map[pasturePb.CowType_Kind]string,
 	breedStatusMap map[pasturePb.BreedStatus_Kind]string,
 	cowKindMap map[pasturePb.CowKind_Kind]string,
-) []*pasturePb.SearchCowList {
-	res := make([]*pasturePb.SearchCowList, len(c))
+	cowSourceMap map[pasturePb.CowSource_Kind]string,
+	admissionStatusMap map[pasturePb.AdmissionStatus_Kind]string,
+	healthStatusMap map[pasturePb.HealthStatus_Kind]string,
+) []*pasturePb.CowDetails {
+	res := make([]*pasturePb.CowDetails, len(c))
 	for i, v := range c {
 		penName := ""
-		for _, pen := range penList {
-			if v.PenId != int64(pen.Id) {
-				continue
-			}
+		if pen, ok := penMap[v.PenId]; ok {
 			penName = pen.Name
 		}
-		res[i] = &pasturePb.SearchCowList{
-			CowId:           int32(v.Id),
-			Sex:             v.Sex,
-			NeckRingNumber:  v.NeckRingNumber,
-			EarNumber:       v.EarNumber,
-			PenId:           int32(v.PenId),
-			PenName:         penName,
-			CowType:         int32(v.CowType),
-			Lact:            v.Lact,
-			CowTypeName:     cowTypeMap[v.CowType],
-			BreedStatus:     v.BreedStatus,
-			BreedStatusName: breedStatusMap[v.BreedStatus],
-			CowKind:         v.CowKind,
-			CowKindName:     cowKindMap[v.CowKind],
-			BirthAt:         int32(v.BirthAt),
-			BirthWeight:     int32(v.BirthWeight) / 1000,
-			CurrentWeight:   int32(v.CurrentWeight) / 1000,
-			LastWeightAt:    int32(v.LastWeightAt),
+
+		sex := "公"
+		if v.Sex == pasturePb.Genders_Female {
+			sex = "母"
+		}
+		lastWeightAtFormat := ""
+		if v.LastWeightAt > 0 {
+			lastWeightAtFormat = time.Unix(v.LastWeightAt, 0).Format(LayoutDate2)
+		}
+
+		isPregnantName := ""
+		if v.IsPregnant == pasturePb.IsShow_Ok {
+			isPregnantName = "已孕"
+		} else {
+			isPregnantName = "未孕"
+		}
+
+		admissionAtFormat := ""
+		if v.AdmissionAt > 0 {
+			admissionAtFormat = time.Unix(v.AdmissionAt, 0).Format(LayoutDate2)
+		}
+
+		birthAtFormat := ""
+		if v.BirthAt > 0 {
+			birthAtFormat = time.Unix(v.BirthAt, 0).Format(LayoutDate2)
+		}
+
+		weaningAtFormat := ""
+		if v.WeaningAt > 0 {
+			weaningAtFormat = time.Unix(v.WeaningAt, 0).Format(LayoutDate2)
+		}
+
+		firstMatingAtFormat := ""
+		if v.FirstMatingAt > 0 {
+			firstMatingAtFormat = time.Unix(v.FirstMatingAt, 0).Format(LayoutDate2)
+		}
+
+		lastMatingAtFormat := ""
+		if v.LastMatingAt > 0 {
+			lastMatingAtFormat = time.Unix(v.LastMatingAt, 0).Format(LayoutDate2)
+		}
+
+		lastPregnantCheckAtFormat := ""
+		if v.LastPregnantCheckAt > 0 {
+			lastPregnantCheckAtFormat = time.Unix(v.LastPregnantCheckAt, 0).Format(LayoutDate2)
+		}
+
+		lastCalvingAtFormat := ""
+		if v.LastCalvingAt > 0 {
+			lastCalvingAtFormat = time.Unix(v.LastCalvingAt, 0).Format(LayoutDate2)
+		}
+		res[i] = &pasturePb.CowDetails{
+			CowId:                     int32(v.Id),
+			Sex:                       sex,
+			NeckRingNumber:            v.NeckRingNumber,
+			PenName:                   penName,
+			Lact:                      v.Lact,
+			CowTypeName:               cowTypeMap[v.CowType],
+			BreedStatusName:           breedStatusMap[v.BreedStatus],
+			CowKindName:               cowKindMap[v.CowKind],
+			EarNumber:                 v.EarNumber,
+			BirthWeight:               float32(v.BirthWeight) / 1000,
+			CurrentWeight:             float32(v.CurrentWeight) / 1000,
+			DayAge:                    v.DayAge,
+			SourceName:                cowSourceMap[v.SourceId],
+			MontherNumber:             v.MotherNumber,
+			FatherNumber:              v.FatherNumber,
+			AdmissionStatusName:       admissionStatusMap[v.AdmissionStatus],
+			HealthStatusName:          healthStatusMap[v.HealthStatus],
+			IsPregnantName:            isPregnantName,
+			AdmissionAtFormat:         admissionAtFormat,
+			BirthAtFormat:             birthAtFormat,
+			WeaningAtFormat:           weaningAtFormat,
+			CalvingAge:                int32(v.GetCalvingAge()),
+			AbortionAge:               int32(v.AbortionAge),
+			MatingTimes:               v.MatingTimes,
+			FirstMatingAtFormat:       firstMatingAtFormat,
+			LastMatingAtFormat:        lastMatingAtFormat,
+			LastBullNumber:            v.LastBullNumber,
+			LastPregnantCheckAtFormat: lastPregnantCheckAtFormat,
+			LastWeightAtFormat:        lastWeightAtFormat,
+			LastCalvingAtFormat:       lastCalvingAtFormat,
+			//PregnancyAge:              v.PregnancyAge,
 		}
 	}
 	return res
 }
 
-func NewCow(req *pasturePb.EventEnterData) *Cow {
+func (c CowSlice) ToPB2(penMap map[int32]*Pen, penWeightSlice PenWeightSlice) []*pasturePb.CowList {
+	res := make([]*pasturePb.CowList, len(c))
+	for i, v := range c {
+		penName := ""
+		if pen, ok := penMap[v.PenId]; ok {
+			penName = pen.Name
+		}
+
+		penWeight := penWeightSlice.GetPenWeight(v.PenId)
+		lastWeightDay := util.Ceil(float64(v.LastWeightAt-v.LastSecondWeightAt) / 86400)
+		penAvgWeight := float32(0)
+		previousStageDailyWeight := float32(0)
+		cowPenAvgWeightDiffValue := float32(0)
+
+		if penWeight != nil {
+			penAvgWeight = float32(penWeight.AvgWeight) / 1000
+			cowPenAvgWeightDiffValue = float32(v.CurrentWeight-int64(penWeight.AvgWeight)) / 1000
+			if lastWeightDay > 0 {
+				previousStageDailyWeight = float32(v.CurrentWeight-v.LastSecondWeight) / 1000 / float32(lastWeightDay)
+			}
+		}
+
+		res[i] = &pasturePb.CowList{
+			CowId:                    int32(v.Id),
+			DayAge:                   v.DayAge,
+			DailyWeightGain:          float32(v.GetDayWeight()),
+			AverageDailyWeightGain:   float32(v.GetAverageDailyWeight()),
+			EarNumber:                v.EarNumber,
+			PenName:                  penName,
+			BirthAt:                  int32(v.BirthAt),
+			BirthWeight:              float32(v.BirthWeight) / 1000,
+			CurrentWeight:            float32(v.CurrentWeight) / 1000,
+			LastWeightAt:             int32(v.LastWeightAt),
+			AdmissionAge:             int32(v.AdmissionAge),
+			AdmissionWeight:          float32(v.AbortionAge) / 1000,
+			PreviousStageDailyWeight: previousStageDailyWeight,
+			PenAvgWeight:             penAvgWeight,
+			CowPenAvgWeightDiffValue: cowPenAvgWeightDiffValue,
+		}
+	}
+	return res
+}
+
+func NewCow(req *pasturePb.EventEnterRequest) *Cow {
 	var isPregnant = pasturePb.IsShow_No
-	if req.BreedStatusId == pasturePb.BreedStatus_Pregnant {
+	if req.BreedStatus == pasturePb.BreedStatus_Pregnant {
 		isPregnant = pasturePb.IsShow_Ok
 	}
-
 	return &Cow{
 		Sex:                 req.Sex,
 		EarNumber:           req.EarNumber,
-		PenId:               int64(req.PenId),
+		PenId:               req.PenId,
 		Lact:                req.Lact,
-		CowType:             req.CowTypeId,
-		BreedStatus:         req.BreedStatusId,
-		CowKind:             req.CowKindId,
-		SourceId:            req.CowSourceId,
-		FatherId:            int64(req.FatherId),
-		MotherId:            int64(req.MotherId),
-		IsRemove:            pasturePb.IsShow_Ok,
+		CowType:             req.CowType,
+		BreedStatus:         req.BreedStatus,
+		CowKind:             req.CowKind,
+		SourceId:            req.CowSource,
+		FatherNumber:        req.FatherNumber,
+		MotherNumber:        req.MotherNumber,
+		AdmissionStatus:     pasturePb.AdmissionStatus_Admission,
+		HealthStatus:        pasturePb.HealthStatus_Health,
 		IsPregnant:          isPregnant,
 		WeaningAt:           int64(req.WeaningAt),
 		BirthAt:             int64(req.BirthAt),
+		AdmissionWeight:     int64(req.Weight * 1000),
 		FirstMatingAt:       int64(req.MatingAt),
 		LastMatingAt:        int64(req.MatingAt),
 		LastPregnantCheckAt: int64(req.PregnancyCheckAt),
+		AdmissionAt:         time.Now().Unix(),
 	}
 }
 
-func NewCalfCow(motherId, fatherId int64, calf *CalvingCalf) *Cow {
+func NewCalfCow(motherId int64, fatherNumber string, calf *CalvingCalf) *Cow {
 	return &Cow{
-		Sex:         calf.Sex,
-		EarNumber:   calf.EarNumber,
-		PenId:       int64(calf.PenId),
-		CowType:     pasturePb.CowType_Lactating_Calf, // 哺乳犊牛
-		BreedStatus: pasturePb.BreedStatus_UnBreed,    // 未配
-		CowKind:     calf.CowKind,                     // 牛只品种
-		BirthWeight: calf.BrithWeight,
-		SourceId:    pasturePb.CowSource_Calving, // 产犊方式
-		FatherId:    fatherId,
-		MotherId:    motherId,
-		IsRemove:    pasturePb.IsShow_Ok,
-		IsPregnant:  pasturePb.IsShow_No,
+		Sex:             calf.Sex,
+		EarNumber:       calf.EarNumber,
+		PenId:           calf.PenId,
+		CowType:         pasturePb.CowType_Lactating_Calf, // 哺乳犊牛
+		BreedStatus:     pasturePb.BreedStatus_UnBreed,    // 未配
+		CowKind:         calf.CowKind,                     // 牛只品种
+		BirthWeight:     calf.BirthWeight,
+		BirthAt:         calf.BirthAt,
+		SourceId:        pasturePb.CowSource_Calving, // 产犊方式
+		FatherNumber:    fatherNumber,
+		MotherNumber:    fmt.Sprintf("%d", motherId),
+		AdmissionStatus: pasturePb.AdmissionStatus_Admission,
+		IsPregnant:      pasturePb.IsShow_No,
+		AdmissionAt:     calf.BirthAt,
 	}
 }
 
@@ -141,6 +258,7 @@ type BarCowStruct struct {
 	TypeId pasturePb.CowType_Kind `json:"type_id"`
 }
 
+// BarCowStructSlice 首页牛群结构
 type BarCowStructSlice []*BarCowStruct
 
 func (b BarCowStructSlice) ToPB(cowTypeMap map[pasturePb.CowType_Kind]string, count int32) []*pasturePb.BarCowStruct {
@@ -162,15 +280,17 @@ func (c *Cow) GetDayAge() int32 {
 
 // GetCalvingAge 产后天数
 func (c *Cow) GetCalvingAge() int64 {
-	if c.CalvingAt <= 0 {
+	if c.LastMatingAt <= 0 {
 		return 0
 	}
-	return int64(math.Floor(float64(time.Now().Unix()-c.CalvingAt) / 86400))
+	return int64(math.Floor(float64(time.Now().Unix()-c.LastMatingAt) / 86400))
 }
 
 // GetDaysPregnant 怀孕天数
 func (c *Cow) GetDaysPregnant() int32 {
-	if c.BreedStatus == pasturePb.BreedStatus_Pregnant && c.IsRemove == pasturePb.IsShow_No && c.IsPregnant == pasturePb.IsShow_Ok {
+	if c.BreedStatus == pasturePb.BreedStatus_Pregnant &&
+		c.AdmissionStatus == pasturePb.AdmissionStatus_Admission &&
+		c.IsPregnant == pasturePb.IsShow_Ok {
 		return int32(math.Floor(float64(time.Now().Unix()-c.LastMatingAt) / 86400))
 	}
 	return 0
@@ -178,7 +298,7 @@ func (c *Cow) GetDaysPregnant() int32 {
 
 // GetLactationDays 泌乳天数
 func (c *Cow) GetLactationDays() int32 {
-	if c.BreedStatus == pasturePb.BreedStatus_Calving && c.IsRemove == pasturePb.IsShow_Ok {
+	if c.BreedStatus == pasturePb.BreedStatus_Calving && c.AdmissionStatus == pasturePb.AdmissionStatus_Admission {
 		return int32(math.Floor(float64(time.Now().Unix()-c.LastCalvingAt) / 86400))
 	}
 	return 0
@@ -186,7 +306,7 @@ func (c *Cow) GetLactationDays() int32 {
 
 // GetAdmissionAge 入场天数
 func (c *Cow) GetAdmissionAge() int32 {
-	if c.AdmissionAt > 0 && c.IsRemove == pasturePb.IsShow_Ok {
+	if c.AdmissionAt > 0 && c.AdmissionStatus == pasturePb.AdmissionStatus_Admission {
 		return int32(math.Floor(float64(time.Now().Unix()-c.AdmissionAt) / 86400))
 	}
 	return 0
@@ -199,7 +319,8 @@ func (c *Cow) GetDayWeight() float64 {
 		if days <= 0 {
 			return 0
 		}
-		return math.Round(1.0 * float64(c.CurrentWeight-c.LastSecondWeight) / float64(days))
+		dayWeight := math.Round(1.0 * float64(c.CurrentWeight-c.LastSecondWeight) / float64(days))
+		return dayWeight / 1000
 	}
 	return 0
 }
@@ -212,7 +333,43 @@ func (c *Cow) GetAverageDailyWeight() float64 {
 			return 0
 		}
 		dailyWeight := math.Round(1.0 * float64(c.CurrentWeight-c.BirthWeight) / float64(days))
-		return dailyWeight
+		return dailyWeight / 1000
+	}
+	return 0
+}
+
+func (c *Cow) GetAbortionAge() int32 {
+	if c.LastAbortionAt > 0 && c.AdmissionStatus == pasturePb.AdmissionStatus_Admission {
+		return int32(math.Floor(float64(time.Now().Unix()-c.LastAbortionAt) / 86400))
 	}
 	return 0
+
+}
+
+type CowWeightRange struct {
+	WeightRange string `json:"weight_range"`
+	Count       int32  `json:"count"`
+}
+
+func (c CowSlice) WeightRangeToPB(penMap map[int32]*Pen) []*pasturePb.CowList {
+	res := make([]*pasturePb.CowList, len(c))
+	for i, v := range c {
+		penName := ""
+		if pen, ok := penMap[v.PenId]; ok {
+			penName = pen.Name
+		}
+		res[i] = &pasturePb.CowList{
+			CowId:                  int32(v.Id),
+			DayAge:                 v.DayAge,
+			DailyWeightGain:        float32(v.GetDayWeight()),
+			AverageDailyWeightGain: float32(v.GetAverageDailyWeight()),
+			EarNumber:              v.EarNumber,
+			PenName:                penName,
+			BirthAt:                int32(v.BirthAt),
+			BirthWeight:            float32(v.BirthWeight) / 1000,
+			CurrentWeight:          float32(v.CurrentWeight) / 1000,
+			LastWeightAt:           int32(v.LastWeightAt),
+		}
+	}
+	return res
 }

+ 58 - 0
model/cow_active_habit.go

@@ -0,0 +1,58 @@
+package model
+
+import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+
+type CowActiveHabit struct {
+	Id                       int64                 `json:"id"`
+	CowId                    int64                 `json:"cowId"`
+	NeckRingNumber           string                `json:"neckRingNumber"`
+	Lact                     int32                 `json:"lact"`
+	FrameId                  int32                 `json:"frameId"`
+	Rumina                   int32                 `json:"rumina"`
+	Intake                   int32                 `json:"intake"`
+	Inactive                 int32                 `json:"inactive"`
+	Gasp                     int32                 `json:"gasp"`
+	Other                    int32                 `json:"other"`
+	High                     int32                 `json:"high"`
+	Active                   int32                 `json:"active"`
+	Voltage                  int32                 `json:"voltage"`
+	Version                  int32                 `json:"version"`
+	FilterHigh               int32                 `json:"filterHigh"`
+	FilterRumina             int32                 `json:"filterRumina"`
+	FilterChew               int32                 `json:"filterChew"`
+	WeekHigh                 int32                 `json:"weekHigh"`
+	WeekAvgHighHabit         int32                 `json:"weekAvgHighHabit"`
+	WeekAvgRuminaHabit       int32                 `json:"WeekAvgRuminaHabit"`
+	WeekAvgIntakeHabit       int32                 `json:"weekAvgIntakeHabit"`
+	WeekAvgChewHabit         int32                 `json:"weekAvgChewHabit"`
+	WeekAvgInactiveHabit     int32                 `json:"weekAvgInactiveHabit"`
+	WeekAvgOtherHabit        int32                 `json:"weekAvgOtherHabit"`
+	ChangeHigh               int32                 `json:"changeHigh"`
+	ChangeRumina             int32                 `json:"changeRumina"`
+	ChangeChew               int32                 `json:"changeChew"`
+	ChangeAdjust             int32                 `json:"changeAdjust"`
+	ChangeFilter             int32                 `json:"changeFilter"`
+	RuminaFilter             int32                 `json:"ruminaFilter"`
+	ChewFilter               int32                 `json:"chewFilter"`
+	FilterCorrect            int32                 `json:"filterCorrect"`
+	SumRumina                int32                 `json:"sumRumina"`
+	SumIntake                int32                 `json:"sumIntake"`
+	SumInactive              int32                 `json:"sumInactive"`
+	SumAct                   int32                 `json:"sumAct"`
+	SumRuminaBeforeThreeDays int32                 `json:"sumRuminaBeforeThreeDays"`
+	SumIntakeBeforeThreeDays int32                 `json:"sumIntakeBeforeThreeDays"`
+	MinHigh                  int32                 `json:"minHigh"`
+	MaxHigh                  int32                 `json:"maxHigh"`
+	MinChew                  int32                 `json:"minChew"`
+	Score                    int32                 `json:"score"`
+	IsMaxTime                pasturePb.IsShow_Kind `json:"isMaxTime"`
+	ReceiveNumber            int32                 `json:"receiveNumber"`
+	RecodeCount              int32                 `json:"recodeCount"`
+	ActiveTime               string                `json:"activeTime"`
+	CreatedAt                int64                 `json:"createdAt"`
+	UpdatedAt                int64                 `json:"updatedAt"`
+}
+
+func (c *CowActiveHabit) TableName() string {
+	return "cow_active_habit"
+}

+ 45 - 0
model/cow_pregnant.go

@@ -0,0 +1,45 @@
+package model
+
+import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+
+type CowPregnant struct {
+	Id           int64                  `json:"id"`
+	CowId        int64                  `json:"cowId"`
+	Lact         int32                  `json:"lact"`
+	DayAge       int32                  `json:"dayAge"`
+	PenId        int32                  `json:"penId"`
+	AdmissionAge int32                  `json:"admissionAge"`
+	CowType      pasturePb.CowType_Kind `json:"cowType"`
+	PregnancyAge int32                  `json:"pregnancyAge"`
+	CreatedAt    int64                  `json:"createdAt"`
+	UpdatedAt    int64                  `json:"updatedAt"`
+}
+
+func (c *CowPregnant) TableName() string {
+	return "cow_pregnant"
+}
+
+func NewCowPregnant(cow *Cow) *CowPregnant {
+	return &CowPregnant{
+		CowId:        cow.Id,
+		Lact:         cow.Lact,
+		DayAge:       cow.DayAge,
+		PenId:        cow.PenId,
+		AdmissionAge: cow.AdmissionAge,
+		CowType:      cow.CowType,
+		PregnancyAge: cow.PregnancyAge,
+	}
+}
+
+func NewCowPregnantList(cow []*Cow) []*CowPregnant {
+	res := make([]*CowPregnant, len(cow))
+	for i, v := range cow {
+		res[i] = NewCowPregnant(v)
+	}
+	return res
+}
+
+type CowPregnantMonth struct {
+	Month    string `json:"month"`
+	CowCount int32  `json:"cowCount"`
+}

+ 35 - 0
model/cow_same_time.go

@@ -0,0 +1,35 @@
+package model
+
+import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+
+type CowSameTime struct {
+	Id             int64                         `json:"id"`
+	SameTimeId     int64                         `json:"sameTimeId"`
+	CowId          int64                         `json:"cowId"`
+	Lact           int32                         `json:"lact"`
+	SameTimeStatus pasturePb.SameTimeStatus_Kind `json:"sameTimeStatus"`
+	CreatedAt      int64                         `json:"createdAt"`
+	UpdatedAt      int64                         `json:"updatedAt"`
+}
+
+func (c *CowSameTime) TableName() string {
+	return "cow_same_time"
+}
+
+func NewCowSameTime(cow *Cow, sameTime *SameTime) *CowSameTime {
+	return &CowSameTime{
+		SameTimeId:     sameTime.Id,
+		CowId:          cow.Id,
+		Lact:           cow.Lact,
+		SameTimeStatus: pasturePb.SameTimeStatus_No_Start,
+	}
+}
+
+func NewCowSameTimeList(cowList []*Cow, sameTime *SameTime) []*CowSameTime {
+	sameTimeCowList := make([]*CowSameTime, 0)
+	for _, cow := range cowList {
+		sameTimeCowList = append(sameTimeCowList, NewCowSameTime(cow, sameTime))
+
+	}
+	return sameTimeCowList
+}

+ 0 - 38
model/cow_weight.go

@@ -1,38 +0,0 @@
-package model
-
-import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
-
-type EventWeight struct {
-	ID            int64  `json:"id"`
-	CowId         int64  `json:"cow_id"`
-	EarNumber     string `json:"ear_number"`
-	DayAge        int32  `json:"day_age"`
-	LactationDay  int64  `json:"lactation_day"`
-	PenId         int32  `json:"pen_id"`
-	Lact          int32  `json:"lact"`
-	Weight        int32  `json:"weight"`
-	WeightAt      int64  `json:"weight_at"`
-	Remarks       string `json:"remarks"`
-	OperationId   int32  `json:"operation_id"`
-	StaffMemberId int32  `json:"staff_member_id"`
-	CreatedAt     int64  `json:"created_at"`
-	UpdatedAt     int64  `json:"updated_at"`
-}
-
-func (c *EventWeight) TableName() string {
-	return "event_weight"
-}
-
-func NewEventWeight(cow *Cow, systemUser *SystemUser, weight int32, req *pasturePb.EventWeight) *EventWeight {
-	return &EventWeight{
-		CowId:         cow.Id,
-		EarNumber:     cow.EarNumber,
-		Weight:        weight,
-		Lact:          cow.Lact,
-		DayAge:        cow.GetDayAge(),
-		WeightAt:      int64(req.WeightAt),
-		Remarks:       req.Remarks,
-		StaffMemberId: req.StaffMemberId,
-		OperationId:   int32(systemUser.Id),
-	}
-}

+ 22 - 0
model/crontab_log.go

@@ -0,0 +1,22 @@
+package model
+
+import "time"
+
+type CronLog struct {
+	Id        int64  `json:"id"`
+	Name      string `json:"name"`
+	Date      string `json:"date"`
+	CreatedAt int64  `json:"created_at"`
+	UpdatedAt int64  `json:"updated_at"`
+}
+
+func (c CronLog) TableName() string {
+	return "cron_log"
+}
+
+func NewCronLog(name string) *CronLog {
+	return &CronLog{
+		Name: name,
+		Date: time.Now().Format(LayoutDate2),
+	}
+}

+ 13 - 12
model/disease.go

@@ -7,15 +7,16 @@ import (
 )
 
 type Disease struct {
-	Id          int64                 `json:"id"`
-	Name        string                `json:"name"`
-	Symptoms    string                `json:"symptoms"`
-	DiseaseType int32                 `json:"disease_type"`
-	IsShow      pasturePb.IsShow_Kind `json:"is_show"`
-	Remarks     string                `json:"remarks"`
-	OperationId int64                 `json:"operation_id"`
-	CreatedAt   int64                 `json:"created_at"`
-	UpdatedAt   int64                 `json:"updated_at"`
+	Id              int64                 `json:"id"`
+	Name            string                `json:"name"`
+	Symptoms        string                `json:"symptoms"`
+	DiseaseType     int32                 `json:"disease_type"`
+	DiseaseTypeName string                `json:"disease_type_name"`
+	IsShow          pasturePb.IsShow_Kind `json:"is_show"`
+	Remarks         string                `json:"remarks"`
+	OperationId     int64                 `json:"operation_id"`
+	CreatedAt       int64                 `json:"created_at"`
+	UpdatedAt       int64                 `json:"updated_at"`
 }
 
 func (d *Disease) TableName() string {
@@ -59,9 +60,9 @@ func (d DiseaseSlice) ToPB(user []*SystemUser, diseaseTypeList []*ConfigDiseaseT
 	return res
 }
 
-func (c DiseaseSlice) ToPB2() []*pasturePb.ConfigOptionsList {
-	res := make([]*pasturePb.ConfigOptionsList, len(c))
-	for i, d := range c {
+func (d DiseaseSlice) ToPB2() []*pasturePb.ConfigOptionsList {
+	res := make([]*pasturePb.ConfigOptionsList, len(d))
+	for i, d := range d {
 		res[i] = &pasturePb.ConfigOptionsList{
 			Value:    int32(d.Id),
 			Label:    d.Name,

+ 28 - 23
model/drugs.go

@@ -5,15 +5,18 @@ import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 type Drugs struct {
 	Id              int64                       `json:"id"`
 	Name            string                      `json:"name"`
-	CategoryId      pasturePb.DrugCategory_Kind `json:"category_id"`
+	CategoryId      pasturePb.DrugCategory_Kind `json:"categoryId"`
+	CategoryName    string                      `json:"categoryName"`
 	Producer        string                      `json:"producer"`
-	BatchNumber     string                      `json:"batch_number"`
-	ProductionAt    int64                       `json:"production_at"`
-	ExpirationAt    int64                       `json:"expiration_at"`
+	BatchNumber     string                      `json:"batchNumber"`
+	ProductionAt    int64                       `json:"productionAt"`
+	ExpirationAt    int64                       `json:"expirationAt"`
 	Unit            pasturePb.Unit_Kind         `json:"unit"`
+	UnitName        string                      `json:"unitName"`
 	Specs           string                      `json:"specs"`
 	Inventory       int32                       `json:"inventory"`
 	UsageMethod     pasturePb.DrugUsage_Kind    `json:"usage_method"`
+	UsageMethodName string                      `json:"usageMethodName"`
 	Price           int32                       `json:"price"`
 	MilkExpiredDays int32                       `json:"milk_expired_days"`
 	MeatExpiredDays int32                       `json:"meat_expired_days"`
@@ -30,44 +33,46 @@ func (d *Drugs) TableName() string {
 
 func NewDrugs(req *pasturePb.SearchDrugsList, currentUser *SystemUser) *Drugs {
 	return &Drugs{
-		Name:          req.Name,
-		CategoryId:    req.CategoryId,
-		Producer:      req.Producer,
-		BatchNumber:   req.BatchNumber,
-		ProductionAt:  int64(req.ProductionAt),
-		ExpirationAt:  int64(req.ExpirationAt),
-		Unit:          req.Unit,
-		Specs:         req.Specs,
-		Inventory:     req.Inventory,
-		UsageMethod:   req.Usage,
-		Price:         int32(req.Price * 100),
-		Remarks:       req.Remarks,
-		OperationId:   int32(currentUser.Id),
-		OperationName: currentUser.Name,
+		Name:            req.Name,
+		CategoryId:      req.CategoryId,
+		CategoryName:    req.CategoryName,
+		Producer:        req.Producer,
+		BatchNumber:     req.BatchNumber,
+		ProductionAt:    int64(req.ProductionAt),
+		ExpirationAt:    int64(req.ExpirationAt),
+		Unit:            req.Unit,
+		UnitName:        req.UnitName,
+		Specs:           req.Specs,
+		Inventory:       req.Inventory,
+		UsageMethod:     req.Usage,
+		UsageMethodName: req.UsageName,
+		Price:           int32(req.Price * 100),
+		Remarks:         req.Remarks,
+		OperationId:     int32(currentUser.Id),
+		OperationName:   currentUser.Name,
 	}
 }
 
 type DrugsSlice []*Drugs
 
-func (d DrugsSlice) ToPB(drugsCategoryMap map[pasturePb.DrugCategory_Kind]string,
-	unitMap map[pasturePb.Unit_Kind]string, drugUsageMap map[pasturePb.DrugUsage_Kind]string) []*pasturePb.SearchDrugsList {
+func (d DrugsSlice) ToPB() []*pasturePb.SearchDrugsList {
 	res := make([]*pasturePb.SearchDrugsList, len(d))
 	for i, v := range d {
 		res[i] = &pasturePb.SearchDrugsList{
 			Id:              int32(v.Id),
 			Name:            v.Name,
 			CategoryId:      v.CategoryId,
-			CategoryName:    drugsCategoryMap[v.CategoryId],
+			CategoryName:    v.CategoryName,
 			Producer:        v.Producer,
 			BatchNumber:     v.BatchNumber,
 			ProductionAt:    int32(v.ProductionAt),
 			ExpirationAt:    int32(v.ExpirationAt),
 			Unit:            v.Unit,
-			UnitName:        unitMap[v.Unit],
+			UnitName:        v.UnitName,
 			Specs:           v.Specs,
 			Inventory:       v.Inventory,
 			Usage:           v.UsageMethod,
-			UsageName:       drugUsageMap[v.UsageMethod],
+			UsageName:       v.UsageMethodName,
 			Price:           float32(v.Price) / 100,
 			MeatExpiredDays: v.MeatExpiredDays,
 			MilkExpiredDays: v.MilkExpiredDays,

+ 74 - 0
model/event_abortion.go

@@ -0,0 +1,74 @@
+package model
+
+import (
+	"strings"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
+
+type EventAbortion struct {
+	Id                  int64                          `json:"id"`
+	CowId               int64                          `json:"cowId"`
+	Lact                int32                          `json:"lact"`
+	CowType             pasturePb.CowType_Kind         `json:"cowType"`
+	DayAge              int32                          `json:"dayAge"`
+	PregnantAge         int32                          `json:"pregnantAge"`
+	AbortionAt          int64                          `json:"abortionAt"`
+	IsAfterbirth        pasturePb.IsShow_Kind          `json:"isAfterbirth"`
+	Photos              string                         `json:"photos"`
+	AbortionReasons     pasturePb.AbortionReasons_Kind `json:"abortionReasons"`
+	AbortionReasonsName string                         `json:"abortionReasonsName"`
+	Remarks             string                         `json:"remarks"`
+	OperationId         int64                          `json:"operationId"`
+	OperationName       string                         `json:"operationName"`
+	CreatedAt           int64                          `json:"createdAt"`
+	UpdatedAt           int64                          `json:"updatedAt"`
+}
+
+func (e *EventAbortion) TableName() string {
+	return "event_abortion"
+}
+
+func NewEventAbortion(cow *Cow, req *pasturePb.EventAbortionRequest, abortionReasonMap map[pasturePb.AbortionReasons_Kind]string) *EventAbortion {
+	return &EventAbortion{
+		CowId:               int64(req.CowId),
+		Lact:                cow.Lact,
+		CowType:             cow.CowType,
+		PregnantAge:         cow.GetDaysPregnant(),
+		DayAge:              cow.DayAge,
+		AbortionAt:          int64(req.AbortionAt),
+		IsAfterbirth:        req.IsAfterbirth,
+		Photos:              strings.Join(req.Photos, ","),
+		AbortionReasons:     req.AbortionReasons,
+		AbortionReasonsName: abortionReasonMap[req.AbortionReasons],
+		Remarks:             req.Remarks,
+		OperationId:         int64(req.OperationId),
+		OperationName:       req.OperationName,
+	}
+}
+
+type AbortionSlice []*EventAbortion
+
+func (a AbortionSlice) ToPB() []*pasturePb.EventAbortionRequest {
+	res := make([]*pasturePb.EventAbortionRequest, len(a))
+	for i, v := range a {
+		res[i] = &pasturePb.EventAbortionRequest{
+			Id:                  int32(v.Id),
+			CowId:               int32(v.CowId),
+			DayAge:              v.DayAge,
+			Lact:                v.Lact,
+			AbortionAt:          int32(v.AbortionAt),
+			IsAfterbirth:        v.IsAfterbirth,
+			Photos:              strings.Split(v.Photos, ","),
+			AbortionReasons:     v.AbortionReasons,
+			AbortionReasonsName: v.AbortionReasonsName,
+			PregnancyAge:        v.PregnantAge,
+			Remarks:             v.Remarks,
+			OperationId:         int32(v.OperationId),
+			OperationName:       v.OperationName,
+			CreatedAt:           int32(v.CreatedAt),
+			UpdatedAt:           int32(v.UpdatedAt),
+		}
+	}
+	return res
+}

+ 15 - 11
model/event_body_score.go

@@ -4,24 +4,26 @@ import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 
 type EventBodyScore struct {
 	Id            int64  `json:"id"`
-	CowId         int64  `json:"cow_id"`
-	EarNumber     string `json:"ear_number"`
+	CowId         int64  `json:"cowId"`
+	EarNumber     string `json:"earNumber"`
 	Score         int32  `json:"score"`
 	Lact          int32  `json:"lact"`
-	DayAge        int32  `json:"day_age"`
-	ScoreAt       int64  `json:"score_at"`
+	DayAge        int32  `json:"dayAge"`
+	ScoreAt       int64  `json:"scoreAt"`
 	Remarks       string `json:"remarks"`
-	StaffMemberId int64  `json:"staff_member_id"`
-	OperationId   int64  `json:"operation_id"`
-	CreatedAt     int64  `json:"created_at"`
-	UpdatedAt     int64  `json:"updated_at"`
+	MessageId     int64  `json:"messageId"`
+	MessageName   string `json:"messageName"`
+	OperationId   int64  `json:"operationId"`
+	OperationName string `json:"operationName"`
+	CreatedAt     int64  `json:"createdAt"`
+	UpdatedAt     int64  `json:"updatedAt"`
 }
 
 func (e *EventBodyScore) TableName() string {
 	return "event_body_score"
 }
 
-func NewEventBodyScore(cow *Cow, operationId int64, req *pasturePb.BodyScoreEventRequest) *EventBodyScore {
+func NewEventBodyScore(cow *Cow, currentSystemUser *SystemUser, req *pasturePb.BodyScoreEventRequest) *EventBodyScore {
 	return &EventBodyScore{
 		CowId:         cow.Id,
 		EarNumber:     cow.EarNumber,
@@ -30,7 +32,9 @@ func NewEventBodyScore(cow *Cow, operationId int64, req *pasturePb.BodyScoreEven
 		DayAge:        cow.GetDayAge(),
 		ScoreAt:       int64(req.ScoreAt),
 		Remarks:       req.Remarks,
-		StaffMemberId: int64(req.StaffMemberId),
-		OperationId:   operationId,
+		MessageId:     currentSystemUser.Id,
+		MessageName:   currentSystemUser.Name,
+		OperationId:   int64(req.OperationId),
+		OperationName: req.OperationName,
 	}
 }

+ 92 - 44
model/event_calving.go

@@ -1,21 +1,32 @@
 package model
 
-import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+import (
+	"kpt-pasture/util"
+	"time"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
 
 type EventCalving struct {
-	Id             int64                         `json:"int_64"`
-	CowId          int64                         `json:"cow_id"`
-	EarNumber      string                        `json:"ear_number"`
+	Id             int64                         `json:"id"`
+	CowId          int64                         `json:"cowId"`
+	CowType        pasturePb.CowType_Kind        `json:"cowType"`
+	CowKind        pasturePb.CowKind_Kind        `json:"cowKind"`
+	EarNumber      string                        `json:"earNumber"`
 	Lact           int32                         `json:"lact"`
-	DayAge         int32                         `json:"day_age"`
-	PenId          int32                         `json:"pen_id"`
-	CalvingAt      int64                         `json:"calving_at"`
-	ChildNumber    int8                          `json:"child_number"`
-	BullId         int64                         `json:"bull_id"`
-	DaysPregnant   int32                         `json:"days_pregnant"`
-	CalvingLevel   pasturePb.CalvingLevel_Kind   `json:"calving_level"`
-	StaffMemberId  int64                         `json:"staff_member_id"`
-	DystociaReason pasturePb.DystociaReason_Kind `json:"dystocia_reason"`
+	DayAge         int32                         `json:"dayAge"`
+	PlanDay        int64                         `json:"planDay"`
+	RealityDay     int64                         `json:"realityDay"`
+	EndDay         int64                         `json:"endDay"`
+	Status         pasturePb.IsShow_Kind         `json:"status"`
+	PenId          int32                         `json:"penId"`
+	ChildNumber    int8                          `json:"childNumber"`
+	BullNumber     string                        `json:"bullNumber"`
+	PregnancyAge   int64                         `json:"pregnancyAge"`
+	CalvingLevel   pasturePb.CalvingLevel_Kind   `json:"calvingLevel"`
+	OperationId    int64                         `json:"operationId"`
+	OperationName  string                        `json:"operationName"`
+	DystociaReason pasturePb.DystociaReason_Kind `json:"dystociaReason"`
 	Remarks        string                        `json:"remarks"`
 	CreatedAt      int64                         `json:"created_at"`
 	UpdatedAt      int64                         `json:"updated_at"`
@@ -25,24 +36,28 @@ func (e *EventCalving) TableName() string {
 	return "event_calving"
 }
 
-func NewEventCalving(cow *Cow, req *pasturePb.EventCalving) *EventCalving {
+func NewEventCalving(cow *Cow) *EventCalving {
 	return &EventCalving{
-		CowId:          cow.Id,
-		EarNumber:      cow.EarNumber,
-		Lact:           cow.Lact,
-		DayAge:         cow.GetDayAge(),
-		PenId:          int32(cow.PenId),
-		CalvingAt:      int64(req.CalvingAt),
-		BullId:         cow.LastBullId,
-		CalvingLevel:   req.CalvingLevel,
-		DystociaReason: req.DystociaReason,
-		DaysPregnant:   cow.GetDaysPregnant(),
-		ChildNumber:    int8(req.ChildNumber),
-		Remarks:        req.Remarks,
-		StaffMemberId:  int64(req.StaffMemberId),
+		CowId:      cow.Id,
+		CowKind:    cow.CowKind,
+		CowType:    cow.CowType,
+		EarNumber:  cow.EarNumber,
+		PenId:      cow.PenId,
+		BullNumber: cow.LastBullNumber,
+		Status:     pasturePb.IsShow_No,
+		PlanDay:    util.TimeParseLocalUnix(time.Now().Format(LayoutTime)),
+		EndDay:     util.TimeParseLocalEndUnix(time.Now().Format(LayoutTime)),
 	}
 }
 
+func NewEventCalvingList(cowList []*Cow) []*EventCalving {
+	eventCalvingList := make([]*EventCalving, 0)
+	for _, cow := range cowList {
+		eventCalvingList = append(eventCalvingList, NewEventCalving(cow))
+	}
+	return eventCalvingList
+}
+
 type EventCalvingList struct {
 	EventCalving
 	PenName         string `json:"pen_name"`
@@ -62,7 +77,7 @@ func (e EventCalvingListSlice) ToPB(req []*CalvingCalf) []*pasturePb.LavingList
 			CalfItemList = append(CalfItemList, &pasturePb.CalfItem{
 				EarNumber:  v.EarNumber,
 				Sex:        v.Sex,
-				Weight:     float32(v.BrithWeight) / 1000,
+				Weight:     float32(v.BirthWeight) / 1000,
 				IsAdoption: v.IsAdoption,
 				IsLive:     v.IsLive,
 				CreatedAt:  int32(v.CreatedAt),
@@ -74,23 +89,56 @@ func (e EventCalvingListSlice) ToPB(req []*CalvingCalf) []*pasturePb.LavingList
 			})
 		}
 		list = append(list, &pasturePb.LavingList{
-			Id:              int32(item.Id),
-			CowId:           int32(item.CowId),
-			Lact:            item.Lact,
-			PenId:           item.PenId,
-			PenName:         item.PenName,
-			CalvingAt:       int32(item.CalvingAt),
-			ChildNumber:     int32(item.ChildNumber),
-			DaysPregnant:    item.DaysPregnant,
-			StaffMemberId:   int32(item.StaffMemberId),
-			StaffMemberName: item.StaffMemberName,
-			CalvingLevel:    item.CalvingLevel,
-			Remarks:         item.Remarks,
-			CreatedAt:       int32(item.CreatedAt),
-			UpdatedAt:       int32(item.UpdatedAt),
-			DystociaReason:  item.DystociaReason,
-			CalfItemList:    CalfItemList,
+			Id:             int32(item.Id),
+			CowId:          int32(item.CowId),
+			Lact:           item.Lact,
+			PenId:          item.PenId,
+			PenName:        item.PenName,
+			CalvingAt:      int32(item.PlanDay),
+			ChildNumber:    int32(item.ChildNumber),
+			DaysPregnant:   int32(item.PregnancyAge),
+			OperationId:    int32(item.OperationId),
+			OperationName:  item.OperationName,
+			CalvingLevel:   item.CalvingLevel,
+			Remarks:        item.Remarks,
+			CreatedAt:      int32(item.CreatedAt),
+			UpdatedAt:      int32(item.UpdatedAt),
+			DystociaReason: item.DystociaReason,
+			CalfItemList:   CalfItemList,
 		})
 	}
 	return list
 }
+
+type EventCalvingSlice []*EventCalving
+
+func (e EventCalvingSlice) ToPB() []*pasturePb.CalvingReportTable {
+	res := make([]*pasturePb.CalvingReportTable, len(e))
+	for i, v := range e {
+		res[i] = &pasturePb.CalvingReportTable{
+			StatisticMethod:     v.Remarks,
+			Twins:               0,
+			TwinsRate:           0,
+			Bulls:               0,
+			BullsRate:           0,
+			Cows:                0,
+			CowsRate:            0,
+			SurviveCount:        0,
+			SurviveRate:         0,
+			DieCount:            0,
+			DieRate:             0,
+			BullsDieCount:       0,
+			BullsDieRate:        0,
+			CowsDieCount:        0,
+			CowsDieRate:         0,
+			AdoptCount:          0,
+			AdoptRate:           0,
+			PrematureLaborCount: 0,
+			PrematureLaborRate:  0,
+			LateLaborCount:      0,
+			LateLaborRate:       0,
+			NormalLaborCount:    0,
+		}
+	}
+	return res
+}

+ 82 - 0
model/event_cow_disease.go

@@ -0,0 +1,82 @@
+package model
+
+import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+
+type EventCowDisease struct {
+	Id                    int64                       `json:"id"`
+	CowId                 int64                       `json:"cowId"`
+	CowType               pasturePb.CowType_Kind      `json:"cowType"`
+	Lact                  int32                       `json:"lact"`
+	DayAge                int32                       `json:"dayAge"`
+	DiseaseId             int32                       `json:"diseaseId"`
+	DiseaseName           string                      `json:"diseaseName"`
+	DiseaseType           int32                       `json:"diseaseType"`
+	DiseaseTypeName       string                      `json:"diseaseTypeName"`
+	DiagnoseId            int32                       `json:"diagnoseId"`
+	DiagnoseName          string                      `json:"diagnoseName"`
+	PenId                 int32                       `json:"penId"`
+	HealthStatus          pasturePb.HealthStatus_Kind `json:"healthStatus"`
+	DiagnosedResult       pasturePb.IsShow_Kind       `json:"diagnosedResult"`
+	DiagnosedAt           int64                       `json:"diagnosedAt"`
+	DiseaseAt             int64                       `json:"diseaseAt"`
+	Temperature           int32                       `json:"temperature"`
+	Remarks               string                      `json:"remarks"`
+	OperationId           int32                       `json:"operationId"`
+	OperationName         string                      `json:"operationName"`
+	DiagnoseOperationId   int32                       `json:"diagnoseOperationId"`
+	DiagnoseOperationName string                      `json:"diagnoseOperationName"`
+	CurableAt             int64                       `json:"curableAt"`
+	CreatedAt             int64                       `json:"createdAt"`
+	UpdatedAt             int64                       `json:"updatedAt"`
+}
+
+func (e *EventCowDisease) TableName() string {
+	return "event_cow_disease"
+}
+
+func NewEventCowDisease(cow *Cow, disease *Disease, req *pasturePb.EventCowDiseaseRequest, operation *SystemUser) *EventCowDisease {
+	return &EventCowDisease{
+		CowId:           cow.Id,
+		CowType:         cow.CowType,
+		Lact:            cow.Lact,
+		DayAge:          cow.DayAge,
+		DiseaseId:       int32(disease.Id),
+		DiseaseName:     disease.Name,
+		DiseaseType:     disease.DiseaseType,
+		DiseaseTypeName: disease.DiseaseTypeName,
+		PenId:           req.PenId,
+		HealthStatus:    pasturePb.HealthStatus_Health,
+		DiseaseAt:       int64(req.DiseaseAt),
+		Temperature:     int32(req.Temperature * 10),
+		OperationId:     int32(operation.Id),
+		OperationName:   operation.Name,
+		Remarks:         req.Remarks,
+	}
+}
+
+type EventCowDiseaseSlice []*EventCowDisease
+
+func (e EventCowDiseaseSlice) ToPB(healthStatusMap map[pasturePb.HealthStatus_Kind]string) []*pasturePb.EventCowDisease {
+	res := make([]*pasturePb.EventCowDisease, len(e))
+	for i, v := range e {
+		res[i] = &pasturePb.EventCowDisease{
+			Id:               int32(v.Id),
+			CowId:            int32(v.CowId),
+			Lact:             v.Lact,
+			DayAge:           v.DayAge,
+			DiseaseId:        v.DiseaseId,
+			DiseaseName:      v.DiseaseName,
+			DiagnoseId:       v.DiagnoseId,
+			DiagnoseName:     v.DiagnoseName,
+			PenId:            v.PenId,
+			HealthStatus:     v.HealthStatus,
+			HealthStatusName: healthStatusMap[v.HealthStatus],
+			Temperature:      float32(v.HealthStatus / 10),
+			DiseaseAt:        int32(v.DiseaseAt),
+			Remarks:          v.Remarks,
+			OperationId:      v.OperationId,
+			OperationName:    v.OperationName,
+		}
+	}
+	return res
+}

+ 61 - 0
model/event_cow_log.go

@@ -0,0 +1,61 @@
+package model
+
+import (
+	"fmt"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
+
+const ShardTableNumber = 6
+
+type EventCowLog struct {
+	Id               int64                  `json:"id"`
+	CowId            int64                  `json:"cowId"`
+	DayAge           int32                  `json:"dayAge"`
+	Lact             int32                  `json:"lact"`
+	PenId            int32                  `json:"penId"`
+	PenName          string                 `json:"penName"`
+	CowType          pasturePb.CowType_Kind `json:"cowType"`
+	CowTypeName      string                 `json:"cowTypeName"`
+	EventType        int64                  `json:"eventType"`
+	EventTypeName    string                 `json:"eventTypeName"`
+	EventDescription string                 `json:"eventDescription"`
+	OperationId      int64                  `json:"operationId"`
+	OperationName    string                 `json:"operationName"`
+	EventAt          string                 `json:"eventAt"`
+	Remarks          string                 `json:"remarks"`
+	CreatedAt        int64                  `json:"createdAt"`
+	UpdatedAt        int64                  `json:"updatedAt"`
+}
+
+func (e *EventCowLog) UnShardTableName() string {
+	return "event_cow_log"
+}
+
+// TableName 表名
+func (e *EventCowLog) TableName() string {
+	return fmt.Sprintf("%s_%04d", e.UnShardTableName(), e.CowId%ShardTableNumber)
+}
+
+func NewCowEventLog(cow *Cow, penMap map[int32]*Pen, cowType map[pasturePb.CowType_Kind]string, operation *SystemUser) *EventCowLog {
+	penName := ""
+	if pen, ok := penMap[cow.PenId]; ok {
+		penName = pen.Name
+	}
+	return &EventCowLog{
+		CowId:            cow.Id,
+		DayAge:           cow.GetDayAge(),
+		Lact:             cow.Lact,
+		PenId:            cow.PenId,
+		PenName:          penName,
+		CowType:          cow.CowType,
+		CowTypeName:      cowType[cow.CowType],
+		EventType:        0,
+		EventTypeName:    "",
+		EventDescription: "",
+		OperationId:      operation.Id,
+		OperationName:    operation.Name,
+		EventAt:          "",
+		Remarks:          "",
+	}
+}

+ 141 - 0
model/event_cow_same_time.go

@@ -0,0 +1,141 @@
+package model
+
+import (
+	"time"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
+
+type EventCowSameTime struct {
+	Id            int64                       `json:"id"`
+	CowId         int64                       `json:"cowId"`
+	CowType       pasturePb.CowType_Kind      `json:"cowType"`
+	PenId         int32                       `json:"penId"`
+	PenName       string                      `json:"penName"`
+	Lact          int32                       `json:"lact"`
+	SameTimeId    int64                       `json:"sameTimeId"`
+	SameTimeName  string                      `json:"sameTimeName"`
+	SameTimeType  pasturePb.SameTimeType_Kind `json:"sameTimeType"`
+	PlanDay       int64                       `json:"planDay"`
+	EndDay        int64                       `json:"endDay"`
+	RealityDay    int64                       `json:"realityDay"`
+	Status        pasturePb.IsShow_Kind       `json:"status"`
+	DrugsId       int64                       `json:"drugsId"`
+	Unit          pasturePb.Unit_Kind         `json:"unit"`
+	Usage         int32                       `json:"usage"`
+	OperationId   int64                       `json:"operationId"`
+	OperationName string                      `json:"operationName"`
+	CreatedAt     int64                       `json:"createdAt"`
+	UpdatedAt     int64                       `json:"updatedAt"`
+}
+
+func (s *EventCowSameTime) TableName() string {
+	return "event_cow_same_time"
+}
+
+func NewEventCowSameTime(cow *Cow, planTime int64, sameTime *SameTime, sameTimeType pasturePb.SameTimeType_Kind) *EventCowSameTime {
+	return &EventCowSameTime{
+		CowId:        cow.Id,
+		Lact:         cow.Lact,
+		CowType:      cow.CowType,
+		PenId:        cow.PenId,
+		SameTimeId:   sameTime.Id,
+		SameTimeName: sameTime.Name,
+		SameTimeType: sameTimeType,
+		Status:       pasturePb.IsShow_No,
+		PlanDay:      planTime,
+		EndDay:       planTime,
+	}
+}
+
+func NewEventCowSameTimeList(cowList []*Cow, sameTime *SameTime, planTime int64, sameTimeType pasturePb.SameTimeType_Kind) []*EventCowSameTime {
+	res := make([]*EventCowSameTime, len(cowList))
+	for i, cow := range cowList {
+		res[i] = NewEventCowSameTime(cow, planTime, sameTime, sameTimeType)
+	}
+	return res
+}
+
+type SameTimeItemBody struct {
+	Id              int64                       `json:"id"`
+	CowId           int64                       `json:"cowId"`
+	BreedStatus     pasturePb.BreedStatus_Kind  `json:"breedStatus"`
+	BreedStatusName string                      `json:"breedStatusName"`
+	CowType         pasturePb.CowType_Kind      `json:"cowType"`
+	CowTypeName     string                      `json:"cowTypeName"`
+	PenId           int32                       `json:"penId"`
+	PenName         string                      `json:"penName"`
+	Lact            int32                       `json:"lact"`
+	CalvingAge      int32                       `json:"calvingAge"`
+	AbortionAge     int32                       `json:"abortionAge"`
+	DayAge          int32                       `json:"dayAge"`
+	Status          pasturePb.IsShow_Kind       `json:"status"`
+	SameTimeType    pasturePb.SameTimeType_Kind `json:"sameTimeType"`
+	LastCalvingAt   int64                       `json:"lastCalvingAt"`
+	LastAbortionAt  int64                       `json:"lastAbortionAt"`
+	MatingTimes     int32                       `json:"matingTimes"`
+	SameTimeName    string                      `json:"sameTimeName"`
+}
+
+type SameTimeBodySlice []*SameTimeItemBody
+
+func (s SameTimeBodySlice) ToPB(
+	breedStatusMap map[pasturePb.BreedStatus_Kind]string,
+	penMap map[int32]*Pen,
+	sameTimeTypeMap map[pasturePb.SameTimeType_Kind]string,
+) []*pasturePb.SameTimeItems {
+	res := make([]*pasturePb.SameTimeItems, len(s))
+	for i, v := range s {
+		penName, calvingAtFormat, abortionAtFormat := "", "", ""
+		if pen, ok := penMap[v.PenId]; ok {
+			penName = pen.Name
+		}
+
+		if v.LastCalvingAt > 0 {
+			calvingAtFormat = time.Unix(v.LastCalvingAt, 0).Format(LayoutDate2)
+		}
+
+		if v.LastAbortionAt > 0 {
+			abortionAtFormat = time.Unix(v.LastAbortionAt, 0).Format(LayoutDate2)
+		}
+
+		res[i] = &pasturePb.SameTimeItems{
+			Id:               int32(v.Id),
+			CowId:            int32(v.CowId),
+			BreedStatus:      v.BreedStatus,
+			BreedStatusName:  breedStatusMap[v.BreedStatus],
+			PenName:          penName,
+			PenId:            v.PenId,
+			Lact:             v.Lact,
+			CalvingAge:       v.CalvingAge,
+			AbortionAge:      v.AbortionAge,
+			DayAge:           v.DayAge,
+			Status:           v.Status,
+			SameTimeTypeName: sameTimeTypeMap[v.SameTimeType],
+			CalvingAtFormat:  calvingAtFormat,
+			AbortionAtFormat: abortionAtFormat,
+			MatingTimes:      v.MatingTimes,
+			SameTimeName:     v.SameTimeName,
+		}
+	}
+	return res
+}
+
+type EventCowSameTimeSlice []*EventCowSameTime
+
+func (s EventCowSameTimeSlice) ToPB(sameTimeTypeMap map[pasturePb.SameTimeType_Kind]string) []*pasturePb.EventSameTime {
+	res := make([]*pasturePb.EventSameTime, len(s))
+	for i, v := range s {
+		res[i] = &pasturePb.EventSameTime{
+			CowId:            int32(v.CowId),
+			PenId:            v.PenId,
+			DrugsId:          int32(v.DrugsId),
+			Usage:            v.Usage,
+			Lact:             v.Lact,
+			SameTimeId:       int32(v.SameTimeId),
+			SameTimeType:     v.SameTimeType,
+			SameTimeTypeName: sameTimeTypeMap[v.SameTimeType],
+		}
+	}
+	return res
+}

+ 93 - 0
model/event_cow_treatment.go

@@ -0,0 +1,93 @@
+package model
+
+import (
+	"encoding/json"
+
+	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
+	"go.uber.org/zap"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
+
+type EventCowTreatment struct {
+	Id                 int64                          `json:"id"`
+	CowId              int64                          `json:"cowId"`
+	CowDiseaseId       int64                          `json:"cowDiseaseId"`
+	DiseaseId          int64                          `json:"diseaseId"`
+	DiseaseName        string                         `json:"diseaseName"`
+	DiseaseType        int32                          `json:"diseaseType"`
+	DiseaseTypeName    string                         `json:"diseaseTypeName"`
+	PrescriptionId     int32                          `json:"prescriptionId"`
+	PrescriptionName   string                         `json:"prescriptionName"`
+	PrescriptionDetail string                         `json:"prescriptionDetail"`
+	TreatmentResult    pasturePb.TreatmentResult_Kind `json:"treatmentResult"`
+	OperationId        int64                          `json:"operationId"`
+	OperationName      string                         `json:"operationName"`
+	Remarks            string                         `json:"remarks"`
+	TreatmentAt        int64                          `json:"treatmentAt"`
+	CreatedAt          int64                          `json:"createdAt"`
+	UpdatedAt          int64                          `json:"updatedAt"`
+}
+
+func (e *EventCowTreatment) TableName() string {
+	return "event_cow_treatment"
+}
+
+func NewEventCowTreatment(prescription *Prescription, req *pasturePb.CowTreatmentRequest, diseaseTypeMap map[int32]string, operation *SystemUser) *EventCowTreatment {
+	b, _ := json.Marshal(req.PrescriptionDetail)
+	return &EventCowTreatment{
+		CowId:              int64(req.CowId),
+		CowDiseaseId:       int64(req.Id),
+		DiseaseId:          int64(req.DiseaseId),
+		DiseaseName:        req.DiseaseName,
+		DiseaseType:        req.DiseaseType,
+		DiseaseTypeName:    diseaseTypeMap[req.DiseaseType],
+		PrescriptionId:     req.PrescriptionId,
+		PrescriptionName:   prescription.Name,
+		PrescriptionDetail: string(b),
+		TreatmentResult:    req.TreatmentResult,
+		OperationId:        operation.Id,
+		OperationName:      operation.Name,
+		Remarks:            req.Remarks,
+	}
+}
+
+type EventCowTreatmentSlice []*EventCowTreatment
+
+func (e EventCowTreatmentSlice) ToPB(eventCowDiseaseList []*EventCowDisease) []*pasturePb.EventCowTreatment {
+	res := make([]*pasturePb.EventCowTreatment, len(e))
+	for i, v := range e {
+		prescriptionDetail := make([]*pasturePb.TreatmentDrugs, 0)
+		if v.PrescriptionDetail != "" {
+			err := json.Unmarshal([]byte(v.PrescriptionDetail), &prescriptionDetail)
+			if err != nil {
+				zaplog.Error("EventCowTreatmentSlice", zap.Any("err", err))
+			}
+		}
+
+		eventCowTreatment := &pasturePb.EventCowTreatment{
+			CowId:              int32(v.CowId),
+			CowDiseaseId:       int32(v.CowDiseaseId),
+			PrescriptionId:     v.PrescriptionId,
+			PrescriptionName:   v.PrescriptionName,
+			PrescriptionDetail: prescriptionDetail,
+			TreatmentResult:    0,
+			OperationId:        int32(v.OperationId),
+			OperationName:      v.OperationName,
+			Remarks:            v.Remarks,
+			CreatedAt:          int32(v.CreatedAt),
+			UpdatedAt:          int32(v.UpdatedAt),
+			DiseaseId:          int32(v.DiseaseId),
+			Id:                 int32(v.Id),
+		}
+		for _, d := range eventCowDiseaseList {
+			if v.CowDiseaseId != d.Id {
+				continue
+			}
+			eventCowTreatment.DiseaseName = d.DiseaseName
+			eventCowTreatment.DiseaseAt = int32(d.DiseaseAt)
+		}
+		res[i] = eventCowTreatment
+	}
+	return res
+}

+ 62 - 39
model/event_enter.go

@@ -9,32 +9,34 @@ import (
 
 type EventEnter struct {
 	Id               int64                      `json:"id"`
-	BatchNumber      string                     `json:"batch_number"`
-	EarNumber        string                     `json:"ear_number"`
-	CowId            int64                      `json:"cow_id"`
+	BatchNumber      string                     `json:"batchNumber"`
+	EarNumber        string                     `json:"earNumber"`
+	CowId            int64                      `json:"cowId"`
 	Sex              pasturePb.Genders_Kind     `json:"sex"`
-	BirthAt          int64                      `json:"birth_at"`
-	CowSourceId      pasturePb.CowSource_Kind   `json:"cow_source_id"`
-	OldEarNumber     string                     `json:"old_ear_number"`
-	CowType          pasturePb.CowType_Kind     `json:"cow_type"`
-	BreedStatus      pasturePb.BreedStatus_Kind `json:"breed_status"`
+	BirthAt          int64                      `json:"birthAt"`
+	CowSource        pasturePb.CowSource_Kind   `json:"cowSource"`
+	OldEarNumber     string                     `json:"oldEarNumber"`
+	CowType          pasturePb.CowType_Kind     `json:"cowType"`
+	BreedStatus      pasturePb.BreedStatus_Kind `json:"breedStatus"`
 	Lact             int32                      `json:"lact"`
-	DayAge           int32                      `json:"day_age"`
-	PenId            int32                      `json:"pen_id"`
-	CowKind          pasturePb.CowKind_Kind     `json:"cow_kind"`
-	FatherId         int64                      `json:"father_id"`
-	MotherId         int64                      `json:"mother_id"`
-	MatingAt         int64                      `json:"mating_at"`
-	PregnancyCheckAt int64                      `json:"pregnancy_check_at"`
-	DryMilkAt        int64                      `json:"dry_milk_at"`
-	WeaningAt        int64                      `json:"weaning_at"`
-	EstrusAt         int64                      `json:"estrus_at"`
-	EnterAt          int64                      `json:"enter_at"`
+	DayAge           int32                      `json:"dayAge"`
+	PenId            int32                      `json:"penId"`
+	CowKind          pasturePb.CowKind_Kind     `json:"cowKind"`
+	FatherNumber     string                     `json:"fatherNumber"`
+	MotherNumber     string                     `json:"motherNumber"`
+	MatingAt         int64                      `json:"matingAt"`
+	PregnancyCheckAt int64                      `json:"pregnancyCheckAt"`
+	DryMilkAt        int64                      `json:"dryMilkAt"`
+	WeaningAt        int64                      `json:"weaningAt"`
+	EstrusAt         int64                      `json:"estrusAt"`
+	EnterAt          int64                      `json:"enterAt"`
 	Remarks          string                     `json:"remarks"`
 	Weight           int64                      `json:"weight"`
 	Price            int64                      `json:"price"`
-	OperationId      int64                      `json:"operation_id"`
-	StaffMemberId    int64                      `json:"staff_member_id"`
+	OperationId      int64                      `json:"operationId"`
+	OperationName    string                     `json:"operationName"`
+	MessengerId      int64                      `json:"messengerId"`
+	MessengerName    string                     `json:"messengerName"`
 	CreatedAt        int64                      `json:"created_at"`
 	UpdatedAt        int64                      `json:"updated_at"`
 }
@@ -42,21 +44,21 @@ type EventEnter struct {
 func (e *EventEnter) TableName() string {
 	return "event_enter"
 }
-func NewEventEnter(cowId, operationId int64, req *pasturePb.EventEnterData) *EventEnter {
+func NewEventEnter(cowId int64, req *pasturePb.EventEnterRequest) *EventEnter {
 	return &EventEnter{
 		EarNumber:        req.EarNumber,
 		CowId:            cowId,
 		Sex:              req.Sex,
 		BirthAt:          int64(req.BirthAt),
-		CowSourceId:      req.CowSourceId,
-		CowType:          req.CowTypeId,
-		BreedStatus:      req.BreedStatusId,
+		CowSource:        req.CowSource,
+		CowType:          req.CowType,
+		BreedStatus:      req.BreedStatus,
 		Lact:             req.Lact,
 		DayAge:           int32(math.Floor(float64(int32(time.Now().Unix())-req.BirthAt) / 86400)),
 		PenId:            req.PenId,
-		CowKind:          req.CowKindId,
-		FatherId:         int64(req.FatherId),
-		MotherId:         int64(req.MotherId),
+		CowKind:          req.CowKind,
+		FatherNumber:     req.FatherNumber,
+		MotherNumber:     req.MotherNumber,
 		MatingAt:         int64(req.MatingAt),
 		PregnancyCheckAt: int64(req.PregnancyCheckAt),
 		DryMilkAt:        int64(req.DryMilkAt),
@@ -66,30 +68,47 @@ func NewEventEnter(cowId, operationId int64, req *pasturePb.EventEnterData) *Eve
 		Remarks:          req.Remarks,
 		Weight:           int64(req.Weight * 100),
 		Price:            int64(req.Price * 100),
-		StaffMemberId:    int64(req.StaffMemberId),
-		OperationId:      operationId,
+		MessengerId:      int64(req.MessengerId),
+		MessengerName:    req.MessengerName,
+		OperationId:      int64(req.OperationId),
+		OperationName:    req.OperationName,
 	}
 }
 
 type EventEnterSlice []*EventEnter
 
-func (e EventEnterSlice) ToPB() []*pasturePb.EventEnterData {
-	res := make([]*pasturePb.EventEnterData, len(e))
+func (e EventEnterSlice) ToPB(
+	penMap map[int32]*Pen,
+	breedStatusMap map[pasturePb.BreedStatus_Kind]string,
+	cowSourceMap map[pasturePb.CowSource_Kind]string,
+	cowTypeMap map[pasturePb.CowType_Kind]string,
+	cowKindMap map[pasturePb.CowKind_Kind]string,
+) []*pasturePb.EventEnterRequest {
+	res := make([]*pasturePb.EventEnterRequest, len(e))
 	for i, d := range e {
-		res[i] = &pasturePb.EventEnterData{
+		penName := ""
+		if pen, ok := penMap[d.PenId]; ok {
+			penName = pen.Name
+		}
+		res[i] = &pasturePb.EventEnterRequest{
 			Id:               int32(d.Id),
 			EarNumber:        d.EarNumber,
 			CowId:            int32(d.CowId),
 			Sex:              d.Sex,
 			BirthAt:          int32(d.BirthAt),
-			CowSourceId:      d.CowSourceId,
-			CowTypeId:        d.CowType,
-			BreedStatusId:    d.BreedStatus,
+			CowSource:        d.CowSource,
+			CowSourceName:    cowSourceMap[d.CowSource],
+			CowType:          d.CowType,
+			CowTypeName:      cowTypeMap[d.CowType],
+			BreedStatus:      d.BreedStatus,
+			BreedStatusName:  breedStatusMap[d.BreedStatus],
 			Lact:             d.Lact,
 			PenId:            d.PenId,
-			CowKindId:        d.CowKind,
-			FatherId:         int32(d.FatherId),
-			MotherId:         int32(d.MotherId),
+			PenName:          penName,
+			CowKind:          d.CowKind,
+			CowKindName:      cowKindMap[d.CowKind],
+			FatherNumber:     d.FatherNumber,
+			MotherNumber:     d.MotherNumber,
 			MatingAt:         int32(d.MatingAt),
 			PregnancyCheckAt: int32(d.PregnancyCheckAt),
 			DryMilkAt:        int32(d.DryMilkAt),
@@ -99,6 +118,10 @@ func (e EventEnterSlice) ToPB() []*pasturePb.EventEnterData {
 			Weight:           float32(d.Weight) / 100,
 			Price:            float32(d.Price) / 100,
 			Remarks:          d.Remarks,
+			MessengerId:      int32(d.MessengerId),
+			MessengerName:    d.MessengerName,
+			OperationId:      int32(d.OperationId),
+			OperationName:    d.OperationName,
 			CreatedAt:        int32(d.CreatedAt),
 			UpdatedAt:        int32(d.UpdatedAt),
 		}

+ 28 - 34
model/event_estrus.go

@@ -4,16 +4,18 @@ import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 
 type EventEstrus struct {
 	Id            int64  `json:"id"`
-	CowId         int64  `json:"cow_id"`
-	DayAge        int32  `json:"day_age"`
+	CowId         int64  `json:"cowId"`
+	DayAge        int32  `json:"dayAge"`
 	Lact          int8   `json:"lact"`
-	LactationDays int32  `json:"lactation_days"`
-	EstrusAt      int64  `json:"estrus_at"`
+	LactationDays int32  `json:"lactationDays"`
+	EstrusAt      int64  `json:"estrusAt"`
 	Remarks       string `json:"remarks"`
-	StallNumberId int64  `json:"stall_number_id"`
-	OperationId   int64  `json:"operation_id"`
-	CreatedAt     int64  `json:"created_at"`
-	UpdatedAt     int64  `json:"updated_at"`
+	OperationId   int64  `json:"operationId"`
+	OperationName string `json:"operationName"`
+	MessageId     int64  `json:"messageId"`
+	MessageName   string `json:"messageName"`
+	CreatedAt     int64  `json:"createdAt"`
+	UpdatedAt     int64  `json:"updatedAt"`
 }
 
 func (e *EventEstrus) TableName() string {
@@ -28,40 +30,32 @@ func NewEventEstrus(cow *Cow, currentUser *SystemUser, req *pasturePb.EventEstru
 		LactationDays: cow.GetLactationDays(),
 		EstrusAt:      int64(req.EstrusAt),
 		Remarks:       req.Remarks,
-		StallNumberId: int64(req.StaffMemberId),
-		OperationId:   currentUser.Id,
+		MessageId:     currentUser.Id,
+		MessageName:   currentUser.Name,
+		OperationId:   int64(req.OperationId),
+		OperationName: req.OperationName,
 	}
 }
 
 type EstrusSlice []*EventEstrus
 
-func (e EstrusSlice) ToPB(userList []*SystemUser) []*pasturePb.SearchEstrusList {
+func (e EstrusSlice) ToPB() []*pasturePb.SearchEstrusList {
 	res := make([]*pasturePb.SearchEstrusList, len(e))
 	for i, v := range e {
-		staffMemberName, operationName := "", ""
-		for _, u := range userList {
-			if u.Id == v.StallNumberId {
-				staffMemberName = u.Name
-			}
-			if u.Id == v.OperationId {
-				operationName = u.Name
-			}
-		}
-
 		res[i] = &pasturePb.SearchEstrusList{
-			Id:              int32(v.Id),
-			CowId:           int32(v.CowId),
-			DayAge:          v.DayAge,
-			Lact:            int32(v.Lact),
-			EstrusAt:        int32(v.EstrusAt),
-			LactationDays:   v.LactationDays,
-			StaffMemberId:   int32(v.StallNumberId),
-			StaffMemberName: staffMemberName,
-			Remarks:         v.Remarks,
-			OperationId:     int32(v.OperationId),
-			OperationName:   operationName,
-			CreatedAt:       int32(v.CreatedAt),
-			UpdatedAt:       int32(v.UpdatedAt),
+			Id:            int32(v.Id),
+			CowId:         int32(v.CowId),
+			DayAge:        v.DayAge,
+			Lact:          int32(v.Lact),
+			EstrusAt:      int32(v.EstrusAt),
+			LactationDays: v.LactationDays,
+			MessengerId:   int32(v.MessageId),
+			MessengerName: v.MessageName,
+			Remarks:       v.Remarks,
+			OperationId:   int32(v.OperationId),
+			OperationName: v.OperationName,
+			CreatedAt:     int32(v.CreatedAt),
+			UpdatedAt:     int32(v.UpdatedAt),
 		}
 	}
 	return res

+ 0 - 22
model/event_frozen_semen_log.go

@@ -1,22 +0,0 @@
-package model
-
-type EventFrozenSemenLog struct {
-	Id            int64  `json:"id"`
-	BullId        string `json:"bull_id"`
-	CowId         int64  `json:"cow_id"`
-	StallNumberId int64  `json:"stall_number_id"`
-	CreatedAt     int64  `json:"created_at"`
-	UpdatedAt     int64  `json:"updated_at"`
-}
-
-func (e *EventFrozenSemenLog) TableName() string {
-	return "event_frozen_semen_log"
-}
-
-func NewEventFrozenSemenLog(bullId string, cow *Cow, stallNumberId int64) *EventFrozenSemenLog {
-	return &EventFrozenSemenLog{
-		BullId:        bullId,
-		CowId:         cow.Id,
-		StallNumberId: stallNumberId,
-	}
-}

+ 99 - 0
model/event_immunization_plan.go

@@ -0,0 +1,99 @@
+package model
+
+import (
+	"kpt-pasture/util"
+	"time"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
+
+type EventImmunizationPlan struct {
+	Id            int64                  `json:"id"`
+	CowId         int64                  `json:"cowId"`
+	Lact          int32                  `json:"lact"`
+	DayAge        int32                  `json:"dayAge"`
+	CowType       pasturePb.CowType_Kind `json:"cowType"`
+	CowKind       pasturePb.CowKind_Kind `json:"cowKind"`
+	PenId         int32                  `json:"penId"`
+	PenName       string                 `json:"penName"`
+	PlanId        int64                  `json:"planId"`
+	PlanName      string                 `json:"planName"`
+	PlanDay       int64                  `json:"planDay"`
+	RealityDay    int64                  `json:"realityDay"`
+	EndDay        int64                  `json:"endDay"`
+	Status        pasturePb.IsShow_Kind  `json:"status"`
+	OperationId   int64                  `json:"operationId"`
+	OperationName string                 `json:"operationName"`
+	DrugsId       int64                  `json:"drugsId"`
+	DrugsName     string                 `json:"drugsName"`
+	Unit          pasturePb.Unit_Kind    `json:"unit"`
+	UnitName      string                 `json:"unitName"`
+	Usage         int32                  `json:"usage"`
+	Remarks       string                 `json:"remarks"`
+	CreateAt      int64                  `json:"createAt"`
+	UpdateAt      int64                  `json:"updateAt"`
+}
+
+func (c *EventImmunizationPlan) TableName() string {
+	return "event_immunization_plan"
+}
+
+func NewCowImmunizationPlan(cow *Cow, pen *Pen, immunizationPlan *ImmunizationPlan) *EventImmunizationPlan {
+	todayTime := time.Now().Format(LayoutDate2)
+	todayStartTime := util.TimeParseLocalUnix(todayTime)
+	todayEndTime := util.TimeParseLocalEndUnix(todayTime)
+	return &EventImmunizationPlan{
+		CowId:    cow.Id,
+		Lact:     cow.Lact,
+		DayAge:   cow.DayAge,
+		CowKind:  cow.CowKind,
+		CowType:  cow.CowType,
+		PenId:    cow.PenId,
+		PenName:  pen.Name,
+		PlanId:   immunizationPlan.Id,
+		PlanName: immunizationPlan.Name,
+		PlanDay:  todayStartTime,
+		EndDay:   todayEndTime,
+		Status:   pasturePb.IsShow_No,
+	}
+}
+
+func NewCowImmunizationPlanList(cowList []*Cow, penMap map[int32]*Pen, immunizationPlan *ImmunizationPlan) []*EventImmunizationPlan {
+	cowImmunizationPlanList := make([]*EventImmunizationPlan, len(cowList))
+	for i, cow := range cowList {
+		pen := penMap[cow.PenId]
+		cowImmunizationPlanList[i] = NewCowImmunizationPlan(cow, pen, immunizationPlan)
+	}
+	return cowImmunizationPlanList
+}
+
+type EventImmunizationPlanSlice []*EventImmunizationPlan
+
+func (I EventImmunizationPlanSlice) ToPB() []*pasturePb.ImmunizationItems {
+	res := make([]*pasturePb.ImmunizationItems, len(I))
+	for i, v := range I {
+		res[i] = &pasturePb.ImmunizationItems{
+			Id:               int32(v.Id),
+			CowId:            int32(v.CowId),
+			PenId:            v.PenId,
+			Lact:             v.Lact,
+			PenName:          v.PenName,
+			DayAge:           v.DayAge,
+			PlanDay:          time.Unix(v.PlanDay, 0).Format(LayoutDate2),
+			Status:           v.Status,
+			ImmunizationName: v.PlanName,
+			ImmunizationId:   int32(v.PlanId),
+			Remarks:          v.Remarks,
+			OperatorId:       int32(v.OperationId),
+			OperatorName:     v.OperationName,
+			DrugId:           int32(v.DrugsId),
+			DrugName:         v.DrugsName,
+			Unit:             v.Unit,
+			UnitName:         v.UnitName,
+			Usage:            v.Usage,
+			CreatedAt:        int32(v.CreateAt),
+			UpdatedAt:        int32(v.UpdateAt),
+		}
+	}
+	return res
+}

+ 77 - 0
model/event_item.go

@@ -0,0 +1,77 @@
+package model
+
+import (
+	"kpt-pasture/util"
+	"time"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
+
+type EventItem struct {
+	Id            int64                       `json:"id"`
+	CowId         int64                       `json:"cowId"`
+	PenId         int32                       `json:"penId"`
+	Lact          int32                       `json:"lact"`
+	CalendarType  pasturePb.CalendarType_Kind `json:"calendarType"`
+	PlanDay       int64                       `json:"planDay"`
+	EndDay        int64                       `json:"endDay"`
+	RealityDay    int64                       `json:"realityDay"`
+	IsFinish      pasturePb.IsShow_Kind       `json:"isFinish"`
+	IsExpire      pasturePb.IsShow_Kind       `json:"isExpire"`
+	OperationId   int64                       `json:"operationId"`
+	OperationName string                      `json:"operationName"`
+	Remarks       string                      `json:"remarks"`
+	CreatedAt     int64                       `json:"createdAt"`
+	UpdatedAt     int64                       `json:"updatedAt"`
+}
+
+func (e *EventItem) TableName() string {
+	return "event_item"
+}
+
+func NewEventItem(cow *Cow, calendarType pasturePb.CalendarType_Kind) *EventItem {
+	return &EventItem{
+		CowId:        cow.Id,
+		PenId:        cow.PenId,
+		Lact:         cow.Lact,
+		CalendarType: calendarType,
+		PlanDay:      util.TimeParseLocalUnix(time.Now().Format(LayoutDate2)),
+		EndDay:       util.TimeParseLocalEndUnix(time.Now().Format(LayoutDate2)),
+		IsFinish:     pasturePb.IsShow_Ok,
+	}
+}
+
+func NewEventItemList(cowList []*Cow, calendarType pasturePb.CalendarType_Kind) []*EventItem {
+	res := make([]*EventItem, len(cowList))
+	for i, v := range cowList {
+		res[i] = NewEventItem(v, calendarType)
+	}
+	return res
+}
+
+type EventItemSlice []*EventItem
+
+func (e EventItemSlice) ToPB(penMap map[int32]*Pen, calendarType map[pasturePb.CalendarType_Kind]string) []*pasturePb.CalendarToDoList {
+	res := make([]*pasturePb.CalendarToDoList, len(e))
+	for i, v := range e {
+		penName := ""
+		if pen, ok := penMap[v.PenId]; ok {
+			penName = pen.Name
+		}
+		res[i] = &pasturePb.CalendarToDoList{
+			Id:               int32(v.Id),
+			Lact:             v.Lact,
+			CalendarType:     v.CalendarType,
+			CalendarTypeName: calendarType[v.CalendarType],
+			PlanDay:          time.Unix(v.PlanDay, 0).Format(LayoutDate2),
+			EndDay:           time.Unix(v.EndDay, 0).Format(LayoutDate2),
+			RealityDay:       time.Unix(v.RealityDay, 0).Format(LayoutDate2),
+			IsFinish:         v.IsFinish,
+			IsExpire:         v.IsExpire,
+			CowId:            int32(v.CowId),
+			PenName:          penName,
+			Remarks:          v.Remarks,
+		}
+	}
+	return res
+}

+ 205 - 38
model/event_mating.go

@@ -1,77 +1,244 @@
 package model
 
-import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+import (
+	"time"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
 
 type EventMating struct {
 	Id                int64                           `json:"id"`
-	CowId             int64                           `json:"cow_id"`
-	DayAge            int64                           `json:"day_age"`
-	Lact              int8                            `json:"lact"`
-	LactationDays     int32                           `json:"lactation_days"`
-	ExposeEstrusType  pasturePb.ExposeEstrusType_Kind `json:"expose_estrus_type"`
-	MatingAt          int64                           `json:"mating_at"`
-	BullId            string                          `json:"bull_id"`
-	FrozenSemenNumber string                          `json:"frozen_semen_number"`
-	StallNumberId     int64                           `json:"stall_number_id"`
-	OperationId       int64                           `json:"operation_id"`
+	CowId             int64                           `json:"cowId"`
+	DayAge            int32                           `json:"dayAge"`
+	Lact              int32                           `json:"lact"`
+	PenId             int32                           `json:"penId"`
+	CowType           pasturePb.CowType_Kind          `json:"cowType"`
+	CowKind           pasturePb.CowKind_Kind          `json:"cowKind"`
+	CalvingAge        int32                           `json:"calvingAge"`
+	PlanDay           int64                           `json:"planDay"`
+	EndDay            int64                           `json:"endDay"`
+	CalvingAt         int64                           `json:"calvingAt"`
+	RealityDay        int64                           `json:"realityDay"`
+	Status            pasturePb.IsShow_Kind           `json:"status"`
+	MatingTimes       int32                           `json:"matingTimes"`
+	MatingResult      pasturePb.MatingResult_Kind     `json:"matingResult"`
+	MatingResultAt    int64                           `json:"matingResultAt"`
+	ExposeEstrusType  pasturePb.ExposeEstrusType_Kind `json:"exposeEstrusType"`
+	FrozenSemenNumber string                          `json:"frozenSemenNumber"`
+	OperationId       int64                           `json:"operationId"`
+	OperationName     string                          `json:"operationName"`
+	MessageId         int64                           `json:"messageId"`
+	MessageName       string                          `json:"messageName"`
 	Remarks           string                          `json:"remarks"`
-	CreatedAt         int64                           `json:"created_at"`
-	UpdatedAt         int64                           `json:"updated_at"`
+	CreatedAt         int64                           `json:"createdAt"`
+	UpdatedAt         int64                           `json:"updatedAt"`
 }
 
 func (e *EventMating) TableName() string {
 	return "event_mating"
 }
 
-func NewEventMating(cow *Cow, currentUser *SystemUser, req *pasturePb.EventMating) *EventMating {
+func NewEventMating(cow *Cow, planDay int64) *EventMating {
+	return &EventMating{
+		CowId:            cow.Id,
+		Lact:             cow.Lact,
+		PenId:            cow.PenId,
+		CowType:          cow.CowType,
+		CowKind:          cow.CowKind,
+		CalvingAt:        cow.LastMatingAt,
+		PlanDay:          planDay,
+		EndDay:           planDay,
+		MatingResult:     pasturePb.MatingResult_Unknown,
+		ExposeEstrusType: pasturePb.ExposeEstrusType_Same_Time,
+		Status:           pasturePb.IsShow_No,
+	}
+}
+
+// NewEventMating2 自然发情的牛只
+func NewEventMating2(cow *Cow, req *pasturePb.EventMating, currentUser *SystemUser) *EventMating {
 	return &EventMating{
 		CowId:             cow.Id,
-		DayAge:            int64(cow.GetDayAge()),
-		Lact:              int8(cow.Lact),
-		LactationDays:     cow.GetLactationDays(),
-		ExposeEstrusType:  req.ExposeEstrusType,
-		MatingAt:          int64(req.MatingAt),
-		BullId:            req.BullId,
+		Lact:              cow.Lact,
+		DayAge:            cow.GetDayAge(),
+		CowType:           cow.CowType,
+		CowKind:           cow.CowKind,
+		CalvingAt:         cow.LastMatingAt,
+		PlanDay:           int64(req.MatingAt),
+		RealityDay:        int64(req.MatingAt),
+		EndDay:            int64(req.MatingAt),
+		MatingResult:      pasturePb.MatingResult_Unknown,
+		ExposeEstrusType:  pasturePb.ExposeEstrusType_Natural_Estrus,
+		Status:            pasturePb.IsShow_Ok,
+		OperationId:       int64(req.OperationId),
+		OperationName:     req.OperationName,
+		MessageId:         currentUser.Id,
+		MessageName:       currentUser.Name,
 		FrozenSemenNumber: req.FrozenSemenNumber,
-		StallNumberId:     int64(req.StaffMemberId),
-		OperationId:       currentUser.Id,
 		Remarks:           req.Remarks,
 	}
 }
 
+func NewEventMatingList(cowList []*Cow, planDay int64) []*EventMating {
+	var matingList []*EventMating
+	for _, cow := range cowList {
+		matingList = append(matingList, NewEventMating(cow, planDay))
+	}
+	return matingList
+}
+
 type EventMatingSlice []*EventMating
 
-func (e EventMatingSlice) ToPB(user []*SystemUser, exposeEstrusTypeMap map[pasturePb.ExposeEstrusType_Kind]string) []*pasturePb.SearchMatingList {
+func (e EventMatingSlice) ToPB(exposeEstrusTypeMap map[pasturePb.ExposeEstrusType_Kind]string) []*pasturePb.SearchMatingList {
 	res := make([]*pasturePb.SearchMatingList, len(e))
 	for i, v := range e {
-		operationName, staffMemberName := "", ""
-		for _, u := range user {
-			if v.OperationId == u.Id {
-				operationName = u.Name
-			}
-			if v.StallNumberId == u.Id {
-				staffMemberName = u.Name
-			}
-		}
 		res[i] = &pasturePb.SearchMatingList{
 			Id:                   int32(v.Id),
 			CowId:                int32(v.CowId),
 			DayAge:               int32(v.DayAge),
 			Lact:                 int32(v.Lact),
+			CalvingAge:           v.CalvingAge,
+			PlanDay:              time.Unix(v.PlanDay, 0).Format(LayoutDate2),
+			RealityDay:           time.Unix(v.RealityDay, 0).Format(LayoutDate2),
 			ExposeEstrusType:     v.ExposeEstrusType,
 			ExposeEstrusTypeName: exposeEstrusTypeMap[v.ExposeEstrusType],
-			MatingAt:             int32(v.MatingAt),
-			BullId:               v.BullId,
 			FrozenSemenNumber:    v.FrozenSemenNumber,
-			LactationDays:        v.LactationDays,
-			StaffMemberId:        int32(v.StallNumberId),
-			StaffMemberName:      staffMemberName,
 			Remarks:              v.Remarks,
 			OperationId:          int32(v.OperationId),
-			OperationName:        operationName,
+			OperationName:        v.OperationName,
 			CreatedAt:            int32(v.CreatedAt),
 			UpdatedAt:            int32(v.UpdatedAt),
 		}
 	}
 	return res
 }
+
+type CowMatingBody struct {
+	Id              int64                      `json:"id"`
+	CowId           int64                      `json:"cowId"`
+	BreedStatus     pasturePb.BreedStatus_Kind `json:"breedStatus"`
+	BreedStatusName string                     `json:"breedStatusName"`
+	CowType         pasturePb.CowType_Kind     `json:"cowType"`
+	CowTypeName     string                     `json:"cowTypeName"`
+	PenId           int32                      `json:"penId"`
+	PenName         string                     `json:"penName"`
+	Lact            int32                      `json:"lact"`
+	CalvingAge      int32                      `json:"calvingAge"`
+	AbortionAge     int32                      `json:"abortionAge"`
+	DayAge          int32                      `json:"dayAge"`
+	Status          pasturePb.IsShow_Kind      `json:"status"`
+}
+
+type CowMatingBodySlice []*CowMatingBody
+
+func (s CowMatingBodySlice) ToPB(
+	cowTypeMap map[pasturePb.CowType_Kind]string,
+	breedStatusMap map[pasturePb.BreedStatus_Kind]string,
+	penMap map[int32]*Pen,
+) []*CowMatingBody {
+	res := make([]*CowMatingBody, len(s))
+	for i, v := range s {
+		res[i] = &CowMatingBody{
+			Id:              v.Id,
+			CowId:           v.CowId,
+			CowType:         v.CowType,
+			CowTypeName:     cowTypeMap[v.CowType],
+			BreedStatus:     v.BreedStatus,
+			BreedStatusName: breedStatusMap[v.BreedStatus],
+			PenName:         penMap[v.PenId].Name,
+			PenId:           v.PenId,
+			Lact:            v.Lact,
+			CalvingAge:      v.CalvingAge,
+			AbortionAge:     v.AbortionAge,
+			DayAge:          v.DayAge,
+			Status:          v.Status,
+		}
+	}
+	return res
+}
+
+type MatingTimelyChart struct {
+	CalvingAge int32  `json:"calvingAge"`
+	RealityDay string `json:"realityDay"`
+	LactGroup  string `json:"lactGroup"`
+}
+
+func (e EventMatingSlice) ToPB2() []*pasturePb.CowList {
+	res := make([]*pasturePb.CowList, len(e))
+	for i, v := range e {
+		calvingAt, matingAtFormat := "", ""
+		if v.CalvingAt > 0 {
+			calvingAt = time.Unix(v.CalvingAt, 0).Format(LayoutDate2)
+		}
+		if v.RealityDay > 0 {
+			matingAtFormat = time.Unix(v.RealityDay, 0).Format(LayoutDate2)
+		}
+		res[i] = &pasturePb.CowList{
+			CowId:           int32(v.CowId),
+			DayAge:          int32(v.DayAge),
+			CalvingAge:      v.CalvingAge,
+			MatingAtFormat:  matingAtFormat,
+			CalvingAtFormat: calvingAt,
+			Lact:            int32(v.Lact),
+		}
+	}
+	return res
+}
+
+type MatingTimelyResponse struct {
+	Code    int32             `json:"code"`
+	Message string            `json:"message"`
+	Data    *MatingTimelyData `json:"data"`
+}
+
+type MatingTimelyData struct {
+	CowList []*pasturePb.CowList `json:"cowList"`
+	Chart   *CowMatingChart      `json:"chart"`
+}
+
+type CowMatingChart struct {
+	Lact0 [][]string `json:"lact0"`
+	Lact1 [][]string `json:"lact1"`
+	Lact2 [][]string `json:"lact2"`
+	Lact3 [][]string `json:"lact3"`
+}
+
+// MultiFactorPregnancyRateResponse 多维度受胎率
+type MultiFactorPregnancyRateResponse struct {
+	Code    int32                         `json:"code"`
+	Message string                        `json:"message"`
+	Data    *MultiFactorPregnancyRateData `json:"data"`
+}
+
+// MultiFactorPregnancyRateList 多维度受胎率分析
+type MultiFactorPregnancyRateList struct {
+	StatisticMethod1   string  `json:"statisticMethod1"`   // 统计方式名称1 (月度、品种)
+	StatisticMethod2   string  `json:"statisticMethod2"`   // 统计方式名称2 (月度、品种)
+	PregnantRate       float32 `json:"pregnantRate"`       // 受胎率%(怀孕数 / 怀孕数 + 空怀数)
+	PregnantCount      int32   `json:"pregnantCount"`      // 怀孕总数
+	EmptyPregnantCount int32   `json:"emptyPregnantCount"` // 空怀数
+	OtherCount         int32   `json:"otherCount"`         // 其他数 (配种后结果未知的个数,小于等于三次配种后,尚未孕检已经淘汰的个数)
+	AbortionCount      int32   `json:"abortionCount"`      // 流产数 (已经怀孕后流产的个数)
+	TotalCount         int32   `json:"totalCount"`         // 合计( 怀孕总数+空怀数+其他数)
+	SpcRate            float32 `json:"spcRate"`            // spc(1 / 受胎率)
+	Months             string  `json:"months"`             // 月份
+	OperationName      string  `json:"operationName"`      // 配种员名称
+	Bull               string  `json:"bull"`               // 公牛
+	Lact               string  `json:"lact"`               // 胎次
+	MatingTimes        string  `json:"matingTimes"`        // 配次
+	ExposeEstrusType   string  `json:"exposeEstrusType"`   // 发情揭发方式
+	Week               string  `json:"week"`               // 周
+}
+
+type MultiFactorPregnancyRateData struct {
+	Total    int32                           `json:"total"`
+	PageSize int32                           `json:"pageSize"`
+	Page     int32                           `json:"page"`
+	List     []*MultiFactorPregnancyRateList `json:"list"`
+	Chart    *MultiFactorPregnancyRateChart  `json:"chart"`
+}
+
+type MultiFactorPregnancyRateChart struct {
+	Header          []string                     `json:"header"` // 标题头
+	PregnantRateMap map[string]map[string]string `json:"pregnantRateMap"`
+	KepMap          []string                     `json:"kepMap"`
+}

+ 134 - 48
model/event_pregnant_check.go

@@ -1,87 +1,173 @@
 package model
 
-import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+import (
+	"kpt-pasture/util"
+	"time"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
 
 type EventPregnantCheck struct {
 	Id                  int64                              `json:"id"`
-	CowId               int64                              `json:"cow_id"`
-	DayAge              int32                              `json:"day_age"`
+	CowId               int64                              `json:"cowId"`
+	CowType             pasturePb.CowType_Kind             `json:"cowType"`
+	PenId               int32                              `json:"penId"`
+	PenName             string                             `json:"penName"`
+	DayAge              int32                              `json:"dayAge"`
 	Lact                int8                               `json:"lact"`
-	PregnantCheckAt     int64                              `json:"pregnant_check_at"`
-	PregnantCheckResult pasturePb.PregnantCheckResult_Kind `json:"pregnant_check_result"`
-	PregnantCheckMethod pasturePb.PregnantCheckMethod_Kind `json:"pregnant_check_method"`
-	StaffMemberId       int64                              `json:"staff_member_id"`
-	OperationId         int64                              `json:"operation_id"`
+	MatingAge           int32                              `json:"matingAge"`
+	PlanDay             int64                              `json:"planDay"`
+	RealityDay          int64                              `json:"realityDay"`
+	EndDay              int64                              `json:"endDay"`
+	PregnantCheckName   string                             `json:"pregnantCheckName"`
+	PregnantCheckResult pasturePb.PregnantCheckResult_Kind `json:"pregnantCheckResult"`
+	PregnantCheckMethod pasturePb.PregnantCheckMethod_Kind `json:"pregnantCheckMethod"`
+	BullId              string                             `json:"bullId"`
+	Status              pasturePb.IsShow_Kind              `json:"status"`
+	OperationId         int64                              `json:"operationId"`
+	OperationName       string                             `json:"operationName"`
+	MessageId           int64                              `json:"messageId"`
+	MessageName         string                             `json:"messageName"`
 	Remarks             string                             `json:"remarks"`
-	CreatedAt           int64                              `json:"created_at"`
-	UpdatedAt           int64                              `json:"updated_at"`
+	CreatedAt           int64                              `json:"createdAt"`
+	UpdatedAt           int64                              `json:"updatedAt"`
 }
 
 func (e *EventPregnantCheck) TableName() string {
 	return "event_pregnant_check"
 }
 
-func NewEventPregnantCheck(cow *Cow, systemUser *SystemUser, req *pasturePb.EventPregnantCheck) *EventPregnantCheck {
+func NewEventPregnantCheck(cow *Cow, penMap map[int32]*Pen, pregnantCheckName string) *EventPregnantCheck {
+	penName := ""
+	if pen, ok := penMap[cow.PenId]; ok {
+		penName = pen.Name
+	}
+	return &EventPregnantCheck{
+		CowId:             cow.Id,
+		CowType:           cow.CowType,
+		PenId:             cow.PenId,
+		PenName:           penName,
+		DayAge:            cow.GetDayAge(),
+		Lact:              int8(cow.Lact),
+		PlanDay:           util.TimeParseLocalUnix(time.Now().Format(LayoutDate2)),
+		EndDay:            util.TimeParseLocalEndUnix(time.Now().Format(LayoutDate2)),
+		PregnantCheckName: pregnantCheckName,
+		BullId:            cow.LastBullNumber,
+		Status:            pasturePb.IsShow_No,
+	}
+}
+
+func NewEventPregnantCheckList(cowList []*Cow, penMap map[int32]*Pen, pregnantCheckName string) []*EventPregnantCheck {
+	res := make([]*EventPregnantCheck, len(cowList))
+	for i, cow := range cowList {
+		if cow.BreedStatus != pasturePb.BreedStatus_Breeding {
+			continue
+		}
+		res[i] = NewEventPregnantCheck(cow, penMap, pregnantCheckName)
+	}
+	return res
+}
+
+type EventPregnantCheck2 struct {
+	Cow                 *Cow
+	OperationUser       *SystemUser
+	CurrentUser         *SystemUser
+	PregnantCheckAt     int64
+	PregnantCheckMethod pasturePb.PregnantCheckMethod_Kind
+	PregnantCheckResult pasturePb.PregnantCheckResult_Kind
+	Remarks             string
+}
+
+func NewEventPregnantCheck2(req *EventPregnantCheck2, penMap map[int32]*Pen) *EventPregnantCheck {
+	penName := ""
+	if pen, ok := penMap[req.Cow.PenId]; ok {
+		penName = pen.Name
+	}
 	return &EventPregnantCheck{
-		CowId:               cow.Id,
-		DayAge:              cow.GetDayAge(),
-		Lact:                int8(cow.Lact),
-		PregnantCheckAt:     int64(req.PregnantCheckAt),
+		CowId:               req.Cow.Id,
+		CowType:             req.Cow.CowType,
+		PenId:               req.Cow.PenId,
+		PenName:             penName,
+		DayAge:              req.Cow.GetDayAge(),
+		Lact:                int8(req.Cow.Lact),
+		PlanDay:             req.PregnantCheckAt,
+		RealityDay:          req.PregnantCheckAt,
+		EndDay:              req.PregnantCheckAt,
 		PregnantCheckResult: req.PregnantCheckResult,
 		PregnantCheckMethod: req.PregnantCheckMethod,
-		StaffMemberId:       int64(req.StaffMemberId),
-		OperationId:         systemUser.Id,
+		PregnantCheckName:   PregnantCheckForFirst,
+		BullId:              req.Cow.LastBullNumber,
+		Status:              pasturePb.IsShow_Ok,
+		OperationId:         req.OperationUser.Id,
+		OperationName:       req.OperationUser.Name,
 		Remarks:             req.Remarks,
+		MessageId:           req.CurrentUser.Id,
+		MessageName:         req.CurrentUser.Name,
 	}
 }
 
 type EventPregnantCheckSlice []*EventPregnantCheck
 
-func (e EventPregnantCheckSlice) ToPB(systemUserList []*SystemUser, pregnantCheckResult, pregnantCheckMethod []*pasturePb.ConfigOptionsList) []*pasturePb.SearchPregnantCheckList {
+func (e EventPregnantCheckSlice) ToPB(
+	pregnantCheckResultMap map[pasturePb.PregnantCheckResult_Kind]string,
+	pregnantCheckMethodMap map[pasturePb.PregnantCheckMethod_Kind]string,
+) []*pasturePb.SearchPregnantCheckList {
 	result := make([]*pasturePb.SearchPregnantCheckList, len(e))
 	for i, v := range e {
-		var pregnantCheckResultName, pregnantCheckMethodName, staffMemberName, operationName = "", "", "", ""
-		for _, u := range systemUserList {
-			if v.StaffMemberId == u.Id {
-				staffMemberName = u.Name
-			}
-			if v.OperationId == u.Id {
-				operationName = u.Name
-			}
-		}
-
-		for _, s := range pregnantCheckResult {
-			if int32(v.PregnantCheckResult) != s.Value {
-				continue
-			}
-			pregnantCheckResultName = s.Label
-		}
-
-		for _, m := range pregnantCheckMethod {
-			if int32(v.PregnantCheckMethod) != m.Value {
-				continue
-			}
-			pregnantCheckMethodName = m.Label
-		}
-
 		result[i] = &pasturePb.SearchPregnantCheckList{
 			Id:                      int32(v.Id),
 			CowId:                   int32(v.CowId),
 			DayAge:                  v.DayAge,
 			Lact:                    int32(v.Lact),
-			PregnantCheckAt:         int32(v.PregnantCheckAt),
+			PregnantCheckAt:         int32(v.PlanDay),
 			PregnantCheckResult:     v.PregnantCheckResult,
-			PregnantCheckResultName: pregnantCheckResultName,
+			PregnantCheckResultName: pregnantCheckResultMap[v.PregnantCheckResult],
 			PregnantCheckMethod:     v.PregnantCheckMethod,
-			PregnantCheckMethodName: pregnantCheckMethodName,
-			StaffMemberId:           int32(v.StaffMemberId),
-			StaffMemberName:         staffMemberName,
+			PregnantCheckMethodName: pregnantCheckMethodMap[v.PregnantCheckMethod],
 			Remarks:                 v.Remarks,
 			OperationId:             int32(v.OperationId),
-			OperationName:           operationName,
+			OperationName:           v.OperationName,
 			CreatedAt:               int32(v.CreatedAt),
 			UpdatedAt:               int32(v.UpdatedAt),
 		}
 	}
 	return result
 }
+
+func (e EventPregnantCheckSlice) ToPB3(
+	pregnantCheckResultMap map[pasturePb.PregnantCheckResult_Kind]string,
+	pregnantCheckMethodMap map[pasturePb.PregnantCheckMethod_Kind]string,
+) []*pasturePb.PregnancyReportTable {
+	res := make([]*pasturePb.PregnancyReportTable, len(e))
+	for i, v := range e {
+		pregnancyCheckName := ""
+		if checkName, ok := PregnantCheckNameKeyMap[v.PregnantCheckName]; ok {
+			pregnancyCheckName = checkName
+		}
+
+		pregnantCheckMethodName := ""
+		if checkMethodName, ok := pregnantCheckMethodMap[v.PregnantCheckMethod]; ok {
+			pregnantCheckMethodName = checkMethodName
+		}
+
+		pregnantCheckResultName := ""
+		if checkResultName, ok := pregnantCheckResultMap[v.PregnantCheckResult]; ok {
+			pregnantCheckResultName = checkResultName
+		}
+
+		res[i] = &pasturePb.PregnancyReportTable{
+			Id:                      int32(v.Id),
+			CowId:                   int32(v.CowId),
+			Lact:                    int32(v.Lact),
+			PregnancyCheckName:      pregnancyCheckName,
+			PregnancyCheckAtFormat:  time.Unix(v.RealityDay, 0).Format(LayoutDate2),
+			MatingAge:               v.MatingAge,
+			PregnantCheckMethod:     v.PregnantCheckMethod,
+			PregnantCheckMethodName: pregnantCheckMethodName,
+			PregnantCheckResult:     v.PregnantCheckResult,
+			PregnantCheckResultName: pregnantCheckResultName,
+			OperationName:           v.OperationName,
+		}
+	}
+	return res
+}

+ 25 - 0
model/event_sale.go

@@ -0,0 +1,25 @@
+package model
+
+type EventSale struct {
+	Id            int64  `json:"id"`
+	DealerId      int32  `json:"dealerId"`
+	DealerName    string `json:"dealerName"`
+	VehicleId     int32  `json:"vehicleId"`
+	SalePrice     int32  `json:"salePrice"`
+	SaleAllWeight int32  `json:"saleAllWeight"`
+	SaleAllAmount int32  `json:"saleAllAmount"`
+	SaleCowCount  int32  `json:"saleCowCount"`
+	CowIds        string `json:"cowIds"`
+	SaleAt        int64  `json:"saleAt"`
+	Remarks       string `json:"remarks"`
+	OperationId   int32  `json:"operationId"`
+	OperationName string `json:"operationName"`
+	MessageId     int64  `json:"messageId"`
+	MessageName   string `json:"messageName"`
+	CreatedAt     int64  `json:"createdAt"`
+	UpdatedAt     int64  `json:"updatedAt"`
+}
+
+func (e *EventSale) TableName() string {
+	return "event_sale"
+}

+ 20 - 0
model/event_sale_vehicle.go

@@ -0,0 +1,20 @@
+package model
+
+type EventSaleVehicle struct {
+	Id              int64  `json:"id"`
+	DealerId        int32  `json:"dealerId"`
+	DealerName      string `json:"dealerName"`
+	SaleAt          int64  `json:"saleAt"`
+	VehicleNumber   string `json:"vehicleNumber"`
+	VehicleCowCount int32  `json:"vehicleCowCount"`
+	CowIds          string `json:"cowIds"`
+	Photo1          string `json:"photo1"`
+	Photo2          string `json:"photo2"`
+	Photo3          string `json:"photo3"`
+	CreatedAt       int64  `json:"createdAt"`
+	UpdatedAt       int64  `json:"updatedAt"`
+}
+
+func (e *EventSaleVehicle) TableName() string {
+	return "event_sale_vehicle"
+}

+ 0 - 46
model/event_same_time.go

@@ -1,46 +0,0 @@
-package model
-
-import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
-
-type EventSameTime struct {
-	Id               int64                       `json:"id"`
-	CowId            int64                       `json:"cowId"`
-	Lact             int32                       `json:"lact"`
-	DayAge           int32                       `json:"dayAge"`
-	CalvingAge       int64                       `json:"calvingAge"`
-	SameTimeId       int64                       `json:"sameTimeId"`
-	SameTimeType     pasturePb.SameTimeType_Kind `json:"sameTimeType"`
-	SameTimeTypeName string                      `json:"sameTimeTypeName"`
-	DrugsId          int64                       `json:"drugsId"`
-	DrugsName        string                      `json:"drugsName"`
-	Unit             pasturePb.Unit_Kind         `json:"unit"`
-	Usage            int32                       `json:"usage"`
-	Remarks          string                      `json:"remarks"`
-	StallNumberId    int64                       `json:"stallNumberId"`
-	OperationId      int64                       `json:"operation_id"`
-	CreatedAt        int64                       `json:"created_at"`
-	UpdatedAt        int64                       `json:"updated_at"`
-}
-
-func (e *EventSameTime) TableName() string {
-	return "event_same_time"
-}
-
-func NewEventSameTime(cow *Cow, req *pasturePb.EventSameTime, drugs *Drugs) *EventSameTime {
-	eventSameTime := &EventSameTime{
-		CowId:            cow.Id,
-		CalvingAge:       cow.CalvingAge,
-		SameTimeId:       int64(req.SameTimeId),
-		SameTimeType:     req.SameTimeType,
-		SameTimeTypeName: req.SameTimeTypeName,
-		Remarks:          req.Remarks,
-	}
-
-	if drugs != nil && drugs.Id > 0 {
-		eventSameTime.DrugsId = drugs.Id
-		eventSameTime.DrugsName = drugs.Name
-		eventSameTime.Unit = drugs.Unit
-		eventSameTime.Usage = req.Usage
-	}
-	return eventSameTime
-}

+ 31 - 10
model/event_transfer_group.go

@@ -1,21 +1,42 @@
 package model
 
+import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+
 type EventTransferGroup struct {
 	Id               int64  `json:"id"`
-	CowId            int64  `json:"cow_id"`
-	TransferInPenId  int64  `json:"transfer_in_pen_id"`
-	TransferOutPenId int64  `json:"transfer_out_pen_id"`
-	DayAge           int32  `json:"day_age"`
+	CowId            int64  `json:"cowId"`
+	PenInId          int32  `json:"penInId"`
+	PenOutId         int32  `json:"penOutId"`
+	DayAge           int32  `json:"dayAge"`
 	Lact             int32  `json:"lact"`
-	TransferDate     string `json:"transfer_date"`
-	TransferReasonId int64  `json:"transfer_reason_id"`
+	TransferDate     string `json:"transferDate"`
+	TransferReasonId int64  `json:"transferReasonId"`
 	Remarks          string `json:"remarks"`
-	StaffMemberId    int64  `json:"staff_member_id"`
-	OperationId      int64  `json:"operation_id"`
-	CreatedAt        int64  `json:"created_at"`
-	UpdatedAt        int64  `json:"updated_at"`
+	MessageId        int64  `json:"messageId"`
+	MessageName      string `json:"messageName"`
+	OperationId      int64  `json:"operationId"`
+	OperationName    string `json:"operationName"`
+	CreatedAt        int64  `json:"createdAt"`
+	UpdatedAt        int64  `json:"updatedAt"`
 }
 
 func (e *EventTransferGroup) TableName() string {
 	return "event_transfer_group"
 }
+
+func NewEventTransferGroup(cow *Cow, req *pasturePb.TransferGroupEventData, currentUser *SystemUser, operationUser *SystemUser) *EventTransferGroup {
+	return &EventTransferGroup{
+		CowId:            int64(req.CowId),
+		PenInId:          req.TransferInPenId,
+		PenOutId:         cow.PenId,
+		Lact:             cow.Lact,
+		DayAge:           cow.GetDayAge(),
+		TransferDate:     req.TransferDate,
+		TransferReasonId: int64(req.TransferReasonId),
+		Remarks:          req.Remarks,
+		MessageId:        currentUser.Id,
+		MessageName:      currentUser.Name,
+		OperationId:      operationUser.Id,
+		OperationName:    operationUser.Name,
+	}
+}

+ 46 - 0
model/event_weaning.go

@@ -0,0 +1,46 @@
+package model
+
+import (
+	"kpt-pasture/util"
+	"time"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
+
+type EventWeaning struct {
+	Id            int64                 `json:"id"`
+	CowId         int64                 `json:"cowId"`
+	PlanDay       int64                 `json:"planDay"`
+	EndDay        int64                 `json:"endDay"`
+	RealityDay    int64                 `json:"realityDay"`
+	Status        pasturePb.IsShow_Kind `json:"status"`
+	BeforePenId   int32                 `json:"beforePenId"`
+	AfterPenId    int32                 `json:"afterPenId"`
+	Remarks       string                `json:"remarks"`
+	OperationId   int32                 `json:"operationId"`
+	OperationName string                `json:"operationName"`
+	CreatedAt     int64                 `json:"createdAt"`
+	UpdatedAt     int64                 `json:"updatedAt"`
+}
+
+func (c *EventWeaning) TableName() string {
+	return "event_weaning"
+}
+
+func NewEventWeaning(cowId int64, penId int32) *EventWeaning {
+	return &EventWeaning{
+		CowId:       cowId,
+		PlanDay:     util.TimeParseLocalUnix(time.Now().Format(LayoutDate2)),
+		EndDay:      util.TimeParseLocalEndUnix(time.Now().Format(LayoutDate2)),
+		Status:      pasturePb.IsShow_No,
+		BeforePenId: penId,
+	}
+}
+
+func NewEventWeaningList(cowList []*Cow) []*EventWeaning {
+	var weaningList = make([]*EventWeaning, 0)
+	for _, cow := range cowList {
+		weaningList = append(weaningList, NewEventWeaning(cow.Id, cow.PenId))
+	}
+	return weaningList
+}

+ 44 - 0
model/event_weight.go

@@ -0,0 +1,44 @@
+package model
+
+import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+
+type EventWeight struct {
+	ID            int64  `json:"id"`
+	CowId         int64  `json:"cowId"`
+	EarNumber     string `json:"earNumber"`
+	DayAge        int32  `json:"dayAge"`
+	LactationDay  int64  `json:"lactationDay"`
+	PenId         int32  `json:"penId"`
+	Lact          int32  `json:"lact"`
+	Weight        int32  `json:"weight"`
+	Height        int32  `json:"height"`
+	WeightAt      int64  `json:"weightAt"`
+	Remarks       string `json:"remarks"`
+	OperationId   int32  `json:"operationId"`
+	OperationName string `json:"operationName"`
+	MessageId     int64  `json:"messageId"`
+	MessageName   string `json:"messageName"`
+	CreatedAt     int64  `json:"created_at"`
+	UpdatedAt     int64  `json:"updated_at"`
+}
+
+func (c *EventWeight) TableName() string {
+	return "event_weight"
+}
+
+func NewEventWeight(cow *Cow, currentUser *SystemUser, weight, height int32, req *pasturePb.EventWeight) *EventWeight {
+	return &EventWeight{
+		CowId:         cow.Id,
+		EarNumber:     cow.EarNumber,
+		Weight:        weight,
+		Height:        height,
+		Lact:          cow.Lact,
+		DayAge:        cow.GetDayAge(),
+		WeightAt:      int64(req.WeightAt),
+		Remarks:       req.Remarks,
+		MessageId:     currentUser.Id,
+		MessageName:   currentUser.Name,
+		OperationId:   req.OperationId,
+		OperationName: req.OperationName,
+	}
+}

+ 7 - 7
model/event_frozen_semen.go → model/frozen_semen.go

@@ -2,7 +2,7 @@ package model
 
 import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 
-type EventFrozenSemen struct {
+type FrozenSemen struct {
 	Id              int64                          `json:"id"`
 	ParentId        int64                          `json:"parent_id"`
 	Producer        string                         `json:"producer"`
@@ -18,8 +18,8 @@ type EventFrozenSemen struct {
 	UpdatedAt       int64                          `json:"updated_at"`
 }
 
-func NewEventFrozenSemen(req *pasturePb.SearchFrozenSemenList, currentUser *SystemUser) *EventFrozenSemen {
-	return &EventFrozenSemen{
+func NewFrozenSemen(req *pasturePb.SearchFrozenSemenList, currentUser *SystemUser) *FrozenSemen {
+	return &FrozenSemen{
 		Producer:        req.Producer,
 		BullId:          req.BullId,
 		KindId:          req.CowKind,
@@ -32,13 +32,13 @@ func NewEventFrozenSemen(req *pasturePb.SearchFrozenSemenList, currentUser *Syst
 	}
 }
 
-func (e *EventFrozenSemen) TableName() string {
-	return "event_frozen_semen"
+func (e *FrozenSemen) TableName() string {
+	return "frozen_semen"
 }
 
-type EventFrozenSemenSlice []*EventFrozenSemen
+type FrozenSemenSlice []*FrozenSemen
 
-func (e EventFrozenSemenSlice) ToPB(
+func (e FrozenSemenSlice) ToPB(
 	frozenSemenTypeMap map[pasturePb.FrozenSemenType_Kind]string,
 	unitMap map[pasturePb.Unit_Kind]string) []*pasturePb.SearchFrozenSemenList {
 	res := make([]*pasturePb.SearchFrozenSemenList, len(e))

+ 32 - 0
model/frozen_semen_log.go

@@ -0,0 +1,32 @@
+package model
+
+import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+
+type FrozenSemenLog struct {
+	Id            int64  `json:"id"`
+	BullId        string `json:"bullId"`
+	CowIds        string `json:"cowId"`
+	Quantity      int32  `json:"quantity"`
+	MatingAt      int64  `json:"matingAt"`
+	OperationId   int64  `json:"operationId"`
+	OperationName string `json:"operationName"`
+	Remarks       string `json:"remarks"`
+	CreatedAt     int64  `json:"createdAt"`
+	UpdatedAt     int64  `json:"updatedAt"`
+}
+
+func (e *FrozenSemenLog) TableName() string {
+	return "frozen_semen_log"
+}
+
+func NewEventFrozenSemenLog(req *pasturePb.EventMating) *FrozenSemenLog {
+	return &FrozenSemenLog{
+		BullId:        req.FrozenSemenNumber,
+		CowIds:        req.CowIds,
+		OperationId:   int64(req.OperationId),
+		OperationName: req.OperationName,
+		Quantity:      req.FrozenSemenCount,
+		MatingAt:      int64(req.MatingAt),
+		Remarks:       req.Remarks,
+	}
+}

+ 35 - 35
model/immunization_plan.go

@@ -1,23 +1,22 @@
 package model
 
 import (
-	"fmt"
-
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 )
 
 type ImmunizationPlan struct {
-	Id            int64                                 `json:"id"`
-	Name          string                                `json:"name"`
-	CowType       pasturePb.CowType_Kind                `json:"cow_type"`
-	Conditions    pasturePb.ImmunizationConditions_Kind `json:"conditions"`
-	Value         int64                                 `json:"value"`
-	Value2        int64                                 `json:"value2"`
-	IsShow        pasturePb.IsShow_Kind                 `json:"is_show"`
-	OperationId   int64                                 `json:"operation_id"`
-	OperationName string                                `json:"operation_name"`
-	CreatedAt     int64                                 `json:"created_at"`
-	UpdatedAt     int64                                 `json:"updated_at"`
+	Id                   int64                                 `json:"id"`
+	Name                 string                                `json:"name"`
+	CowType              pasturePb.CowType_Kind                `json:"cowType"`
+	Conditions           pasturePb.ImmunizationConditions_Kind `json:"conditions"`
+	Value                int64                                 `json:"value"`
+	IsShow               pasturePb.IsShow_Kind                 `json:"isShow"`
+	ImmunizationPlanId   int64                                 `json:"immunizationPlanId"`
+	ImmunizationPlanName string                                `json:"immunizationPlanName"`
+	OperationId          int64                                 `json:"operationId"`
+	OperationName        string                                `json:"operationName"`
+	CreatedAt            int64                                 `json:"createdAt"`
+	UpdatedAt            int64                                 `json:"updatedAt"`
 }
 
 func (i *ImmunizationPlan) TableName() string {
@@ -26,14 +25,15 @@ func (i *ImmunizationPlan) TableName() string {
 
 func NewImmunizationPlan(systemUser *SystemUser, req *pasturePb.ImmunizationRequest) *ImmunizationPlan {
 	return &ImmunizationPlan{
-		Name:          req.Name,
-		CowType:       req.CowType,
-		Conditions:    req.Conditions,
-		Value:         int64(req.Value),
-		Value2:        int64(req.Value2),
-		IsShow:        req.IsShow,
-		OperationId:   systemUser.Id,
-		OperationName: systemUser.Name,
+		Name:                 req.Name,
+		CowType:              req.CowType,
+		Conditions:           req.Conditions,
+		Value:                int64(req.Value),
+		ImmunizationPlanId:   int64(req.ImmunizationPlanId),
+		ImmunizationPlanName: req.ImmunizationPlanName,
+		IsShow:               req.IsShow,
+		OperationId:          systemUser.Id,
+		OperationName:        systemUser.Name,
 	}
 }
 
@@ -56,20 +56,20 @@ func (i ImmunizationPlanSlice) ToPB(cowTypeOptions []*pasturePb.ConfigOptionsLis
 			conditionsName = cd.Label
 		}
 		res[d] = &pasturePb.ImmunizationRequest{
-			Id:             int32(v.Id),
-			Name:           v.Name,
-			CowType:        v.CowType,
-			CowTypeName:    cowTypeName,
-			Conditions:     v.Conditions,
-			ConditionsName: conditionsName,
-			Value:          int32(v.Value),
-			IsShow:         v.IsShow,
-			OperationId:    int32(v.OperationId),
-			OperationName:  v.OperationName,
-			CreatedAt:      int32(v.CreatedAt),
-			UpdatedAt:      int32(v.UpdatedAt),
-			Value2:         int32(v.Value2),
-			DaysRange:      fmt.Sprintf("%d ~ %d", v.Value, v.Value2),
+			Id:                   int32(v.Id),
+			Name:                 v.Name,
+			CowType:              v.CowType,
+			CowTypeName:          cowTypeName,
+			Conditions:           v.Conditions,
+			ConditionsName:       conditionsName,
+			Value:                int32(v.Value),
+			IsShow:               v.IsShow,
+			ImmunizationPlanId:   int32(v.ImmunizationPlanId),
+			ImmunizationPlanName: v.ImmunizationPlanName,
+			OperationId:          int32(v.OperationId),
+			OperationName:        v.OperationName,
+			CreatedAt:            int32(v.CreatedAt),
+			UpdatedAt:            int32(v.UpdatedAt),
 		}
 	}
 	return res

+ 34 - 0
model/neck_ring_error.go

@@ -0,0 +1,34 @@
+package model
+
+import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+
+type NeckRingError struct {
+	Id             int64                 `json:"id"`
+	Uuid           string                `json:"uuid"`
+	FrameId        int32                 `json:"frameId"`
+	Low            int32                 `json:"low"`
+	High           int32                 `json:"high"`
+	Rumina         int32                 `json:"rumina"`
+	Active         int32                 `json:"active"`
+	Intake         int32                 `json:"intake"`
+	Inactive       int32                 `json:"inactive"`
+	Other          int32                 `json:"other"`
+	Voltage        int32                 `json:"voltage"`
+	Upper          int32                 `json:"upper"`
+	Version        int32                 `json:"version"`
+	Sign           int32                 `json:"sign"`
+	Remain         int32                 `json:"remain"`
+	Feed           int32                 `json:"feed"`
+	Imei           string                `json:"imei" `
+	Temp           int32                 `json:"temp"`
+	Gasp           int32                 `json:"gasp"`
+	ActiveDateTime string                `json:"activeDateTime"`
+	IsShow         pasturePb.IsShow_Kind `json:"isShow"`
+	ReceiveNumber  string                `json:"receiveNumber"`
+	CreatedAt      int64                 `json:"createdAt"`
+	UpdatedAt      int64                 `json:"updatedAt"`
+}
+
+func (s *NeckRingError) TableName() string {
+	return "neck_ring_error"
+}

+ 63 - 0
model/neck_ring_log.go

@@ -0,0 +1,63 @@
+package model
+
+import (
+	"time"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
+
+type NeckRingLog struct {
+	Id            int64                         `json:"id"`
+	Number        string                        `json:"number"`
+	CowId         int64                         `json:"cowId"`
+	WearAt        int64                         `json:"wearAt"`
+	UnbindAt      int64                         `json:"unbindAt"`
+	Status        pasturePb.NeckRingStatus_Kind `json:"status"`
+	ErrorReason   string                        `json:"errorReason"`
+	OperationId   int32                         `json:"operationId"`
+	OperationName string                        `json:"operationName"`
+	CreatedAt     int64                         `json:"createdAt"`
+	UpdatedAt     int64                         `json:"updatedAt"`
+}
+
+func (n *NeckRingLog) TableName() string {
+	return "neck_ring_log"
+}
+
+func NewNeckRingLog(number string, cowId int64, currentUser *SystemUser) *NeckRingLog {
+	return &NeckRingLog{
+		Number:        number,
+		CowId:         cowId,
+		WearAt:        time.Now().Unix(),
+		Status:        pasturePb.NeckRingStatus_Bind,
+		OperationId:   int32(currentUser.Id),
+		OperationName: currentUser.Name,
+	}
+}
+
+func NewNeckRingLogList(req []*pasturePb.NeckRingCreateItem, currentUser *SystemUser) []*NeckRingLog {
+	res := make([]*NeckRingLog, len(req))
+	for i, v := range req {
+		res[i] = NewNeckRingLog(v.Number, int64(v.CowId), currentUser)
+	}
+	return res
+}
+
+type NeckRingLogSlice []*NeckRingLog
+
+func (n NeckRingLogSlice) ToPB(neckRingStatus map[pasturePb.NeckRingStatus_Kind]string) []*pasturePb.SearchNeckRingList {
+	res := make([]*pasturePb.SearchNeckRingList, len(n))
+	for i, v := range n {
+		res[i] = &pasturePb.SearchNeckRingList{
+			Id:           int32(v.Id),
+			Number:       v.Number,
+			CowId:        int32(v.CowId),
+			WearAtFormat: time.Unix(v.WearAt, 0).Format(LayoutDate2),
+			WearDays:     int32(time.Now().Sub(time.Unix(v.WearAt, 0)).Hours() / 24),
+			Status:       v.Status,
+			StatusName:   neckRingStatus[v.Status],
+			ErrorReason:  v.ErrorReason,
+		}
+	}
+	return res
+}

+ 37 - 0
model/neck_ring_original.go

@@ -0,0 +1,37 @@
+package model
+
+import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+
+type NeckRingOriginal struct {
+	Id                 int64                         `json:"id"`
+	Uuid               string                        `json:"uuid"`
+	FrameId            int32                         `json:"frameId"`
+	Low                int32                         `json:"low"`
+	High               int32                         `json:"high"`
+	Rumina             int32                         `json:"rumina"`
+	Active             int32                         `json:"active"`
+	Intake             int32                         `json:"intake"`
+	Inactive           int32                         `json:"inactive"`
+	Other              int32                         `json:"other"`
+	Voltage            int32                         `json:"voltage"`
+	Upper              int32                         `json:"upper"`
+	Version            int32                         `json:"version"`
+	Sign               int32                         `json:"sign"`
+	Remain             int32                         `json:"remain"`
+	Feed               int32                         `json:"feed"`
+	Imei               string                        `json:"imei" `
+	Temp               int32                         `json:"temp"`
+	Gasp               int32                         `json:"gasp"`
+	Hours              int32                         `json:"hours"`
+	ActiveDate         string                        `json:"activeDate"`
+	ActiveDateType     pasturePb.ActiveTimeType_Kind `json:"ActiveDateTimeType"`
+	IsShow             pasturePb.IsShow_Kind         `json:"isShow"`
+	ReceiveNumber      string                        `json:"receiveNumber"`
+	ShortReceiveNumber string                        `json:"shortReceiveNumber"`
+	CreatedAt          int64                         `json:"createdAt"`
+	UpdatedAt          int64                         `json:"updatedAt"`
+}
+
+func (s *NeckRingOriginal) TableName() string {
+	return "neck_ring_original"
+}

+ 32 - 0
model/neck_ring_unregist.go

@@ -0,0 +1,32 @@
+package model
+
+import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+
+type NeckRingUnRegister struct {
+	Id             int64                 `json:"id"`
+	Uuid           string                `json:"uuid"`
+	FrameId        int32                 `json:"frameId"`
+	Low            int32                 `json:"low"`
+	High           int32                 `json:"high"`
+	Rumina         int32                 `json:"rumina"`
+	Active         int32                 `json:"active"`
+	Intake         int32                 `json:"intake"`
+	Inactive       int32                 `json:"inactive"`
+	Other          int32                 `json:"other"`
+	Voltage        int32                 `json:"voltage"`
+	Upper          int32                 `json:"upper"`
+	Version        int32                 `json:"version"`
+	Sign           int32                 `json:"sign"`
+	Remain         int32                 `json:"remain"`
+	Feed           int32                 `json:"feed"`
+	Imei           string                `json:"imei" `
+	Temp           int32                 `json:"temp"`
+	ActiveDateTime string                `json:"activeDateTime"`
+	IsShow         pasturePb.IsShow_Kind `json:"isShow"`
+	CreatedAt      int64                 `json:"createdAt"`
+	UpdatedAt      int64                 `json:"updatedAt"`
+}
+
+func (s *NeckRingUnRegister) TableName() string {
+	return "neck_ring_unregister"
+}

+ 81 - 0
model/outbound.go

@@ -0,0 +1,81 @@
+package model
+
+import (
+	"fmt"
+	"kpt-pasture/util"
+	"time"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
+
+type Outbound struct {
+	Id               int32                      `json:"id"`
+	Number           string                     `json:"number"`
+	OutType          pasturePb.OutType_Kind     `json:"outType"`
+	AuditStatus      pasturePb.AuditStatus_Kind `json:"auditStatus"`
+	ApplicantId      int32                      `json:"applicantId"`
+	ApplicantName    string                     `json:"applicantName"`
+	ApplicantAt      int64                      `json:"applicantAt"`
+	ApplicantRemarks string                     `json:"applicantRemarks"`
+	ExamineId        int32                      `json:"examineId"`
+	ExamineName      string                     `json:"examineName"`
+	ExamineAt        int64                      `json:"examineAt"`
+	ExamineRemarks   string                     `json:"examineRemarks"`
+	CreatedAt        int64                      `json:"createdAt"`
+	UpdatedAt        int64                      `json:"updatedAt"`
+}
+
+func (o *Outbound) TableName() string {
+	return "outbound"
+}
+
+func NewOutbound(req *pasturePb.OutboundApplyItem, currentUser *SystemUser) *Outbound {
+	return &Outbound{
+		Number:           fmt.Sprintf("%s%s", util.GenerateRandomNumberString(6), time.Now().Format(LayoutTime)),
+		OutType:          req.OutType,
+		AuditStatus:      pasturePb.AuditStatus_Pending,
+		ApplicantId:      int32(currentUser.Id),
+		ApplicantName:    currentUser.Name,
+		ApplicantAt:      time.Now().Unix(),
+		ApplicantRemarks: req.ApplicantRemarks,
+	}
+}
+
+type OutboundSlice []*Outbound
+
+func (o OutboundSlice) ToPB(outTypeMap map[pasturePb.OutType_Kind]string, auditStatusMap map[pasturePb.AuditStatus_Kind]string) []*pasturePb.OutboundApplyDetail {
+	res := make([]*pasturePb.OutboundApplyDetail, len(o))
+	for i, v := range o {
+		applicantAtFormat, examineAtFormat, outTypeName, auditStatusName := "", "", "", ""
+		if v.ApplicantAt > 0 {
+			applicantAtFormat = time.Unix(v.ApplicantAt, 0).Format(LayoutTime)
+		}
+		if v.ExamineAt > 0 {
+			examineAtFormat = time.Unix(v.ExamineAt, 0).Format(LayoutTime)
+		}
+
+		if outType, ok := outTypeMap[v.OutType]; ok {
+			outTypeName = outType
+		}
+
+		if auditStatus, ok := auditStatusMap[v.AuditStatus]; ok {
+			auditStatusName = auditStatus
+		}
+
+		res[i] = &pasturePb.OutboundApplyDetail{
+			Id:                v.Id,
+			Number:            v.Number,
+			OutType:           v.OutType,
+			OutTypeName:       outTypeName,
+			AuditStatus:       v.AuditStatus,
+			AuditStatusName:   auditStatusName,
+			ApplicantName:     v.ApplicantName,
+			ApplicantRemarks:  v.ApplicantRemarks,
+			ExamineName:       v.ExamineName,
+			ExamineRemarks:    v.ExamineRemarks,
+			ApplicantAtFormat: applicantAtFormat,
+			ExamineAtFormat:   examineAtFormat,
+		}
+	}
+	return res
+}

+ 64 - 0
model/outbound_log.go

@@ -0,0 +1,64 @@
+package model
+
+import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+
+type OutboundLog struct {
+	Id          int64               `json:"id"`
+	OutboundId  int64               `json:"outboundId"`
+	GoodsId     int64               `json:"goodsId"`
+	GoodsName   string              `json:"goodsName"`
+	Specs       string              `json:"specs"`
+	Producer    string              `json:"producer"`
+	BatchNumber string              `json:"batchNumber"`
+	Price       int32               `json:"price"`
+	Unit        pasturePb.Unit_Kind `json:"unit"`
+	UnitName    string              `json:"unitName"`
+	Quantity    int32               `json:"quantity"`
+	CreatedAt   int64               `json:"createdAt"`
+	UpdatedAt   int64               `json:"updatedAt"`
+}
+
+func (o *OutboundLog) TableName() string {
+	return "outband_log"
+}
+
+func NewOutboundLogList(req []*pasturePb.OutboundApplyGoodsItem, unitMap map[pasturePb.Unit_Kind]string) []*OutboundLog {
+	res := make([]*OutboundLog, 0)
+	for _, v := range req {
+		unitName := ""
+		if unit, ok := unitMap[v.Unit]; ok {
+			unitName = unit
+		}
+		res = append(res, &OutboundLog{
+			GoodsId:     int64(v.GoodsId),
+			GoodsName:   v.GoodsName,
+			Specs:       v.Specs,
+			Producer:    v.Producer,
+			BatchNumber: v.BatchNumber,
+			Price:       int32(v.Price * 100),
+			Unit:        v.Unit,
+			UnitName:    unitName,
+			Quantity:    int32(v.Quantity),
+		})
+	}
+	return res
+}
+
+type OutboundLogSlice []*OutboundLog
+
+func (o OutboundLogSlice) ToPB() []*pasturePb.OutboundApplyGoodsItem {
+	res := make([]*pasturePb.OutboundApplyGoodsItem, len(o))
+	for i, v := range o {
+		res[i] = &pasturePb.OutboundApplyGoodsItem{
+			GoodsId:     int32(v.GoodsId),
+			GoodsName:   v.GoodsName,
+			Specs:       v.Specs,
+			Producer:    v.Producer,
+			BatchNumber: v.BatchNumber,
+			Price:       float32(v.Price) / 100,
+			Unit:        v.Unit,
+			Quantity:    uint32(v.Quantity),
+		}
+	}
+	return res
+}

+ 48 - 6
model/pen.go

@@ -6,8 +6,10 @@ import (
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 )
 
+const IsAllYes = "Yes"
+
 type Pen struct {
-	Id                int64                 `json:"id"`
+	Id                int32                 `json:"id"`
 	Name              string                `json:"name"`
 	Remarks           string                `json:"remarks"`
 	PenType           int32                 `json:"pen_type"`
@@ -41,7 +43,7 @@ func (p PenSlice) ToPB(configBarnTypes []*ConfigPenType) []*pasturePb.SearchBarn
 		}
 
 		res[i] = &pasturePb.SearchBarnList{
-			Id:                int32(v.Id),
+			Id:                v.Id,
 			Name:              v.Name,
 			IsShow:            v.IsShow,
 			Remarks:           v.Remarks,
@@ -60,9 +62,16 @@ func (p PenSlice) ToPB(configBarnTypes []*ConfigPenType) []*pasturePb.SearchBarn
 	return res
 }
 
-func (p PenSlice) ToPB2(req []*pasturePb.ConfigOptionsList) []*pasturePb.ConfigOptionsList {
-	res := make([]*pasturePb.ConfigOptionsList, len(p))
-	for i, d := range p {
+func (p PenSlice) ToPB2(req []*pasturePb.ConfigOptionsList, isAll string) []*pasturePb.ConfigOptionsList {
+	res := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == IsAllYes {
+		res = append(res, &pasturePb.ConfigOptionsList{
+			Value:    int32(0),
+			Label:    "全部",
+			Disabled: true,
+		})
+	}
+	for _, d := range p {
 		label := d.Name
 		for _, r := range req {
 			if r.Value != d.PenType {
@@ -70,11 +79,44 @@ func (p PenSlice) ToPB2(req []*pasturePb.ConfigOptionsList) []*pasturePb.ConfigO
 			}
 			label = fmt.Sprintf("%s-%s", label, r.Label)
 		}
-		res[i] = &pasturePb.ConfigOptionsList{
+		res = append(res, &pasturePb.ConfigOptionsList{
 			Value:    int32(d.Id),
 			Label:    label,
 			Disabled: true,
+		})
+	}
+	return res
+}
+
+type PenWeight struct {
+	PenId     int32 `json:"penId"`
+	CowCount  int32 `json:"cowCount"`
+	AllWeight int32 `json:"allWeight"`
+	AvgWeight int32 `json:"avgWeight"`
+}
+
+type PenWeightSlice []*PenWeight
+
+func (p PenWeightSlice) ToPB(penMap map[int32]*Pen) *pasturePb.PenWeightChart {
+	res := &pasturePb.PenWeightChart{}
+	for _, v := range p {
+		penName := ""
+		if pen, ok := penMap[v.PenId]; ok {
+			penName = pen.Name
 		}
+		res.Header = append(res.Header, penName)
+		res.AllWeight = append(res.AllWeight, v.AllWeight)
+		res.AvgWeight = append(res.AvgWeight, v.AvgWeight)
+		res.CowCount = append(res.CowCount, v.CowCount)
 	}
 	return res
 }
+
+func (p PenWeightSlice) GetPenWeight(penId int32) *PenWeight {
+	for _, v := range p {
+		if v.PenId == penId {
+			return v
+		}
+	}
+	return nil
+}

+ 34 - 30
model/prescription.go

@@ -1,15 +1,14 @@
 package model
 
 import (
-	"encoding/json"
+	"strconv"
+	"strings"
 
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
-	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
-	"go.uber.org/zap"
 )
 
 type Prescription struct {
-	Id                int64                 `json:"id"`
+	Id                int32                 `json:"id"`
 	Name              string                `json:"name"`
 	ApplicableDisease string                `json:"applicable_disease"`
 	UseDays           int32                 `json:"use_days"`
@@ -28,11 +27,6 @@ func (p *Prescription) TableName() string {
 	return "prescription"
 }
 
-type ApplicableDisease struct {
-	DiseaseId   int64  `json:"disease_id"`
-	DiseaseName string `json:"disease_name"`
-}
-
 func NewPrescription(req *pasturePb.PrescriptionRequest, applicableDisease string, useDays,
 	meatExpiredDays, milkExpiredDays int32, systemUser *SystemUser) *Prescription {
 	return &Prescription{
@@ -51,38 +45,36 @@ func NewPrescription(req *pasturePb.PrescriptionRequest, applicableDisease strin
 
 type PrescriptionSlice []*Prescription
 
-func (p PrescriptionSlice) ToPB(prescriptionDrugsList []*PrescriptionDrugs) []*pasturePb.SearchPrescriptionList {
+func (p PrescriptionSlice) ToPB(prescriptionDrugsList []*PrescriptionDrugs, diseaseMap map[int64]*Disease) []*pasturePb.SearchPrescriptionList {
 	res := make([]*pasturePb.SearchPrescriptionList, len(p))
 	for i, v := range p {
 		drugsList := make([]*pasturePb.PrescriptionDrugsList, 0)
-		for _, d := range prescriptionDrugsList {
-			if d.PrescriptionId != v.Id {
+		for _, pl := range prescriptionDrugsList {
+			if pl.PrescriptionId != v.Id {
 				continue
 			}
 			drugsList = append(drugsList, &pasturePb.PrescriptionDrugsList{
-				Id:        int32(d.Id),
-				DrugsId:   int32(d.DrugsId),
-				DrugsName: d.DrugsName,
-				Unit:      d.Unit,
-				UnitName:  d.UnitName,
-				Dosages:   d.Dosages,
-				UseDays:   d.UseDays,
-				Specs:     d.Specs,
+				Id:        pl.Id,
+				DrugsId:   int32(pl.DrugsId),
+				DrugsName: pl.DrugsName,
+				Unit:      pl.Unit,
+				UnitName:  pl.UnitName,
+				Dosages:   pl.Dosages,
+				UseDays:   pl.UseDays,
+				Specs:     pl.Specs,
 			})
 		}
-		applicableDiseaseList := make([]*ApplicableDisease, 0)
-		if v.ApplicableDisease != "" {
-			err := json.Unmarshal([]byte(v.ApplicableDisease), &applicableDiseaseList)
-			if err != nil {
-				zaplog.Error("PrescriptionSliceToPB", zap.Any("err", err))
-			}
-		}
+		applicableDiseaseList := strings.Split(v.ApplicableDisease, ",")
 		applicableDiseaseNames := make([]string, 0)
 		applicableDiseaseIds := make([]int32, 0)
-		for _, a := range applicableDiseaseList {
-			applicableDiseaseNames = append(applicableDiseaseNames, a.DiseaseName)
-			applicableDiseaseIds = append(applicableDiseaseIds, int32(a.DiseaseId))
+		for _, ad := range applicableDiseaseList {
+			diseaseId, _ := strconv.ParseInt(ad, 10, 64)
+			applicableDiseaseIds = append(applicableDiseaseIds, int32(diseaseId))
+			if dis, ok := diseaseMap[diseaseId]; ok {
+				applicableDiseaseNames = append(applicableDiseaseNames, dis.Name)
+			}
 		}
+
 		res[i] = &pasturePb.SearchPrescriptionList{
 			Id:                     int32(v.Id),
 			Name:                   v.Name,
@@ -104,3 +96,15 @@ func (p PrescriptionSlice) ToPB(prescriptionDrugsList []*PrescriptionDrugs) []*p
 	}
 	return res
 }
+
+func (p PrescriptionSlice) ToPB2() []*pasturePb.ConfigOptionsList {
+	res := make([]*pasturePb.ConfigOptionsList, len(p))
+	for i, d := range p {
+		res[i] = &pasturePb.ConfigOptionsList{
+			Value:    int32(d.Id),
+			Label:    d.Name,
+			Disabled: true,
+		}
+	}
+	return res
+}

+ 3 - 3
model/prescription_drugs.go

@@ -3,8 +3,8 @@ package model
 import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 
 type PrescriptionDrugs struct {
-	Id             int64                 `json:"id"`
-	PrescriptionId int64                 `json:"prescription_id"`
+	Id             int32                 `json:"id"`
+	PrescriptionId int32                 `json:"prescription_id"`
 	DrugsId        int64                 `json:"drugs_id"`
 	DrugsName      string                `json:"drugs_name"`
 	UseDays        int32                 `json:"use_days"`
@@ -21,7 +21,7 @@ func (p *PrescriptionDrugs) TableName() string {
 	return "prescription_drugs"
 }
 
-func NewPrescriptionDrugs(prescriptionId int64, req *pasturePb.PrescriptionRequest) []*PrescriptionDrugs {
+func NewPrescriptionDrugs(prescriptionId int32, req *pasturePb.PrescriptionRequest) []*PrescriptionDrugs {
 	res := make([]*PrescriptionDrugs, len(req.DrugsList))
 	for i, v := range req.DrugsList {
 		res[i] = &PrescriptionDrugs{

+ 14 - 0
model/sale_dealer.go

@@ -0,0 +1,14 @@
+package model
+
+type SaleDealer struct {
+	Id        int64  `json:"id"`
+	Name      string `json:"name"`
+	Phone     string `json:"phone"`
+	Address   string `json:"address"`
+	CreatedAt int64  `json:"createdAt"`
+	UpdatedAt int64  `json:"updatedAt"`
+}
+
+func (s *SaleDealer) TableName() string {
+	return "sale_dealer"
+}

+ 15 - 15
model/same_time.go

@@ -10,19 +10,19 @@ import (
 )
 
 type SameTime struct {
-	Id                  int64                  `json:"id"`
-	Name                string                 `json:"name"`
-	WeekType            pasturePb.Week_Kind    `json:"weekType"`
-	CowType             pasturePb.CowType_Kind `json:"cowType"`
-	IsShow              pasturePb.IsShow_Kind  `json:"isShow"`
-	IsDelete            pasturePb.IsShow_Kind  `json:"isDelete"`
-	PostpartumDaysStart int32                  `json:"postpartumDaysStart"`
-	PostpartumDaysEnd   int32                  `json:"postpartumDaysEnd"`
-	CollateNodes        string                 `json:"collateNodes"`
-	Remarks             string                 `json:"remarks"`
-	OperationId         int64                  `json:"operationId"`
-	CreatedAt           int64                  `json:"createdAt"`
-	UpdatedAt           int64                  `json:"updatedAt"`
+	Id                  int64                          `json:"id"`
+	Name                string                         `json:"name"`
+	WeekType            pasturePb.Week_Kind            `json:"weekType"`
+	CowType             pasturePb.SameTimeCowType_Kind `json:"cowType"`
+	IsShow              pasturePb.IsShow_Kind          `json:"isShow"`
+	IsDelete            pasturePb.IsShow_Kind          `json:"isDelete"`
+	PostpartumDaysStart int32                          `json:"postpartumDaysStart"`
+	PostpartumDaysEnd   int32                          `json:"postpartumDaysEnd"`
+	CollateNodes        string                         `json:"collateNodes"`
+	Remarks             string                         `json:"remarks"`
+	OperationId         int64                          `json:"operationId"`
+	CreatedAt           int64                          `json:"createdAt"`
+	UpdatedAt           int64                          `json:"updatedAt"`
 }
 
 func (e *SameTime) TableName() string {
@@ -52,7 +52,7 @@ type SameTimeSlice []*SameTime
 
 func (e SameTimeSlice) ToPB(
 	weekMap map[pasturePb.Week_Kind]string,
-	cowTypeMap map[pasturePb.CowType_Kind]string,
+	sameTimeCowTypeMap map[pasturePb.SameTimeCowType_Kind]string,
 	systemUserList []*SystemUser,
 ) []*pasturePb.SearchSameTimeList {
 	res := make([]*pasturePb.SearchSameTimeList, len(e))
@@ -75,7 +75,7 @@ func (e SameTimeSlice) ToPB(
 			WeekType:            v.WeekType,
 			WeekName:            weekMap[v.WeekType],
 			CowType:             v.CowType,
-			CowTypeName:         cowTypeMap[v.CowType],
+			CowTypeName:         sameTimeCowTypeMap[v.CowType],
 			IsShow:              v.IsShow,
 			PostpartumDaysStart: v.PostpartumDaysStart,
 			PostpartumDaysEnd:   v.PostpartumDaysEnd,

+ 0 - 27
model/same_time_cow.go

@@ -1,27 +0,0 @@
-package model
-
-import (
-	"time"
-
-	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
-)
-
-type SameTimeCow struct {
-	Id         int64                 `json:"id"`
-	CowId      int64                 `json:"cowId"`
-	SameTimeId int64                 `json:"sameTimeId"`
-	Status     pasturePb.IsShow_Kind `json:"status"`
-	StartAt    int64                 `json:"startAt"`
-	EndAt      int64                 `json:"endAt"`
-	CreatedAt  int64                 `json:"createdAt"`
-	UpdatedAt  int64                 `json:"updatedAt"`
-}
-
-func NewSameTimeCow(cowId, sameTimeId int64) *SameTimeCow {
-	return &SameTimeCow{
-		CowId:      cowId,
-		SameTimeId: sameTimeId,
-		Status:     pasturePb.IsShow_Ok,
-		StartAt:    time.Now().Unix(),
-	}
-}

+ 44 - 0
model/system_basic.go

@@ -0,0 +1,44 @@
+package model
+
+import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+
+const (
+	ProactivelyStopBreedingForBackup = "proactively_stop_breeding_for_backup" // 后备牛主动停配
+	ProactivelyStopBreedingForAdult  = "proactively_stop_breeding_for_adult"  // 成母牛主动停配
+	PregnantCheckForFirst            = "pregnant_check_for_first"             // 怀孕检查-第一次
+	PregnantCheckForSecond           = "pregnant_check_for_second"            // 怀孕检查-第二次
+	PregnancyAge                     = "pregnancy_age"                        // 怀孕天数
+	WeaningAge                       = "weaning_age"                          // 断奶天数
+
+	ValueTypeFixed = 1 // 固定值
+	ValueTypeRange = 2 // 范围值
+)
+
+var PregnantCheckNameKeyMap = map[string]string{
+	PregnantCheckForFirst:  "初检",
+	PregnantCheckForSecond: "复检",
+}
+
+var PregnantCheckNameValueMap = map[int32]string{
+	1: "pregnant_check_for_first",
+	2: "pregnant_check_for_second",
+}
+
+type SystemBasic struct {
+	Id           int32                 `json:"id"`
+	Name         string                `json:"name"`
+	CategoryName string                `json:"categoryName"`
+	CategoryId   int32                 `json:"categoryId"`
+	MinValue     int32                 `json:"minValue"`
+	MaxValue     int32                 `json:"maxValue"`
+	WeekValue    pasturePb.Week_Kind   `json:"weekValue"`
+	ValueType    int8                  `json:"valueType"`
+	Remarks      string                `json:"remarks"`
+	IsShow       pasturePb.IsShow_Kind `json:"isShow"`
+	CreatedAt    int64                 `json:"createdAt"`
+	UpdatedAt    int64                 `json:"updatedAt"`
+}
+
+func (s *SystemBasic) TableName() string {
+	return "system_basic"
+}

+ 1 - 0
model/system_role.go

@@ -24,6 +24,7 @@ const (
 	LayoutTime  = "2006-01-02 15:04:05"
 	LayoutDate  = "20060102"
 	LayoutDate2 = "2006-01-02"
+	LayoutMonth = "2006-01"
 )
 
 type SystemRoleSlice []*SystemRole

+ 0 - 32
model/work_order_calendar.go

@@ -1,32 +0,0 @@
-package model
-
-import (
-	"time"
-
-	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
-)
-
-type WorkOrderCalendar struct {
-	Id           int64                       `json:"id"`
-	Name         string                      `json:"name"`
-	CalendarType pasturePb.CalendarType_Kind `json:"calendarType"`
-	Count        int32                       `json:"count"`
-	ShowDay      string                      `json:"showDay"`
-	IsShow       pasturePb.IsShow_Kind       `json:"isShow"`
-	CreatedAt    int64                       `json:"createdAt"`
-	UpdatedAt    int64                       `json:"updatedAt"`
-}
-
-func (w *WorkOrderCalendar) TableName() string {
-	return "work_order_calendar"
-}
-
-func NewWorkOrderCalendar(name string, calendarType pasturePb.CalendarType_Kind, count int32) *WorkOrderCalendar {
-	return &WorkOrderCalendar{
-		Name:         name,
-		Count:        count,
-		CalendarType: calendarType,
-		ShowDay:      time.Now().Format(LayoutDate2),
-		IsShow:       pasturePb.IsShow_Ok,
-	}
-}

+ 0 - 45
model/work_order_list.go

@@ -1,45 +0,0 @@
-package model
-
-import (
-	"kpt-pasture/util"
-	"time"
-
-	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
-)
-
-type WorkOrderList struct {
-	Id           int64                 `json:"id"`
-	CalendarId   int64                 `json:"calendarId"`
-	Name         string                `json:"name"`
-	CowId        int64                 `json:"cowId"`
-	StartAt      int64                 `json:"startAt"`
-	FinishAt     int64                 `json:"finishAt"`
-	EndAt        int64                 `json:"endAt"`
-	DisUserId    int64                 `json:"disUserId"`
-	ExecUserId   int64                 `json:"execUserId"`
-	IsCompletion pasturePb.IsShow_Kind `json:"isCompletion"`
-	IsShow       pasturePb.IsShow_Kind `json:"isShow"`
-	Remarks      string                `json:"remarks"`
-	CreatedAt    int64                 `json:"createdAt"`
-	UpdatedAt    int64                 `json:"updatedAt"`
-}
-
-func (w *WorkOrderList) TableName() string {
-	return "work_order_list"
-}
-
-func NewWorkOrderList(name string, calendarId, cowId int64) *WorkOrderList {
-	return &WorkOrderList{
-		CalendarId:   calendarId,
-		Name:         name,
-		CowId:        cowId,
-		StartAt:      util.TimeParseLocalUnix(time.Now().Format(LayoutDate2)),
-		FinishAt:     0,
-		EndAt:        0,
-		DisUserId:    0,
-		ExecUserId:   0,
-		IsCompletion: pasturePb.IsShow_No,
-		IsShow:       pasturePb.IsShow_Ok,
-		Remarks:      "",
-	}
-}

+ 8 - 5
model/work_order_master.go

@@ -16,12 +16,12 @@ import (
 )
 
 const (
-	QueueWorkOrder = "workOrder"
-	TaskWorkOrder  = "event:workOrder"
+	QueueWork     = "work"
+	TaskWorkOrder = "event:workOrder"
 )
 
 func AsynqQueueWorkOrder() asynq.Option {
-	return asynq.Queue(QueueWorkOrder)
+	return asynq.Queue(QueueWork)
 }
 
 type WorkOrderMaster struct {
@@ -113,8 +113,11 @@ func NewTaskWorkOrderPayload(id int64, execTime time.Duration) *asynq.Task {
 		WorkOrderId: id,
 	})
 	processAt := time.Now().Add(execTime).Unix()
-
-	return asynq.NewTask(fmt.Sprintf("%s:%s", config.Options().FarmName, TaskWorkOrder), payload, NewTaskWorkOrderOption(processAt)...)
+	return asynq.NewTask(
+		fmt.Sprintf("%s:%s", config.Options().FarmName, TaskWorkOrder),
+		payload,
+		NewTaskWorkOrderOption(processAt)...,
+	)
 }
 
 type WorkOrderMasterSlice []*WorkOrderMaster

+ 6 - 6
module/consumer/consumer.go → module/asynq/consumer.go

@@ -1,4 +1,4 @@
-package consumer
+package asynq
 
 import (
 	"context"
@@ -7,10 +7,10 @@ import (
 	"kpt-pasture/model"
 	"kpt-pasture/util"
 
-	"gorm.io/gorm"
-
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 
+	"gorm.io/gorm"
+
 	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
 	"gitee.com/xuyiping_admin/pkg/xerr"
 	"go.uber.org/zap"
@@ -34,9 +34,9 @@ func (entry *Entry) DayWorkOrder(ctx context.Context, t *asynq.Task) error {
 
 	localExecTime, _ := util.ConvertParseLocalUnix(workOrder.ExecTime)
 	workOrderSubList := make([]*model.WorkOrderSub, 0)
-	if err := entry.DB.Where("work_order_master_id = ?", req.WorkOrderId).
+	if err := entry.DB.Where("is_show = ?", pasturePb.IsShow_Ok).
+		Where("work_order_master_id = ?", req.WorkOrderId).
 		Where("exec_time = ?", localExecTime).
-		Where("is_show = ?", pasturePb.IsShow_Ok).
 		Find(&workOrderSubList).Error; err != nil {
 		if !errors.Is(err, gorm.ErrRecordNotFound) {
 			zaplog.Error("consumer", zap.Any("mark", "DayWorkOrder"), zap.Any("WorkOrderSub", err))
@@ -52,6 +52,6 @@ func (entry *Entry) DayWorkOrder(ctx context.Context, t *asynq.Task) error {
 	if err := entry.DB.Create(workOrderSubList).Error; err != nil {
 		zaplog.Error("consumer", zap.Any("mark", "DayWorkOrder"), zap.Any("NewWorkOrderSub", err))
 	}
-
+	zaplog.Info("consumer", zap.Any("DayWorkOrder", "success"))
 	return nil
 }

+ 2 - 4
module/consumer/interface.go → module/asynq/interface.go

@@ -1,4 +1,4 @@
-package consumer
+package asynq
 
 import (
 	"context"
@@ -12,9 +12,7 @@ import (
 	"go.uber.org/dig"
 )
 
-var Module = di.Options(
-	di.Provide(NewJob),
-)
+var Module = di.Options(di.Provide(NewJob))
 
 func NewJob(entry Entry) BizExec {
 	return &entry

+ 441 - 3
module/backend/analysis.go

@@ -2,21 +2,24 @@ package backend
 
 import (
 	"context"
+	"fmt"
 	"kpt-pasture/model"
+	"kpt-pasture/util"
 	"net/http"
 	"strings"
 	"time"
 
-	"gitee.com/xuyiping_admin/pkg/xerr"
-
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
+	"gitee.com/xuyiping_admin/pkg/xerr"
+	"go.uber.org/zap"
 )
 
 // GrowthCurve 生长曲线 获取图表数据
 func (s *StoreEntry) GrowthCurve(ctx context.Context, req *pasturePb.SearchGrowthCurvesRequest) (*pasturePb.GrowthCurvesResponse, error) {
 	// 查询数据
 	cowList := make([]*model.Cow, 0)
-	pref := s.DB.Model(new(model.Cow)).Where("is_remove = ?", pasturePb.IsShow_Ok)
+	pref := s.DB.Model(new(model.Cow)).Where("admission_status = ?", pasturePb.AdmissionStatus_Admission)
 	if req.GetCowId() != "" {
 		pref.Where("id IN ?", strings.Split(req.CowId, ","))
 	}
@@ -80,3 +83,438 @@ func (s *StoreEntry) GrowthCurve(ctx context.Context, req *pasturePb.SearchGrowt
 	}, nil
 
 }
+
+func (s *StoreEntry) WeightRange(ctx context.Context, req *pasturePb.WeightRangeRequest) (*pasturePb.WeightRangeResponse, error) {
+	cowWeightRange := make([]*model.CowWeightRange, 0)
+
+	prefix := s.DB.Model(new(model.Cow)).Where("admission_status = ?", pasturePb.AdmissionStatus_Admission)
+	if req.CowKind > 0 {
+		prefix.Where("cow_kind = ?", req.CowKind)
+	}
+	if err := prefix.Select(`
+		CASE 
+			WHEN current_weight BETWEEN 0 AND 50000 THEN '0-50'  
+			WHEN current_weight BETWEEN 50001 AND 100000 THEN '51-100' 
+			WHEN current_weight BETWEEN 100001 AND 150000 THEN '101-150' 
+			WHEN current_weight BETWEEN 150001 AND 200000 THEN '151-200' 
+			WHEN current_weight BETWEEN 200001 AND 250000 THEN '201-250' 
+			WHEN current_weight BETWEEN 250001 AND 300000 THEN '251-300' 
+			WHEN current_weight BETWEEN 300001 AND 350000 THEN '301-350' 
+			WHEN current_weight BETWEEN 350001 AND 400000 THEN '351-400' 
+			WHEN current_weight BETWEEN 400001 AND 450000 THEN '401-450' 
+			WHEN current_weight BETWEEN 450001 AND 500000 THEN '451-500' 
+			WHEN current_weight BETWEEN 500001 AND 550000 THEN '500-550' 
+			WHEN current_weight BETWEEN 550001 AND 600000 THEN '551-600' 
+			WHEN current_weight BETWEEN 600001 AND 650000 THEN '601-650' 
+			WHEN current_weight BETWEEN 650001 AND 700000 THEN '651-700' 
+			WHEN current_weight BETWEEN 700001 AND 750000 THEN '701-750' 
+			ELSE '750+'  
+		END AS weight_range, 
+		COUNT(*) AS count `,
+	).Group("weight_range").Order("MIN(current_weight)").Find(&cowWeightRange).Error; err != nil {
+		return nil, err
+	}
+
+	if len(cowWeightRange) == 0 {
+		return &pasturePb.WeightRangeResponse{
+			Code:    http.StatusOK,
+			Message: "ok",
+			Data: &pasturePb.WeightRangeData{
+				CowList: make([]*pasturePb.CowList, 0),
+				WeightBarChart: &pasturePb.WeightBarChart{
+					Header: make([]string, 0),
+					Data:   make([]int32, 0),
+				},
+			},
+		}, nil
+	}
+	header := make([]string, 0)
+	data := make([]int32, 0)
+	for _, v := range cowWeightRange {
+		header = append(header, v.WeightRange)
+		data = append(data, v.Count)
+	}
+	// 牛只详情列表
+	pref := s.DB.Model(new(model.Cow)).Where("admission_status = ?", pasturePb.AdmissionStatus_Admission)
+	if req.CowKind > 0 {
+		pref.Where("cow_kind = ?", req.CowKind)
+	}
+	cowList := make([]*model.Cow, 0)
+	if req.MinWeight >= 0 && req.MaxWeight >= 0 && req.MinWeight < req.MaxWeight {
+		pref.Where("current_weight BETWEEN  ? AND ? ", req.MinWeight*1000, req.MaxWeight*1000)
+	}
+
+	if err := pref.Find(&cowList).Error; err != nil {
+		return nil, err
+	}
+
+	penMap := s.PenMap(ctx)
+	return &pasturePb.WeightRangeResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data: &pasturePb.WeightRangeData{
+			CowList: model.CowSlice(cowList).WeightRangeToPB(penMap),
+			WeightBarChart: &pasturePb.WeightBarChart{
+				Header: header,
+				Data:   data,
+			},
+		},
+	}, nil
+}
+
+func (s *StoreEntry) MatingTimely(ctx context.Context, req *pasturePb.MatingTimelyRequest) (*model.MatingTimelyResponse, error) {
+	matingTimelyChart := make([]*model.MatingTimelyChart, 0)
+	sql := `SELECT calving_age,cow_type, DATE_FORMAT(FROM_UNIXTIME(reality_day), '%Y-%m-%d') AS reality_day, lact_group
+		FROM (
+			SELECT calving_age, cow_type,reality_day, '0' AS lact_group
+			FROM event_mating
+			WHERE lact = 0 AND status = 1
+			UNION ALL
+			SELECT calving_age,cow_type, reality_day, '1' AS lact_group
+			FROM event_mating
+			WHERE lact = 1 AND status = 1
+			UNION ALL
+			SELECT calving_age,cow_type,  reality_day, '2' AS lact_group
+			FROM event_mating
+			WHERE lact = 2 AND status = 1
+			UNION ALL
+			SELECT calving_age, cow_type, reality_day, '3+' AS lact_group
+			FROM event_mating
+			WHERE lact >= 3 AND status = 1
+		) AS subquery WHERE 1 = 1 `
+
+	whereSql := ""
+	if req.CowType > 0 {
+		whereSql += fmt.Sprintf("AND cow_type = %d ", req.CowType)
+	}
+
+	if req.StartDayAt > 0 && req.EndDayAt > 0 {
+		whereSql += fmt.Sprintf("AND reality_day BETWEEN %d AND %d", req.StartDayAt, req.EndDayAt)
+	}
+	if err := s.DB.Raw(fmt.Sprintf("%s %s", sql, whereSql)).Find(&matingTimelyChart).Error; err != nil {
+		return nil, err
+	}
+
+	chart := &model.CowMatingChart{
+		Lact0: make([][]string, 0),
+		Lact1: make([][]string, 0),
+		Lact2: make([][]string, 0),
+		Lact3: make([][]string, 0),
+	}
+	if len(matingTimelyChart) == 0 {
+		return &model.MatingTimelyResponse{
+			Code:    http.StatusOK,
+			Message: "ok",
+			Data: &model.MatingTimelyData{
+				CowList: make([]*pasturePb.CowList, 0),
+				Chart:   chart,
+			},
+		}, nil
+	}
+	for _, v := range matingTimelyChart {
+		t, _ := time.Parse(model.LayoutDate2, v.RealityDay)
+		switch v.LactGroup {
+		case "0":
+			chart.Lact0 = append(chart.Lact0, []string{fmt.Sprintf("%d", t.Day()), fmt.Sprintf("%d", v.CalvingAge), v.RealityDay})
+		case "1":
+			chart.Lact1 = append(chart.Lact1, []string{fmt.Sprintf("%d", t.Day()), fmt.Sprintf("%d", v.CalvingAge), v.RealityDay})
+		case "2":
+			chart.Lact2 = append(chart.Lact2, []string{fmt.Sprintf("%d", t.Day()), fmt.Sprintf("%d", v.CalvingAge), v.RealityDay})
+		case "3+":
+			chart.Lact3 = append(chart.Lact3, []string{fmt.Sprintf("%d", t.Day()), fmt.Sprintf("%d", v.CalvingAge), v.RealityDay})
+		}
+	}
+
+	// 牛只详情列表
+	eventMatingList := make([]*model.EventMating, 0)
+	pref := s.DB.Model(new(model.EventMating)).
+		Where("status = ?", pasturePb.IsShow_Ok)
+	if req.CowType > 0 {
+		pref.Where("cow_type = ?", req.CowType)
+	}
+
+	if req.StartDayAt > 0 && req.EndDayAt > 0 {
+		pref.Where("reality_day BETWEEN ? AND ?", req.StartDayAt, req.EndDayAt)
+	}
+
+	if err := pref.Find(&eventMatingList).Error; err != nil {
+		return nil, err
+	}
+
+	return &model.MatingTimelyResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data: &model.MatingTimelyData{
+			CowList: model.EventMatingSlice(eventMatingList).ToPB2(),
+			Chart:   chart,
+		},
+	}, nil
+}
+
+func (s *StoreEntry) PenWeight(ctx context.Context, req *pasturePb.PenWeightRequest, pagination *pasturePb.PaginationModel) (*pasturePb.PenWeightResponse, error) {
+	penWeightList := make([]*model.PenWeight, 0)
+	pref := s.DB.Model(new(model.Cow)).
+		Select(`
+			pen_id,
+			CEILING(AVG(current_weight) / 1000 ) AS avg_weight,
+			CEILING(SUM(current_weight) / 1000 ) AS all_weight,
+			COUNT(*) AS cow_count`,
+		).Where("admission_status = ?", pasturePb.AdmissionStatus_Admission)
+	if len(req.PenId) > 0 && req.BarId <= 0 {
+		pref.Where("pen_id IN ?", req.PenId)
+	}
+	if err := pref.Group("pen_id").
+		Order("pen_id").
+		Find(&penWeightList).Error; err != nil {
+		return nil, err
+	}
+
+	chart := &pasturePb.PenWeightChart{
+		Header:    make([]string, 0),
+		AllWeight: make([]int32, 0),
+		AvgWeight: make([]int32, 0),
+		CowCount:  make([]int32, 0),
+	}
+	if len(penWeightList) <= 0 {
+		return &pasturePb.PenWeightResponse{
+			Code:    http.StatusOK,
+			Message: "ok",
+			Data: &pasturePb.PenWeightData{
+				CowList: make([]*pasturePb.CowList, 0),
+				Chart:   chart,
+			},
+		}, nil
+	}
+	cowList := make([]*model.Cow, 0)
+	var count int64 = 0
+	prefList := s.DB.Model(new(model.Cow)).
+		Where("admission_status = ?", pasturePb.AdmissionStatus_Admission)
+
+	if len(req.PenId) <= 0 && req.BarId > 0 {
+		prefList.Where("pen_id IN ?", []int32{req.BarId})
+	} else {
+		prefList.Where("pen_id IN ?", req.PenId)
+	}
+
+	if err := prefList.Count(&count).Limit(int(pagination.PageSize)).
+		Offset(int(pagination.PageOffset)).Order("pen_id").
+		Find(&cowList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	penMap := s.PenMap(ctx)
+	return &pasturePb.PenWeightResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data: &pasturePb.PenWeightData{
+			CowList:  model.CowSlice(cowList).ToPB2(penMap, penWeightList),
+			Total:    int32(count),
+			Page:     pagination.Page,
+			PageSize: pagination.PageSize,
+			Chart:    model.PenWeightSlice(penWeightList).ToPB(penMap),
+		},
+	}, nil
+}
+
+func (s *StoreEntry) AbortionRate(ctx context.Context, req *pasturePb.AbortionRateRequest) (*pasturePb.AbortionRateResponse, error) {
+
+	dayTimeList, err := util.GetMonthsInRange(req.StartDayTime, req.EndDayTime)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	lastDayForMonth := make([]string, 0)
+	for _, v := range dayTimeList {
+		lastDayTime, _ := util.GetLastDayOfMonth(v)
+		lastDayForMonth = append(lastDayForMonth, lastDayTime)
+	}
+	// 历史每月怀孕牛头数量
+	cowPregnantMonthList := make([]*model.CowPregnantMonth, 0)
+	pref := s.DB.Model(new(model.CowPregnant)).
+		Select(`
+			COUNT(cow_id) AS cow_count,
+			DATE_FORMAT(FROM_UNIXTIME(created_at),'%Y-%m') as month`,
+		).Where("cow_type = ?", req.CowType).
+		Where("DATE_FORMAT(FROM_UNIXTIME(`created_at`),'%Y-%m-%d') IN ?", lastDayForMonth)
+
+	if req.Lact >= 0 && req.Lact <= 3 {
+		pref.Where("lact = ?", req.Lact)
+	} else {
+		pref.Where("lact > ?", req.Lact)
+	}
+	if err = pref.Group("month").
+		Find(&cowPregnantMonthList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+	// 历史每月流产牛头数量
+	cowAbortionMonthList := make([]*model.CowPregnantMonth, 0)
+	pref2 := s.DB.Model(new(model.EventAbortion)).
+		Select(`
+			COUNT(cow_id) AS cow_count,
+			DATE_FORMAT(FROM_UNIXTIME(abortion_at),'%Y-%m') as month`,
+		).Where("cow_type = ?", req.CowType).
+		Where("DATE_FORMAT(FROM_UNIXTIME(`abortion_at`),'%Y-%m') IN ?", dayTimeList)
+
+	if req.Lact >= 0 {
+		pref2.Where("lact = ?", req.Lact)
+	}
+	if err = pref2.Group("month").Find(&cowAbortionMonthList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	chart := &pasturePb.AbortionRateChart{
+		Header:             make([]string, 0),
+		AbortionCountMonth: make([]int32, 0),
+		PregnantCountMonth: make([]int32, 0),
+		AbortionRateMonth:  make([]float32, 0),
+	}
+
+	table := make([]*pasturePb.AbortionRateTable, 0)
+	for _, v2 := range cowAbortionMonthList {
+		pregnantCountMonth := int32(0)
+		for _, v := range cowPregnantMonthList {
+			if v.Month == v2.Month {
+				pregnantCountMonth = v.CowCount
+			}
+		}
+		abortionRateMonth := float64(0)
+		if pregnantCountMonth > 0 && v2.CowCount > 0 {
+			abortionRateMonth = util.RoundToTwoDecimals(float64(v2.CowCount) / float64(pregnantCountMonth) * 100)
+		}
+
+		chart.Header = append(chart.Header, v2.Month)
+		chart.AbortionCountMonth = append(chart.AbortionCountMonth, v2.CowCount)
+		chart.PregnantCountMonth = append(chart.PregnantCountMonth, pregnantCountMonth)
+		chart.AbortionRateMonth = append(chart.AbortionRateMonth, float32(abortionRateMonth))
+
+		table = append(table, &pasturePb.AbortionRateTable{
+			AbortionCount: v2.CowCount,
+			MonthName:     v2.Month,
+			PregnantCount: pregnantCountMonth,
+			AbortionRate:  float32(abortionRateMonth),
+		})
+	}
+
+	return &pasturePb.AbortionRateResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data: &pasturePb.AbortionRateData{
+			Chart: chart,
+			Table: table,
+		},
+	}, nil
+}
+
+func (s *StoreEntry) TwentyOnePregnantRate(ctx context.Context, req *pasturePb.TwentyOnePregnantRateRequest) (*pasturePb.TwentyOnePregnantRateResponse, error) {
+	startUnix := util.TimeParseLocalUnix(req.StartDate)
+	endUnix := util.TimeParseLocalUnix(req.EndDate)
+
+	if startUnix > endUnix {
+		return nil, xerr.Customf("开始时间不能大于结束时间: %s ~ %d", req.StartDate, req.EndDate)
+	}
+
+	nowDateTime := time.Now()
+	if endUnix > nowDateTime.Unix() {
+		return nil, xerr.Customf("结束时间不能大于当前时间: %s ~ %s", req.EndDate, nowDateTime.Format(model.LayoutDate2))
+	}
+
+	dataRange, err := util.Get21DayPeriods(req.StartDate, req.EndDate)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+	chart := &pasturePb.TwentyOnePregnantRateChart{
+		Header:       make([]string, 0),
+		PregnantRate: make([]float32, 0),
+		MatingRate:   make([]float32, 0),
+	}
+
+	// 牛只主动停配期
+	systemBasicName := ""
+	switch req.CowType {
+	case pasturePb.CowType_Breeding_Calf:
+		systemBasicName = model.ProactivelyStopBreedingForAdult
+	case pasturePb.CowType_Reserve_Calf:
+		systemBasicName = model.ProactivelyStopBreedingForBackup
+	default:
+		return nil, xerr.Customf("不支持的牛只类型: %d", req.CowType)
+	}
+
+	systemBasic, err := s.GetSystemBasicByName(ctx, systemBasicName)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	stopBreedingDay := systemBasic.MinValue * 86400
+	dateCowList := make([][]*model.Cow, len(dataRange))
+
+	twentyOnePregnantRateList := make([]*pasturePb.TwentyOnePregnantRateList, 0)
+	for i, v := range dataRange {
+		middleDay, err := util.GetRangeDayMiddleDay(v, 11)
+		if err != nil {
+			return nil, xerr.WithStack(err)
+		}
+		middleDayUnix := util.TimeParseLocalEndUnix(middleDay)
+		chart.Header = append(chart.Header, fmt.Sprintf("%s ~ %s", v[0], v[1]))
+		cowList := s.TwentyonePregnantCowList(ctx, req.CowType, stopBreedingDay, middleDayUnix, []int64{})
+		twentyOnePregnantRateList = append(twentyOnePregnantRateList, &pasturePb.TwentyOnePregnantRateList{
+			StartDay:             v[0],
+			EndDay:               v[1],
+			ShouldBreedCount:     int32(len(cowList)),
+			RealityBreedCount:    0,
+			BreedRate:            0,
+			ShouldPregnantCount:  0,
+			RealityPregnantCount: 0,
+			PregnantRate:         0,
+			RealityAbortionCount: 0,
+			AbortionRate:         0,
+		})
+		dateCowList[i] = cowList
+	}
+
+	return &pasturePb.TwentyOnePregnantRateResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data: &pasturePb.TwentyOnePregnantRateData{
+			Chart: chart,
+			Table: &pasturePb.TwentyOnePregnantRateTable{
+				List:  twentyOnePregnantRateList,
+				Total: int32(len(dataRange)),
+			},
+		},
+	}, nil
+}
+
+// TwentyonePregnantCowList 21天牛只停配期牛只列表
+func (s *StoreEntry) TwentyonePregnantCowList(
+	ctx context.Context,
+	cowType pasturePb.CowType_Kind,
+	stopBreedingDay int32,
+	middleDay int64,
+	notInCow []int64,
+) []*model.Cow {
+	cowList := make([]*model.Cow, 0)
+	switch cowType {
+	case pasturePb.CowType_Reserve_Calf:
+		pref := s.DB.Model(new(model.Cow)).
+			Where("cow_type = ?", cowType).
+			Where("admission_status = ?", pasturePb.AdmissionStatus_Admission).
+			Where("is_pregnant = ?", pasturePb.IsShow_No).
+			Where("lact = ?", 0).
+			Where("birth_at + ? < ?", stopBreedingDay, middleDay)
+		if len(notInCow) > 0 {
+			pref = pref.Where("id NOT IN ?", notInCow)
+		}
+		if err := pref.Find(&cowList).Error; err != nil {
+			zaplog.Error("TwentyonePregnantCowList",
+				zap.Any("cowType", cowType),
+				zap.Any("stopBreedingDay", stopBreedingDay),
+				zap.Any("middleDay", middleDay),
+				zap.Any("notInCow", notInCow),
+			)
+		}
+	case pasturePb.CowType_Breeding_Calf:
+
+	}
+
+	return cowList
+}

+ 706 - 0
module/backend/analysis_breed.go

@@ -0,0 +1,706 @@
+package backend
+
+import (
+	"context"
+	"fmt"
+	"kpt-pasture/model"
+	"kpt-pasture/util"
+	"net/http"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+	"gitee.com/xuyiping_admin/pkg/xerr"
+)
+
+// SingleFactorInfantSurvivalRateAnalysis 单因素受胎率分析
+func (s *StoreEntry) SingleFactorInfantSurvivalRateAnalysis(ctx context.Context, req *pasturePb.SingleFactorPregnancyRateRequest) (*pasturePb.SingleFactorPregnancyRateResponse, error) {
+	startTimeUnix := util.TimeParseLocalUnix(req.StartDayTime)
+	endTimeUnix := util.TimeParseLocalEndUnix(req.EndDayTime)
+	if startTimeUnix == 0 || endTimeUnix == 0 || endTimeUnix <= startTimeUnix {
+		return nil, xerr.Custom("开始时间不能大于结束时间")
+	}
+	var err error
+	list := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
+	chart := &pasturePb.SingleFactorPregnancyRateChart{
+		Headers:             make([]string, 0),
+		PregnantRate:        make([]float32, 0),
+		MaxValue:            make([]int32, 0),
+		MinValue:            make([]int32, 0),
+		AveragePregnantRate: 0,
+	}
+	switch req.AnalysisMethod {
+	case pasturePb.SingleFactorAnalysisMethod_Cycle:
+		list, err = s.SingleFactorAnalysisMethodCycle(ctx, req)
+	case pasturePb.SingleFactorAnalysisMethod_Months:
+		list, err = s.SingleFactorAnalysisMethodMonths(ctx, req)
+	case pasturePb.SingleFactorAnalysisMethod_Mating_Times:
+		list, err = s.SingleFactorAnalysisMethodMatingTimes(ctx, req)
+	case pasturePb.SingleFactorAnalysisMethod_Breeding_Method:
+		list, err = s.SingleFactorAnalysisMethodBreeding(ctx, req)
+	case pasturePb.SingleFactorAnalysisMethod_Breeding_Company:
+		list, err = s.SingleFactorAnalysisMethodBreedingCompany(ctx, req)
+	case pasturePb.SingleFactorAnalysisMethod_Operation:
+		list, err = s.SingleFactorAnalysisMethodOperation(ctx, req)
+	case pasturePb.SingleFactorAnalysisMethod_Mating_Interval:
+		list, err = s.SingleFactorAnalysisMethodMatingInterval(ctx, req)
+	case pasturePb.SingleFactorAnalysisMethod_Bull:
+		list, err = s.SingleFactorAnalysisMethodBull(ctx, req)
+	case pasturePb.SingleFactorAnalysisMethod_Breeding_Cycle:
+		list, err = s.SingleFactorAnalysisMethodBreedingCycle(ctx, req)
+	case pasturePb.SingleFactorAnalysisMethod_Week:
+		list, err = s.SingleFactorAnalysisMethodWeek(ctx, req)
+	case pasturePb.SingleFactorAnalysisMethod_Lact:
+		list, err = s.SingleFactorAnalysisMethodLact(ctx, req)
+	default:
+		return nil, xerr.Custom("错误的统计方式")
+	}
+
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+	totalCountMap := make(map[int]int32, len(list))
+	allTotalCount := int32(0)     // 总头数
+	allPregnantRate := float64(0) // 总受胎率
+	for i, v := range list {
+		chart.Headers = append(chart.Headers, v.StatisticMethod)
+		pregnantRate := float64(0)
+		if v.EmptyPregnantCount+v.PregnantCount > 0 {
+			pregnantRate = float64(v.PregnantCount) / float64(v.EmptyPregnantCount+v.PregnantCount)
+		}
+		chart.PregnantRate = append(chart.PregnantRate, float32(util.RoundToTwoDecimals(pregnantRate*100)))
+		v.TotalCount = v.PregnantCount + v.EmptyPregnantCount + v.OtherCount
+		v.PregnantRate = float32(util.RoundToTwoDecimals(pregnantRate * 100))
+		spcRate := float32(0)
+		if v.PregnantRate > 0 {
+			spcRate = float32(util.RoundToTwoDecimals((float64(v.PregnantCount) / float64(v.TotalCount)) * 100))
+		}
+		v.SpceRate = spcRate
+		ci95Min, ci95Max := util.ConfidenceInterval2(pregnantRate, float64(v.TotalCount))
+		v.Ci95 = fmt.Sprintf("%d ~ %d", int32(ci95Min), int32(ci95Max))
+		chart.MaxValue = append(chart.MaxValue, int32(ci95Max))
+		chart.MinValue = append(chart.MinValue, int32(ci95Min))
+		totalCountMap[i] = v.TotalCount
+		allTotalCount += v.TotalCount
+		allPregnantRate += pregnantRate
+	}
+	for i, v := range totalCountMap {
+		if allTotalCount <= 0 || list[i].TotalCount <= 0 {
+			continue
+		}
+		list[i].TotalRate = float32(util.RoundToTwoDecimals(float64(v) / float64(allTotalCount) * 100))
+	}
+
+	if len(list) > 0 && allPregnantRate > 0 {
+		chart.AveragePregnantRate = float32(util.RoundToTwoDecimals(allPregnantRate/float64(len(list))) * 100)
+	}
+
+	return &pasturePb.SingleFactorPregnancyRateResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data: &pasturePb.SingleFactorPregnancyRateData{
+			Total: int32(len(list)),
+			List:  list,
+			Chart: chart,
+		},
+	}, nil
+}
+
+func (s *StoreEntry) SingleFactorAnalysisMethodCycle(ctx context.Context, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
+	dateTimeRange, err := util.GetRangeDayByDays(req.StartDayTime, req.EndDayTime, req.Value)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+	res := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
+
+	selectSql := ""
+	for _, v := range dateTimeRange {
+		if len(v) != 2 {
+			continue
+		}
+		startDayTimeUnix := util.TimeParseLocalUnix(v[0])
+		endDayTimeUnix := util.TimeParseLocalEndUnix(v[1])
+
+		selectSql += fmt.Sprintf(`
+			SELECT
+			'%s ~ %s' as  statistic_method,   
+			COUNT(DISTINCT CASE WHEN mating_result = %d AND mating_result_at > 0 THEN cow_id END) AS pregnant_count, -- 怀孕头数
+			COUNT(DISTINCT CASE WHEN mating_result = %d AND mating_result_at > 0 THEN cow_id END) AS empty_pregnant_count, -- 空怀头数
+			COUNT(DISTINCT CASE WHEN mating_result = %d AND mating_result_at > 0 THEN cow_id END) AS abortion_count, -- 流产头数
+			COUNT(DISTINCT CASE WHEN mating_result IN (%d, %d) THEN cow_id END) AS other_count, -- 其他数
+			(
+				COUNT(DISTINCT CASE WHEN mating_result = %d AND mating_result_at > 0 THEN cow_id END) +
+				COUNT(DISTINCT CASE WHEN mating_result = %d AND mating_result_at > 0 THEN cow_id END) +
+				COUNT(DISTINCT CASE WHEN mating_result IN (%d, %d) THEN cow_id END)
+			) AS total_count -- 总数
+			FROM event_mating WHERE status = %d AND reality_day BETWEEN %d AND %d
+		UNION ALL `, v[0], v[1], pasturePb.MatingResult_Pregnant, pasturePb.MatingResult_Empty, pasturePb.MatingResult_Abort,
+			pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch, pasturePb.MatingResult_Pregnant,
+			pasturePb.MatingResult_Empty, pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch,
+			pasturePb.IsShow_Ok, startDayTimeUnix, endDayTimeUnix)
+	}
+
+	if len(selectSql) > 0 {
+		selectSql = selectSql[:len(selectSql)-len("UNION ALL")-3] + ";"
+	}
+
+	if err = s.DB.Raw(selectSql).Scan(&res).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	return res, nil
+}
+
+func (s *StoreEntry) SingleFactorAnalysisMethodMonths(ctx context.Context, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
+	startDayTimeUnix := util.TimeParseLocalUnix(req.StartDayTime)
+	endDayTimeUnix := util.TimeParseLocalEndUnix(req.EndDayTime)
+	if startDayTimeUnix == 0 || endDayTimeUnix == 0 || endDayTimeUnix <= startDayTimeUnix {
+		return nil, xerr.Custom("开始时间不能大于结束时间")
+	}
+
+	res := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
+	pref := s.DB.Model(new(model.EventMating)).
+		Select(`
+		DATE_FORMAT(FROM_UNIXTIME(reality_day), '%Y-%m') AS months,
+		DATE_FORMAT(FROM_UNIXTIME(reality_day), '%Y-%m') AS statistic_method,
+		COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS pregnant_count, -- 怀孕头数  
+		COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS empty_pregnant_count, -- 空怀头数  
+		COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS abortion_count, -- 流产头数  
+		COUNT(DISTINCT CASE WHEN mating_result IN (?, ?) THEN cow_id END) AS other_count, -- 其他数
+		(  
+        	COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) +  
+        	COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) +  
+        	COUNT(DISTINCT CASE WHEN mating_result IN (?, ?) THEN cow_id END)  
+		) AS total_count -- 总数   
+		`, pasturePb.MatingResult_Pregnant, pasturePb.MatingResult_Empty, pasturePb.MatingResult_Abort,
+			pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch, pasturePb.MatingResult_Pregnant,
+			pasturePb.MatingResult_Empty, pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch).
+		Where("status = ?", pasturePb.IsShow_Ok).
+		Where("reality_day BETWEEN ? AND ?", startDayTimeUnix, endDayTimeUnix)
+	if req.CowType > 0 {
+		pref.Where("cow_type = ?", req.CowType)
+	}
+
+	if req.CowKind > 0 {
+		pref.Where("cow_kind = ?", req.CowKind)
+	}
+
+	if req.LactInterval > 0 {
+		switch req.LactInterval {
+		case pasturePb.CompareSymbol_Less_Than:
+			pref.Where("lact < ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Less_Than_Or_Equal_To:
+			pref.Where("lact <= ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Greater_Than:
+			pref.Where("lact > ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Greater_Than_Or_Equal_To:
+			pref.Where("lact >= ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Equal_To:
+			pref.Where("lact = ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Not_Equal_To:
+			pref.Where("lact != ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Between:
+			pref.Where("lact BETWEEN ? AND ? ", req.LactIntervalStartValue, req.LactIntervalEndValue)
+		default:
+			return nil, xerr.Custom("错误的胎次区间符号")
+		}
+	}
+
+	if err := pref.Group("months").Order("months").Find(&res).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+	return res, nil
+}
+
+func (s *StoreEntry) SingleFactorAnalysisMethodMatingTimes(ctx context.Context, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
+	res := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
+	return res, nil
+}
+
+func (s *StoreEntry) SingleFactorAnalysisMethodBreeding(ctx context.Context, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
+	startDayTimeUnix := util.TimeParseLocalUnix(req.StartDayTime)
+	endDayTimeUnix := util.TimeParseLocalEndUnix(req.EndDayTime)
+	res := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
+
+	if err := s.DB.Model(new(model.EventMating)).
+		Select(`
+		CASE  
+			WHEN expose_estrus_type = ? THEN '脖环揭发'  
+			WHEN expose_estrus_type = ? THEN '脚环/计步器'  
+			WHEN expose_estrus_type = ? THEN '自然发情'  
+			WHEN expose_estrus_type = ? THEN '同期'  
+        ELSE '未知'  
+    	END AS statistic_method,
+		COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS pregnant_count, -- 怀孕头数  
+		COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS empty_pregnant_count, -- 空怀头数  
+		COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS abortion_count, -- 流产头数  
+		COUNT(DISTINCT CASE WHEN mating_result IN (?, ?) THEN cow_id END) AS other_count, -- 其他数
+		(  
+        	COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) +  
+        	COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) +  
+        	COUNT(DISTINCT CASE WHEN mating_result IN (?, ?) THEN cow_id END)  
+		) AS total_count -- 总数
+		`, pasturePb.ExposeEstrusType_Neck_Ring, pasturePb.ExposeEstrusType_Foot_Ring,
+			pasturePb.ExposeEstrusType_Natural_Estrus, pasturePb.ExposeEstrusType_Same_Time,
+			pasturePb.MatingResult_Pregnant, pasturePb.MatingResult_Empty, pasturePb.MatingResult_Abort,
+			pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch, pasturePb.MatingResult_Pregnant,
+			pasturePb.MatingResult_Empty, pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch,
+		).Where("status = ?", pasturePb.IsShow_Ok).
+		Where("reality_day BETWEEN ? AND ?", startDayTimeUnix, endDayTimeUnix).
+		Where("cow_type = ?", req.CowType).
+		Group("expose_estrus_type").
+		Order("expose_estrus_type").
+		Find(&res).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+	return res, nil
+}
+
+func (s *StoreEntry) SingleFactorAnalysisMethodBreedingCompany(ctx context.Context, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
+	res := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
+	startDayTimeUnix := util.TimeParseLocalUnix(req.StartDayTime)
+	endDayTimeUnix := util.TimeParseLocalEndUnix(req.EndDayTime)
+	pref := s.DB.Table(fmt.Sprintf("%s as a", new(model.EventMating).TableName())).
+		Select(`
+		b.producer AS statistic_method,
+		COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS pregnant_count, -- 怀孕头数  
+		COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS empty_pregnant_count, -- 空怀头数  
+		COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS abortion_count, -- 流产头数  
+		COUNT(DISTINCT CASE WHEN mating_result IN (?, ?) THEN cow_id END) AS other_count, -- 其他数
+		(  
+        	COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) +  
+        	COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) +  
+        	COUNT(DISTINCT CASE WHEN mating_result IN (?, ?) THEN cow_id END)  
+		) AS total_count -- 总数
+	`, pasturePb.MatingResult_Pregnant, pasturePb.MatingResult_Empty, pasturePb.MatingResult_Abort,
+			pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch, pasturePb.MatingResult_Pregnant,
+			pasturePb.MatingResult_Empty, pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch).
+		Joins(fmt.Sprintf("left join %s as b on a.frozen_semen_number = b.bull_id ", new(model.FrozenSemen).TableName()))
+	if req.CowType > 0 {
+		pref.Where("a.cow_type = ?", req.CowType)
+	}
+	if req.CowKind > 0 {
+		pref.Where("a.cow_kind = ?", req.CowKind)
+	}
+
+	if req.LactInterval > 0 {
+		switch req.LactInterval {
+		case pasturePb.CompareSymbol_Less_Than:
+			pref.Where("a.lact < ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Less_Than_Or_Equal_To:
+			pref.Where("a.lact <= ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Greater_Than:
+			pref.Where("a.lact > ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Greater_Than_Or_Equal_To:
+			pref.Where("a.lact >= ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Equal_To:
+			pref.Where("a.lact = ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Not_Equal_To:
+			pref.Where("a.lact != ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Between:
+			pref.Where("a.lact BETWEEN ? AND ? ", req.LactIntervalStartValue, req.LactIntervalEndValue)
+		default:
+			return nil, xerr.Custom("错误的胎次区间符号")
+		}
+	}
+
+	if err := pref.Where("a.status = ?", pasturePb.IsShow_Ok).
+		Where("a.reality_day BETWEEN ? AND ?", startDayTimeUnix, endDayTimeUnix).
+		Group("b.producer").
+		Find(&res).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	return res, nil
+}
+
+func (s *StoreEntry) SingleFactorAnalysisMethodOperation(ctx context.Context, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
+	res := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
+	startDayTimeUnix := util.TimeParseLocalUnix(req.StartDayTime)
+	endDayTimeUnix := util.TimeParseLocalEndUnix(req.EndDayTime)
+	pref := s.DB.Model(new(model.EventMating)).Select(`
+		operation_name AS statistic_method,
+		COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS pregnant_count, -- 怀孕头数  
+		COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS empty_pregnant_count, -- 空怀头数  
+		COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS abortion_count, -- 流产头数  
+		COUNT(DISTINCT CASE WHEN mating_result IN (?, ?) THEN cow_id END) AS other_count, -- 其他数
+		(  
+        	COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) +  
+        	COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) +  
+        	COUNT(DISTINCT CASE WHEN mating_result IN (?, ?) THEN cow_id END)  
+		) AS total_count -- 总数
+	`, pasturePb.MatingResult_Pregnant, pasturePb.MatingResult_Empty, pasturePb.MatingResult_Abort,
+		pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch, pasturePb.MatingResult_Pregnant,
+		pasturePb.MatingResult_Empty, pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch)
+	if req.CowType > 0 {
+		pref.Where("cow_type = ?", req.CowType)
+	}
+	if req.CowKind > 0 {
+		pref.Where("cow_kind = ?", req.CowKind)
+	}
+
+	if req.LactInterval > 0 {
+		switch req.LactInterval {
+		case pasturePb.CompareSymbol_Less_Than:
+			pref.Where("lact < ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Less_Than_Or_Equal_To:
+			pref.Where("lact <= ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Greater_Than:
+			pref.Where("lact > ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Greater_Than_Or_Equal_To:
+			pref.Where("lact >= ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Equal_To:
+			pref.Where("lact = ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Not_Equal_To:
+			pref.Where("lact != ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Between:
+			pref.Where("lact BETWEEN ? AND ? ", req.LactIntervalStartValue, req.LactIntervalEndValue)
+		default:
+			return nil, xerr.Custom("错误的胎次区间符号")
+		}
+	}
+
+	if err := pref.Where("status = ?", pasturePb.IsShow_Ok).
+		Where("reality_day BETWEEN ? AND ?", startDayTimeUnix, endDayTimeUnix).
+		Group("operation_id").
+		Find(&res).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	return res, nil
+}
+
+func (s *StoreEntry) SingleFactorAnalysisMethodMatingInterval(ctx context.Context, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
+	res := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
+	return res, nil
+}
+
+func (s *StoreEntry) SingleFactorAnalysisMethodBull(ctx context.Context, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
+	res := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
+	startDayTimeUnix := util.TimeParseLocalUnix(req.StartDayTime)
+	endDayTimeUnix := util.TimeParseLocalEndUnix(req.EndDayTime)
+	pref := s.DB.Model(new(model.EventMating)).
+		Select(`
+		frozen_semen_number AS statistic_method,
+		COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS pregnant_count, -- 怀孕头数  
+		COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS empty_pregnant_count, -- 空怀头数  
+		COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS abortion_count, -- 流产头数  
+		COUNT(DISTINCT CASE WHEN mating_result IN (?, ?) THEN cow_id END) AS other_count, -- 其他数
+		(  
+        	COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) +  
+        	COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) +  
+        	COUNT(DISTINCT CASE WHEN mating_result IN (?, ?) THEN cow_id END)  
+		) AS total_count -- 总数
+	`, pasturePb.MatingResult_Pregnant, pasturePb.MatingResult_Empty, pasturePb.MatingResult_Abort,
+			pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch, pasturePb.MatingResult_Pregnant,
+			pasturePb.MatingResult_Empty, pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch)
+	if req.CowType > 0 {
+		pref.Where("cow_type = ?", req.CowType)
+	}
+	if req.CowKind > 0 {
+		pref.Where("cow_kind = ?", req.CowKind)
+	}
+
+	if req.LactInterval > 0 {
+		switch req.LactInterval {
+		case pasturePb.CompareSymbol_Less_Than:
+			pref.Where("lact < ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Less_Than_Or_Equal_To:
+			pref.Where("lact <= ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Greater_Than:
+			pref.Where("lact > ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Greater_Than_Or_Equal_To:
+			pref.Where("lact >= ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Equal_To:
+			pref.Where("lact = ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Not_Equal_To:
+			pref.Where("lact != ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Between:
+			pref.Where("lact BETWEEN ? AND ? ", req.LactIntervalStartValue, req.LactIntervalEndValue)
+		default:
+			return nil, xerr.Custom("错误的胎次区间符号")
+		}
+	}
+
+	if err := pref.Where("status = ?", pasturePb.IsShow_Ok).
+		Where("reality_day BETWEEN ? AND ?", startDayTimeUnix, endDayTimeUnix).
+		Group("frozen_semen_number").
+		Find(&res).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	return res, nil
+}
+
+func (s *StoreEntry) SingleFactorAnalysisMethodBreedingCycle(ctx context.Context, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
+	res := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
+	return res, nil
+}
+
+func (s *StoreEntry) SingleFactorAnalysisMethodWeek(ctx context.Context, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
+	res := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
+	startDayTimeUnix := util.TimeParseLocalUnix(req.StartDayTime)
+	endDayTimeUnix := util.TimeParseLocalEndUnix(req.EndDayTime)
+	pref := s.DB.Model(new(model.EventMating)).
+		Select(`
+		CASE  
+			DAYOFWEEK(DATE(FROM_UNIXTIME(reality_day)))
+			WHEN 2 THEN '星期一'  
+			WHEN 3 THEN '星期二'  
+			WHEN 4 THEN '星期三'  
+			WHEN 5 THEN '星期四'  
+			WHEN 6 THEN '星期五'  
+			WHEN 7 THEN '星期六'  
+			WHEN 1 THEN '星期日'  
+			ELSE '未知'  
+    	END AS statistic_method,
+		COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS pregnant_count, -- 怀孕头数  
+		COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS empty_pregnant_count, -- 空怀头数  
+		COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS abortion_count, -- 流产头数  
+		COUNT(DISTINCT CASE WHEN mating_result IN (?, ?) THEN cow_id END) AS other_count, -- 其他数
+		(  
+        	COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) +  
+        	COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) +  
+        	COUNT(DISTINCT CASE WHEN mating_result IN (?, ?) THEN cow_id END)  
+		) AS total_count -- 总数
+	`, pasturePb.MatingResult_Pregnant, pasturePb.MatingResult_Empty, pasturePb.MatingResult_Abort,
+			pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch, pasturePb.MatingResult_Pregnant,
+			pasturePb.MatingResult_Empty, pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch)
+	if req.CowType > 0 {
+		pref.Where("cow_type = ?", req.CowType)
+	}
+	if req.CowKind > 0 {
+		pref.Where("cow_kind = ?", req.CowKind)
+	}
+
+	if req.LactInterval > 0 {
+		switch req.LactInterval {
+		case pasturePb.CompareSymbol_Less_Than:
+			pref.Where("lact < ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Less_Than_Or_Equal_To:
+			pref.Where("lact <= ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Greater_Than:
+			pref.Where("lact > ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Greater_Than_Or_Equal_To:
+			pref.Where("lact >= ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Equal_To:
+			pref.Where("lact = ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Not_Equal_To:
+			pref.Where("lact != ?", req.LactIntervalStartValue)
+		case pasturePb.CompareSymbol_Between:
+			pref.Where("lact BETWEEN ? AND ? ", req.LactIntervalStartValue, req.LactIntervalEndValue)
+		default:
+			return nil, xerr.Custom("错误的胎次区间符号")
+		}
+	}
+
+	if err := pref.Where("status = ?", pasturePb.IsShow_Ok).
+		Where("reality_day BETWEEN ? AND ?", startDayTimeUnix, endDayTimeUnix).
+		Group("statistic_method").
+		Find(&res).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	return res, nil
+}
+
+func (s *StoreEntry) SingleFactorAnalysisMethodLact(ctx context.Context, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
+	res := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
+	startDayTimeUnix := util.TimeParseLocalUnix(req.StartDayTime)
+	endDayTimeUnix := util.TimeParseLocalEndUnix(req.EndDayTime)
+	pref := s.DB.Model(new(model.EventMating)).
+		Select(`
+		lact AS statistic_method,
+		COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS pregnant_count, -- 怀孕头数  
+		COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS empty_pregnant_count, -- 空怀头数  
+		COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS abortion_count, -- 流产头数  
+		COUNT(DISTINCT CASE WHEN mating_result IN (?, ?) THEN cow_id END) AS other_count, -- 其他数
+		(  
+        	COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) +  
+        	COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) +  
+        	COUNT(DISTINCT CASE WHEN mating_result IN (?, ?) THEN cow_id END)  
+		) AS total_count -- 总数
+	`, pasturePb.MatingResult_Pregnant, pasturePb.MatingResult_Empty, pasturePb.MatingResult_Abort,
+			pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch, pasturePb.MatingResult_Pregnant,
+			pasturePb.MatingResult_Empty, pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch)
+	if req.CowType > 0 {
+		pref.Where("cow_type = ?", req.CowType)
+	}
+	if req.CowKind > 0 {
+		pref.Where("cow_kind = ?", req.CowKind)
+	}
+
+	if err := pref.Where("status = ?", pasturePb.IsShow_Ok).
+		Where("reality_day BETWEEN ? AND ?", startDayTimeUnix, endDayTimeUnix).
+		Group("lact").
+		Find(&res).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	return res, nil
+}
+
+func (s *StoreEntry) MultipleFactorAnalysis(ctx context.Context, req *pasturePb.MultiFactorPregnancyRateRequest) (*model.MultiFactorPregnancyRateResponse, error) {
+	startTimeUnix := util.TimeParseLocalUnix(req.StartDayTime)
+	endTimeUnix := util.TimeParseLocalEndUnix(req.EndDayTime)
+	if startTimeUnix == 0 || endTimeUnix == 0 || endTimeUnix <= startTimeUnix {
+		return nil, xerr.Custom("开始时间不能大于结束时间")
+	}
+
+	if req.XAxle == req.YAxle {
+		return nil, xerr.Custom("X轴和Y轴不能相同")
+	}
+
+	if req.XAxle == 0 || req.YAxle == 0 {
+		return nil, xerr.Custom("错误的XY轴数据")
+	}
+
+	pref := s.DB.Model(new(model.EventMating)).
+		Select(`
+			DATE_FORMAT(FROM_UNIXTIME(reality_day), '%Y-%m') AS months,  
+			operation_name,frozen_semen_number as bull,lact,mating_times,
+			CASE expose_estrus_type
+				WHEN 1 THEN '脖环揭发'  
+				WHEN 2 THEN '脚环/计步器'  
+				WHEN 3 THEN '自然发情'  
+				WHEN 4 THEN '同期'  
+				ELSE '未知'  
+    		END AS expose_estrus_type,
+			CASE DAYOFWEEK(DATE(FROM_UNIXTIME(reality_day)))
+				WHEN 2 THEN '星期一'  
+				WHEN 3 THEN '星期二'  
+				WHEN 4 THEN '星期三'  
+				WHEN 5 THEN '星期四'  
+				WHEN 6 THEN '星期五'  
+				WHEN 7 THEN '星期六'  
+				WHEN 1 THEN '星期日'  
+				ELSE '未知'  
+			END AS week,
+			COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS pregnant_count, -- 怀孕头数  
+			COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS empty_pregnant_count, -- 空怀头数  
+			COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) AS abortion_count, -- 流产头数  
+			COUNT(DISTINCT CASE WHEN mating_result IN (?, ?) THEN cow_id END) AS other_count, -- 其他数
+			(  
+				COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) +  
+				COUNT(DISTINCT CASE WHEN mating_result = ? AND mating_result_at > 0 THEN cow_id END) +  
+				COUNT(DISTINCT CASE WHEN mating_result IN (?, ?) THEN cow_id END)  
+			) AS total_count -- 总数
+		`, pasturePb.MatingResult_Pregnant, pasturePb.MatingResult_Empty, pasturePb.MatingResult_Abort,
+			pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch, pasturePb.MatingResult_Pregnant,
+			pasturePb.MatingResult_Empty, pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch).
+		Where("status = ?", pasturePb.IsShow_Ok).
+		Where("cow_type = ?", req.CowType).
+		Where("reality_day BETWEEN ? AND ?", startTimeUnix, endTimeUnix)
+
+	if req.LactCompareSymbol > 0 {
+		switch req.LactCompareSymbol {
+		case pasturePb.CompareSymbol_Less_Than:
+			pref.Where("lact < ?", req.LactStartValue)
+		case pasturePb.CompareSymbol_Less_Than_Or_Equal_To:
+			pref.Where("lact <= ?", req.LactStartValue)
+		case pasturePb.CompareSymbol_Greater_Than:
+			pref.Where("lact > ?", req.LactStartValue)
+		case pasturePb.CompareSymbol_Greater_Than_Or_Equal_To:
+			pref.Where("lact >= ?", req.LactStartValue)
+		case pasturePb.CompareSymbol_Equal_To:
+			pref.Where("lact = ?", req.LactStartValue)
+		case pasturePb.CompareSymbol_Not_Equal_To:
+			pref.Where("lact != ?", req.LactStartValue)
+		case pasturePb.CompareSymbol_Between:
+			pref.Where("lact BETWEEN ? AND ? ", req.LactStartValue, req.LactEndValue)
+		}
+	}
+
+	multiFactorAnalysisMethod := s.MultiFactorAnalysisMethodMap()
+	groupMap := make(map[string]string)
+	for k1, v1 := range multiFactorAnalysisMethod {
+		for k2, v2 := range multiFactorAnalysisMethod {
+			groupMap[fmt.Sprintf("%d%d", k1, k2)] = fmt.Sprintf("%s,%s", v1, v2)
+		}
+	}
+
+	list := make([]*model.MultiFactorPregnancyRateList, 0)
+	if err := pref.Group(groupMap[fmt.Sprintf("%d%d", req.XAxle, req.YAxle)]).
+		Order(fmt.Sprintf("%s", multiFactorAnalysisMethod[req.XAxle])).Find(&list).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	chart := &model.MultiFactorPregnancyRateChart{
+		Header:          make([]string, 0),
+		PregnantRateMap: make(map[string]map[string]string),
+	}
+
+	for _, v := range list {
+		switch req.XAxle {
+		case pasturePb.MultiFactorAnalysisMethod_Months:
+			chart.Header = append(chart.Header, v.Months)
+			v.StatisticMethod1 = v.Months
+		case pasturePb.MultiFactorAnalysisMethod_Week:
+			chart.Header = append(chart.Header, v.Week)
+			v.StatisticMethod1 = v.Week
+		case pasturePb.MultiFactorAnalysisMethod_Operation:
+			chart.Header = append(chart.Header, v.OperationName)
+			v.StatisticMethod1 = v.OperationName
+		case pasturePb.MultiFactorAnalysisMethod_Bull:
+			chart.Header = append(chart.Header, v.Bull)
+			v.StatisticMethod1 = v.Bull
+		case pasturePb.MultiFactorAnalysisMethod_Lact:
+			chart.Header = append(chart.Header, v.Lact)
+			v.StatisticMethod1 = v.Lact
+		case pasturePb.MultiFactorAnalysisMethod_Mating_Times:
+			chart.Header = append(chart.Header, v.MatingTimes)
+			v.StatisticMethod1 = v.MatingTimes
+		case pasturePb.MultiFactorAnalysisMethod_Breeding_Method:
+			chart.Header = append(chart.Header, v.ExposeEstrusType)
+			v.StatisticMethod1 = v.ExposeEstrusType
+		}
+
+		switch req.YAxle {
+		case pasturePb.MultiFactorAnalysisMethod_Months:
+			v.StatisticMethod2 = v.Months
+		case pasturePb.MultiFactorAnalysisMethod_Week:
+			v.StatisticMethod2 = v.Week
+		case pasturePb.MultiFactorAnalysisMethod_Operation:
+			v.StatisticMethod2 = v.OperationName
+		case pasturePb.MultiFactorAnalysisMethod_Bull:
+			v.StatisticMethod2 = v.Bull
+		case pasturePb.MultiFactorAnalysisMethod_Lact:
+			v.StatisticMethod2 = v.Lact
+		case pasturePb.MultiFactorAnalysisMethod_Mating_Times:
+			v.StatisticMethod2 = v.MatingTimes
+		case pasturePb.MultiFactorAnalysisMethod_Breeding_Method:
+			v.StatisticMethod2 = v.ExposeEstrusType
+		}
+
+		if chart.PregnantRateMap[v.StatisticMethod1] == nil {
+			chart.PregnantRateMap[v.StatisticMethod1] = make(map[string]string)
+		}
+
+		if chart.KepMap == nil {
+			chart.KepMap = make([]string, 0)
+		}
+
+		pregnantRate := float64(0)
+		if v.EmptyPregnantCount+v.PregnantCount > 0 {
+			pregnantRate = float64(v.PregnantCount) / float64(v.EmptyPregnantCount+v.PregnantCount)
+		}
+		v.PregnantRate = float32(util.RoundToTwoDecimals(pregnantRate * 100))
+		spcRate := float32(0)
+		if v.PregnantRate > 0 {
+			spcRate = float32(util.RoundToTwoDecimals((float64(v.PregnantCount) / float64(v.TotalCount)) * 100))
+		}
+		v.SpcRate = spcRate
+		chart.PregnantRateMap[v.StatisticMethod1][v.StatisticMethod2] = fmt.Sprintf("%.0f", v.PregnantRate)
+		chart.KepMap = append(chart.KepMap, v.StatisticMethod2)
+	}
+
+	chart.Header = util.RemoveDuplicates(chart.Header)
+	chart.KepMap = util.RemoveDuplicates(chart.KepMap)
+	return &model.MultiFactorPregnancyRateResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data: &model.MultiFactorPregnancyRateData{
+			Total: int32(len(list)),
+			List:  list,
+			Chart: chart,
+		},
+	}, nil
+}

+ 436 - 0
module/backend/analysis_other.go

@@ -0,0 +1,436 @@
+package backend
+
+import (
+	"context"
+	"fmt"
+	"kpt-pasture/model"
+	"kpt-pasture/util"
+	"net/http"
+
+	"gorm.io/gorm"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+	"gitee.com/xuyiping_admin/pkg/xerr"
+)
+
+// PregnancyReport 孕检报告
+func (s *StoreEntry) PregnancyReport(ctx context.Context, req *pasturePb.PregnancyReportRequest, pagination *pasturePb.PaginationModel) (*pasturePb.PregnancyReportResponse, error) {
+	startDayUnix := util.TimeParseLocalUnix(req.StartDayTime)
+	endDayUnix := util.TimeParseLocalEndUnix(req.EndDayTime)
+	if startDayUnix > endDayUnix || startDayUnix == 0 || endDayUnix == 0 {
+		return nil, xerr.Custom("开始时间不能大于结束时间")
+	}
+
+	eventPregnantCheckList := make([]*model.EventPregnantCheck, 0)
+	pref := s.DB.Model(new(model.EventPregnantCheck)).Where("status = ?", pasturePb.IsShow_Ok).Where("cow_type = ?", req.CowType)
+
+	if startDayUnix > 0 && endDayUnix > 0 && endDayUnix >= startDayUnix {
+		pref = pref.Where("create_time BETWEEN  ? AND ?", startDayUnix, endDayUnix)
+	}
+
+	if req.PregnantCheckResult > 0 {
+		pref = pref.Where("pregnant_check_result = ?", req.PregnantCheckResult)
+	}
+
+	var count int64 = 0
+	if err := pref.Count(&count).
+		Limit(int(pagination.PageSize)).
+		Offset(int(pagination.PageOffset)).
+		Order("id desc").
+		Find(&eventPregnantCheckList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	pregnantCheckResultMap := s.PregnantCheckResultMap()
+	pregnantCheckMethodMap := s.PregnantCheckMethodMap()
+	return &pasturePb.PregnancyReportResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data: &pasturePb.PregnancyReportData{
+			List:     model.EventPregnantCheckSlice(eventPregnantCheckList).ToPB3(pregnantCheckResultMap, pregnantCheckMethodMap),
+			Total:    int32(count),
+			PageSize: pagination.PageSize,
+			Page:     pagination.Page,
+		},
+	}, nil
+}
+
+// CalvingReport 产犊报告
+func (s *StoreEntry) CalvingReport(ctx context.Context, req *pasturePb.CalvingReportRequest) (*pasturePb.CalvingReportResponse, error) {
+	lastDayOfMonth, err := util.GetLastDayOfMonth(req.EndDayTime)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	endDayTimeUnix := util.TimeParseLocalEndUnix(lastDayOfMonth)
+	startDayTimeUnix := util.TimeParseLocalUnix(fmt.Sprintf("%s-01", req.StartDayTime))
+	if startDayTimeUnix == 0 || endDayTimeUnix == 0 || endDayTimeUnix <= startDayTimeUnix {
+		return nil, xerr.Custom("开始时间不能大于结束时间")
+	}
+
+	eventCalving1 := make([]*pasturePb.CalvingReportTable, 0)
+	pref1 := s.DB.Model(new(model.EventCalving)).
+		Select(fmt.Sprint(`DATE_FORMAT(FROM_UNIXTIME(reality_day), '%Y-%m') AS statistic_method,cow_kind,`)+fmt.Sprintf(
+			`SUM(child_number) AS totalCount,
+			SUM(CASE WHEN child_number > 1 THEN child_number ELSE 0 END) AS twins,
+			SUM(CASE WHEN pregnancy_age <= %d THEN 1 ELSE 0 END) AS premature_labor_count,
+			SUM(CASE WHEN pregnancy_age >= %d THEN 1 ELSE 0 END) AS late_labor_count,
+			count(*) as total_count`, req.PrematureLabor, req.LateLabor),
+		).Where("reality_day BETWEEN  ? AND ? ", startDayTimeUnix, endDayTimeUnix)
+
+	if req.AnalysisMethod > 0 {
+		switch req.AnalysisMethod {
+		case pasturePb.CalvingAnalysisMethod_Months:
+			pref1.Group("statistic_method").Order("statistic_method")
+		case pasturePb.CalvingAnalysisMethod_CowKind:
+			pref1.Group("cow_kind").Order("cow_kind")
+		}
+	}
+
+	if err = pref1.Find(&eventCalving1).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	eventCalving2 := make([]*pasturePb.CalvingReportTable, 0)
+	pref2 := s.DB.Model(new(model.CalvingCalf)).
+		Select(fmt.Sprint(`DATE_FORMAT(FROM_UNIXTIME(birth_at), '%Y-%m') AS statistic_method, cow_kind,
+			SUM(CASE WHEN sex = 1 THEN 1 ELSE 0 END) AS bulls,
+    		SUM(CASE WHEN sex = 2 THEN 1 ELSE 0 END) AS cows,
+    		SUM(CASE WHEN is_live = 1 THEN 1 ELSE 0 END) AS survive_count,
+    		SUM(CASE WHEN is_live = 2 THEN 1 ELSE 0 END) AS die_count,
+    		SUM(CASE WHEN is_live = 2 AND sex = 1 THEN 1 ELSE 0 END) AS bulls_die_count,
+			SUM(CASE WHEN is_live = 2 AND sex = 2 THEN 1 ELSE 0 END) AS cows_die_count,
+    		SUM(CASE WHEN is_adoption = 1 THEN 1 ELSE 0 END) AS adopt_count`)).
+		Where("birth_at BETWEEN ? AND ?", startDayTimeUnix, endDayTimeUnix)
+
+	if req.AnalysisMethod > 0 {
+		switch req.AnalysisMethod {
+		case pasturePb.CalvingAnalysisMethod_Months:
+			pref2.Group("statistic_method").Order("statistic_method")
+		case pasturePb.CalvingAnalysisMethod_CowKind:
+			pref2.Group("cow_kind").Order("cow_kind")
+		}
+	}
+
+	if err = pref2.Find(&eventCalving2).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	// 合并数据集
+	for _, v1 := range eventCalving1 {
+		for _, v2 := range eventCalving2 {
+			if v1.StatisticMethod != v2.StatisticMethod && v1.CowKind != v2.CowKind {
+				continue
+			}
+			v1.Bulls = v2.Bulls
+			v1.Cows = v2.Cows
+			v1.SurviveCount = v2.SurviveCount
+			v1.DieCount = v2.DieCount
+			v1.BullsDieCount = v2.BullsDieCount
+			v1.CowsDieCount = v2.CowsDieCount
+			v1.AdoptCount = v2.AdoptCount
+		}
+	}
+
+	cowKindMap := s.CowKindMap()
+	for _, v := range eventCalving1 {
+		if req.AnalysisMethod == pasturePb.CalvingAnalysisMethod_CowKind {
+			v.StatisticMethod = cowKindMap[v.CowKind]
+		}
+		if v.TotalCount > 0 {
+			v.TwinsRate = float32(util.RoundToTwoDecimals(float64(v.Twins) / float64(v.TotalCount) * 100))
+			v.BullsDieRate = float32(util.RoundToTwoDecimals(float64(v.Bulls) / float64(v.TotalCount) * 100))
+			v.CowsRate = float32(util.RoundToTwoDecimals(float64(v.Cows) / float64(v.TotalCount) * 100))
+			v.DieRate = float32(util.RoundToTwoDecimals(float64(v.DieCount) / float64(v.TotalCount) * 100))
+		}
+
+		if v.Bulls > 0 {
+			v.BullsDieRate = float32(util.RoundToTwoDecimals(float64(v.BullsDieCount) / float64(v.Bulls) * 100))
+		}
+
+		if v.Cows > 0 {
+			v.CowsDieRate = float32(util.RoundToTwoDecimals(float64(v.CowsDieCount) / float64(v.Cows) * 100))
+		}
+		v.NormalLaborCount = v.TotalCount - (v.PrematureLaborCount + v.LateLaborCount)
+		if v.NormalLaborCount <= 0 {
+			v.NormalLaborCount = 0
+		}
+	}
+
+	return &pasturePb.CalvingReportResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data: &pasturePb.CalvingReportData{
+			List:  eventCalving1,
+			Total: int32(len(eventCalving1)),
+		},
+	}, nil
+}
+
+// DiseaseCureReport 疾病治愈率报告
+func (s *StoreEntry) DiseaseCureReport(ctx context.Context, req *pasturePb.DiseaseCureRateRequest) (*pasturePb.DiseaseCureRateResponse, error) {
+	lastDayOfMonth, err := util.GetLastDayOfMonth(req.EndDayTime)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	endDayTimeUnix := util.TimeParseLocalEndUnix(lastDayOfMonth)
+	startDayTimeUnix := util.TimeParseLocalUnix(fmt.Sprintf("%s-01", req.StartDayTime))
+	if startDayTimeUnix == 0 || endDayTimeUnix == 0 || endDayTimeUnix <= startDayTimeUnix {
+		return nil, xerr.Custom("开始时间不能大于结束时间")
+	}
+
+	diseaseCureRateList1 := make([]*pasturePb.DiseaseCureRateList, 0)
+	diseaseCureRateList2 := make([]*pasturePb.DiseaseCureRateList, 0)
+	pref1, err := s.query1(ctx, req.CowType, startDayTimeUnix, endDayTimeUnix)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+	pref2, err := s.query2(ctx, startDayTimeUnix, endDayTimeUnix)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+	switch req.AnalysisMethod {
+	case pasturePb.DiseaseAnalysisMethod_Months:
+		pref1.Where("diagnosed_at > 0").Group("months").Order("months")
+		pref2.Where("treatment_at > 0").Group("months").Order("months")
+	case pasturePb.DiseaseAnalysisMethod_Disease_Category:
+		pref1.Where("disease_type > 0").Group("disease_type").Order("disease_type")
+		pref2.Where("disease_type > 0").Group("disease_type").Order("disease_type")
+	case pasturePb.DiseaseAnalysisMethod_Disease:
+		pref1.Where("diagnose_id > 0").Group("diagnose_id").Order("diagnose_id")
+		pref2.Where("disease_id > 0").Group("disease_id").Order("disease_id")
+	case pasturePb.DiseaseAnalysisMethod_Operator:
+		pref1.Where("diagnose_operation_id > 0").Group("diagnose_operation_id").Order("diagnose_operation_id")
+		pref2.Where("operation_id > 0").Group("operation_id").Order("operation_id")
+	default:
+		return nil, xerr.Custom("错误的统计方式")
+	}
+
+	if err = pref1.Find(&diseaseCureRateList1).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	if err = pref2.Find(&diseaseCureRateList2).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	// 处理数据
+	processDiseaseCureRateList(diseaseCureRateList1, diseaseCureRateList2, req.AnalysisMethod)
+	chart := &pasturePb.DiseaseCureRateChart{
+		Headers:          make([]string, 0),
+		DiseaseCureCount: make([]int32, 0),
+		DiseaseCureRate:  make([]float32, 0),
+		DiseaseCount:     make([]int32, 0),
+	}
+
+	for _, v := range diseaseCureRateList1 {
+		switch req.AnalysisMethod {
+		case pasturePb.DiseaseAnalysisMethod_Months:
+			v.StatisticMethod = v.Months
+		case pasturePb.DiseaseAnalysisMethod_Disease_Category:
+			diseaseTypeMap := s.DiseaseTypeMap()
+			v.StatisticMethod = diseaseTypeMap[v.DiseaseType]
+		case pasturePb.DiseaseAnalysisMethod_Disease:
+			v.StatisticMethod = v.DiseaseName
+		case pasturePb.DiseaseAnalysisMethod_Operator:
+			v.StatisticMethod = v.OperationName
+		case pasturePb.DiseaseAnalysisMethod_Prescription:
+			v.StatisticMethod = v.PrescriptionName
+		}
+
+		chart.Headers = append(chart.Headers, v.StatisticMethod)
+		chart.DiseaseCureCount = append(chart.DiseaseCureCount, v.DiseaseTreatmentCount)
+		diseaseCureRate := float32(0)
+		if v.DiseaseTreatmentCount > 0 {
+			diseaseCureRate = float32(util.RoundToTwoDecimals(float64(v.DiseaseCureCount) / float64(v.DiseaseCount) * 100))
+		}
+		chart.DiseaseCureRate = append(chart.DiseaseCureRate, diseaseCureRate)
+		chart.DiseaseCount = append(chart.DiseaseCount, v.DiseaseCount)
+	}
+
+	return &pasturePb.DiseaseCureRateResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data: &pasturePb.DiseaseCureRateData{
+			List:  diseaseCureRateList1,
+			Chart: chart,
+		},
+	}, nil
+}
+
+func (s *StoreEntry) query1(ctx context.Context, cowType pasturePb.CowType_Kind, startDayTimeUnix, endDayTimeUnix int64) (*gorm.DB, error) {
+	pref := s.DB.Model(new(model.EventCowDisease)).
+		Select(
+			`DATE_FORMAT(FROM_UNIXTIME(diagnosed_at), '%Y-%m') AS months,
+				diagnose_id as disease_id,
+				diagnose_name as disease_name,
+				diagnose_operation_id as operation_id,
+				diagnose_operation_name as operation_name,
+				disease_type,
+				COUNT(DISTINCT CASE WHEN health_status = ? THEN cow_id END) AS disease_treatment_count, -- 治疗头数  
+				COUNT(DISTINCT CASE WHEN health_status = ? AND curable_at > 0 THEN cow_id END) AS disease_cure_count, -- 治愈头数  
+				COUNT(DISTINCT CASE WHEN diagnosed_result = ? THEN cow_id END) AS disease_count, -- 发病数  
+				COUNT(DISTINCT CASE WHEN health_status IN (?, ?) THEN cow_id END) AS die_out_count, -- 死淘数  
+				COUNT(DISTINCT CASE   
+						   WHEN health_status = ?  
+						   AND TIMESTAMPDIFF(DAY, FROM_UNIXTIME(disease_at), FROM_UNIXTIME(curable_at)) <= 7   
+						   THEN cow_id   
+					   END) AS seven_cure_count, -- 7天内治愈头数  
+				COUNT(DISTINCT CASE   
+						   WHEN health_status = ?  
+						   AND TIMESTAMPDIFF(DAY, FROM_UNIXTIME(disease_at), FROM_UNIXTIME(curable_at)) <= 14   
+						   THEN cow_id   
+					   END) AS seventeen_cure_count, -- 14天内治愈头数 
+				COUNT(DISTINCT CASE   
+						   WHEN health_status = ?  
+						   AND TIMESTAMPDIFF(DAY, FROM_UNIXTIME(disease_at), FROM_UNIXTIME(curable_at)) <= 30  
+						   THEN cow_id   
+					   END) AS thirty_cure_count -- 30天内治愈头数
+				`,
+			pasturePb.HealthStatus_Treatment, pasturePb.HealthStatus_Curable, pasturePb.IsShow_Ok, pasturePb.HealthStatus_Out,
+			pasturePb.HealthStatus_Dead, pasturePb.HealthStatus_Curable, pasturePb.HealthStatus_Curable, pasturePb.HealthStatus_Curable,
+		).
+		Where("diagnosed_result = ?", pasturePb.IsShow_Ok).
+		Where("diagnosed_at BETWEEN ? AND ?", startDayTimeUnix, endDayTimeUnix)
+	if cowType > 0 {
+		pref.Where("cow_type = ?", cowType)
+	}
+
+	return pref, nil
+}
+
+func (s *StoreEntry) query2(ctx context.Context, startDayTimeUnix, endDayTimeUnix int64) (*gorm.DB, error) {
+	pref := s.DB.Model(new(model.EventCowTreatment)).
+		Select(`
+		DATE_FORMAT(FROM_UNIXTIME(treatment_at), '%Y-%m') AS months,
+		disease_id,
+		disease_name,
+		disease_type,
+		prescription_id,
+		prescription_name,
+		operation_id,
+		operation_name,
+		COUNT(DISTINCT cow_id) AS disease_treatment_count`,
+		).Where("treatment_at BETWEEN ? AND ?", startDayTimeUnix, endDayTimeUnix)
+	return pref, nil
+}
+
+// 构建哈希表
+func buildMap(list []*pasturePb.DiseaseCureRateList, method pasturePb.DiseaseAnalysisMethod_Kind) map[interface{}]*pasturePb.DiseaseCureRateList {
+	m := make(map[interface{}]*pasturePb.DiseaseCureRateList)
+	for _, v := range list {
+		var key interface{}
+		switch method {
+		case pasturePb.DiseaseAnalysisMethod_Months:
+			key = v.Months
+		case pasturePb.DiseaseAnalysisMethod_Disease_Category:
+			key = v.DiseaseType
+		case pasturePb.DiseaseAnalysisMethod_Disease:
+			key = v.DiseaseId
+		case pasturePb.DiseaseAnalysisMethod_Operator:
+			key = v.OperationId
+		case pasturePb.DiseaseAnalysisMethod_Prescription:
+			key = v.PrescriptionId
+		}
+		m[key] = v
+	}
+	return m
+}
+
+// 更新 DiseaseTreatmentCount
+func updateDiseaseTreatmentCount(v1 *pasturePb.DiseaseCureRateList, v2 *pasturePb.DiseaseCureRateList) {
+	v1.DiseaseTreatmentCount = v2.DiseaseTreatmentCount
+}
+
+// 主逻辑
+func processDiseaseCureRateList(diseaseCureRateList1, diseaseCureRateList2 []*pasturePb.DiseaseCureRateList, analysisMethod pasturePb.DiseaseAnalysisMethod_Kind) {
+	if len(diseaseCureRateList1) == 0 || len(diseaseCureRateList2) == 0 {
+		return
+	}
+
+	map2 := buildMap(diseaseCureRateList2, analysisMethod)
+	for i := range diseaseCureRateList1 {
+		v1 := diseaseCureRateList1[i]
+		var key interface{}
+		switch analysisMethod {
+		case pasturePb.DiseaseAnalysisMethod_Months:
+			key = v1.Months
+		case pasturePb.DiseaseAnalysisMethod_Disease_Category:
+			key = v1.DiseaseType
+		case pasturePb.DiseaseAnalysisMethod_Disease:
+			key = v1.DiseaseId
+		case pasturePb.DiseaseAnalysisMethod_Operator:
+			key = v1.OperationId
+		case pasturePb.DiseaseAnalysisMethod_Prescription:
+			key = v1.PrescriptionId
+		default:
+			continue // 处理无效的 AnalysisMethod
+		}
+		if v2, ok := map2[key]; ok {
+			updateDiseaseTreatmentCount(v1, v2)
+		}
+	}
+}
+
+func (s *StoreEntry) SaleCowReport(ctx context.Context, req *pasturePb.SaleCowReportRequest) (*pasturePb.SaleCowReportResponse, error) {
+	lastDayOfMonth, err := util.GetLastDayOfMonth(req.EndDay)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	endDayTimeUnix := util.TimeParseLocalEndUnix(lastDayOfMonth)
+	startDayTimeUnix := util.TimeParseLocalUnix(fmt.Sprintf("%s-01", req.StartDay))
+	if startDayTimeUnix == 0 || endDayTimeUnix == 0 || endDayTimeUnix <= startDayTimeUnix {
+		return nil, xerr.Custom("开始时间不能大于结束时间")
+	}
+
+	list := make([]*pasturePb.SaleCowReportList, 0)
+	pref := s.DB.Model(new(model.EventSale)).
+		Select(
+			`SUM(sale_cow_count) AS sale_all_count,
+			SUM(sale_all_amount) AS sale_all_amount,
+			SUM(sale_cow_count) AS sale_all_count,
+			SUM(sale_all_weight) AS sale_all_weight`,
+		).Where("sale_at BETWEEN ? AND ?", startDayTimeUnix, endDayTimeUnix)
+	if req.AnalysisMethod == pasturePb.SaleCowAnalysisMethod_Months {
+		pref.Select(`DATE_FORMAT(FROM_UNIXTIME(sale_at), '%Y-%m') AS statisticMethod`)
+	}
+
+	if req.AnalysisMethod == pasturePb.SaleCowAnalysisMethod_Dealer {
+		pref.Select(`dealer_name as statisticMethod`)
+	}
+
+	if err = pref.Group("statisticMethod").Order("statisticMethod ASC").Find(&list).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	chart := &pasturePb.SaleCowReportChart{
+		Headers:           make([]string, 0),
+		SaleMount:         make([]float32, 0),
+		SaleWeight:        make([]float32, 0),
+		SaleCount:         make([]int32, 0),
+		AverageSaleWeight: make([]float32, 0),
+	}
+	for i, v := range list {
+		if v.SaleAllCount > 0 && v.SaleAllWeight > 0 {
+			v.SaleAvgWeight = float32(util.RoundToTwoDecimals(float64(v.SaleAllWeight / float32(v.SaleAllCount))))
+		}
+		chart.Headers = append(chart.Headers, v.StatisticMethod)
+		chart.SaleMount = append(chart.SaleMount, v.SaleAllMount)
+		chart.SaleWeight = append(chart.SaleWeight, v.SaleAllWeight)
+		chart.SaleCount = append(chart.SaleCount, v.SaleAllCount)
+		chart.AverageSaleWeight = append(chart.AverageSaleWeight, v.SaleAvgWeight)
+		v.Id = int32(i)
+	}
+
+	return &pasturePb.SaleCowReportResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data: &pasturePb.SaleCowReportData{
+			Chart: chart,
+			List:  list,
+			Total: int32(len(list)),
+		},
+	}, err
+}

+ 508 - 0
module/backend/calendar.go

@@ -0,0 +1,508 @@
+package backend
+
+import (
+	"context"
+	"fmt"
+	"kpt-pasture/model"
+	"kpt-pasture/util"
+	"net/http"
+	"time"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+	"gitee.com/xuyiping_admin/pkg/xerr"
+)
+
+// CalendarToDoList 获取日历待办列表
+func (s *StoreEntry) CalendarToDoList(ctx context.Context, req *pasturePb.CalendarToDoRequest, pagination *pasturePb.PaginationModel) (*pasturePb.CalendarToDoResponse, error) {
+	currentUser, err := s.GetCurrentSystemUser(ctx)
+	if err != nil || currentUser.Id <= 0 {
+		return nil, xerr.WithStack(err)
+	}
+	var count int64 = 0
+	eventItem := make([]*model.EventItem, 0)
+	pref := s.DB.Model(&model.EventItem{})
+	if req.StartAt > 0 && req.EndAt > 0 && req.StartAt <= req.EndAt {
+		pref = pref.Where("plan_day >= ?", req.StartAt).
+			Where("plan_day <= ?", req.EndAt)
+	}
+
+	if len(req.CowIds) > 0 {
+		cowList, _ := s.ParseCowIds(ctx, req.CowIds)
+		cowIds := make([]int64, 0)
+		for _, cow := range cowList {
+			cowIds = append(cowIds, cow.Id)
+		}
+		if len(cowIds) > 0 {
+			pref.Where("cow_id IN (?)", cowIds)
+		}
+
+	}
+
+	if req.CalendarType > 0 {
+		pref.Where("calendar_type = ?", req.CalendarType)
+	}
+
+	if req.IsFinish > 0 {
+		pref.Where("is_finish = ?", req.IsFinish)
+	}
+
+	if req.IsExpire > 0 {
+		pref.Where("is_expire = ?", req.IsExpire)
+	}
+
+	if err = pref.Order("id desc").
+		Count(&count).
+		Limit(int(pagination.PageSize)).
+		Offset(int(pagination.PageOffset)).
+		Find(&eventItem).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	penMap := s.PenMap(ctx)
+	calendarMap := CalendarTypeMap()
+
+	return &pasturePb.CalendarToDoResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data: &pasturePb.CalendarToDoData{
+			List:     model.EventItemSlice(eventItem).ToPB(penMap, calendarMap),
+			Total:    int32(count),
+			PageSize: pagination.PageSize,
+			Page:     pagination.Page,
+		},
+	}, nil
+}
+func (s *StoreEntry) CalendarList(ctx context.Context, req *pasturePb.CalendarRequest) (*pasturePb.CalendarResponse, error) {
+	calendarList := make([]*model.Calendar, 0)
+	if err := s.DB.Model(&model.Calendar{}).
+		Where("show_day >= ?", req.ShowStartDay).
+		Where("show_day <= ?", req.ShowEndDay).
+		Where("is_show = ?", pasturePb.IsShow_Ok).
+		Find(&calendarList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+	return &pasturePb.CalendarResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data:    model.CalendarSlice(calendarList).ToPB(),
+	}, nil
+}
+
+func (s *StoreEntry) CalendarTableDetail(
+	ctx context.Context,
+	req *pasturePb.CalendarTableRequest,
+	pagination *pasturePb.PaginationModel,
+) (interface{}, error) {
+
+	if req.Start != time.Now().Format(model.LayoutDate2) {
+		return nil, xerr.New("参数错误")
+	}
+
+	newCalendar := &model.Calendar{}
+	if err := s.DB.Model(&model.Calendar{}).
+		Where("calendar_type = ?", req.CalendarType).
+		Where("show_day = ?", req.Start).
+		Where("is_show = ?", pasturePb.IsShow_Ok).
+		First(newCalendar).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	if newCalendar.Id <= 0 {
+		return nil, xerr.New("不存在该日历数据")
+	}
+	return s.getCalendarCowList(ctx, req.CalendarType, req.Start, pagination)
+}
+
+func (s *StoreEntry) getCalendarCowList(
+	ctx context.Context,
+	calendarType pasturePb.CalendarType_Kind,
+	showDay string,
+	pagination *pasturePb.PaginationModel) (interface{}, error) {
+	req := &pasturePb.ItemsRequest{EndDay: showDay, CalendarType: calendarType, Status: pasturePb.IsShow_No}
+	switch calendarType {
+	case pasturePb.CalendarType_Immunisation: // 免疫
+		return s.ImmunisationCowList(ctx, req, pagination)
+	case pasturePb.CalendarType_PG, pasturePb.CalendarType_RnGH: // 同期
+		return s.SameTimeCowList(ctx, req, pagination)
+	case pasturePb.CalendarType_Pregnancy_Check: // 孕检
+		return s.PregnancyCheckCowList(ctx, req, pagination)
+	case pasturePb.CalendarType_WorkOrder: // 工作单
+		return s.WorkOrderCowList(ctx, req, pagination)
+	case pasturePb.CalendarType_Weaning: // 断奶
+		return s.WeaningCowList(ctx, req, pagination)
+	case pasturePb.CalendarType_Treatment: // 治疗
+		return s.TreatmentCowList(ctx, req, pagination)
+	case pasturePb.CalendarType_Mating: // 配种
+		return s.MatingCowList(ctx, req, pagination)
+	case pasturePb.CalendarType_Calving: // 产犊
+		return s.CalvingCowList(ctx, req, pagination)
+	default:
+		return nil, xerr.New("不支持的日历类型")
+	}
+}
+
+func (s *StoreEntry) ImmunisationCowList(ctx context.Context, req *pasturePb.ItemsRequest, pagination *pasturePb.PaginationModel) (*pasturePb.ImmunizationItemsResponse, error) {
+	eventImmunizationPlanList := make([]*model.EventImmunizationPlan, 0)
+	count := int64(0)
+	pref := s.DB.Model(&model.EventImmunizationPlan{}).
+		Where("status = ?", pasturePb.IsShow_No)
+	if req.StartDay != "" {
+		dateTime := util.TimeParseLocalUnix(req.StartDay)
+		pref.Where("plan_day >= ?", dateTime)
+	}
+
+	if req.EndDay != "" {
+		dateTime := util.TimeParseLocalEndUnix(req.EndDay)
+		pref.Where("plan_day <= ?", dateTime)
+	}
+
+	if req.CowId > 0 {
+		pref.Where("cow_id = ?", req.CowId)
+	}
+
+	if req.ImmunizationId > 0 {
+		pref.Where("plan_id = ?", req.ImmunizationId)
+	}
+
+	if req.Lact >= 0 {
+		pref.Where("lact = ?", req.Lact)
+	}
+
+	if req.PenId > 0 {
+		pref.Where("pen_id = ?", req.PenId)
+	}
+
+	if req.Status > 0 {
+		pref.Where("status = ?", req.Status)
+	}
+
+	if err := pref.Order("id desc").
+		Count(&count).
+		Limit(int(pagination.PageSize)).
+		Offset(int(pagination.PageOffset)).
+		Order("id desc").
+		Find(&eventImmunizationPlanList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	return &pasturePb.ImmunizationItemsResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data: &pasturePb.ImmunizationItemsData{
+			Total:    int32(count),
+			Page:     pagination.Page,
+			PageSize: pagination.PageSize,
+			Header: map[string]string{
+				"id":                   "编号",
+				"cowId":                "牛号",
+				"penName":              "栏舍",
+				"dayAge":               "日龄",
+				"planStartTime":        "免疫开始时间",
+				"immunizationPlanName": "免疫名称",
+				"status":               "状态",
+			},
+			List: model.EventImmunizationPlanSlice(eventImmunizationPlanList).ToPB(),
+		},
+	}, nil
+
+}
+
+func (s *StoreEntry) SameTimeCowList(ctx context.Context, req *pasturePb.ItemsRequest, pagination *pasturePb.PaginationModel) (*pasturePb.SameTimeItemResponse, error) {
+	sameTimeBodyList := make([]*model.SameTimeItemBody, 0)
+	count := int64(0)
+	pref := s.DB.Table(fmt.Sprintf("%s as a", new(model.EventCowSameTime).TableName())).
+		Select("a.id,a.cow_id,a.pen_name,a.status,a.same_time_type,b.breed_status,a.same_time_name,b.cow_type,b.day_age,b.calving_age,b.abortion_age,b.last_calving_at,b.last_abortion_at").
+		Joins("left join cow as b on a.cow_id = b.id").
+		Where("b.admission_status = ?", pasturePb.AdmissionStatus_Admission).
+		Where("a.status = ?", pasturePb.IsShow_No)
+
+	if req.EndDay != "" {
+		dateTime := util.TimeParseLocalEndUnix(req.EndDay)
+		pref.Where("a.plan_day <= ?", dateTime)
+	}
+
+	if req.CalendarType > 0 {
+		pref.Where("a.same_time_type = ?", req.CalendarType)
+	}
+
+	if req.CowType > 0 {
+		pref.Where("b.cow_type = ?", req.CowType)
+	}
+
+	if req.Status > 0 {
+		pref.Where("a.status = ?", pasturePb.IsShow_No)
+	}
+
+	if err := pref.Order("a.id desc").Count(&count).
+		Limit(int(pagination.PageSize)).
+		Offset(int(pagination.PageOffset)).
+		Order("id desc").
+		Find(&sameTimeBodyList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+	breedStatusMap := s.CowBreedStatusMap()
+	penMap := s.PenMap(ctx)
+	sameTimeTypeMap := s.SameTimeTypeMap()
+	return &pasturePb.SameTimeItemResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data: &pasturePb.SameTimeItemsData{
+			Total:    int32(count),
+			Page:     pagination.Page,
+			PageSize: pagination.PageSize,
+			Header: map[string]string{
+				"id":               "编号",
+				"cowId":            "牛号",
+				"breedStatusName":  "繁殖状态",
+				"cowTypeName":      "牛只类型",
+				"penName":          "栏舍",
+				"lact":             "胎次",
+				"calvingAge":       "产后天数",
+				"abortionAge":      "流产天数",
+				"dayAge":           "日龄",
+				"status":           "状态",
+				"sameTimeTypeName": "处理方式",
+				"matingTimes":      "本胎次配次",
+				"calvingAtFormat":  "产犊日期",
+				"abortionAtFormat": "流产日期",
+				"sameTimeName":     "同情名称",
+			},
+			List: model.SameTimeBodySlice(sameTimeBodyList).ToPB(breedStatusMap, penMap, sameTimeTypeMap),
+		},
+	}, nil
+}
+
+func (s *StoreEntry) PregnancyCheckCowList(ctx context.Context, req *pasturePb.ItemsRequest, pagination *pasturePb.PaginationModel) (*pasturePb.PregnancyCheckItemsResponse, error) {
+	newPregnancyCheckItems := make([]*pasturePb.PregnancyCheckItems, 0)
+	var count int64
+	pref := s.DB.Table(fmt.Sprintf("%s as a", new(model.EventPregnantCheck).TableName())).
+		Select("a.id,a.cow_id,a.pen_id,a.status,b.breed_status,b.cow_type,b.day_age,b.calving_age,b.abortion_age,a.bull_id").
+		Joins("left join cow as b on a.cow_id = b.id").
+		Where("b.admission_status = ?", pasturePb.AdmissionStatus_Admission).
+		Where("a.status = ?", pasturePb.IsShow_No)
+
+	if req.EndDay != "" {
+		dateTime := util.TimeParseLocalEndUnix(req.EndDay)
+		pref.Where("plan_day <= ?", dateTime)
+	}
+
+	if req.CowType > 0 {
+		pref.Where("cow_type = ?", req.CowType)
+	}
+
+	if req.Status > 0 {
+		pref.Where("a.status = ?", req.Status)
+	}
+
+	if req.PregnantCheckType > 0 {
+		pref.Where("pregnant_check_name = ?", model.PregnantCheckNameValueMap[req.PregnantCheckType])
+	}
+
+	if err := pref.Order("id desc").
+		Count(&count).
+		Limit(int(pagination.PageSize)).
+		Offset(int(pagination.PageOffset)).
+		Order("id desc").
+		Find(&newPregnancyCheckItems).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	return &pasturePb.PregnancyCheckItemsResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data: &pasturePb.PregnancyCheckItemsData{
+			Total:    int32(count),
+			Page:     pagination.Page,
+			PageSize: pagination.PageSize,
+			Header: map[string]string{
+				"id":              "编号",
+				"cowId":           "牛号",
+				"cowTypeName":     "牛只类型",
+				"penName":         "栏舍",
+				"lact":            "胎次",
+				"dayAge":          "日龄",
+				"planDay":         "孕检日期",
+				"checkTypeName":   "孕检名称",
+				"status":          "状态",
+				"matingTimes":     "配次",
+				"calvingAtFormat": "产检日期",
+				"matingAtFormat":  "配种日期",
+				"matingAge":       "配后天数",
+				"bullId":          "配种公牛",
+			},
+			List: newPregnancyCheckItems,
+		},
+	}, nil
+}
+
+func (s *StoreEntry) WeaningCowList(ctx context.Context, req *pasturePb.ItemsRequest, pagination *pasturePb.PaginationModel) (*pasturePb.WeaningItemsResponse, error) {
+	weaningItems := make([]*pasturePb.WeaningItems, 0)
+	count := int64(0)
+
+	pref := s.DB.Table(fmt.Sprintf("%s as a", new(model.EventWeaning).TableName())).
+		Select("a.*,b.day_age,c.name as pen_name").
+		Joins("left join cow as b on a.cow_id = b.id").
+		Joins("left join pen as c on a.before_pen_id = c.id").
+		Where("b.admission_status = ?", pasturePb.AdmissionStatus_Admission).
+		Where("a.status = ?", pasturePb.IsShow_No)
+
+	if req.EndDay != "" {
+		dateTime := util.TimeParseLocalEndUnix(req.EndDay)
+		pref.Where("a.plan_day <= ?", dateTime)
+	}
+
+	if req.Status > 0 {
+		pref.Where("a.status = ?", req.Status)
+	}
+
+	if err := pref.Order("a.id desc").Count(&count).
+		Limit(int(pagination.PageSize)).
+		Offset(int(pagination.PageOffset)).
+		Find(&weaningItems).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	return &pasturePb.WeaningItemsResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data: &pasturePb.WeaningItemsData{
+			Total:    int32(count),
+			Page:     pagination.Page,
+			PageSize: pagination.PageSize,
+			Header: map[string]string{
+				"id":      "编号",
+				"cowId":   "牛号",
+				"penName": "栏舍",
+				"planDay": "断奶日期",
+				"dayAge":  "日龄",
+				"status":  "状态",
+			},
+			List: weaningItems,
+		},
+	}, nil
+}
+
+func (s *StoreEntry) MatingCowList(ctx context.Context, req *pasturePb.ItemsRequest, pagination *pasturePb.PaginationModel) (*pasturePb.MatingItemsResponse, error) {
+	matingItems := make([]*pasturePb.MatingItems, 0)
+	count := int64(0)
+	pref := s.DB.Table(fmt.Sprintf("%s as a", new(model.EventMating).TableName())).
+		Select("a.id,a.cow_id,a.status,b.breed_status,b.cow_type,b.pen_id,b.day_age,b.calving_age,b.abortion_age,c.name as pen_name").
+		Joins("left join cow as b on a.cow_id = b.id").
+		Joins("left join pen as c on a.pen_id = c.id").
+		Where("a.status = ?", pasturePb.IsShow_No)
+
+	if req.EndDay != "" {
+		dateTime := util.TimeParseLocalEndUnix(req.EndDay)
+		pref.Where("a.plan_day <= ?", dateTime)
+	}
+
+	if req.PenId > 0 {
+		pref.Where("a.pen_id = ?", req.PenId)
+	}
+
+	if req.Status > 0 {
+		pref.Where("a.status = ?", req.Status)
+	}
+
+	if err := pref.Order("a.id desc").
+		Count(&count).
+		Limit(int(pagination.PageSize)).
+		Offset(int(pagination.PageOffset)).
+		Find(&matingItems).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	return &pasturePb.MatingItemsResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data: &pasturePb.MatingItemsData{
+			Total:    int32(count),
+			Page:     pagination.Page,
+			PageSize: pagination.PageSize,
+			Header: map[string]string{
+				"id":              "编号",
+				"cowId":           "牛号",
+				"breedStatusName": "繁殖状态",
+				"cowTypeName":     "牛只类型",
+				"penName":         "栏舍",
+				"lact":            "胎次",
+				"calvingAge":      "产后天数",
+				"abortionAge":     "流产天数",
+				"dayAge":          "日龄",
+				"status":          "状态",
+			},
+			List: matingItems,
+		},
+	}, nil
+}
+
+func (s *StoreEntry) CalvingCowList(ctx context.Context, req *pasturePb.ItemsRequest, pagination *pasturePb.PaginationModel) (*pasturePb.CalvingItemsResponse, error) {
+	calvingItems := make([]*pasturePb.CalvingItems, 0)
+	count := int64(0)
+	pref := s.DB.Table(fmt.Sprintf("%s as a", new(model.EventCalving).TableName())).
+		Select(`a.id,a.cow_id,a.status,b.breed_status,b.pen_id,DATE_FORMAT(FROM_UNIXTIME(last_mating_at), '%Y-%m-%d') AS mating_at_format,
+		b.day_age,b.last_bull_number as bull_id,DATEDIFF(NOW(),FROM_UNIXTIME(last_mating_at)) AS mating_age,DATE_FORMAT(FROM_UNIXTIME(a.plan_day), '%Y-%m-%d') AS plan_day`).
+		Joins("left join cow as b on a.cow_id = b.id").
+		Where("b.admission_status = ?", pasturePb.AdmissionStatus_Admission)
+
+	if req.EndDay != "" {
+		dateTime := util.TimeParseLocalEndUnix(req.EndDay)
+		pref.Where("a.plan_day <= ?", dateTime)
+	}
+
+	if req.Status > 0 {
+		pref.Where("a.status = ?", req.Status)
+	}
+
+	if err := pref.Order("a.id desc").
+		Count(&count).
+		Limit(int(pagination.PageSize)).
+		Offset(int(pagination.PageOffset)).
+		Find(&calvingItems).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	breedStatusMap := s.CowBreedStatusMap()
+	for _, v := range calvingItems {
+		breedStatusName := ""
+		if breedStatus, ok := breedStatusMap[v.BreedStatus]; ok {
+			breedStatusName = breedStatus
+		}
+		v.BreedStatusName = breedStatusName
+	}
+
+	return &pasturePb.CalvingItemsResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data: &pasturePb.CalvingItemsData{
+			Total:    int32(count),
+			Page:     pagination.Page,
+			PageSize: pagination.PageSize,
+			Header: map[string]string{
+				"id":              "编号",
+				"cowId":           "牛号",
+				"breedStatusName": "繁殖状态",
+				"penName":         "栏舍",
+				"lact":            "胎次",
+				"matingAge":       "配后天数",
+				"dayAge":          "日龄",
+				"status":          "是否完成",
+				"bullId":          "配种公牛号",
+				"planDay":         "预产时间",
+				"matingAtFormat":  "配种时间",
+			},
+			List: calvingItems,
+		},
+	}, nil
+
+}
+
+// WorkOrderCowList 暂时不处理工单业务
+func (s *StoreEntry) WorkOrderCowList(ctx context.Context, req *pasturePb.ItemsRequest, pagination *pasturePb.PaginationModel) (interface{}, error) {
+	return nil, nil
+}
+
+// TreatmentCowList 治疗清单
+func (s *StoreEntry) TreatmentCowList(ctx context.Context, req *pasturePb.ItemsRequest, pagination *pasturePb.PaginationModel) (interface{}, error) {
+	return nil, nil
+}

+ 123 - 427
module/backend/config_data.go

@@ -1,12 +1,8 @@
 package backend
 
 import (
-	"fmt"
 	"kpt-pasture/model"
 
-	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
-	"go.uber.org/zap"
-
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 )
 
@@ -14,11 +10,11 @@ func (s *StoreEntry) BarnTypeEnumList() []*pasturePb.ConfigOptionsList {
 	barnTypeList := make([]*pasturePb.ConfigOptionsList, 0)
 	barnTypeList = append(barnTypeList, &pasturePb.ConfigOptionsList{
 		Value:    int32(pasturePb.PenType_Lactating_Calves),
-		Label:    "哺乳牛舍",
+		Label:    "哺乳牛舍",
 		Disabled: true,
 	}, &pasturePb.ConfigOptionsList{
 		Value:    int32(pasturePb.PenType_Weaned_Calves),
-		Label:    "断奶牛舍",
+		Label:    "断奶牛舍",
 		Disabled: true,
 	}, &pasturePb.ConfigOptionsList{
 		Value:    int32(pasturePb.PenType_Youth),
@@ -45,10 +41,15 @@ func (s *StoreEntry) BarnTypeEnumList() []*pasturePb.ConfigOptionsList {
 		Label:    "病牛舍",
 		Disabled: true,
 	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.PenType_Eliminate),
+		Value:    int32(pasturePb.PenType_Out),
 		Label:    "淘汰牛舍",
 		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.PenType_Segregate),
+		Label:    "隔离牛舍",
+		Disabled: true,
 	})
+
 	return barnTypeList
 }
 
@@ -79,7 +80,7 @@ func (s *StoreEntry) BreedStatusEnumList() []*pasturePb.ConfigOptionsList {
 		Label:    "流产",
 		Disabled: true,
 	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.BreedStatus_No_Pregnant),
+		Value:    int32(pasturePb.BreedStatus_No_Mating),
 		Label:    "禁配",
 		Disabled: true,
 	})
@@ -89,28 +90,28 @@ func (s *StoreEntry) BreedStatusEnumList() []*pasturePb.ConfigOptionsList {
 func (s *StoreEntry) CowKindEnumList() []*pasturePb.ConfigOptionsList {
 	cowKindList := make([]*pasturePb.ConfigOptionsList, 0)
 	cowKindList = append(cowKindList, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.CowKind_HST),
-		Label:    "荷斯坦",
+		Value:    int32(pasturePb.CowKind_XMTEN),
+		Label:    "西门塔尔牛",
 		Disabled: true,
 	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.CowKind_JSN),
-		Label:    "娟姗牛",
+		Value:    int32(pasturePb.CowKind_AGSN),
+		Label:    "安格斯牛",
 		Disabled: true,
 	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.CowKind_SHN),
-		Label:    "三河牛",
+		Value:    int32(pasturePb.CowKind_XNLN),
+		Label:    "夏洛莱牛",
 		Disabled: true,
 	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.CowKind_XJHN),
-		Label:    "新疆褐牛",
+		Value:    int32(pasturePb.CowKind_LMZN),
+		Label:    "利木赞牛",
 		Disabled: true,
 	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.CowKind_MN),
-		Label:    "牛",
+		Value:    int32(pasturePb.CowKind_HFTN),
+		Label:    "海福特牛",
 		Disabled: true,
 	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.CowKind_XMTEN),
-		Label:    "西门塔尔牛",
+		Value:    int32(pasturePb.CowKind_HN),
+		Label:    "牛",
 		Disabled: true,
 	})
 	return cowKindList
@@ -133,15 +134,35 @@ func (s *StoreEntry) CowSourceEnumList() []*pasturePb.ConfigOptionsList {
 	})
 	return cowSourceList
 }
-func (s *StoreEntry) CowTypeEnumList() []*pasturePb.ConfigOptionsList {
+func (s *StoreEntry) CowTypeEnumList(optionName, isAll string) []*pasturePb.ConfigOptionsList {
 	cowTypeList := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		cowTypeList = append(cowTypeList, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.CowType_Invalid),
+			Label:    "全部",
+			Disabled: true,
+		})
+	}
+	if optionName == "breed" {
+		cowTypeList = append(cowTypeList, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.CowType_Reserve_Calf),
+			Label:    "后备牛",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.CowType_Breeding_Calf),
+			Label:    "经产牛",
+			Disabled: true,
+		})
+		return cowTypeList
+	}
+
 	cowTypeList = append(cowTypeList, &pasturePb.ConfigOptionsList{
 		Value:    int32(pasturePb.CowType_Lactating_Calf),
 		Label:    "哺乳犊牛",
 		Disabled: true,
 	}, &pasturePb.ConfigOptionsList{
 		Value:    int32(pasturePb.CowType_Weaned_Calf),
-		Label:    "断奶犊牛",
+		Label:    "育成牛",
 		Disabled: true,
 	}, &pasturePb.ConfigOptionsList{
 		Value:    int32(pasturePb.CowType_Youth_Calf),
@@ -164,25 +185,40 @@ func (s *StoreEntry) CowTypeEnumList() []*pasturePb.ConfigOptionsList {
 		Label:    "种公牛",
 		Disabled: true,
 	})
+
 	return cowTypeList
 }
 
-func (s *StoreEntry) SemeTimeCowTypeEnumList() []*pasturePb.ConfigOptionsList {
+func (s *StoreEntry) SameTimeCowTypeEnumList(isAll string) []*pasturePb.ConfigOptionsList {
 	cowTypeList := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		cowTypeList = append(cowTypeList, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.SameTimeStatus_Invalid),
+			Label:    "全部",
+			Disabled: true,
+		})
+	}
 	cowTypeList = append(cowTypeList, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.CowType_Reserve_Calf),
-		Label:    "后备牛",
+		Value:    int32(pasturePb.SameTimeCowType_Empty),
+		Label:    "空怀牛",
 		Disabled: true,
 	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.CowType_Breeding_Calf),
+		Value:    int32(pasturePb.SameTimeCowType_Breeding_Calf),
 		Label:    "种母牛",
 		Disabled: true,
 	})
 	return cowTypeList
 }
 
-func (s *StoreEntry) SameTimeTypeEnumList() []*pasturePb.ConfigOptionsList {
+func (s *StoreEntry) SameTimeTypeEnumList(isAll string) []*pasturePb.ConfigOptionsList {
 	cowTypeList := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		cowTypeList = append(cowTypeList, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.SameTimeStatus_Invalid),
+			Label:    "全部",
+			Disabled: true,
+		})
+	}
 	cowTypeList = append(cowTypeList, &pasturePb.ConfigOptionsList{
 		Value:    int32(pasturePb.SameTimeType_PGBJ),
 		Label:    "PG保健",
@@ -203,7 +239,7 @@ func (s *StoreEntry) SameTimeTypeEnumList() []*pasturePb.ConfigOptionsList {
 	return cowTypeList
 }
 
-func (s *StoreEntry) ImmunizationCowTypeEnumList() []*pasturePb.ConfigOptionsList {
+func (s *StoreEntry) ImmunizationCowTypeEnumList(isAll string) []*pasturePb.ConfigOptionsList {
 	cowTypeList := make([]*pasturePb.ConfigOptionsList, 0)
 	cowTypeList = append(cowTypeList, &pasturePb.ConfigOptionsList{
 		Value:    int32(pasturePb.CowType_Lactating_Calf),
@@ -237,8 +273,15 @@ func (s *StoreEntry) ImmunizationCowTypeEnumList() []*pasturePb.ConfigOptionsLis
 	return cowTypeList
 }
 
-func (s *StoreEntry) ImmunizationConditionsEnumList() []*pasturePb.ConfigOptionsList {
+func (s *StoreEntry) ImmunizationConditionsEnumList(isAll string) []*pasturePb.ConfigOptionsList {
 	cowTypeList := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		cowTypeList = append(cowTypeList, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.ImmunizationConditions_Invalid),
+			Label:    "全部",
+			Disabled: true,
+		})
+	}
 	cowTypeList = append(cowTypeList, &pasturePb.ConfigOptionsList{
 		Value:    int32(pasturePb.ImmunizationConditions_Days_Age),
 		Label:    "日龄",
@@ -255,12 +298,23 @@ func (s *StoreEntry) ImmunizationConditionsEnumList() []*pasturePb.ConfigOptions
 		Value:    int32(pasturePb.ImmunizationConditions_Admission_Days),
 		Label:    "入场天数",
 		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.ImmunizationConditions_Other_Vaccine_After),
+		Label:    "基于其他疫苗之后",
+		Disabled: true,
 	})
 	return cowTypeList
 }
 
-func (s *StoreEntry) TransferPenEnumList() []*pasturePb.ConfigOptionsList {
+func (s *StoreEntry) TransferPenEnumList(isAll string) []*pasturePb.ConfigOptionsList {
 	transferPenList := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		transferPenList = append(transferPenList, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.TransferPenReason_Invalid),
+			Label:    "全部",
+			Disabled: true,
+		})
+	}
 	transferPenList = append(transferPenList, &pasturePb.ConfigOptionsList{
 		Value:    int32(pasturePb.TransferPenReason_Normal),
 		Label:    "正常转群",
@@ -285,8 +339,16 @@ func (s *StoreEntry) TransferPenEnumList() []*pasturePb.ConfigOptionsList {
 	return transferPenList
 }
 
-func (s *StoreEntry) ChildNumberEnumList() []*pasturePb.ConfigOptionsList {
+func (s *StoreEntry) ChildNumberEnumList(isAll string) []*pasturePb.ConfigOptionsList {
 	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions,
+			&pasturePb.ConfigOptionsList{
+				Value:    int32(pasturePb.ChildNumber_Invalid),
+				Label:    "全部",
+				Disabled: true,
+			})
+	}
 	configOptions = append(configOptions,
 		&pasturePb.ConfigOptionsList{
 			Value:    int32(pasturePb.ChildNumber_One),
@@ -308,8 +370,16 @@ func (s *StoreEntry) ChildNumberEnumList() []*pasturePb.ConfigOptionsList {
 	return configOptions
 }
 
-func (s *StoreEntry) CalvingLevelEnumList() []*pasturePb.ConfigOptionsList {
+func (s *StoreEntry) CalvingLevelEnumList(isAll string) []*pasturePb.ConfigOptionsList {
 	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions,
+			&pasturePb.ConfigOptionsList{
+				Value:    int32(pasturePb.CalvingLevel_Invalid),
+				Label:    "全部",
+				Disabled: true,
+			})
+	}
 	configOptions = append(configOptions,
 		&pasturePb.ConfigOptionsList{
 			Value:    int32(pasturePb.CalvingLevel_Natural_Childbirth),
@@ -331,8 +401,16 @@ func (s *StoreEntry) CalvingLevelEnumList() []*pasturePb.ConfigOptionsList {
 	return configOptions
 }
 
-func (s *StoreEntry) DystociaReasonEnumList() []*pasturePb.ConfigOptionsList {
+func (s *StoreEntry) DystociaReasonEnumList(isAll string) []*pasturePb.ConfigOptionsList {
 	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions,
+			&pasturePb.ConfigOptionsList{
+				Value:    int32(pasturePb.DystociaReason_Invalid),
+				Label:    "全部",
+				Disabled: true,
+			})
+	}
 	configOptions = append(configOptions,
 		&pasturePb.ConfigOptionsList{
 			Value:    int32(pasturePb.DystociaReason_Malposition),
@@ -358,405 +436,23 @@ func (s *StoreEntry) DystociaReasonEnumList() []*pasturePb.ConfigOptionsList {
 	return configOptions
 }
 
-func (s *StoreEntry) PregnantCheckResultEnumList() []*pasturePb.ConfigOptionsList {
-	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
-	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.PregnantCheckResult_InCheck_UnPregnant),
-		Label:    "初检未孕",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.PregnantCheckResult_InCheck_Pregnant),
-		Label:    "初检已孕",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.PregnantCheckResult_Recheck_UnPregnant),
-		Label:    "复检未孕",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.PregnantCheckResult_Recheck_Pregnant),
-		Label:    "初检已孕",
-		Disabled: true,
-	})
-	return configOptions
-}
-
-func (s *StoreEntry) PregnantCheckMethodEnumList() []*pasturePb.ConfigOptionsList {
-	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
-	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.PregnantCheckMethod_B_Ultrasound),
-		Label:    "B超",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.PregnantCheckMethod_Blood_Testing),
-		Label:    "血检",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.PregnantCheckMethod_Manual_Inspection),
-		Label:    "人工检查",
-		Disabled: true,
-	})
-	return configOptions
-}
-
-func (s *StoreEntry) DrugCategoryEnumList() []*pasturePb.ConfigOptionsList {
-	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
-	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.DrugCategory_Antibiotics),
-		Label:    "抗生素类",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.DrugCategory_Antivirals),
-		Label:    "抗病毒类",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.DrugCategory_Antifungals),
-		Label:    "抗真菌类",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.DrugCategory_Antiparasitics),
-		Label:    "驱虫类",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.DrugCategory_Analgesics),
-		Label:    "镇痛类",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.DrugCategory_Antipyretic),
-		Label:    "退烧类",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.DrugCategory_Vitamin),
-		Label:    "维生素类",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.DrugCategory_Brine),
-		Label:    "盐水",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.DrugCategory_Glucose),
-		Label:    "葡萄糖",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.DrugCategory_Hormone),
-		Label:    "激素类",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.DrugCategory_Anti_Stress),
-		Label:    "抗应激类",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.DrugCategory_Disinfect),
-		Label:    "消毒类",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.DrugCategory_Chinese_Herbal),
-		Label:    "中药合剂",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.DrugCategory_Tocolytic),
-		Label:    "保胎类",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.DrugCategory_Immunity),
-		Label:    "疫苗类",
-		Disabled: true,
-	})
-	return configOptions
-}
-
-func (s *StoreEntry) DrugUsageEnumList() []*pasturePb.ConfigOptionsList {
-	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
-	configOptions = append(configOptions,
-		&pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.DrugUsage_Oral_Medications),
-			Label:    "口服",
-			Disabled: true,
-		}, &pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.DrugUsage_Injectable_Medications),
-			Label:    "肌注",
-			Disabled: true,
-		}, &pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.DrugUsage_Topical_Medications),
-			Label:    "外用",
-			Disabled: true,
-		}, &pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.DrugUsage_Inhalation_Medications),
-			Label:    "吸入",
-			Disabled: true,
-		}, &pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.DrugUsage_Drink_Medications),
-			Label:    "饮水",
-			Disabled: true,
-		})
-	return configOptions
-}
-
-func (s *StoreEntry) UnitEnumList() []*pasturePb.ConfigOptionsList {
-	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
-	configOptions = append(configOptions,
-		&pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.Unit_Pieces),
-			Label:    "个",
-			Disabled: true,
-		}, &pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.Unit_Package),
-			Label:    "包/袋",
-			Disabled: true,
-		}, &pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.Unit_Bottle),
-			Label:    "瓶",
-			Disabled: true,
-		}, &pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.Unit_Box),
-			Label:    "盒",
-			Disabled: true,
-		}, &pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.Unit_Boxful),
-			Label:    "箱",
-			Disabled: true,
-		}, &pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.Unit_Branch),
-			Label:    "支",
-			Disabled: true,
-		}, &pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.Unit_Barrel),
-			Label:    "桶",
-			Disabled: true,
-		}, &pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.Unit_Pot),
-			Label:    "罐",
-			Disabled: true,
-		}, &pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.Unit_ML),
-			Label:    "毫升",
-			Disabled: true,
-		}, &pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.Unit_L),
-			Label:    "升",
-			Disabled: true,
-		})
-	return configOptions
-}
-
-func (s *StoreEntry) ExposeEstrusTypeEnumList() []*pasturePb.ConfigOptionsList {
+func (s *StoreEntry) PregnantCheckResultEnumList(isAll string) []*pasturePb.ConfigOptionsList {
 	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
-	configOptions = append(configOptions,
-		&pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.ExposeEstrusType_Neck_Ring),
-			Label:    "脖环揭发",
-			Disabled: true,
-		}, &pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.ExposeEstrusType_Foot_Ring),
-			Label:    "脚环/计步器揭发",
-			Disabled: true,
-		}, &pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.ExposeEstrusType_Manual_Observation),
-			Label:    "人工观察",
-			Disabled: true,
-		})
-	return configOptions
-}
-
-func (s *StoreEntry) FrozenSemenTypeEnumList() []*pasturePb.ConfigOptionsList {
-	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
-	configOptions = append(configOptions,
-		&pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.FrozenSemenType_Ordinary),
-			Label:    "常规冻精",
-			Disabled: true,
-		}, &pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.FrozenSemenType_Gender_Control),
-			Label:    "性控冻精",
-			Disabled: true,
-		})
-	return configOptions
-}
-
-func (s *StoreEntry) BullNumberEnumList() []*pasturePb.BullOptionsList {
-	frozenSemenList := make([]*model.EventFrozenSemen, 0)
-	bullNumberList := make([]*pasturePb.BullOptionsList, 0)
-	if err := s.DB.Where("quantity > 0").Group("bull_id").Find(&frozenSemenList).Error; err != nil {
-		zaplog.Error("BullNumberEnumList", zap.Any("Find", err))
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions,
+			&pasturePb.ConfigOptionsList{
+				Value:    int32(pasturePb.PregnantCheckResult_Invalid),
+				Label:    "全部",
+				Disabled: true,
+			})
 	}
-
-	for _, v := range frozenSemenList {
-		bullNumberList = append(bullNumberList, &pasturePb.BullOptionsList{
-			Value:    v.BullId,
-			Label:    v.BullId,
-			Disabled: true,
-		})
-	}
-	return bullNumberList
-}
-
-func (s *StoreEntry) WeekEnumList() []*pasturePb.ConfigOptionsList {
-	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
-	configOptions = append(configOptions,
-		&pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.Week_Monday),
-			Label:    "周一",
-			Disabled: true,
-		}, &pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.Week_Tuesday),
-			Label:    "周二",
-			Disabled: true,
-		}, &pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.Week_Wednesday),
-			Label:    "周三",
-			Disabled: true,
-		}, &pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.Week_Thursday),
-			Label:    "周四",
-			Disabled: true,
-		}, &pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.Week_Friday),
-			Label:    "周五",
-			Disabled: true,
-		}, &pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.Week_Saturday),
-			Label:    "周六",
-			Disabled: true,
-		}, &pasturePb.ConfigOptionsList{
-			Value:    int32(pasturePb.Week_Sunday),
-			Label:    "周日",
-			Disabled: true,
-		})
-	return configOptions
-}
-
-func (s *StoreEntry) MonthEnumList() []*pasturePb.ConfigOptionsList {
-	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
-	for v := 1; v <= 31; v++ {
-		configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
-			Value:    int32(v),
-			Label:    fmt.Sprintf("%d号", v),
-			Disabled: true,
-		})
-	}
-	return configOptions
-}
-
-func (s *StoreEntry) WorkOrderFrequencyEnumList() []*pasturePb.ConfigOptionsList {
-	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
 	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.WorkOrderFrequency_None),
-		Label:    "一次性",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.WorkOrderFrequency_Daily),
-		Label:    "每天",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.WorkOrderFrequency_Weekly),
-		Label:    "每周",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.WorkOrderFrequency_Monthly),
-		Label:    "每月",
-		Disabled: true,
-	})
-	return configOptions
-}
-
-func (s *StoreEntry) WorkOrderSubUnitEnumList() []*pasturePb.ConfigOptionsList {
-	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
-	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.WorkOrderSubscribeUnit_Person),
-		Label:    "个人",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.WorkOrderSubscribeUnit_dept),
-		Label:    "部门",
-		Disabled: true,
-	})
-	return configOptions
-}
-
-func (s *StoreEntry) WorkOrderPriorityEnumList() []*pasturePb.ConfigOptionsList {
-	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
-	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.Priority_Low),
-		Label:    "低",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.Priority_Middle),
-		Label:    "一般",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.Priority_High),
-		Label:    "紧急",
-		Disabled: true,
-	})
-	return configOptions
-}
-
-func (s *StoreEntry) WorkOrderCategoryEnumList() []*pasturePb.ConfigOptionsList {
-	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
-	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.WorkOrderCategory_Health),
-		Label:    "保健",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.WorkOrderCategory_Breed),
-		Label:    "繁殖",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.WorkOrderCategory_Nutrition),
-		Label:    "营养",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.WorkOrderCategory_Ordinary),
-		Label:    "日常",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.WorkOrderCategory_Other),
-		Label:    "其他",
-		Disabled: true,
-	})
-	return configOptions
-}
-
-func CalendarTypeEnumList() []*pasturePb.ConfigOptionsList {
-	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
-	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.CalendarType_Immunisation),
-		Label:    "免疫",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.CalendarType_PG),
-		Label:    "PG",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.CalendarType_RnGH),
-		Label:    "RnGH",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.CalendarType_First_Pregnancy_Check),
-		Label:    "孕检-初检",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.CalendarType_Second_Pregnancy_Check),
-		Label:    "孕检-二检",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.CalendarType_Third_Pregnancy_Check),
-		Label:    "孕检-三检",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.CalendarType_Fourth_Pregnancy_Check),
-		Label:    "孕检-四检",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.CalendarType_WorkOrder),
-		Label:    "工单",
-		Disabled: true,
-	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.CalendarType_Weaning),
-		Label:    "断奶",
+		Value:    int32(pasturePb.PregnantCheckResult_Pregnant),
+		Label:    "有胎",
 		Disabled: true,
 	}, &pasturePb.ConfigOptionsList{
-		Value:    int32(pasturePb.CalendarType_Treatment),
-		Label:    "治疗",
+		Value:    int32(pasturePb.PregnantCheckResult_UnPregnant),
+		Label:    "无胎",
 		Disabled: true,
 	})
 	return configOptions

+ 461 - 0
module/backend/config_data_breed.go

@@ -0,0 +1,461 @@
+package backend
+
+import (
+	"kpt-pasture/model"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
+	"go.uber.org/zap"
+)
+
+func (s *StoreEntry) LactEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+			Value:    int32(0),
+			Label:    "全部",
+			Disabled: true,
+		})
+	}
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(1),
+		Label:    "1",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(2),
+		Label:    "2",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(3),
+		Label:    "3",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(4),
+		Label:    ">3",
+		Disabled: true,
+	})
+	return configOptions
+}
+
+func (s *StoreEntry) DiseaseAnalysisMethodEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.DiseaseAnalysisMethod_Invalid),
+			Label:    "全部",
+			Disabled: true,
+		})
+	}
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DiseaseAnalysisMethod_Months),
+		Label:    "按月份",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DiseaseAnalysisMethod_Disease_Category),
+		Label:    "疾病分类",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DiseaseAnalysisMethod_Disease),
+		Label:    "疾病名称",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DiseaseAnalysisMethod_Operator),
+		Label:    "兽医",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DiseaseAnalysisMethod_Prescription),
+		Label:    "处方",
+		Disabled: true,
+	})
+	return configOptions
+}
+
+func (s *StoreEntry) diseaseTypeEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configDiseaseTypeList := make([]*model.ConfigDiseaseType, 0)
+	configOptionsList := make([]*pasturePb.ConfigOptionsList, 0)
+	if err := s.DB.Where("is_show = ?", pasturePb.IsShow_Ok).Find(&configDiseaseTypeList).Error; err != nil {
+		zaplog.Error("diseaseTypeEnumList", zap.Any("Find", err))
+	}
+
+	for _, v := range configDiseaseTypeList {
+		configOptionsList = append(configOptionsList, &pasturePb.ConfigOptionsList{
+			Value:    int32(v.Id),
+			Label:    v.Name,
+			Disabled: true,
+		})
+	}
+	return configOptionsList
+}
+
+func (s *StoreEntry) SingleFactorAnalysisMethodEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.SingleFactorAnalysisMethod_Cycle),
+		Label:    "按周期分析",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.SingleFactorAnalysisMethod_Months),
+		Label:    "按月份分析",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.SingleFactorAnalysisMethod_Mating_Times),
+		Label:    "按配种次数分析",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.SingleFactorAnalysisMethod_Breeding_Method),
+		Label:    "按配种方式分析",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.SingleFactorAnalysisMethod_Breeding_Company),
+		Label:    "按育种公司分析",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.SingleFactorAnalysisMethod_Operation),
+		Label:    "按兽医人员分析",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.SingleFactorAnalysisMethod_Mating_Interval),
+		Label:    "按配种间隔分析",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.SingleFactorAnalysisMethod_Bull),
+		Label:    "按公牛号分析",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.SingleFactorAnalysisMethod_Breeding_Cycle),
+		Label:    "按配种周期分析",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.SingleFactorAnalysisMethod_Week),
+		Label:    "按星期分析",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.SingleFactorAnalysisMethod_Lact),
+		Label:    "按胎次分析",
+		Disabled: true,
+	})
+	return configOptions
+}
+
+func (s *StoreEntry) LactIntervalSymbolEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.CompareSymbol_Less_Than),
+		Label:    "<",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.CompareSymbol_Less_Than_Or_Equal_To),
+		Label:    "<=",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.CompareSymbol_Greater_Than),
+		Label:    ">",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.CompareSymbol_Greater_Than_Or_Equal_To),
+		Label:    ">=",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.CompareSymbol_Equal_To),
+		Label:    "=",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.CompareSymbol_Not_Equal_To),
+		Label:    "!=",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.CompareSymbol_Between),
+		Label:    "区间",
+		Disabled: true,
+	})
+	return configOptions
+}
+
+func (s *StoreEntry) MultiFactorAnalysisMethodEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.MultiFactorAnalysisMethod_Months),
+		Label:    "月份",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.MultiFactorAnalysisMethod_Week),
+		Label:    "周",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.MultiFactorAnalysisMethod_Operation),
+		Label:    "配种员",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.MultiFactorAnalysisMethod_Bull),
+		Label:    "公牛",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.MultiFactorAnalysisMethod_Lact),
+		Label:    "胎次",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.MultiFactorAnalysisMethod_Mating_Times),
+		Label:    "配次",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.MultiFactorAnalysisMethod_Breeding_Method),
+		Label:    "配种方式",
+		Disabled: true,
+	})
+	return configOptions
+}
+
+func (s *StoreEntry) SaleCowAnalysisMethodEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.SaleCowAnalysisMethod_Months),
+		Label:    "月份",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.SaleCowAnalysisMethod_Dealer),
+		Label:    "经销商",
+		Disabled: true,
+	})
+	return configOptions
+}
+
+func (s *StoreEntry) NeckRingStatusEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions,
+			&pasturePb.ConfigOptionsList{
+				Value:    int32(pasturePb.NeckRingStatus_Invalid),
+				Label:    "全部",
+				Disabled: true,
+			})
+	}
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.NeckRingStatus_Bind),
+		Label:    "绑定",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.NeckRingStatus_Normal),
+		Label:    "正常",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.NeckRingStatus_Offline),
+		Label:    "在线",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.NeckRingStatus_Error),
+		Label:    "异常",
+		Disabled: true,
+	})
+	return configOptions
+}
+
+func (s *StoreEntry) WorkOrderSubUnitEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.WorkOrderSubscribeUnit_Person),
+		Label:    "个人",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.WorkOrderSubscribeUnit_dept),
+		Label:    "部门",
+		Disabled: true,
+	})
+	return configOptions
+}
+
+func (s *StoreEntry) WorkOrderPriorityEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.Priority_Low),
+		Label:    "低",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.Priority_Middle),
+		Label:    "一般",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.Priority_High),
+		Label:    "紧急",
+		Disabled: true,
+	})
+	return configOptions
+}
+
+func (s *StoreEntry) WorkOrderCategoryEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.WorkOrderCategory_Health),
+		Label:    "保健",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.WorkOrderCategory_Breed),
+		Label:    "繁殖",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.WorkOrderCategory_Nutrition),
+		Label:    "营养",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.WorkOrderCategory_Ordinary),
+		Label:    "日常",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.WorkOrderCategory_Other),
+		Label:    "其他",
+		Disabled: true,
+	})
+	return configOptions
+}
+
+func CalendarTypeEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.SameTimeStatus_Invalid),
+			Label:    "全部",
+			Disabled: true,
+		})
+	}
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.CalendarType_Immunisation),
+		Label:    "免疫",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.CalendarType_PG),
+		Label:    "同期PG",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.CalendarType_RnGH),
+		Label:    "同期RnGH",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.CalendarType_Pregnancy_Check),
+		Label:    "孕检",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.CalendarType_WorkOrder),
+		Label:    "工单",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.CalendarType_Weaning),
+		Label:    "断奶",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.CalendarType_Treatment),
+		Label:    "治疗",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.CalendarType_Mating),
+		Label:    "配种",
+		Disabled: true,
+	})
+	return configOptions
+}
+
+func (s *StoreEntry) AbortionReasonsEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.AbortionReasons_Invalid),
+			Label:    "全部",
+			Disabled: true,
+		})
+	}
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.AbortionReasons_Mechanical_Abortion),
+		Label:    "机械性流产",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.AbortionReasons_Malnutrition_Abortion),
+		Label:    "营养不良性流产",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.AbortionReasons_Mycotoxin_Abortion),
+		Label:    "霉菌毒素流产",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.AbortionReasons_Habitual_Abortion),
+		Label:    "习惯性流产",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.AbortionReasons_Brucellosis_Abortion),
+		Label:    "布病流产",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.AbortionReasons_Inflammatory_Abortion),
+		Label:    "产道炎症性流产",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.AbortionReasons_Heat_Stress_Abortion),
+		Label:    "热应激流产",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.AbortionReasons_Infectious_Abortion),
+		Label:    "传染病性流产",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.AbortionReasons_Other),
+		Label:    "其他",
+		Disabled: true,
+	})
+	return configOptions
+}
+
+func (s *StoreEntry) HealthStatusEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.HealthStatus_Invalid),
+			Label:    "全部",
+			Disabled: true,
+		})
+	}
+
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.HealthStatus_Health),
+		Label:    "健康",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.HealthStatus_Disease),
+		Label:    "发病",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.HealthStatus_Treatment),
+		Label:    "治疗",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.HealthStatus_Curable),
+		Label:    "治愈",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.HealthStatus_Out),
+		Label:    "淘汰",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.HealthStatus_Dead),
+		Label:    "死亡",
+		Disabled: true,
+	})
+	return configOptions
+}
+
+func (s *StoreEntry) CalvingAnalysisMethodEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.CalvingAnalysisMethod_Invalid),
+			Label:    "全部",
+			Disabled: true,
+		})
+	}
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.CalvingAnalysisMethod_Months),
+		Label:    "按月份统计",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.CalvingAnalysisMethod_CowKind),
+		Label:    "按照品种统计",
+		Disabled: true,
+	})
+	return configOptions
+}

+ 41 - 0
module/backend/config_data_extend.go

@@ -0,0 +1,41 @@
+package backend
+
+import (
+	"kpt-pasture/model"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
+
+func (s *StoreEntry) AdmissionStatusEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions,
+			&pasturePb.ConfigOptionsList{
+				Value:    int32(pasturePb.AuditStatus_Invalid),
+				Label:    "全部",
+				Disabled: true,
+			})
+	}
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.AdmissionStatus_Admission),
+		Label:    "在群",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.AdmissionStatus_Die),
+		Label:    "死亡",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.AdmissionStatus_Out),
+		Label:    "淘汰",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.AdmissionStatus_Sale),
+		Label:    "售卖",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.AdmissionStatus_Transfer),
+		Label:    "转出",
+		Disabled: true,
+	})
+	return configOptions
+}

+ 401 - 0
module/backend/config_data_other.go

@@ -0,0 +1,401 @@
+package backend
+
+import (
+	"fmt"
+	"kpt-pasture/model"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
+	"go.uber.org/zap"
+)
+
+func (s *StoreEntry) PregnantCheckMethodEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions,
+			&pasturePb.ConfigOptionsList{
+				Value: int32(pasturePb.PregnantCheckMethod_Invalid),
+			})
+	}
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.PregnantCheckMethod_B_Ultrasound),
+		Label:    "B超",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.PregnantCheckMethod_Blood_Testing),
+		Label:    "血检",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.PregnantCheckMethod_Manual_Inspection),
+		Label:    "人工检查",
+		Disabled: true,
+	})
+	return configOptions
+}
+
+func (s *StoreEntry) DrugCategoryEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions,
+			&pasturePb.ConfigOptionsList{
+				Value:    int32(pasturePb.DrugCategory_Invalid),
+				Label:    "全部",
+				Disabled: true,
+			})
+	}
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DrugCategory_Antibiotics),
+		Label:    "抗生素类",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DrugCategory_Antivirals),
+		Label:    "抗病毒类",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DrugCategory_Antifungals),
+		Label:    "抗真菌类",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DrugCategory_Antiparasitics),
+		Label:    "驱虫类",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DrugCategory_Analgesics),
+		Label:    "镇痛类",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DrugCategory_Antipyretic),
+		Label:    "退烧类",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DrugCategory_Vitamin),
+		Label:    "维生素类",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DrugCategory_Brine),
+		Label:    "盐水",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DrugCategory_Glucose),
+		Label:    "葡萄糖",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DrugCategory_Hormone),
+		Label:    "激素类",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DrugCategory_Anti_Stress),
+		Label:    "抗应激类",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DrugCategory_Disinfect),
+		Label:    "消毒类",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DrugCategory_Chinese_Herbal),
+		Label:    "中药合剂",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DrugCategory_Tocolytic),
+		Label:    "保胎类",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DrugCategory_Immunity),
+		Label:    "疫苗类",
+		Disabled: true,
+	})
+	return configOptions
+}
+
+func (s *StoreEntry) DrugUsageEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions,
+			&pasturePb.ConfigOptionsList{
+				Value:    int32(pasturePb.DrugUsage_Invalid),
+				Label:    "全部",
+				Disabled: true,
+			})
+	}
+	configOptions = append(configOptions,
+		&pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.DrugUsage_Oral_Medications),
+			Label:    "口服",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.DrugUsage_Injectable_Medications),
+			Label:    "肌注",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.DrugUsage_Topical_Medications),
+			Label:    "外用",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.DrugUsage_Inhalation_Medications),
+			Label:    "吸入",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.DrugUsage_Drink_Medications),
+			Label:    "饮水",
+			Disabled: true,
+		})
+	return configOptions
+}
+
+func (s *StoreEntry) UnitEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	configOptions = append(configOptions,
+		&pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.Unit_Pieces),
+			Label:    "个",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.Unit_Package),
+			Label:    "包/袋",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.Unit_Bottle),
+			Label:    "瓶",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.Unit_Box),
+			Label:    "盒",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.Unit_Boxful),
+			Label:    "箱",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.Unit_Branch),
+			Label:    "支",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.Unit_Barrel),
+			Label:    "桶",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.Unit_Pot),
+			Label:    "罐",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.Unit_ML),
+			Label:    "毫升",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.Unit_L),
+			Label:    "升",
+			Disabled: true,
+		})
+	return configOptions
+}
+
+func (s *StoreEntry) ExposeEstrusTypeEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions,
+			&pasturePb.ConfigOptionsList{
+				Value:    int32(pasturePb.ExposeEstrusType_Invalid),
+				Label:    "全部",
+				Disabled: true,
+			})
+	}
+
+	configOptions = append(configOptions,
+		&pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.ExposeEstrusType_Neck_Ring),
+			Label:    "脖环揭发",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.ExposeEstrusType_Foot_Ring),
+			Label:    "脚环揭发",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.ExposeEstrusType_Natural_Estrus),
+			Label:    "自然发情",
+			Disabled: true,
+		})
+	return configOptions
+}
+
+func (s *StoreEntry) FrozenSemenTypeEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions,
+			&pasturePb.ConfigOptionsList{
+				Value:    int32(pasturePb.FrozenSemenType_Invalid),
+				Label:    "全部",
+				Disabled: true,
+			})
+	}
+	configOptions = append(configOptions,
+		&pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.FrozenSemenType_Ordinary),
+			Label:    "常规冻精",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.FrozenSemenType_Gender_Control),
+			Label:    "性控冻精",
+			Disabled: true,
+		})
+	return configOptions
+}
+
+func (s *StoreEntry) BullNumberEnumList(isAll string) []*pasturePb.BullOptionsList {
+	frozenSemenList := make([]*model.FrozenSemen, 0)
+	bullNumberList := make([]*pasturePb.BullOptionsList, 0)
+	if err := s.DB.Where("quantity > 0").Group("bull_id").Find(&frozenSemenList).Error; err != nil {
+		zaplog.Error("BullNumberEnumList", zap.Any("Find", err))
+	}
+
+	for _, v := range frozenSemenList {
+		bullNumberList = append(bullNumberList, &pasturePb.BullOptionsList{
+			Value:    v.BullId,
+			Label:    v.BullId,
+			Disabled: true,
+		})
+	}
+	return bullNumberList
+}
+
+func (s *StoreEntry) WeekEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	configOptions = append(configOptions,
+		&pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.Week_Monday),
+			Label:    "周一",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.Week_Tuesday),
+			Label:    "周二",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.Week_Wednesday),
+			Label:    "周三",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.Week_Thursday),
+			Label:    "周四",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.Week_Friday),
+			Label:    "周五",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.Week_Saturday),
+			Label:    "周六",
+			Disabled: true,
+		}, &pasturePb.ConfigOptionsList{
+			Value:    int32(pasturePb.Week_Sunday),
+			Label:    "周日",
+			Disabled: true,
+		})
+	return configOptions
+}
+
+func (s *StoreEntry) MonthEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	for v := 1; v <= 31; v++ {
+		configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+			Value:    int32(v),
+			Label:    fmt.Sprintf("%d号", v),
+			Disabled: true,
+		})
+	}
+	return configOptions
+}
+
+func (s *StoreEntry) WorkOrderFrequencyEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.WorkOrderFrequency_None),
+		Label:    "一次性",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.WorkOrderFrequency_Daily),
+		Label:    "每天",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.WorkOrderFrequency_Weekly),
+		Label:    "每周",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.WorkOrderFrequency_Monthly),
+		Label:    "每月",
+		Disabled: true,
+	})
+	return configOptions
+}
+
+func (s *StoreEntry) OutTypeEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions,
+			&pasturePb.ConfigOptionsList{
+				Value:    int32(pasturePb.OutType_Invalid),
+				Label:    "全部",
+				Disabled: true,
+			})
+	}
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutType_Drugs),
+		Label:    "药品",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutType_Medical_Equipment),
+		Label:    "医疗器械",
+		Disabled: true,
+	})
+	return configOptions
+}
+
+func (s *StoreEntry) AuditStatusEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions,
+			&pasturePb.ConfigOptionsList{
+				Value:    int32(pasturePb.AuditStatus_Invalid),
+				Label:    "全部",
+				Disabled: true,
+			})
+	}
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.AuditStatus_Pending),
+		Label:    "待审核",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.AuditStatus_Pass),
+		Label:    "已通过",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.AuditStatus_Reject),
+		Label:    "已拒绝",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.AuditStatus_Cancel),
+		Label:    "已取消",
+		Disabled: true,
+	})
+	return configOptions
+}
+
+func (s *StoreEntry) PregnantCheckNameEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions,
+			&pasturePb.ConfigOptionsList{
+				Value:    int32(0),
+				Label:    "全部",
+				Disabled: true,
+			})
+	}
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(1),
+		Label:    "初检",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(2),
+		Label:    "复检",
+		Disabled: true,
+	})
+	return configOptions
+}

Some files were not shown because too many files changed in this diff