From aa13239e89b11582fd4fe497cd87c1a14a03571a Mon Sep 17 00:00:00 2001 From: huang <1724659546@qq.com> Date: Thu, 20 Nov 2025 22:55:18 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E4=BB=8Ejson=E8=AF=BB?= =?UTF-8?q?=E5=8F=96=E7=8C=AA=E8=90=A5=E5=85=BB=E9=9C=80=E6=B1=82=E5=B9=B6?= =?UTF-8?q?=E5=86=99=E5=85=A5=E6=95=B0=E6=8D=AE=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/presets-data/nutrient.json | 2 +- .../pig_nutrient_requirement.json | 914 ++++++++++++++++++ design/archive/recipe-management/index.md | 3 +- internal/infra/database/seeder.go | 361 ++++++- internal/infra/models/pig.go | 8 +- 5 files changed, 1254 insertions(+), 34 deletions(-) create mode 100644 config/presets-data/pig_nutrient_requirement.json diff --git a/config/presets-data/nutrient.json b/config/presets-data/nutrient.json index e589b34..9c322a8 100644 --- a/config/presets-data/nutrient.json +++ b/config/presets-data/nutrient.json @@ -1864,7 +1864,7 @@ "氢氰酸 (mg/kg)": "木薯、苦杏仁等原料中潜在剧毒物质,阻断细胞呼吸,极微量即可引起猪中毒死亡。构树原料标0为已脱毒处理,使用前必须确认氢氰酸含量合格。", "总黄酮 (mg/kg)": "构树等植物次生代谢物,具有抗氧化、抗菌、改善血管功能的作用,对母猪繁殖性能和仔猪抗应激有一定正面作用,但过量也可能影响适口性。", "生物碱 (mg/kg)": "构树等原料中潜在有害物质,高量会引起猪神经症状、食欲下降甚至中毒,使用时需严格控制比例。", - "沙门氏菌": "进口鱼粉卫生指标,必须为0(即阴性)。一旦检出阳性,整批原料禁止用于猪饲料,否则极易引发仔猪副伤寒和全身感染。", + "沙门氏菌 (mg/kg)": "进口鱼粉卫生指标,必须为0(即阴性)。一旦检出阳性,整批原料禁止用于猪饲料,否则极易引发仔猪副伤寒和全身感染。", "总棉酚 (mg/kg)": "棉粕中主要毒素,包括游离棉酚和结合棉酚。高量引起公猪精子畸形、母猪流产、生长猪肝肾损伤。生长育肥猪建议总棉酚<300mg/kg,种猪<100mg/kg。", "环丙烯酸 (mg/kg)": "棉粕中另一种毒素,与棉酚协同作用,破坏赖氨酸利用率,严重影响蛋白质沉积。优质脱酚棉粕应<500mg/kg。", "硫酸盐 (mg/kg)": "玉米DDGS发酵副产物,高硫酸盐(>8000mg/kg常见)易导致猪脑软化症(硫中毒),生长猪日粮硫酸盐建议不超过4000mg/kg。", diff --git a/config/presets-data/pig_nutrient_requirement.json b/config/presets-data/pig_nutrient_requirement.json new file mode 100644 index 0000000..c6aacf8 --- /dev/null +++ b/config/presets-data/pig_nutrient_requirement.json @@ -0,0 +1,914 @@ +{ + "type": "pig_nutrient_requirements", + "data": { + "杜长大 (DLY)": { + "保育期": { + "可消化赖氨酸 (SID %)": { + "min_requirement": 0.012, + "max_requirement": 0.015 + }, + "蛋+胱氨酸 (%)": { + "min_requirement": 0.0072, + "max_requirement": 0.0105 + }, + "可消化苏氨酸 (SID %)": { + "min_requirement": 0.0078, + "max_requirement": 0.0108 + }, + "可消化色氨酸 (SID %)": { + "min_requirement": 0.0022, + "max_requirement": 0.0030 + }, + "粗蛋白 (%)": { + "min_requirement": 0.18, + "max_requirement": 0.22 + }, + "粗脂肪 (%)": { + "min_requirement": 0.03, + "max_requirement": 0.06 + }, + "粗纤维 (%)": { + "min_requirement": 0.02, + "max_requirement": 0.06 + }, + "钙 (%)": { + "min_requirement": 0.009, + "max_requirement": 0.012 + }, + "总磷 (%)": { + "min_requirement": 0.006, + "max_requirement": 0.008 + }, + "有效磷 (%)": { + "min_requirement": 0.002, + "max_requirement": 0.0045 + }, + "代谢能 (kcal/kg)": { + "min_requirement": 3226.5, + "max_requirement": 3585.0 + }, + "钠 (%)": { + "min_requirement": 0.0015, + "max_requirement": 0.0025 + }, + "氯 (%)": { + "min_requirement": 0.0025, + "max_requirement": 0.0045 + }, + "黄曲霉毒素B1 (μg/kg)": { + "max_requirement": 10 + }, + "呕吐毒素DON (μg/kg)": { + "max_requirement": 1 + }, + "玉米赤霉烯酮ZEN (μg/kg)": { + "max_requirement": 0.15 + } + }, + "育肥前期": { + "可消化赖氨酸 (SID %)": { + "min_requirement": 0.0094, + "max_requirement": 0.0110 + }, + "蛋+胱氨酸 (%)": { + "min_requirement": 0.0055, + "max_requirement": 0.0073 + }, + "可消化苏氨酸 (SID %)": { + "min_requirement": 0.0058, + "max_requirement": 0.0077 + }, + "可消化色氨酸 (SID %)": { + "min_requirement": 0.0016, + "max_requirement": 0.0022 + }, + "粗蛋白 (%)": { + "min_requirement": 0.16, + "max_requirement": 0.18 + }, + "粗脂肪 (%)": { + "min_requirement": 0.03, + "max_requirement": 0.06 + }, + "粗纤维 (%)": { + "min_requirement": 0.02, + "max_requirement": 0.06 + }, + "钙 (%)": { + "min_requirement": 0.007, + "max_requirement": 0.009 + }, + "总磷 (%)": { + "min_requirement": 0.005, + "max_requirement": 0.007 + }, + "有效磷 (%)": { + "min_requirement": 0.002, + "max_requirement": 0.0040 + }, + "代谢能 (kcal/kg)": { + "min_requirement": 3107.0, + "max_requirement": 3346.0 + }, + "钠 (%)": { + "min_requirement": 0.0015, + "max_requirement": 0.0025 + }, + "氯 (%)": { + "min_requirement": 0.0025, + "max_requirement": 0.0045 + }, + "黄曲霉毒素B1 (μg/kg)": { + "max_requirement": 10 + }, + "呕吐毒素DON (μg/kg)": { + "max_requirement": 1 + }, + "玉米赤霉烯酮ZEN (μg/kg)": { + "max_requirement": 0.15 + } + }, + "育肥后期": { + "可消化赖氨酸 (SID %)": { + "min_requirement": 0.0081, + "max_requirement": 0.0090 + }, + "蛋+胱氨酸 (%)": { + "min_requirement": 0.0045, + "max_requirement": 0.0058 + }, + "可消化苏氨酸 (SID %)": { + "min_requirement": 0.0048, + "max_requirement": 0.0061 + }, + "可消化色氨酸 (SID %)": { + "min_requirement": 0.0013, + "max_requirement": 0.0018 + }, + "粗蛋白 (%)": { + "min_requirement": 0.14, + "max_requirement": 0.16 + }, + "粗脂肪 (%)": { + "min_requirement": 0.03, + "max_requirement": 0.06 + }, + "粗纤维 (%)": { + "min_requirement": 0.02, + "max_requirement": 0.06 + }, + "钙 (%)": { + "min_requirement": 0.006, + "max_requirement": 0.008 + }, + "总磷 (%)": { + "min_requirement": 0.0045, + "max_requirement": 0.006 + }, + "有效磷 (%)": { + "min_requirement": 0.0018, + "max_requirement": 0.0035 + }, + "代谢能 (kcal/kg)": { + "min_requirement": 2987.5, + "max_requirement": 3226.5 + }, + "钠 (%)": { + "min_requirement": 0.0015, + "max_requirement": 0.0025 + }, + "氯 (%)": { + "min_requirement": 0.0025, + "max_requirement": 0.0045 + }, + "黄曲霉毒素B1 (μg/kg)": { + "max_requirement": 10 + }, + "呕吐毒素DON (μg/kg)": { + "max_requirement": 1 + }, + "玉米赤霉烯酮ZEN (μg/kg)": { + "max_requirement": 0.15 + } + }, + "二次育肥期": { + "可消化赖氨酸 (SID %)": { + "min_requirement": 0.0053, + "max_requirement": 0.0065 + }, + "蛋+胱氨酸 (%)": { + "min_requirement": 0.0030, + "max_requirement": 0.0041 + }, + "可消化苏氨酸 (SID %)": { + "min_requirement": 0.0031, + "max_requirement": 0.0043 + }, + "可消化色氨酸 (SID %)": { + "min_requirement": 0.0010, + "max_requirement": 0.0013 + }, + "粗蛋白 (%)": { + "min_requirement": 0.12, + "max_requirement": 0.14 + }, + "粗脂肪 (%)": { + "min_requirement": 0.03, + "max_requirement": 0.06 + }, + "粗纤维 (%)": { + "min_requirement": 0.02, + "max_requirement": 0.06 + }, + "钙 (%)": { + "min_requirement": 0.005, + "max_requirement": 0.007 + }, + "总磷 (%)": { + "min_requirement": 0.004, + "max_requirement": 0.0055 + }, + "有效磷 (%)": { + "min_requirement": 0.0015, + "max_requirement": 0.0030 + }, + "代谢能 (kcal/kg)": { + "min_requirement": 2868.0, + "max_requirement": 3107.0 + }, + "钠 (%)": { + "min_requirement": 0.0015, + "max_requirement": 0.0025 + }, + "氯 (%)": { + "min_requirement": 0.0025, + "max_requirement": 0.0045 + }, + "黄曲霉毒素B1 (μg/kg)": { + "max_requirement": 10 + }, + "呕吐毒素DON (μg/kg)": { + "max_requirement": 1 + }, + "玉米赤霉烯酮ZEN (μg/kg)": { + "max_requirement": 0.15 + } + } + }, + "杜大长 (DY L)": { + "保育期": { + "可消化赖氨酸 (SID %)": { + "min_requirement": 0.012, + "max_requirement": 0.015 + }, + "蛋+胱氨酸 (%)": { + "min_requirement": 0.0072, + "max_requirement": 0.0105 + }, + "可消化苏氨酸 (SID %)": { + "min_requirement": 0.0078, + "max_requirement": 0.0108 + }, + "可消化色氨酸 (SID %)": { + "min_requirement": 0.0022, + "max_requirement": 0.0030 + }, + "粗蛋白 (%)": { + "min_requirement": 0.18, + "max_requirement": 0.22 + }, + "粗脂肪 (%)": { + "min_requirement": 0.03, + "max_requirement": 0.06 + }, + "粗纤维 (%)": { + "min_requirement": 0.02, + "max_requirement": 0.06 + }, + "钙 (%)": { + "min_requirement": 0.009, + "max_requirement": 0.012 + }, + "总磷 (%)": { + "min_requirement": 0.006, + "max_requirement": 0.008 + }, + "有效磷 (%)": { + "min_requirement": 0.002, + "max_requirement": 0.0045 + }, + "代谢能 (kcal/kg)": { + "min_requirement": 3226.5, + "max_requirement": 3585.0 + }, + "钠 (%)": { + "min_requirement": 0.0015, + "max_requirement": 0.0025 + }, + "氯 (%)": { + "min_requirement": 0.0025, + "max_requirement": 0.0045 + }, + "黄曲霉毒素B1 (μg/kg)": { + "max_requirement": 10 + }, + "呕吐毒素DON (μg/kg)": { + "max_requirement": 1 + }, + "玉米赤霉烯酮ZEN (μg/kg)": { + "max_requirement": 0.15 + } + }, + "育肥前期": { + "可消化赖氨酸 (SID %)": { + "min_requirement": 0.0094, + "max_requirement": 0.0110 + }, + "蛋+胱氨酸 (%)": { + "min_requirement": 0.0055, + "max_requirement": 0.0073 + }, + "可消化苏氨酸 (SID %)": { + "min_requirement": 0.0058, + "max_requirement": 0.0077 + }, + "可消化色氨酸 (SID %)": { + "min_requirement": 0.0016, + "max_requirement": 0.0022 + }, + "粗蛋白 (%)": { + "min_requirement": 0.16, + "max_requirement": 0.18 + }, + "粗脂肪 (%)": { + "min_requirement": 0.03, + "max_requirement": 0.06 + }, + "粗纤维 (%)": { + "min_requirement": 0.02, + "max_requirement": 0.06 + }, + "钙 (%)": { + "min_requirement": 0.007, + "max_requirement": 0.009 + }, + "总磷 (%)": { + "min_requirement": 0.005, + "max_requirement": 0.007 + }, + "有效磷 (%)": { + "min_requirement": 0.002, + "max_requirement": 0.0040 + }, + "代谢能 (kcal/kg)": { + "min_requirement": 3107.0, + "max_requirement": 3346.0 + }, + "钠 (%)": { + "min_requirement": 0.0015, + "max_requirement": 0.0025 + }, + "氯 (%)": { + "min_requirement": 0.0025, + "max_requirement": 0.0045 + }, + "黄曲霉毒素B1 (μg/kg)": { + "max_requirement": 10 + }, + "呕吐毒素DON (μg/kg)": { + "max_requirement": 1 + }, + "玉米赤霉烯酮ZEN (μg/kg)": { + "max_requirement": 0.15 + } + }, + "育肥后期": { + "可消化赖氨酸 (SID %)": { + "min_requirement": 0.0081, + "max_requirement": 0.0090 + }, + "蛋+胱氨酸 (%)": { + "min_requirement": 0.0045, + "max_requirement": 0.0058 + }, + "可消化苏氨酸 (SID %)": { + "min_requirement": 0.0048, + "max_requirement": 0.0061 + }, + "可消化色氨酸 (SID %)": { + "min_requirement": 0.0013, + "max_requirement": 0.0018 + }, + "粗蛋白 (%)": { + "min_requirement": 0.14, + "max_requirement": 0.16 + }, + "粗脂肪 (%)": { + "min_requirement": 0.03, + "max_requirement": 0.06 + }, + "粗纤维 (%)": { + "min_requirement": 0.02, + "max_requirement": 0.06 + }, + "钙 (%)": { + "min_requirement": 0.006, + "max_requirement": 0.008 + }, + "总磷 (%)": { + "min_requirement": 0.0045, + "max_requirement": 0.006 + }, + "有效磷 (%)": { + "min_requirement": 0.0018, + "max_requirement": 0.0035 + }, + "代谢能 (kcal/kg)": { + "min_requirement": 2987.5, + "max_requirement": 3226.5 + }, + "钠 (%)": { + "min_requirement": 0.0015, + "max_requirement": 0.0025 + }, + "氯 (%)": { + "min_requirement": 0.0025, + "max_requirement": 0.0045 + }, + "黄曲霉毒素B1 (μg/kg)": { + "max_requirement": 10 + }, + "呕吐毒素DON (μg/kg)": { + "max_requirement": 1 + }, + "玉米赤霉烯酮ZEN (μg/kg)": { + "max_requirement": 0.15 + } + }, + "二次育肥期": { + "可消化赖氨酸 (SID %)": { + "min_requirement": 0.0053, + "max_requirement": 0.0065 + }, + "蛋+胱氨酸 (%)": { + "min_requirement": 0.0030, + "max_requirement": 0.0041 + }, + "可消化苏氨酸 (SID %)": { + "min_requirement": 0.0031, + "max_requirement": 0.0043 + }, + "可消化色氨酸 (SID %)": { + "min_requirement": 0.0010, + "max_requirement": 0.0013 + }, + "粗蛋白 (%)": { + "min_requirement": 0.12, + "max_requirement": 0.14 + }, + "粗脂肪 (%)": { + "min_requirement": 0.03, + "max_requirement": 0.06 + }, + "粗纤维 (%)": { + "min_requirement": 0.02, + "max_requirement": 0.06 + }, + "钙 (%)": { + "min_requirement": 0.005, + "max_requirement": 0.007 + }, + "总磷 (%)": { + "min_requirement": 0.004, + "max_requirement": 0.0055 + }, + "有效磷 (%)": { + "min_requirement": 0.0015, + "max_requirement": 0.0030 + }, + "代谢能 (kcal/kg)": { + "min_requirement": 2868.0, + "max_requirement": 3107.0 + }, + "钠 (%)": { + "min_requirement": 0.0015, + "max_requirement": 0.0025 + }, + "氯 (%)": { + "min_requirement": 0.0025, + "max_requirement": 0.0045 + }, + "黄曲霉毒素B1 (μg/kg)": { + "max_requirement": 10 + }, + "呕吐毒素DON (μg/kg)": { + "max_requirement": 1 + }, + "玉米赤霉烯酮ZEN (μg/kg)": { + "max_requirement": 0.15 + } + } + }, + "皮长大 (PL Y)": { + "保育期": { + "可消化赖氨酸 (SID %)": { + "min_requirement": 0.012, + "max_requirement": 0.015 + }, + "蛋+胱氨酸 (%)": { + "min_requirement": 0.0072, + "max_requirement": 0.0105 + }, + "可消化苏氨酸 (SID %)": { + "min_requirement": 0.0078, + "max_requirement": 0.0108 + }, + "可消化色氨酸 (SID %)": { + "min_requirement": 0.0022, + "max_requirement": 0.0030 + }, + "粗蛋白 (%)": { + "min_requirement": 0.18, + "max_requirement": 0.22 + }, + "粗脂肪 (%)": { + "min_requirement": 0.03, + "max_requirement": 0.06 + }, + "粗纤维 (%)": { + "min_requirement": 0.02, + "max_requirement": 0.06 + }, + "钙 (%)": { + "min_requirement": 0.009, + "max_requirement": 0.012 + }, + "总磷 (%)": { + "min_requirement": 0.006, + "max_requirement": 0.008 + }, + "有效磷 (%)": { + "min_requirement": 0.002, + "max_requirement": 0.0045 + }, + "代谢能 (kcal/kg)": { + "min_requirement": 3226.5, + "max_requirement": 3585.0 + }, + "钠 (%)": { + "min_requirement": 0.0015, + "max_requirement": 0.0025 + }, + "氯 (%)": { + "min_requirement": 0.0025, + "max_requirement": 0.0045 + }, + "黄曲霉毒素B1 (μg/kg)": { + "max_requirement": 10 + }, + "呕吐毒素DON (μg/kg)": { + "max_requirement": 1 + }, + "玉米赤霉烯酮ZEN (μg/kg)": { + "max_requirement": 0.15 + } + }, + "育肥前期": { + "可消化赖氨酸 (SID %)": { + "min_requirement": 0.0094, + "max_requirement": 0.0110 + }, + "蛋+胱氨酸 (%)": { + "min_requirement": 0.0055, + "max_requirement": 0.0073 + }, + "可消化苏氨酸 (SID %)": { + "min_requirement": 0.0058, + "max_requirement": 0.0077 + }, + "可消化色氨酸 (SID %)": { + "min_requirement": 0.0016, + "max_requirement": 0.0022 + }, + "粗蛋白 (%)": { + "min_requirement": 0.16, + "max_requirement": 0.18 + }, + "粗脂肪 (%)": { + "min_requirement": 0.03, + "max_requirement": 0.06 + }, + "粗纤维 (%)": { + "min_requirement": 0.02, + "max_requirement": 0.06 + }, + "钙 (%)": { + "min_requirement": 0.007, + "max_requirement": 0.009 + }, + "总磷 (%)": { + "min_requirement": 0.005, + "max_requirement": 0.007 + }, + "有效磷 (%)": { + "min_requirement": 0.002, + "max_requirement": 0.0040 + }, + "代谢能 (kcal/kg)": { + "min_requirement": 3107.0, + "max_requirement": 3346.0 + }, + "钠 (%)": { + "min_requirement": 0.0015, + "max_requirement": 0.0025 + }, + "氯 (%)": { + "min_requirement": 0.0025, + "max_requirement": 0.0045 + }, + "黄曲霉毒素B1 (μg/kg)": { + "max_requirement": 10 + }, + "呕吐毒素DON (μg/kg)": { + "max_requirement": 1 + }, + "玉米赤霉烯酮ZEN (μg/kg)": { + "max_requirement": 0.15 + } + }, + "育肥后期": { + "可消化赖氨酸 (SID %)": { + "min_requirement": 0.0081, + "max_requirement": 0.0090 + }, + "蛋+胱氨酸 (%)": { + "min_requirement": 0.0045, + "max_requirement": 0.0058 + }, + "可消化苏氨酸 (SID %)": { + "min_requirement": 0.0048, + "max_requirement": 0.0061 + }, + "可消化色氨酸 (SID %)": { + "min_requirement": 0.0013, + "max_requirement": 0.0018 + }, + "粗蛋白 (%)": { + "min_requirement": 0.14, + "max_requirement": 0.16 + }, + "粗脂肪 (%)": { + "min_requirement": 0.03, + "max_requirement": 0.06 + }, + "粗纤维 (%)": { + "min_requirement": 0.02, + "max_requirement": 0.06 + }, + "钙 (%)": { + "min_requirement": 0.006, + "max_requirement": 0.008 + }, + "总磷 (%)": { + "min_requirement": 0.0045, + "max_requirement": 0.006 + }, + "有效磷 (%)": { + "min_requirement": 0.0018, + "max_requirement": 0.0035 + }, + "代谢能 (kcal/kg)": { + "min_requirement": 2987.5, + "max_requirement": 3226.5 + }, + "钠 (%)": { + "min_requirement": 0.0015, + "max_requirement": 0.0025 + }, + "氯 (%)": { + "min_requirement": 0.0025, + "max_requirement": 0.0045 + }, + "黄曲霉毒素B1 (μg/kg)": { + "max_requirement": 10 + }, + "呕吐毒素DON (μg/kg)": { + "max_requirement": 1 + }, + "玉米赤霉烯酮ZEN (μg/kg)": { + "max_requirement": 0.15 + } + }, + "二次育肥期": { + "可消化赖氨酸 (SID %)": { + "min_requirement": 0.0053, + "max_requirement": 0.0065 + }, + "蛋+胱氨酸 (%)": { + "min_requirement": 0.0030, + "max_requirement": 0.0041 + }, + "可消化苏氨酸 (SID %)": { + "min_requirement": 0.0031, + "max_requirement": 0.0043 + }, + "可消化色氨酸 (SID %)": { + "min_requirement": 0.0010, + "max_requirement": 0.0013 + }, + "粗蛋白 (%)": { + "min_requirement": 0.12, + "max_requirement": 0.14 + }, + "粗脂肪 (%)": { + "min_requirement": 0.03, + "max_requirement": 0.06 + }, + "粗纤维 (%)": { + "min_requirement": 0.02, + "max_requirement": 0.06 + }, + "钙 (%)": { + "min_requirement": 0.005, + "max_requirement": 0.007 + }, + "总磷 (%)": { + "min_requirement": 0.004, + "max_requirement": 0.0055 + }, + "有效磷 (%)": { + "min_requirement": 0.0015, + "max_requirement": 0.0030 + }, + "代谢能 (kcal/kg)": { + "min_requirement": 2868.0, + "max_requirement": 3107.0 + }, + "钠 (%)": { + "min_requirement": 0.0015, + "max_requirement": 0.0025 + }, + "氯 (%)": { + "min_requirement": 0.0025, + "max_requirement": 0.0045 + }, + "黄曲霉毒素B1 (μg/kg)": { + "max_requirement": 10 + }, + "呕吐毒素DON (μg/kg)": { + "max_requirement": 1 + }, + "玉米赤霉烯酮ZEN (μg/kg)": { + "max_requirement": 0.15 + } + } + } + }, + "descriptions": { + "pig_breeds": { + "杜长大 (DLY)": { + "description": "杜长大是中国市场占有率最高的商品肉猪。通过利用杜洛克、长白、大约克三品种的杂种优势,实现高效生长和高瘦肉率。", + "parent_info": "终端父本:杜洛克 (D);二元母本:长白 (L) × 大约克 (Y)。", + "appearance_features": "全身白色,体型健壮、体躯较长,肌肉发达,背腰平直。", + "breed_advantages": "生长速度快、日增重极高、饲料转化率最优、瘦肉率稳定在60%以上、适应性良好、出栏时间最短。", + "breed_disadvantages": "抗应激能力中等,对疫病和环境变化相对敏感;无法作为种猪进行自繁。" + }, + "杜大长 (DY L)": { + "description": "杜大长是另一种重要的外三元猪,与杜长大体系相似,但在母本的搭配上有所区别,同样追求高生长速度和高瘦肉率。", + "parent_info": "终端父本:杜洛克 (D);二元母本:大约克 (Y) × 长白 (L)。", + "appearance_features": "全身白色,体型比杜长大略微魁梧,肌肉丰满度高。", + "breed_advantages": "生长性能和瘦肉率与杜长大相当,同时遗传了大约克母本的良好体型和生长潜力,综合性能优秀。", + "breed_disadvantages": "与杜长大相似,无法留作种用,需要依赖稳定的种源体系;对饲养管理要求高。" + }, + "皮长大 (PL Y)": { + "description": "皮长大是以皮特兰作为终端父本的杂交体系,专注于生产超高瘦肉率的商品肉猪。", + "parent_info": "终端父本:皮特兰 (P);二元母本:长白 (L) × 大约克 (Y)。", + "appearance_features": "多数为白色或带有黑色斑点,肌肉极其发达,后臀饱满,体型呈方形。", + "breed_advantages": "瘦肉率极高(能达到65%以上),胴体丰满,背膘薄。", + "breed_disadvantages": "生长速度和日增重逊于杜长大;应激敏感性极高(易发生P.S.S.),管理难度大,肉质易出现PSE(苍白、软、渗水)现象,影响口感和加工性能。" + } + }, + "pig_age_stages": { + "保育期": "从断奶到转入生长舍。主要目标是适应固体饲料,建立肠道菌群,确保健康稳定过渡,体重约5kg~30kg。", + "育肥前期": "小猪转入育肥舍后到体重达到约60kg的阶段。以骨骼和肌肉生长为主,是高效增重期。", + "育肥后期": "体重从约60kg到达到出栏体重(约110-120kg)的阶段。脂肪沉积速度开始加快,是出栏前的冲刺期。", + "二次育肥期": "指收购达到常规出栏体重(约100-120kg)的商品猪,继续饲养至更大体重(140-180kg+)的阶段。其存在主要受市场价格波动驱动,目的是提高单体出肉量。" + }, + "pig_breed_age_stages": { + "杜长大 (DLY)": { + "保育期": { + "description": "遗传自杜洛克的生长优势在断奶后开始显现,需精细化管理以避免断奶应激和腹泻。", + "daily_feed_intake": 400.0, + "daily_gain_weight": 350.0, + "min_days": 21, + "max_days": 70, + "min_weight": 5000.0, + "max_weight": 30000.0 + }, + "育肥前期": { + "description": "生长速度和饲料转化率表现良好,是瘦肉沉积效率高的阶段。", + "daily_feed_intake": 1800.0, + "daily_gain_weight": 700.0, + "min_days": 71, + "max_days": 120, + "min_weight": 30000.0, + "max_weight": 60000.0 + }, + "育肥后期": { + "description": "继续实现较高日增重,脂肪沉积开始加快,管理目标为达到目标出栏体重并保持料肉比。", + "daily_feed_intake": 2800.0, + "daily_gain_weight": 800.0, + "min_days": 121, + "max_days": 180, + "min_weight": 60000.0, + "max_weight": 100000.0 + }, + "二次育肥期": { + "description": "增重效率下降,料肉比恶化,增重多为脂肪沉积,注意热应激与蹄部问题。", + "daily_feed_intake": 3500.0, + "daily_gain_weight": 600.0, + "min_days": 181, + "max_days": 240, + "min_weight": 100000.0, + "max_weight": 140000.0 + } + }, + "杜大长 (DY L)": { + "保育期": { + "description": "与杜长大相近,生长潜力强,管理重点为断奶适应与稳定采食。", + "daily_feed_intake": 400.0, + "daily_gain_weight": 330.0, + "min_days": 21, + "max_days": 70, + "min_weight": 5000.0, + "max_weight": 30000.0 + }, + "育肥前期": { + "description": "生长期增重与料肉比接近杜长大,肌肉发展迅速。", + "daily_feed_intake": 1750.0, + "daily_gain_weight": 680.0, + "min_days": 71, + "max_days": 120, + "min_weight": 30000.0, + "max_weight": 60000.0 + }, + "育肥后期": { + "description": "保持较高增重速度,脂肪沉积稍快于部分 DLY 群体,需配方微调以控制背膘。", + "daily_feed_intake": 2700.0, + "daily_gain_weight": 770.0, + "min_days": 121, + "max_days": 180, + "min_weight": 60000.0, + "max_weight": 100000.0 + }, + "二次育肥期": { + "description": "与杜长大相似,采食量高但增重多为脂肪,注意健康与福利管理。", + "daily_feed_intake": 3500.0, + "daily_gain_weight": 580.0, + "min_days": 181, + "max_days": 240, + "min_weight": 100000.0, + "max_weight": 140000.0 + } + }, + "皮长大 (PLY)": { + "保育期": { + "description": "个体应激敏感性可能更高,需要稳定环境与逐步换料以减少应激性下降重。", + "daily_feed_intake": 350.0, + "daily_gain_weight": 300.0, + "min_days": 21, + "max_days": 70, + "min_weight": 5000.0, + "max_weight": 30000.0 + }, + "育肥前期": { + "description": "增重速度一般,但瘦肉率高;需注意高应激个体的管理以避免肉质问题。", + "daily_feed_intake": 1600.0, + "daily_gain_weight": 600.0, + "min_days": 71, + "max_days": 120, + "min_weight": 30000.0, + "max_weight": 60000.0 + }, + "育肥后期": { + "description": "瘦肉率高且脂肪沉积较慢,但应激易导致肉质问题,育肥管理需谨慎。", + "daily_feed_intake": 2400.0, + "daily_gain_weight": 650.0, + "min_days": 121, + "max_days": 180, + "min_weight": 60000.0, + "max_weight": 100000.0 + }, + "二次育肥期": { + "description": "超重育肥带来的应激和死亡风险增加,通常不推荐长期二次育肥。", + "daily_feed_intake": 3200.0, + "daily_gain_weight": 450.0, + "min_days": 181, + "max_days": 240, + "min_weight": 100000.0, + "max_weight": 140000.0 + } + } + } + } +} diff --git a/design/archive/recipe-management/index.md b/design/archive/recipe-management/index.md index 60bf2fa..0348367 100644 --- a/design/archive/recipe-management/index.md +++ b/design/archive/recipe-management/index.md @@ -52,4 +52,5 @@ http://git.huangwc.com/pig/pig-farm-controller/issues/66 2. 迁移配置文件, 实现从json文件中读取原材料营养预设值, 并自动写入数据库 3. 定义配方领域, 实现营养元素的增删改查 4. 实现原材料的增删改查和仓库层的原料库存记录表增查 -5. 定义猪的模型和营养需求模型 \ No newline at end of file +5. 定义猪的模型和营养需求模型 +6. 实现从json读取猪营养需求并写入数据库 \ No newline at end of file diff --git a/internal/infra/database/seeder.go b/internal/infra/database/seeder.go index c595d60..186c03f 100644 --- a/internal/infra/database/seeder.go +++ b/internal/infra/database/seeder.go @@ -26,60 +26,87 @@ type SeederFunc func(tx *gorm.DB, jsonData []byte) error func SeedFromPreset(ctx context.Context, db *gorm.DB, presetDir string) error { logger := logs.TraceLogger(ctx, ctx, "SeedFromPreset") - // 定义必须存在的预设数据类型 - requiredTypes := []string{"nutrient"} - processedTypes := make(map[string]bool) + // 定义必须存在的预设数据类型及其处理顺序 + // 确保 "nutrient" 在 "pig_nutrient_requirements" 之前处理,因为后者依赖于前者。 + processingOrder := []string{"nutrient", "pig_nutrient_requirements"} + requiredTypes := make(map[string]bool) + for _, t := range processingOrder { + requiredTypes[t] = true + } - // 用于检测重复的 type - typeToFileMap := make(map[string]string) + processedTypes := make(map[string]bool) + typeToFileMap := make(map[string]string) // 用于检测重复的 type,并存储每个 type 对应的文件路径 + groupedFiles := make(map[string][][]byte) // 按 type 分组存储 jsonData files, err := os.ReadDir(presetDir) if err != nil { return fmt.Errorf("读取预设数据目录 '%s' 失败: %w", presetDir, err) } + // 第一阶段:读取所有文件并按 type 分组 + for _, file := range files { + if filepath.Ext(file.Name()) != ".json" { + continue + } + + filePath := filepath.Join(presetDir, file.Name()) + jsonData, err := os.ReadFile(filePath) + if err != nil { + return fmt.Errorf("读取文件 '%s' 失败: %w", filePath, err) + } + + dataType := gjson.GetBytes(jsonData, "type") + if !dataType.Exists() { + logger.Warnf("警告: 文件 '%s' 中缺少 'type' 字段,已跳过", filePath) + continue + } + dataTypeStr := dataType.String() + + // 检查是否存在重复的 type + if existingFile, found := typeToFileMap[dataTypeStr]; found { + return fmt.Errorf("预设数据校验失败: type '%s' 在文件 '%s' 和 '%s' 中重复定义", dataTypeStr, existingFile, filePath) + } + typeToFileMap[dataTypeStr] = filePath // 记录该 type 对应的文件路径 + + groupedFiles[dataTypeStr] = append(groupedFiles[dataTypeStr], jsonData) + } + + // 第二阶段:按照预定义顺序处理分组后的数据 return db.Transaction(func(tx *gorm.DB) error { - for _, file := range files { - if filepath.Ext(file.Name()) != ".json" { - continue + for _, dataTypeStr := range processingOrder { + jsonDatas, ok := groupedFiles[dataTypeStr] + if !ok { + // 如果是必需类型但没有找到文件,则报错 + if requiredTypes[dataTypeStr] { + return fmt.Errorf("预设数据校验失败: 缺少必需的预设文件类型: '%s'", dataTypeStr) + } + continue // 非必需类型,跳过 } - filePath := filepath.Join(presetDir, file.Name()) - jsonData, err := os.ReadFile(filePath) - if err != nil { - return fmt.Errorf("读取文件 '%s' 失败: %w", filePath, err) - } - - dataType := gjson.GetBytes(jsonData, "type") - if !dataType.Exists() { - logger.Warnf("警告: 文件 '%s' 中缺少 'type' 字段,已跳过", filePath) - continue - } - dataTypeStr := dataType.String() - - if existingFile, found := typeToFileMap[dataTypeStr]; found { - return fmt.Errorf("预设数据校验失败: type '%s' 在文件 '%s' 和 '%s' 中重复定义", dataTypeStr, existingFile, filePath) - } - typeToFileMap[dataTypeStr] = filePath - var seederFunc SeederFunc switch dataTypeStr { case "nutrient": seederFunc = seedNutrients + case "pig_nutrient_requirements": + seederFunc = seedPigNutrientRequirements default: - logger.Warnf("警告: 文件 '%s' 中存在未知的 type: '%s',已跳过", filePath, dataTypeStr) + logger.Warnf("警告: 存在未知的 type: '%s',已跳过", dataTypeStr) continue } - if err := seederFunc(tx, jsonData); err != nil { - return fmt.Errorf("处理文件 '%s' (type: %s) 时发生错误: %w", filePath, dataTypeStr, err) + for _, jsonData := range jsonDatas { + // 获取原始文件路径用于错误报告 + originalFilePath := typeToFileMap[dataTypeStr] + if err := seederFunc(tx, jsonData); err != nil { + return fmt.Errorf("处理文件 (type: %s, path: %s) 时发生错误: %w", dataTypeStr, originalFilePath, err) + } } processedTypes[dataTypeStr] = true } // 校验所有必需的类型是否都已处理 var missingTypes []string - for _, reqType := range requiredTypes { + for reqType := range requiredTypes { if !processedTypes[reqType] { missingTypes = append(missingTypes, reqType) } @@ -158,6 +185,280 @@ func seedNutrients(tx *gorm.DB, jsonData []byte) error { return nil } +// seedPigNutrientRequirements 先严格校验JSON源文件,然后以“有则跳过”的模式播种数据。 +func seedPigNutrientRequirements(tx *gorm.DB, jsonData []byte) error { + // 1. 严格校验JSON文件,检查内部重复键 + parsedData, err := validateAndParsePigNutrientRequirementJSON(jsonData) + if err != nil { + return fmt.Errorf("JSON源文件校验失败: %w", err) + } + + // 2. 解析简介信息 + descriptionsNode := gjson.GetBytes(jsonData, "descriptions") + pigBreedDescriptions := make(map[string]models.PigBreed) + pigAgeStageDescriptions := make(map[string]models.PigAgeStage) + pigTypeDescriptions := make(map[string]map[string]models.PigType) + + if descriptionsNode.Exists() { + // 解析 pig_breeds 描述 + descriptionsNode.Get("pig_breeds").ForEach(func(key, value gjson.Result) bool { + var pb models.PigBreed + pb.Name = key.String() + pb.Description = value.Get("description").String() + pb.ParentInfo = value.Get("parent_info").String() + pb.AppearanceFeatures = value.Get("appearance_features").String() + pb.BreedAdvantages = value.Get("breed_advantages").String() + pb.BreedDisadvantages = value.Get("breed_disadvantages").String() + pigBreedDescriptions[key.String()] = pb + return true + }) + + // 解析 pig_age_stages 描述 + descriptionsNode.Get("pig_age_stages").ForEach(func(key, value gjson.Result) bool { + var pas models.PigAgeStage + pas.Name = key.String() + pas.Description = value.String() + pigAgeStageDescriptions[key.String()] = pas + return true + }) + + // 解析 pig_breed_age_stages (PigType) 描述 + descriptionsNode.Get("pig_breed_age_stages").ForEach(func(breedKey, breedValue gjson.Result) bool { + if _, ok := pigTypeDescriptions[breedKey.String()]; !ok { + pigTypeDescriptions[breedKey.String()] = make(map[string]models.PigType) + } + breedValue.ForEach(func(ageStageKey, ageStageValue gjson.Result) bool { + var pt models.PigType + pt.Description = ageStageValue.Get("description").String() + pt.DailyFeedIntake = float32(ageStageValue.Get("daily_feed_intake").Float()) + pt.DailyGainWeight = float32(ageStageValue.Get("daily_gain_weight").Float()) + pt.MinDays = uint32(ageStageValue.Get("min_days").Uint()) + pt.MaxDays = uint32(ageStageValue.Get("max_days").Uint()) + pt.MinWeight = float32(ageStageValue.Get("min_weight").Float()) + pt.MaxWeight = float32(ageStageValue.Get("max_weight").Float()) + pigTypeDescriptions[breedKey.String()][ageStageKey.String()] = pt + return true + }) + return true + }) + } + + // 3. 将通过校验的、干净的数据写入数据库 + for breedName, ageStagesData := range parsedData { + var pigBreed models.PigBreed + // 查找或创建 PigBreed + pbDesc := pigBreedDescriptions[breedName] + err := tx.Where(models.PigBreed{Name: breedName}). + FirstOrCreate(&pigBreed, models.PigBreed{ + Name: breedName, + Description: pbDesc.Description, + ParentInfo: pbDesc.ParentInfo, + AppearanceFeatures: pbDesc.AppearanceFeatures, + BreedAdvantages: pbDesc.BreedAdvantages, + BreedDisadvantages: pbDesc.BreedDisadvantages, + }).Error + if err != nil { + return fmt.Errorf("预设猪品种 '%s' 失败: %w", breedName, err) + } + + for ageStageName, nutrientsData := range ageStagesData { + var pigAgeStage models.PigAgeStage + // 查找或创建 PigAgeStage + pasDesc := pigAgeStageDescriptions[ageStageName] + err := tx.Where(models.PigAgeStage{Name: ageStageName}). + FirstOrCreate(&pigAgeStage, models.PigAgeStage{ + Name: ageStageName, + Description: pasDesc.Description, + }).Error + if err != nil { + return fmt.Errorf("预设猪年龄阶段 '%s' 失败: %w", ageStageName, err) + } + + var pigType models.PigType + // 查找或创建 PigType + ptDesc := pigTypeDescriptions[breedName][ageStageName] + err = tx.Where(models.PigType{BreedID: pigBreed.ID, AgeStageID: pigAgeStage.ID}). + FirstOrCreate(&pigType, models.PigType{ + BreedID: pigBreed.ID, + AgeStageID: pigAgeStage.ID, + Description: ptDesc.Description, + DailyFeedIntake: ptDesc.DailyFeedIntake, + DailyGainWeight: ptDesc.DailyGainWeight, + MinDays: ptDesc.MinDays, + MaxDays: ptDesc.MaxDays, + MinWeight: ptDesc.MinWeight, + MaxWeight: ptDesc.MaxWeight, + }).Error + if err != nil { + return fmt.Errorf("预设猪类型 '%s' - '%s' 失败: %w", breedName, ageStageName, err) + } + + for nutrientName, requirement := range nutrientsData { + var nutrient models.Nutrient + // 查找或创建 Nutrient (这里假设 Nutrient 已经在 seedNutrients 中处理,但为了健壮性,再次 FirstOrCreate) + err := tx.Where(models.Nutrient{Name: nutrientName}). + FirstOrCreate(&nutrient, models.Nutrient{ + Name: nutrientName, + // Description 字段在 nutrient seeder 中处理,这里不设置 + }).Error + if err != nil { + return fmt.Errorf("预设营养素 '%s' 失败: %w", nutrientName, err) + } + + linkData := models.PigNutrientRequirement{ + PigTypeID: pigType.ID, + NutrientID: nutrient.ID, + MinRequirement: requirement.MinRequirement, + MaxRequirement: requirement.MaxRequirement, + } + // 使用 FirstOrCreate 确保关联的唯一性 + if err := tx.Where(models.PigNutrientRequirement{ + PigTypeID: pigType.ID, + NutrientID: nutrient.ID, + }).FirstOrCreate(&linkData, linkData).Error; err != nil { + return fmt.Errorf("为猪类型 '%s' - '%s' 和营养素 '%s' 创建营养需求失败: %w", breedName, ageStageName, nutrientName, err) + } + } + } + } + return nil +} + +// validateAndParsePigNutrientRequirementJSON 严格校验并解析猪营养需求JSON文件 +func validateAndParsePigNutrientRequirementJSON(jsonData []byte) (map[string]map[string]map[string]struct { + MinRequirement float32 + MaxRequirement float32 +}, error) { + dataNode := gjson.GetBytes(jsonData, "data") + if !dataNode.Exists() { + return nil, errors.New("JSON文件中缺少 'data' 字段") + } + if !dataNode.IsObject() { + return nil, errors.New("'data' 字段必须是一个JSON对象") + } + + decoder := json.NewDecoder(bytes.NewReader([]byte(dataNode.Raw))) + decoder.UseNumber() + + if t, err := decoder.Token(); err != nil || t != json.Delim('{') { + return nil, fmt.Errorf("'data' 字段解析起始符失败: %v", err) + } + + result := make(map[string]map[string]map[string]struct { + MinRequirement float32 + MaxRequirement float32 + }) + seenBreeds := make(map[string]bool) + + for decoder.More() { + // 解析 PigBreed 名称 + t, err := decoder.Token() + if err != nil { + return nil, fmt.Errorf("解析猪品种名称失败: %w", err) + } + breedName := t.(string) + if seenBreeds[breedName] { + return nil, fmt.Errorf("猪品种名称 '%s' 重复", breedName) + } + seenBreeds[breedName] = true + + // 解析该品种的年龄阶段对象 + if t, err := decoder.Token(); err != nil || t != json.Delim('{') { + return nil, fmt.Errorf("期望猪品种 '%s' 的值是一个JSON对象", breedName) + } + + ageStages := make(map[string]map[string]struct { + MinRequirement float32 + MaxRequirement float32 + }) + seenAgeStages := make(map[string]bool) + + for decoder.More() { + // 解析 PigAgeStage 名称 + t, err := decoder.Token() + if err != nil { + return nil, fmt.Errorf("在猪品种 '%s' 中解析年龄阶段名称失败: %w", breedName, err) + } + ageStageName := t.(string) + if seenAgeStages[ageStageName] { + return nil, fmt.Errorf("在猪品种 '%s' 中, 年龄阶段名称 '%s' 重复", breedName, ageStageName) + } + seenAgeStages[ageStageName] = true + + // 解析该年龄阶段的营养成分对象 + if t, err := decoder.Token(); err != nil || t != json.Delim('{') { + return nil, fmt.Errorf("期望年龄阶段 '%s' 的值是一个JSON对象", ageStageName) + } + + nutrients := make(map[string]struct { + MinRequirement float32 + MaxRequirement float32 + }) + seenNutrients := make(map[string]bool) + + for decoder.More() { + // 解析 Nutrient 名称 + t, err := decoder.Token() + if err != nil { + return nil, fmt.Errorf("在年龄阶段 '%s' 中解析营养素名称失败: %w", ageStageName, err) + } + nutrientName := t.(string) + if seenNutrients[nutrientName] { + return nil, fmt.Errorf("在年龄阶段 '%s' 中, 营养素名称 '%s' 重复", ageStageName, nutrientName) + } + seenNutrients[nutrientName] = true + + // 解析 min_requirement 和 max_requirement 对象 + if t, err := decoder.Token(); err != nil || t != json.Delim('{') { + return nil, fmt.Errorf("期望营养素 '%s' 的值是一个JSON对象", nutrientName) + } + + var req struct { + MinRequirement float32 + MaxRequirement float32 + } + for decoder.More() { + t, err := decoder.Token() + if err != nil { + return nil, fmt.Errorf("解析营养素 '%s' 的需求键失败: %w", nutrientName, err) + } + key := t.(string) + + t, err = decoder.Token() + if err != nil { + return nil, fmt.Errorf("解析营养素 '%s' 的需求值失败: %w", nutrientName, err) + } + if value, ok := t.(json.Number); ok { + f64, _ := value.Float64() + if key == "min_requirement" { + req.MinRequirement = float32(f64) + } else if key == "max_requirement" { + req.MaxRequirement = float32(f64) + } else { + return nil, fmt.Errorf("营养素 '%s' 中存在未知键 '%s'", nutrientName, key) + } + } else { + return nil, fmt.Errorf("期望营养素 '%s' 的 '%s' 值是数字, 但实际得到的类型是 %T, 值为 '%v'", nutrientName, key, t, t) + } + } + if t, err := decoder.Token(); err != nil || t != json.Delim('}') { + return nil, fmt.Errorf("解析营养素 '%s' 的值结束符 '}' 失败", nutrientName) + } + nutrients[nutrientName] = req + } + if t, err := decoder.Token(); err != nil || t != json.Delim('}') { + return nil, fmt.Errorf("解析年龄阶段 '%s' 的值结束符 '}' 失败", ageStageName) + } + ageStages[ageStageName] = nutrients + } + if t, err := decoder.Token(); err != nil || t != json.Delim('}') { + return nil, fmt.Errorf("解析猪品种 '%s' 的值结束符 '}' 失败", breedName) + } + result[breedName] = ageStages + } + return result, nil +} + // validateAndParseNutrientJSON 使用 json.Decoder 手动解析,以捕获重复的键。 func validateAndParseNutrientJSON(jsonData []byte) (map[string]map[string]float32, error) { dataNode := gjson.GetBytes(jsonData, "data") diff --git a/internal/infra/models/pig.go b/internal/infra/models/pig.go index 132c270..788e575 100644 --- a/internal/infra/models/pig.go +++ b/internal/infra/models/pig.go @@ -3,8 +3,12 @@ package models // PigBreed 猪品种模型 type PigBreed struct { Model - Name string `gorm:"size:50;not null;comment:品种名称"` - Description string `gorm:"size:255;comment:品种描述"` + Name string `gorm:"size:50;not null;comment:品种名称"` + Description string `gorm:"type:text" json:"description"` // 保留描述字段 + ParentInfo string `gorm:"type:text" json:"parent_info"` // 父母信息 + AppearanceFeatures string `gorm:"type:text" json:"appearance_features"` // 外貌特征 + BreedAdvantages string `gorm:"type:text" json:"breed_advantages"` // 品种优点 + BreedDisadvantages string `gorm:"type:text" json:"breed_disadvantages"` // 品种缺点 } func (PigBreed) TableName() string {