Compare commits

...

2 Commits

Author SHA1 Message Date
faf0a5e00e 更新swag 2025-11-22 17:59:06 +08:00
2711bbd42d 优化展示 2025-11-22 17:38:09 +08:00
6 changed files with 486 additions and 24 deletions

View File

@@ -2648,6 +2648,64 @@
} }
} }
}, },
"/api/v1/feed/pig-types/{id}/nutrient-requirements": {
"put": {
"security": [
{
"BearerAuth": []
}
],
"description": "根据猪类型ID替换其所有的营养需求信息。这是一个覆盖操作。",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"饲料管理"
],
"summary": "全量更新猪类型的营养需求",
"parameters": [
{
"type": "integer",
"description": "猪类型ID",
"name": "id",
"in": "path",
"required": true
},
{
"description": "新的营养需求列表",
"name": "nutrientRequirements",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.UpdatePigTypeNutrientRequirementsRequest"
}
}
],
"responses": {
"200": {
"description": "业务码为200代表更新成功",
"schema": {
"allOf": [
{
"$ref": "#/definitions/controller.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/dto.PigTypeResponse"
}
}
}
]
}
}
}
}
},
"/api/v1/feed/raw-materials": { "/api/v1/feed/raw-materials": {
"get": { "get": {
"security": [ "security": [
@@ -3139,6 +3197,7 @@
}, },
{ {
"enum": [ "enum": [
7,
-1, -1,
0, 0,
1, 1,
@@ -3148,12 +3207,12 @@
5, 5,
-1, -1,
5, 5,
6, 6
7
], ],
"type": "integer", "type": "integer",
"format": "int32", "format": "int32",
"x-enum-varnames": [ "x-enum-varnames": [
"_numLevels",
"DebugLevel", "DebugLevel",
"InfoLevel", "InfoLevel",
"WarnLevel", "WarnLevel",
@@ -3163,8 +3222,7 @@
"FatalLevel", "FatalLevel",
"_minLevel", "_minLevel",
"_maxLevel", "_maxLevel",
"InvalidLevel", "InvalidLevel"
"_numLevels"
], ],
"name": "level", "name": "level",
"in": "query" "in": "query"
@@ -7759,6 +7817,28 @@
} }
} }
}, },
"dto.PigNutrientRequirementItem": {
"type": "object",
"required": [
"nutrient_id"
],
"properties": {
"max_requirement": {
"description": "最高营养需求量",
"type": "number",
"minimum": 0
},
"min_requirement": {
"description": "最低营养需求量",
"type": "number",
"minimum": 0
},
"nutrient_id": {
"description": "营养素ID",
"type": "integer"
}
}
},
"dto.PigPurchaseDTO": { "dto.PigPurchaseDTO": {
"type": "object", "type": "object",
"properties": { "properties": {
@@ -8928,6 +9008,20 @@
} }
} }
}, },
"dto.UpdatePigTypeNutrientRequirementsRequest": {
"type": "object",
"required": [
"nutrient_requirements"
],
"properties": {
"nutrient_requirements": {
"type": "array",
"items": {
"$ref": "#/definitions/dto.PigNutrientRequirementItem"
}
}
}
},
"dto.UpdatePigTypeRequest": { "dto.UpdatePigTypeRequest": {
"type": "object", "type": "object",
"required": [ "required": [
@@ -9312,10 +9406,10 @@
"models.Operator": { "models.Operator": {
"type": "string", "type": "string",
"enum": [ "enum": [
"\u003C", "\u003c",
"\u003C=", "\u003c=",
"\u003E", "\u003e",
"\u003E=", "\u003e=",
"=", "=",
"!=" "!="
], ],
@@ -9700,6 +9794,7 @@
"type": "integer", "type": "integer",
"format": "int32", "format": "int32",
"enum": [ "enum": [
7,
-1, -1,
0, 0,
1, 1,
@@ -9709,10 +9804,10 @@
5, 5,
-1, -1,
5, 5,
6, 6
7
], ],
"x-enum-varnames": [ "x-enum-varnames": [
"_numLevels",
"DebugLevel", "DebugLevel",
"InfoLevel", "InfoLevel",
"WarnLevel", "WarnLevel",
@@ -9722,8 +9817,7 @@
"FatalLevel", "FatalLevel",
"_minLevel", "_minLevel",
"_maxLevel", "_maxLevel",
"InvalidLevel", "InvalidLevel"
"_numLevels"
] ]
} }
}, },

View File

@@ -200,6 +200,18 @@ import {PaginationDTO, Response} from '../enums';
* @property {number} [daily_feed_intake] * @property {number} [daily_feed_intake]
*/ */
/**
* @typedef {object} PigNutrientRequirementItem
* @property {number} nutrient_id - 营养素ID
* @property {number} [min_requirement] - 最低营养需求量
* @property {number} [max_requirement] - 最高营养需求量
*/
/**
* @typedef {object} UpdatePigTypeNutrientRequirementsRequest
* @property {Array<PigNutrientRequirementItem>} nutrient_requirements - 新的营养需求列表
*/
// --- RawMaterial --- // --- RawMaterial ---
/** /**
@@ -451,6 +463,277 @@ export const deletePigType = (id) => {
return http.delete(`/api/v1/feed/pig-types/${id}`); return http.delete(`/api/v1/feed/pig-types/${id}`);
}; };
/**
* 全量更新猪类型的营养需求
* @param {number} id - 猪类型ID
* @param {UpdatePigTypeNutrientRequirementsRequest} data - 新的营养需求列表
* @returns {Promise<Response<PigTypeResponse>>}
*/
export const updatePigTypeNutrientRequirements = (id, data) => {
return http.put(`/api/v1/feed/pig-types/${id}/nutrient-requirements`, data);
};
// --- RawMaterial ---
/**
* @typedef {object} RawMaterialNutrientItem
* @property {number} nutrient_id - 营养素ID
* @property {number} value - 含量值必须大于等于0
*/
/**
* @typedef {object} UpdateRawMaterialNutrientsRequest
* @property {Array<RawMaterialNutrientItem>} nutrients
*/
/**
* @typedef {object} RawMaterialNutrientDTO
* @property {number} id
* @property {number} nutrient_id
* @property {string} nutrient_name
* @property {number} value
*/
/**
* @typedef {object} RawMaterialResponse
* @property {number} id
* @property {string} name
* @property {string} description
* @property {Array<RawMaterialNutrientDTO>} raw_material_nutrients
*/
/**
* @typedef {object} ListRawMaterialResponse
* @property {Array<RawMaterialResponse>} list
* @property {PaginationDTO} pagination
*/
/**
* @typedef {object} RawMaterialsParams
* @property {string} [name] - 按原料名称模糊查询
* @property {string} [nutrient_name] - 按营养名称模糊查询
* @property {string} [order_by] - 排序字段,例如 "id DESC"
* @property {number} [page]
* @property {number} [page_size]
*/
/**
* @typedef {object} CreateRawMaterialRequest
* @property {string} name - 原料名称
* @property {string} [description] - 描述
*/
/**
* @typedef {object} UpdateRawMaterialRequest
* @property {string} name - 原料名称
* @property {string} [description] - 描述
*/
// --- API Functions ---
// --- Nutrient ---
/**
* 获取营养种类列表
* @param {NutrientsParams} params - 查询参数
* @returns {Promise<Response<ListNutrientResponse>>}
*/
export const getNutrients = (params) => {
return http.get('/api/v1/feed/nutrients', {params});
};
/**
* 创建营养种类
* @param {CreateNutrientRequest} data - 请求体
* @returns {Promise<Response<NutrientResponse>>}
*/
export const createNutrient = (data) => {
return http.post('/api/v1/feed/nutrients', data);
};
/**
* 获取营养种类详情
* @param {number} id - 营养种类ID
* @returns {Promise<Response<NutrientResponse>>}
*/
export const getNutrientById = (id) => {
return http.get(`/api/v1/feed/nutrients/${id}`);
};
/**
* 更新营养种类
* @param {number} id - 营养种类ID
* @param {UpdateNutrientRequest} data - 请求体
* @returns {Promise<Response<NutrientResponse>>}
*/
export const updateNutrient = (id, data) => {
return http.put(`/api/v1/feed/nutrients/${id}`, data);
};
/**
* 删除营养种类
* @param {number} id - 营养种类ID
* @returns {Promise<Response>}
*/
export const deleteNutrient = (id) => {
return http.delete(`/api/v1/feed/nutrients/${id}`);
};
// --- PigAgeStage ---
/**
* 获取猪年龄阶段列表
* @param {PigAgeStagesParams} params - 查询参数
* @returns {Promise<Response<ListPigAgeStageResponse>>}
*/
export const getPigAgeStages = (params) => {
return http.get('/api/v1/feed/pig-age-stages', {params});
};
/**
* 创建猪年龄阶段
* @param {CreatePigAgeStageRequest} data - 请求体
* @returns {Promise<Response<PigAgeStageResponse>>}
*/
export const createPigAgeStage = (data) => {
return http.post('/api/v1/feed/pig-age-stages', data);
};
/**
* 获取猪年龄阶段详情
* @param {number} id - 猪年龄阶段ID
* @returns {Promise<Response<PigAgeStageResponse>>}
*/
export const getPigAgeStageById = (id) => {
return http.get(`/api/v1/feed/pig-age-stages/${id}`);
};
/**
* 更新猪年龄阶段
* @param {number} id - 猪年龄阶段ID
* @param {UpdatePigAgeStageRequest} data - 请求体
* @returns {Promise<Response<PigAgeStageResponse>>}
*/
export const updatePigAgeStage = (id, data) => {
return http.put(`/api/v1/feed/pig-age-stages/${id}`, data);
};
/**
* 删除猪年龄阶段
* @param {number} id - 猪年龄阶段ID
* @returns {Promise<Response>}
*/
export const deletePigAgeStage = (id) => {
return http.delete(`/api/v1/feed/pig-age-stages/${id}`);
};
// --- PigBreed ---
/**
* 获取猪品种列表
* @param {PigBreedsParams} params - 查询参数
* @returns {Promise<Response<ListPigBreedResponse>>}
*/
export const getPigBreeds = (params) => {
return http.get('/api/v1/feed/pig-breeds', {params});
};
/**
* 创建猪品种
* @param {CreatePigBreedRequest} data - 请求体
* @returns {Promise<Response<PigBreedResponse>>}
*/
export const createPigBreed = (data) => {
return http.post('/api/v1/feed/pig-breeds', data);
};
/**
* 获取猪品种详情
* @param {number} id - 猪品种ID
* @returns {Promise<Response<PigBreedResponse>>}
*/
export const getPigBreedById = (id) => {
return http.get(`/api/v1/feed/pig-breeds/${id}`);
};
/**
* 更新猪品种
* @param {number} id - 猪品种ID
* @param {UpdatePigBreedRequest} data - 请求体
* @returns {Promise<Response<PigBreedResponse>>}
*/
export const updatePigBreed = (id, data) => {
return http.put(`/api/v1/feed/pig-breeds/${id}`, data);
};
/**
* 删除猪品种
* @param {number} id - 猪品种ID
* @returns {Promise<Response>}
*/
export const deletePigBreed = (id) => {
return http.delete(`/api/v1/feed/pig-breeds/${id}`);
};
// --- PigType ---
/**
* 获取猪类型列表
* @param {PigTypesParams} params - 查询参数
* @returns {Promise<Response<ListPigTypeResponse>>}
*/
export const getPigTypes = (params) => {
return http.get('/api/v1/feed/pig-types', {params});
};
/**
* 创建猪类型
* @param {CreatePigTypeRequest} data - 请求体
* @returns {Promise<Response<PigTypeResponse>>}
*/
export const createPigType = (data) => {
return http.post('/api/v1/feed/pig-types', data);
};
/**
* 获取猪类型详情
* @param {number} id - 猪类型ID
* @returns {Promise<Response<PigTypeResponse>>}
*/
export const getPigTypeById = (id) => {
return http.get(`/api/v1/feed/pig-types/${id}`);
};
/**
* 更新猪类型
* @param {number} id - 猪类型ID
* @param {UpdatePigTypeRequest} data - 请求体
* @returns {Promise<Response<PigTypeResponse>>}
*/
export const updatePigType = (id, data) => {
return http.put(`/api/v1/feed/pig-types/${id}`, data);
};
/**
* 删除猪类型
* @param {number} id - 猪类型ID
* @returns {Promise<Response>}
*/
export const deletePigType = (id) => {
return http.delete(`/api/v1/feed/pig-types/${id}`);
};
/**
* 全量更新猪类型的营养需求
* @param {number} id - 猪类型ID
* @param {UpdatePigTypeNutrientRequirementsRequest} data - 新的营养需求列表
* @returns {Promise<Response<PigTypeResponse>>}
*/
export const updatePigTypeNutrientRequirements = (id, data) => {
return http.put(`/api/v1/feed/pig-types/${id}/nutrient-requirements`, data);
};
// --- RawMaterial --- // --- RawMaterial ---
/** /**
@@ -531,6 +814,7 @@ export const FeedApi = {
getPigTypeById, getPigTypeById,
updatePigType, updatePigType,
deletePigType, deletePigType,
updatePigTypeNutrientRequirements, // 新增的 API 方法
getRawMaterials, getRawMaterials,
createRawMaterial, createRawMaterial,
getRawMaterialById, getRawMaterialById,

View File

@@ -18,12 +18,20 @@
</div> </div>
<!-- 营养列表 --> <!-- 营养列表 -->
<el-table :data="tableData" style="width: 100%" v-loading="loading" row-key="id" <el-table
:expand-row-keys="expandRowKeys" @expand-change="handleExpandChange"> ref="mainTable"
:data="tableData"
style="width: 100%"
v-loading="loading"
row-key="id"
:expand-row-keys="expandRowKeys"
@expand-change="handleExpandChange"
@row-click="handleRowClick"
>
<el-table-column type="expand"> <el-table-column type="expand">
<template #default="props"> <template #default="props">
<div style="padding: 10px 20px;"> <div style="padding: 10px 20px;">
<h4>包含此营养的原料</h4> <h4 style="margin-bottom: 16px;">包含此营养的原料</h4>
<el-table :data="props.row.raw_materials" border> <el-table :data="props.row.raw_materials" border>
<el-table-column prop="name" label="原料名称"></el-table-column> <el-table-column prop="name" label="原料名称"></el-table-column>
<el-table-column prop="value" label="含量"></el-table-column> <el-table-column prop="value" label="含量"></el-table-column>
@@ -64,6 +72,7 @@ export default {
name: 'NutrientTable', name: 'NutrientTable',
emits: ['edit'], // 声明触发的事件 emits: ['edit'], // 声明触发的事件
setup(props, { emit }) { setup(props, { emit }) {
const mainTable = ref(null); // el-table 的引用
const tableData = ref([]); const tableData = ref([]);
const loading = ref(false); const loading = ref(false);
const searchKeyword = ref(''); const searchKeyword = ref('');
@@ -137,6 +146,16 @@ export default {
} }
}; };
// 处理行点击事件
const handleRowClick = (row, column) => {
// 如果点击的是操作列,则不执行任何操作
if (column.label === '操作') {
return;
}
// 否则,切换行的展开状态
mainTable.value.toggleRowExpansion(row);
};
const handleEdit = (row) => { const handleEdit = (row) => {
emit('edit', row); // 触发 edit 事件,并传递当前行数据 emit('edit', row); // 触发 edit 事件,并传递当前行数据
}; };
@@ -168,6 +187,7 @@ export default {
}); });
return { return {
mainTable, // 暴露出 ref
tableData, tableData,
loading, loading,
searchKeyword, searchKeyword,
@@ -178,6 +198,7 @@ export default {
handleSizeChange, handleSizeChange,
handleCurrentChange, handleCurrentChange,
handleExpandChange, handleExpandChange,
handleRowClick, // 暴露出点击处理方法
handleEdit, handleEdit,
handleDelete, handleDelete,
fetchNutrients, // 将方法暴露出去 fetchNutrients, // 将方法暴露出去

View File

@@ -13,12 +13,20 @@
</div> </div>
<!-- 年龄阶段列表 --> <!-- 年龄阶段列表 -->
<el-table :data="tableData" style="width: 100%" v-loading="loading" row-key="id" <el-table
:expand-row-keys="expandRowKeys" @expand-change="handleExpandChange"> ref="mainTable"
:data="tableData"
style="width: 100%"
v-loading="loading"
row-key="id"
:expand-row-keys="expandRowKeys"
@expand-change="handleExpandChange"
@row-click="handleRowClick"
>
<el-table-column type="expand"> <el-table-column type="expand">
<template #default="props"> <template #default="props">
<div style="padding: 10px 20px;"> <div style="padding: 10px 20px;">
<h4>各品种当前年龄简介</h4> <h4 style="margin-bottom: 16px;">各品种当前年龄简介</h4>
<el-table :data="props.row.pig_types" border> <el-table :data="props.row.pig_types" border>
<el-table-column prop="breed_name" label="品种"></el-table-column> <el-table-column prop="breed_name" label="品种"></el-table-column>
<el-table-column prop="description" label="描述"></el-table-column> <el-table-column prop="description" label="描述"></el-table-column>
@@ -89,6 +97,7 @@ export default {
PigNutrientRequirementsDisplay, // 注册组件 PigNutrientRequirementsDisplay, // 注册组件
}, },
setup(props, { emit }) { setup(props, { emit }) {
const mainTable = ref(null); // el-table 的引用
const tableData = ref([]); const tableData = ref([]);
const loading = ref(false); const loading = ref(false);
const searchKeyword = ref(''); const searchKeyword = ref('');
@@ -170,6 +179,16 @@ export default {
} }
}; };
// 处理行点击事件
const handleRowClick = (row, column) => {
// 如果点击的是操作列,则不执行任何操作
if (column.label === '操作') {
return;
}
// 否则,切换行的展开状态
mainTable.value.toggleRowExpansion(row);
};
// 将克转换为公斤并格式化,只返回数值 // 将克转换为公斤并格式化,只返回数值
const weightFormatter = (row, column, cellValue) => { const weightFormatter = (row, column, cellValue) => {
if (typeof cellValue === 'number') { if (typeof cellValue === 'number') {
@@ -217,6 +236,7 @@ export default {
}); });
return { return {
mainTable, // 暴露出 ref
tableData, tableData,
loading, loading,
searchKeyword, searchKeyword,
@@ -230,6 +250,7 @@ export default {
handleSizeChange, handleSizeChange,
handleCurrentChange, handleCurrentChange,
handleExpandChange, handleExpandChange,
handleRowClick, // 暴露出点击处理方法
weightFormatter, // 暴露给模板 weightFormatter, // 暴露给模板
handleViewNutrientRequirements, // 暴露给模板 handleViewNutrientRequirements, // 暴露给模板
handleEdit, handleEdit,

View File

@@ -13,8 +13,16 @@
</div> </div>
<!-- 品种列表 --> <!-- 品种列表 -->
<el-table :data="tableData" style="width: 100%" v-loading="loading" row-key="id" <el-table
:expand-row-keys="expandRowKeys" @expand-change="handleExpandChange"> ref="mainTable"
:data="tableData"
style="width: 100%"
v-loading="loading"
row-key="id"
:expand-row-keys="expandRowKeys"
@expand-change="handleExpandChange"
@row-click="handleRowClick"
>
<el-table-column type="expand"> <el-table-column type="expand">
<template #default="props"> <template #default="props">
<div style="padding: 10px 20px;"> <div style="padding: 10px 20px;">
@@ -45,7 +53,7 @@
<el-divider></el-divider> <el-divider></el-divider>
<!-- 下半段该品种下的年龄阶段简介 --> <!-- 下半段该品种下的年龄阶段简介 -->
<h4>该品种下的年龄阶段简介</h4> <h4 style="margin-bottom: 16px;">该品种下的年龄阶段简介</h4>
<el-table <el-table
:data="props.row.pig_types" :data="props.row.pig_types"
border border
@@ -120,6 +128,7 @@ export default {
PigNutrientRequirementsDisplay, // 注册组件 PigNutrientRequirementsDisplay, // 注册组件
}, },
setup(props, { emit }) { setup(props, { emit }) {
const mainTable = ref(null); // el-table 的引用
const tableData = ref([]); const tableData = ref([]);
const loading = ref(false); const loading = ref(false);
const searchKeyword = ref(''); const searchKeyword = ref('');
@@ -203,6 +212,16 @@ export default {
} }
}; };
// 处理行点击事件
const handleRowClick = (row, column) => {
// 如果点击的是操作列,则不执行任何操作
if (column.label === '操作') {
return;
}
// 否则,切换行的展开状态
mainTable.value.toggleRowExpansion(row);
};
// 将克转换为公斤并格式化,只返回数值 // 将克转换为公斤并格式化,只返回数值
const weightFormatter = (row, column, cellValue) => { const weightFormatter = (row, column, cellValue) => {
if (typeof cellValue === 'number') { if (typeof cellValue === 'number') {
@@ -250,6 +269,7 @@ export default {
}); });
return { return {
mainTable, // 暴露出 ref
tableData, tableData,
loading, loading,
searchKeyword, searchKeyword,
@@ -263,6 +283,7 @@ export default {
handleSizeChange, handleSizeChange,
handleCurrentChange, handleCurrentChange,
handleExpandChange, handleExpandChange,
handleRowClick, // 暴露出点击处理方法
weightFormatter, // 暴露给模板 weightFormatter, // 暴露给模板
handleViewNutrientRequirements, // 暴露给模板 handleViewNutrientRequirements, // 暴露给模板
handleEdit, handleEdit,

View File

@@ -17,12 +17,20 @@
</div> </div>
<!-- 原料列表 --> <!-- 原料列表 -->
<el-table :data="tableData" style="width: 100%" v-loading="loading" row-key="id" <el-table
:expand-row-keys="expandRowKeys" @expand-change="handleExpandChange"> ref="mainTable"
:data="tableData"
style="width: 100%"
v-loading="loading"
row-key="id"
:expand-row-keys="expandRowKeys"
@expand-change="handleExpandChange"
@row-click="handleRowClick"
>
<el-table-column type="expand"> <el-table-column type="expand">
<template #default="props"> <template #default="props">
<div style="padding: 10px 20px;"> <div style="padding: 10px 20px;">
<h4>营养成分</h4> <h4 style="margin-bottom: 16px;">营养成分</h4>
<el-table :data="props.row.raw_material_nutrients" border> <el-table :data="props.row.raw_material_nutrients" border>
<el-table-column prop="nutrient_name" label="营养名称"></el-table-column> <el-table-column prop="nutrient_name" label="营养名称"></el-table-column>
<el-table-column prop="value" label="含量"></el-table-column> <el-table-column prop="value" label="含量"></el-table-column>
@@ -63,6 +71,7 @@ export default {
name: 'RawMaterialTable', name: 'RawMaterialTable',
emits: ['edit', 'edit-nutrients'], // 声明触发的事件 emits: ['edit', 'edit-nutrients'], // 声明触发的事件
setup(props, { emit }) { setup(props, { emit }) {
const mainTable = ref(null); // el-table 的引用
const tableData = ref([]); const tableData = ref([]);
const loading = ref(false); const loading = ref(false);
const searchKeyword = ref(''); const searchKeyword = ref('');
@@ -135,6 +144,16 @@ export default {
} }
}; };
// 处理行点击事件
const handleRowClick = (row, column) => {
// 如果点击的是操作列,则不执行任何操作
if (column.label === '操作') {
return;
}
// 否则,切换行的展开状态
mainTable.value.toggleRowExpansion(row);
};
const handleDelete = (row) => { const handleDelete = (row) => {
ElMessageBox.confirm( ElMessageBox.confirm(
`确定要删除原料 "${row.name}" 吗?`, `确定要删除原料 "${row.name}" 吗?`,
@@ -170,6 +189,7 @@ export default {
}); });
return { return {
mainTable, // 暴露出 ref
tableData, tableData,
loading, loading,
searchKeyword, searchKeyword,
@@ -180,6 +200,7 @@ export default {
handleSizeChange, handleSizeChange,
handleCurrentChange, handleCurrentChange,
handleExpandChange, handleExpandChange,
handleRowClick, // 暴露出点击处理方法
handleEdit, handleEdit,
handleDelete, handleDelete,
handleEditNutrients, handleEditNutrients,