Compare commits
	
		
			11 Commits
		
	
	
		
			accbb1a9f6
			...
			d85cfb303b
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| d85cfb303b | |||
| 2e5c04d2d4 | |||
| 2fe6f0c576 | |||
| c176fadafe | |||
| ced688a7a3 | |||
| 263af9fa3a | |||
| 1a55330734 | |||
| 0026f24002 | |||
| 2d6bb69387 | |||
| 70e3a4f2b0 | |||
| 98cd24ee29 | 
| @@ -191,3 +191,21 @@ export const recordDeathInBatch = (id, deathData) => { | |||||||
| export const recordCullInBatch = (id, cullData) => { | export const recordCullInBatch = (id, cullData) => { | ||||||
|   return http.post(`/api/v1/pig-batches/record-cull/${id}`, cullData); |   return http.post(`/api/v1/pig-batches/record-cull/${id}`, cullData); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | // --- 新增的猪栏和猪舍API --- | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 获取所有猪栏的列表 | ||||||
|  |  * @returns {Promise<*>} | ||||||
|  |  */ | ||||||
|  | export const getAllPens = () => { | ||||||
|  |   return http.get('/api/v1/pens'); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 获取所有猪舍的列表 | ||||||
|  |  * @returns {Promise<*>} | ||||||
|  |  */ | ||||||
|  | export const getAllPigHouses = () => { | ||||||
|  |   return http.get('/api/v1/pig-houses'); | ||||||
|  | }; | ||||||
|   | |||||||
| @@ -3,24 +3,44 @@ | |||||||
|     <div v-for="batch in pigBatches" :key="batch.id" class="pig-batch-item"> |     <div v-for="batch in pigBatches" :key="batch.id" class="pig-batch-item"> | ||||||
|       <div class="batch-header" @click="toggleExpand(batch)"> |       <div class="batch-header" @click="toggleExpand(batch)"> | ||||||
|         <div class="batch-info"> |         <div class="batch-info"> | ||||||
|           <span>批次编号: {{ batch.batch_number }}</span> |           <div class="batch-info-line"> | ||||||
|           <span>状态: {{ batch.status }}</span> |             <span>批次编号: {{ batch.batch_number }}</span> | ||||||
|           <span>初始数量: {{ batch.initial_count }}</span> |             <span>状态: {{ batch.status }}</span> | ||||||
|  |             <span>初始数量: {{ batch.initial_count }}</span> | ||||||
|  |             <span v-if="batch.currentTotalQuantity !== undefined && batch.currentTotalQuantity !== null">当前总数: {{ batch.currentTotalQuantity }}</span> | ||||||
|  |             <span v-if="batch.origin_type">批次来源: {{ batch.origin_type }}</span> | ||||||
|  |           </div> | ||||||
|  |           <div class="batch-info-line"> | ||||||
|  |             <span v-if="batch.start_date">批次开始日期: {{ formatRFC3339(batch.start_date) }}</span> | ||||||
|  |             <span v-if="batch.end_date"> | ||||||
|  |               批次结束日期: | ||||||
|  |               <template v-if="formatRFC3339(batch.end_date) === '0001-01-01 08:00:00'"> | ||||||
|  |                 正在饲养中 | ||||||
|  |               </template> | ||||||
|  |               <template v-else> | ||||||
|  |                 {{ formatRFC3339(batch.end_date) }} | ||||||
|  |               </template> | ||||||
|  |             </span> | ||||||
|  |             <span v-if="batch.unassigned_pig_count !== undefined && batch.unassigned_pig_count > 0" class="red-text"> | ||||||
|  |               未分配数量: {{ batch.unassigned_pig_count }} | ||||||
|  |             </span> | ||||||
|  |           </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="batch-actions"> |         <div class="batch-actions"> | ||||||
|           <el-button size="small" type="primary" @click.stop="emitAddPen(batch)">增加猪栏</el-button> |           <el-button size="small" type="primary" @click.stop="showAddPenDialog(batch)" :disabled="!batch.is_active">增加猪栏</el-button> | ||||||
|           <el-button size="small" @click.stop="emitEditBatch(batch)">编辑</el-button> |           <el-button size="small" @click.stop="emitEditBatch(batch)">编辑</el-button> | ||||||
|           <el-button size="small" type="danger" @click.stop="emitDeleteBatch(batch)">删除</el-button> |           <el-button size="small" type="danger" @click.stop="emitDeleteBatch(batch)">删除</el-button> | ||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
|       <div v-if="batch.isExpanded" class="batch-content"> |       <div v-if="batch.isExpanded" class="batch-content"> | ||||||
|         <div v-if="batch.pens && batch.pens.length > 0" class="pig-pen-list"> |         <div v-if="batch.pens && batch.pens.length > 0" class="pig-pen-list"> | ||||||
|           <PigPenInfoCard |           <PigBatchPenCard | ||||||
|             v-for="pen in batch.pens" |             v-for="pen in batch.pens" | ||||||
|             :key="pen.id" |             :key="pen.id" | ||||||
|             :pen="pen" |             :pen="pen" | ||||||
|             @edit="emitEditPen" |             :isBatchActive="batch.is_active" | ||||||
|             @delete="emitDeletePen" |             @modify-pig-count="emitModifyPigCountPen" | ||||||
|  |             @remove="emitRemovePen" | ||||||
|           /> |           /> | ||||||
|         </div> |         </div> | ||||||
|         <div v-else class="no-pens-message"> |         <div v-else class="no-pens-message"> | ||||||
| @@ -28,16 +48,36 @@ | |||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
|  |     <!-- 增加猪栏对话框 --> | ||||||
|  |     <el-dialog title="选择猪栏" v-model="addPenDialogVisible" width="30%"> | ||||||
|  |       <el-select v-model="selectedPenId" placeholder="请选择猪栏" style="width: 100%;"> | ||||||
|  |         <el-option | ||||||
|  |           v-for="pen in availablePens" | ||||||
|  |           :key="pen.id" | ||||||
|  |           :label="pen.label" | ||||||
|  |           :value="pen.id"> | ||||||
|  |         </el-option> | ||||||
|  |       </el-select> | ||||||
|  |       <template #footer> | ||||||
|  |         <span class="dialog-footer"> | ||||||
|  |           <el-button @click="addPenDialogVisible = false">取 消</el-button> | ||||||
|  |           <el-button type="primary" @click="assignPen">确 定</el-button> | ||||||
|  |         </span> | ||||||
|  |       </template> | ||||||
|  |     </el-dialog> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script> | <script> | ||||||
| import PigPenInfoCard from './PigPenInfoCard.vue'; | import PigBatchPenCard from './PigBatchPenCard.vue'; | ||||||
|  | import { getAllPens, getAllPigHouses } from '../api/pigBatch'; | ||||||
|  | import { formatRFC3339 } from '../utils/format'; // 导入格式化函数 | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|   name: 'PigBatchList', |   name: 'PigBatchList', | ||||||
|   components: { |   components: { | ||||||
|     PigPenInfoCard |     PigBatchPenCard | ||||||
|   }, |   }, | ||||||
|   props: { |   props: { | ||||||
|     pigBatches: { |     pigBatches: { | ||||||
| @@ -45,15 +85,60 @@ export default { | |||||||
|       required: true |       required: true | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   emits: ['edit-batch', 'delete-batch', 'add-pen', 'edit-pen', 'delete-pen'], |   emits: ['edit-batch', 'delete-batch', 'add-pen', 'modify-pig-count-pen', 'remove-pen', 'assign-pen-to-batch'], | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       addPenDialogVisible: false, | ||||||
|  |       availablePens: [], | ||||||
|  |       selectedPenId: null, | ||||||
|  |       currentBatch: null // To store the batch for which we are adding a pen | ||||||
|  |     }; | ||||||
|  |   }, | ||||||
|   methods: { |   methods: { | ||||||
|  |     formatRFC3339, | ||||||
|     toggleExpand(batch) { |     toggleExpand(batch) { | ||||||
|       batch.isExpanded = !batch.isExpanded; |       batch.isExpanded = !batch.isExpanded; | ||||||
|     }, |     }, | ||||||
|     // 猪群操作 |     async fetchAvailablePens() { | ||||||
|     emitAddPen(batch) { |       try { | ||||||
|       this.$emit('add-pen', batch); |         const [pensResponse, housesResponse] = await Promise.all([ | ||||||
|  |           getAllPens(), | ||||||
|  |           getAllPigHouses() | ||||||
|  |         ]); | ||||||
|  |  | ||||||
|  |         const pens = pensResponse.data;  | ||||||
|  |         const houses = housesResponse.data; | ||||||
|  |  | ||||||
|  |         // Create a map for quick lookup of house names by ID | ||||||
|  |         const houseMap = new Map(houses.map(house => [house.id, house.name])); | ||||||
|  |  | ||||||
|  |         this.availablePens = pens.map(pen => ({ | ||||||
|  |           id: pen.id, | ||||||
|  |           label: `${pen.pen_number}(${houseMap.get(pen.house_id) || '未知猪舍'})` // Changed format here | ||||||
|  |         })); | ||||||
|  |       } catch (error) { | ||||||
|  |         console.error("Error fetching pens or houses:", error); | ||||||
|  |         this.$message.error("获取猪栏或猪舍信息失败"); | ||||||
|  |       } | ||||||
|     }, |     }, | ||||||
|  |     showAddPenDialog(batch) { | ||||||
|  |       this.currentBatch = batch; | ||||||
|  |       this.selectedPenId = null; // Reset selection | ||||||
|  |       this.fetchAvailablePens(); | ||||||
|  |       this.addPenDialogVisible = true; | ||||||
|  |     }, | ||||||
|  |     assignPen() { | ||||||
|  |       if (this.selectedPenId && this.currentBatch) { | ||||||
|  |         this.$emit('assign-pen-to-batch', { | ||||||
|  |           batchId: this.currentBatch.id, | ||||||
|  |           penId: this.selectedPenId | ||||||
|  |         }); | ||||||
|  |         this.addPenDialogVisible = false; | ||||||
|  |       } else { | ||||||
|  |         this.$message.warning("请选择一个猪栏"); | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     // 猪群操作 | ||||||
|     emitEditBatch(batch) { |     emitEditBatch(batch) { | ||||||
|       this.$emit('edit-batch', batch); |       this.$emit('edit-batch', batch); | ||||||
|     }, |     }, | ||||||
| @@ -61,11 +146,11 @@ export default { | |||||||
|       this.$emit('delete-batch', batch); |       this.$emit('delete-batch', batch); | ||||||
|     }, |     }, | ||||||
|     // 猪栏操作 |     // 猪栏操作 | ||||||
|     emitEditPen(pen) { |     emitModifyPigCountPen(pen) { | ||||||
|       this.$emit('edit-pen', pen); |       this.$emit('modify-pig-count-pen', pen); | ||||||
|     }, |     }, | ||||||
|     emitDeletePen(pen) { |     emitRemovePen(pen) { | ||||||
|       this.$emit('delete-pen', pen); |       this.$emit('remove-pen', pen); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @@ -99,16 +184,21 @@ export default { | |||||||
|  |  | ||||||
| .batch-info { | .batch-info { | ||||||
|   display: flex; |   display: flex; | ||||||
|   flex-direction: column; |   flex-direction: column; /* 垂直堆叠子元素 */ | ||||||
|   gap: 8px; |   gap: 8px; /* 行间距 */ | ||||||
| } | } | ||||||
|  |  | ||||||
| .batch-info span:first-child { | .batch-info-line { | ||||||
|  |   display: flex; | ||||||
|  |   flex-wrap: wrap; | ||||||
|  |   gap: 0 20px; /* 列间距 */ | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .batch-info-line:first-child span:first-child { | ||||||
|   font-weight: bold; |   font-weight: bold; | ||||||
| } | } | ||||||
|  |  | ||||||
| .batch-info span { | .batch-info span { | ||||||
|   margin-right: 20px; |  | ||||||
|   font-size: 14px; |   font-size: 14px; | ||||||
|   color: #606266; |   color: #606266; | ||||||
| } | } | ||||||
| @@ -134,4 +224,8 @@ export default { | |||||||
|   text-align: center; |   text-align: center; | ||||||
|   padding: 20px 0; |   padding: 20px 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .batch-info-line .red-text { | ||||||
|  |   color: red !important; | ||||||
|  | } | ||||||
| </style> | </style> | ||||||
|   | |||||||
							
								
								
									
										127
									
								
								src/components/PigBatchPenCard.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								src/components/PigBatchPenCard.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,127 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="pig-pen-info-card"> | ||||||
|  |     <div class="info-section"> | ||||||
|  |       <div class="title"> | ||||||
|  |         猪栏: {{ pen.pen_number }} <el-tag size="small" :type="statusType">{{ pen.status || '未知' }}</el-tag> | ||||||
|  |       </div> | ||||||
|  |       <div class="info-item">猪舍: {{ pen.house_name || '未知' }}</div> | ||||||
|  |       <div class="info-item border-left">容量: {{ pen.capacity }}</div> | ||||||
|  |       <div class="info-item">批次: {{ pen.batch_number || '未分配' }}</div> | ||||||
|  |       <div class="info-item border-left">存栏: {{ pen.current_pig_count || 0 }}</div> | ||||||
|  |     </div> | ||||||
|  |     <div class="actions-section"> | ||||||
|  |       <el-button size="small" @click="emitModifyPigCount" :disabled="!isBatchActive">修改猪只数量</el-button> | ||||||
|  |       <el-button size="small" type="danger" @click="emitRemove" :disabled="!isBatchActive">移除</el-button> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import { computed } from 'vue'; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: 'PigBatchPenCard', | ||||||
|  |   props: { | ||||||
|  |     pen: { | ||||||
|  |       type: Object, | ||||||
|  |       required: true | ||||||
|  |     }, | ||||||
|  |     isBatchActive: { | ||||||
|  |       type: Boolean, | ||||||
|  |       default: true // 默认活跃,以防万一没有传递 | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   emits: ['remove', 'modify-pig-count'], | ||||||
|  |   setup(props, { emit }) { | ||||||
|  |     const statusType = computed(() => { | ||||||
|  |       switch (props.pen.status) { | ||||||
|  |         case '使用中': | ||||||
|  |           return 'success'; | ||||||
|  |         case '病猪栏': | ||||||
|  |         case '维修中': | ||||||
|  |           return 'danger'; | ||||||
|  |         case '清洗消毒': | ||||||
|  |           return 'warning'; | ||||||
|  |         case '空闲': | ||||||
|  |         default: | ||||||
|  |           return 'info'; | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     const emitModifyPigCount = () => { | ||||||
|  |       emit('modify-pig-count', props.pen); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     const emitRemove = () => { | ||||||
|  |       emit('remove', props.pen); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     return { | ||||||
|  |       statusType, | ||||||
|  |       emitModifyPigCount, | ||||||
|  |       emitRemove | ||||||
|  |     }; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style scoped> | ||||||
|  | .pig-pen-info-card { | ||||||
|  |   border: 2px solid #ccc; | ||||||
|  |   border-radius: 8px; | ||||||
|  |   padding: 16px; | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: column; | ||||||
|  |   justify-content: space-between; | ||||||
|  |   width: 220px; /* 适当加宽以容纳更多信息 */ | ||||||
|  |   height: auto; /* 让高度自适应内容 */ | ||||||
|  |   min-height: 240px; /* 设置最小高度 */ | ||||||
|  |   background-color: #fff; | ||||||
|  |   box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); | ||||||
|  |   transition: box-shadow 0.3s; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .pig-pen-info-card:hover { | ||||||
|  |   box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .info-section { | ||||||
|  |   display: grid; /* 使用grid布局创建两列 */ | ||||||
|  |   grid-template-columns: 1fr 1fr; /* 两列等宽 */ | ||||||
|  |   gap: 8px 10px; /* 行间距 8px, 列间距 10px */ | ||||||
|  |   margin-bottom: 10px; | ||||||
|  |   flex-grow: 1; /* 允许信息部分填充可用空间 */ | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .info-section .title { | ||||||
|  |   font-weight: bold; | ||||||
|  |   font-size: 1.1em; | ||||||
|  |   color: #303133; | ||||||
|  |   grid-column: 1 / -1; /* 标题横跨两列 */ | ||||||
|  |   margin-bottom: 5px; /* 标题下方增加一点间距 */ | ||||||
|  |   display: flex; /* Add flexbox for alignment */ | ||||||
|  |   align-items: center; /* Vertically align items */ | ||||||
|  |   gap: 8px; /* Space between title text and tag */ | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .info-section .info-item { | ||||||
|  |   font-size: 0.9em; | ||||||
|  |   color: #606266; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .info-item.border-left { | ||||||
|  |   border-left: 1px solid #eee; /* 添加左边框作为分隔线 */ | ||||||
|  |   padding-left: 10px; /* 增加左内边距,使内容不紧贴边框 */ | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .actions-section { | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: column; | ||||||
|  |   gap: 8px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .actions-section .el-button { | ||||||
|  |   width: 100%; | ||||||
|  |   margin: 0; | ||||||
|  | } | ||||||
|  | </style> | ||||||
| @@ -1,7 +1,7 @@ | |||||||
| <template> | <template> | ||||||
|   <div class="pig-house-list"> |   <div class="pig-house-list"> | ||||||
|     <div v-for="house in pigHouses" :key="house.id" class="pig-house-item"> |     <div v-for="house in enrichedPigHouses" :key="house.id" class="pig-house-item"> | ||||||
|       <div class="house-header" @click="toggleExpand(house)"> |       <div class="house-header" @click="emitToggleExpand(house.id)"> | ||||||
|         <div class="house-info"> |         <div class="house-info"> | ||||||
|           <span>猪舍: {{ house.name }}</span> |           <span>猪舍: {{ house.name }}</span> | ||||||
|           <span v-if="house.description">描述: {{ house.description }}</span> |           <span v-if="house.description">描述: {{ house.description }}</span> | ||||||
| @@ -44,10 +44,25 @@ export default { | |||||||
|       required: true |       required: true | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   emits: ['edit-house', 'delete-house', 'add-pen', 'edit-pen', 'delete-pen'], |   emits: ['edit-house', 'delete-house', 'add-pen', 'edit-pen', 'delete-pen', 'toggle-house-expand'], | ||||||
|  |   computed: { | ||||||
|  |     enrichedPigHouses() { | ||||||
|  |       return this.pigHouses.map(house => { | ||||||
|  |         const pensWithHouseInfo = house.pens ? house.pens.map(pen => ({ | ||||||
|  |           ...pen, | ||||||
|  |           house_name: house.name, | ||||||
|  |           house_id: house.id | ||||||
|  |         })) : []; | ||||||
|  |         return { | ||||||
|  |           ...house, | ||||||
|  |           pens: pensWithHouseInfo | ||||||
|  |         }; | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|   methods: { |   methods: { | ||||||
|     toggleExpand(house) { |     emitToggleExpand(houseId) { | ||||||
|       house.isExpanded = !house.isExpanded; |       this.$emit('toggle-house-expand', houseId); | ||||||
|     }, |     }, | ||||||
|     // 猪舍操作 |     // 猪舍操作 | ||||||
|     emitAddPen(house) { |     emitAddPen(house) { | ||||||
| @@ -79,7 +94,7 @@ export default { | |||||||
|   border: 1px solid #eee; |   border: 1px solid #eee; | ||||||
|   border-radius: 4px; |   border-radius: 4px; | ||||||
|   margin-bottom: 16px; |   margin-bottom: 16px; | ||||||
|   overflow: hidden; /* 防止子元素溢出圆角 */ |   overflow: hidden; | ||||||
| } | } | ||||||
|  |  | ||||||
| .house-header { | .house-header { | ||||||
|   | |||||||
| @@ -1,12 +1,13 @@ | |||||||
| <template> | <template> | ||||||
|   <div class="pig-pen-info-card"> |   <div class="pig-pen-info-card"> | ||||||
|     <div class="info-section"> |     <div class="info-section"> | ||||||
|       <div class="title">猪栏: {{ pen.pen_number }}</div> |       <div class="title"> | ||||||
|       <div class="info-item">状态: <el-tag size="small" :type="statusType">{{ pen.status || '未知' }}</el-tag></div> |         猪栏: {{ pen.pen_number }} <el-tag size="small" :type="statusType">{{ pen.status || '未知' }}</el-tag> | ||||||
|       <div class="info-item">容量: {{ pen.capacity }}</div> |       </div> | ||||||
|       <div class="info-item">存栏: {{ pen.current_pig_count || 0 }}</div> |  | ||||||
|       <div class="info-item">批次: {{ pen.batch_number || '未分配' }}</div> |  | ||||||
|       <div class="info-item">猪舍: {{ pen.house_name || '未知' }}</div> |       <div class="info-item">猪舍: {{ pen.house_name || '未知' }}</div> | ||||||
|  |       <div class="info-item border-left">容量: {{ pen.capacity }}</div> | ||||||
|  |       <div class="info-item">批次: {{ pen.batch_number || '未分配' }}</div> | ||||||
|  |       <div class="info-item border-left">存栏: {{ pen.current_pig_count || 0 }}</div> | ||||||
|     </div> |     </div> | ||||||
|     <div class="actions-section"> |     <div class="actions-section"> | ||||||
|       <el-button size="small" @click="emitEdit">编辑</el-button> |       <el-button size="small" @click="emitEdit">编辑</el-button> | ||||||
| @@ -62,14 +63,15 @@ export default { | |||||||
|  |  | ||||||
| <style scoped> | <style scoped> | ||||||
| .pig-pen-info-card { | .pig-pen-info-card { | ||||||
|   border: 1px solid #eee; |   border: 2px solid #ccc; | ||||||
|   border-radius: 8px; |   border-radius: 8px; | ||||||
|   padding: 16px; |   padding: 16px; | ||||||
|   display: flex; |   display: flex; | ||||||
|   flex-direction: column; |   flex-direction: column; | ||||||
|   justify-content: space-between; |   justify-content: space-between; | ||||||
|   width: 200px; /* 适当加宽以容纳更多信息 */ |   width: 220px; /* 适当加宽以容纳更多信息 */ | ||||||
|   height: 260px; /* 调整高度以适应更多信息 */ |   height: auto; /* 让高度自适应内容 */ | ||||||
|  |   min-height: 240px; /* 设置最小高度 */ | ||||||
|   background-color: #fff; |   background-color: #fff; | ||||||
|   box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); |   box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); | ||||||
|   transition: box-shadow 0.3s; |   transition: box-shadow 0.3s; | ||||||
| @@ -80,16 +82,22 @@ export default { | |||||||
| } | } | ||||||
|  |  | ||||||
| .info-section { | .info-section { | ||||||
|   display: flex; |   display: grid; /* 使用grid布局创建两列 */ | ||||||
|   flex-direction: column; |   grid-template-columns: 1fr 1fr; /* 两列等宽 */ | ||||||
|   gap: 10px; /* 调整信息项间距 */ |   gap: 8px 10px; /* 行间距 8px, 列间距 10px */ | ||||||
|   margin-bottom: 10px; |   margin-bottom: 10px; | ||||||
|  |   flex-grow: 1; /* 允许信息部分填充可用空间 */ | ||||||
| } | } | ||||||
|  |  | ||||||
| .info-section .title { | .info-section .title { | ||||||
|   font-weight: bold; |   font-weight: bold; | ||||||
|   font-size: 1.1em; |   font-size: 1.1em; | ||||||
|   color: #303133; |   color: #303133; | ||||||
|  |   grid-column: 1 / -1; /* 标题横跨两列 */ | ||||||
|  |   margin-bottom: 5px; /* 标题下方增加一点间距 */ | ||||||
|  |   display: flex; /* Add flexbox for alignment */ | ||||||
|  |   align-items: center; /* Vertically align items */ | ||||||
|  |   gap: 8px; /* Space between title text and tag */ | ||||||
| } | } | ||||||
|  |  | ||||||
| .info-section .info-item { | .info-section .info-item { | ||||||
| @@ -97,6 +105,11 @@ export default { | |||||||
|   color: #606266; |   color: #606266; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .info-item.border-left { | ||||||
|  |   border-left: 1px solid #eee; /* 添加左边框作为分隔线 */ | ||||||
|  |   padding-left: 10px; /* 增加左内边距,使内容不紧贴边框 */ | ||||||
|  | } | ||||||
|  |  | ||||||
| .actions-section { | .actions-section { | ||||||
|   display: flex; |   display: flex; | ||||||
|   flex-direction: column; |   flex-direction: column; | ||||||
|   | |||||||
| @@ -39,8 +39,9 @@ | |||||||
|           @edit-batch="handleEditBatch"  |           @edit-batch="handleEditBatch"  | ||||||
|           @delete-batch="handleDeleteBatch"  |           @delete-batch="handleDeleteBatch"  | ||||||
|           @add-pen="handleAddPen" |           @add-pen="handleAddPen" | ||||||
|           @edit-pen="handleEditPen" |           @modify-pig-count-pen="handleModifyPigCountPen" | ||||||
|           @delete-pen="handleDeletePen" |           @remove-pen="handleRemovePen" | ||||||
|  |           @assign-pen-to-batch="handleAssignPenToBatch" | ||||||
|         /> |         /> | ||||||
|         <el-empty v-else description="暂无数据" /> |         <el-empty v-else description="暂无数据" /> | ||||||
|       </div> |       </div> | ||||||
| @@ -68,12 +69,12 @@ | |||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script> | <script> | ||||||
| import { getPigBatches, deletePigBatch } from '@/api/pigBatch.js'; | import { getPigBatches, deletePigBatch, assignPensToBatch } from '@/api/pigBatch.js'; | ||||||
| import { getPens, deletePen } from '@/api/pen.js'; | import { getPens, deletePen } from '@/api/pen.js'; | ||||||
| import { getPigHouses } from '@/api/pigHouse.js'; | import { getPigHouses } from '@/api/pigHouse.js'; | ||||||
| import PigBatchList from '@/components/PigBatchList.vue'; | import PigBatchList from '@/components/PigBatchList.vue'; | ||||||
| import PigBatchForm from '@/components/PigBatchForm.vue'; | import PigBatchForm from '@/components/PigBatchForm.vue'; | ||||||
| import PenForm from '@/components/PenForm.vue'; // 引入 PenForm | import PenForm from '@/components/PenForm.vue'; | ||||||
| import { Refresh } from '@element-plus/icons-vue'; | import { Refresh } from '@element-plus/icons-vue'; | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
| @@ -119,8 +120,9 @@ export default { | |||||||
|         const pens = Array.isArray(pensResponse.data) ? pensResponse.data : []; |         const pens = Array.isArray(pensResponse.data) ? pensResponse.data : []; | ||||||
|         const houses = Array.isArray(housesResponse.data) ? housesResponse.data : []; |         const houses = Array.isArray(housesResponse.data) ? housesResponse.data : []; | ||||||
|  |  | ||||||
|         // 更新 houseMap |         // 更新 batchMap 和 houseMap | ||||||
|         this.houseMap = new Map(houses.map(h => [h.id, h.name])); |         this.houseMap = new Map(houses.map(h => [h.id, h.name])); | ||||||
|  |         this.batchMap = new Map(batches.map(batch => [batch.id, batch.batch_number])); | ||||||
|         this.pigBatchesData = this.assembleData(batches, pens); |         this.pigBatchesData = this.assembleData(batches, pens); | ||||||
|  |  | ||||||
|       } catch (err) { |       } catch (err) { | ||||||
| @@ -141,12 +143,19 @@ export default { | |||||||
|         if (pen.pig_batch_id && batchMap.has(pen.pig_batch_id)) { |         if (pen.pig_batch_id && batchMap.has(pen.pig_batch_id)) { | ||||||
|           const penWithDetails = { |           const penWithDetails = { | ||||||
|             ...pen, |             ...pen, | ||||||
|             house_name: this.houseMap.get(pen.house_id) || '未知猪舍' |             house_name: this.houseMap.get(pen.house_id) || '未知猪舍', | ||||||
|  |             batch_number: batchMap.get(pen.pig_batch_id)?.batch_number || null | ||||||
|           }; |           }; | ||||||
|           batchMap.get(pen.pig_batch_id).pens.push(penWithDetails); |           batchMap.get(pen.pig_batch_id).pens.push(penWithDetails); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|       return Array.from(batchMap.values()); |       // Calculate unassigned_pig_count for each batch using currentTotalQuantity and currentTotalPigsInPens | ||||||
|  |       const assembledBatches = Array.from(batchMap.values()); | ||||||
|  |       assembledBatches.forEach(batch => { | ||||||
|  |         // Use currentTotalQuantity and currentTotalPigsInPens directly from the batch object | ||||||
|  |         batch.unassigned_pig_count = (batch.currentTotalQuantity || 0) - (batch.currentTotalPigsInPens || 0); | ||||||
|  |       }); | ||||||
|  |       return assembledBatches; | ||||||
|     }, |     }, | ||||||
|     // --- 猪群操作 --- |     // --- 猪群操作 --- | ||||||
|     handleAddBatch() { |     handleAddBatch() { | ||||||
| @@ -198,17 +207,12 @@ export default { | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     // --- 猪栏操作 (在猪群管理中) --- |     // --- 猪栏操作 (在猪群管理中) --- | ||||||
|     handleAddPen(batch) { |     handleModifyPigCountPen(pen) { | ||||||
|       this.currentPen = { pig_batch_id: batch.id }; // 预设猪栏所属批次 |  | ||||||
|       this.isEditPen = false; |  | ||||||
|       this.penDialogVisible = true; |  | ||||||
|     }, |  | ||||||
|     handleEditPen(pen) { |  | ||||||
|       this.currentPen = { ...pen }; |       this.currentPen = { ...pen }; | ||||||
|       this.isEditPen = true; |       this.isEditPen = true; | ||||||
|       this.penDialogVisible = true; |       this.penDialogVisible = true; | ||||||
|     }, |     }, | ||||||
|     async handleDeletePen(pen) { |     async handleRemovePen(pen) { | ||||||
|       try { |       try { | ||||||
|         await this.$confirm(`确认删除猪栏 "${pen.pen_number}" 吗?`, '提示', { |         await this.$confirm(`确认删除猪栏 "${pen.pen_number}" 吗?`, '提示', { | ||||||
|           confirmButtonText: '确定', |           confirmButtonText: '确定', | ||||||
| @@ -253,6 +257,16 @@ export default { | |||||||
|           this.$message.success('猪栏添加成功'); |           this.$message.success('猪栏添加成功'); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  |     }, | ||||||
|  |     async handleAssignPenToBatch({ batchId, penId }) { | ||||||
|  |       try { | ||||||
|  |         await assignPensToBatch(batchId, { penIds: [penId] }); | ||||||
|  |         this.$message.success('猪栏分配成功'); | ||||||
|  |         await this.loadData(); // Refresh data to show assigned pen | ||||||
|  |       } catch (error) { | ||||||
|  |         this.$message.error('分配猪栏失败: ' + (error.response?.data?.message || error.message || '未知错误')); | ||||||
|  |         console.error('Failed to assign pen to batch:', error); | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -6,7 +6,9 @@ | |||||||
|           <div class="title-container"> |           <div class="title-container"> | ||||||
|             <h2 class="page-title">栏舍管理</h2> |             <h2 class="page-title">栏舍管理</h2> | ||||||
|             <el-button type="text" @click="loadData" class="refresh-btn" title="刷新列表"> |             <el-button type="text" @click="loadData" class="refresh-btn" title="刷新列表"> | ||||||
|               <el-icon :size="20"><Refresh /></el-icon> |               <el-icon :size="20"> | ||||||
|  |                 <Refresh/> | ||||||
|  |               </el-icon> | ||||||
|             </el-button> |             </el-button> | ||||||
|           </div> |           </div> | ||||||
|           <el-button type="primary" @click="handleAddHouse">添加猪舍</el-button> |           <el-button type="primary" @click="handleAddHouse">添加猪舍</el-button> | ||||||
| @@ -15,18 +17,18 @@ | |||||||
|  |  | ||||||
|       <!-- 加载状态 --> |       <!-- 加载状态 --> | ||||||
|       <div v-if="loading" class="loading"> |       <div v-if="loading" class="loading"> | ||||||
|         <el-skeleton animated /> |         <el-skeleton animated/> | ||||||
|       </div> |       </div> | ||||||
|  |  | ||||||
|       <!-- 错误状态 --> |       <!-- 错误状态 --> | ||||||
|       <div v-else-if="error" class="error"> |       <div v-else-if="error" class="error"> | ||||||
|         <el-alert |         <el-alert | ||||||
|           title="获取栏舍数据失败" |             title="获取栏舍数据失败" | ||||||
|           :description="error" |             :description="error" | ||||||
|           type="error" |             type="error" | ||||||
|           show-icon |             show-icon | ||||||
|           closable |             closable | ||||||
|           @close="error = null" |             @close="error = null" | ||||||
|         /> |         /> | ||||||
|         <el-button type="primary" @click="loadData" class="retry-btn">重新加载</el-button> |         <el-button type="primary" @click="loadData" class="retry-btn">重新加载</el-button> | ||||||
|       </div> |       </div> | ||||||
| @@ -34,47 +36,48 @@ | |||||||
|       <!-- 数据展示或空状态 --> |       <!-- 数据展示或空状态 --> | ||||||
|       <div v-else> |       <div v-else> | ||||||
|         <PigHouseList |         <PigHouseList | ||||||
|           v-if="pigHousesData.length > 0"  |             v-if="pigHousesData.length > 0" | ||||||
|           :pigHouses="pigHousesData"  |             :pigHouses="pigHousesData" | ||||||
|           @edit-house="handleEditHouse"  |             @edit-house="handleEditHouse" | ||||||
|           @delete-house="handleDeleteHouse"  |             @delete-house="handleDeleteHouse" | ||||||
|           @add-pen="handleAddPen" |             @add-pen="handleAddPen" | ||||||
|           @edit-pen="handleEditPen" |             @edit-pen="handleEditPen" | ||||||
|           @delete-pen="handleDeletePen" |             @delete-pen="handleDeletePen" | ||||||
|  |             @toggle-house-expand="handleToggleHouseExpand" | ||||||
|         /> |         /> | ||||||
|         <el-empty v-else description="暂无数据" /> |         <el-empty v-else description="暂无数据"/> | ||||||
|       </div> |       </div> | ||||||
|  |  | ||||||
|     </el-card> |     </el-card> | ||||||
|  |  | ||||||
|     <!-- 猪舍表单对话框 --> |     <!-- 猪舍表单对话框 --> | ||||||
|     <PigHouseForm |     <PigHouseForm | ||||||
|       v-model:visible="houseDialogVisible" |         v-model:visible="houseDialogVisible" | ||||||
|       :house-data="currentHouse" |         :house-data="currentHouse" | ||||||
|       :is-edit="isEditHouse" |         :is-edit="isEditHouse" | ||||||
|       @success="handleHouseSuccess" |         @success="handleHouseSuccess" | ||||||
|       @cancel="houseDialogVisible = false" |         @cancel="houseDialogVisible = false" | ||||||
|     /> |     /> | ||||||
|  |  | ||||||
|     <!-- 猪栏表单对话框 --> |     <!-- 猪栏表单对话框 --> | ||||||
|     <PenForm |     <PenForm | ||||||
|       v-model:visible="penDialogVisible" |         v-model:visible="penDialogVisible" | ||||||
|       :pen-data="currentPen" |         :pen-data="currentPen" | ||||||
|       :is-edit="isEditPen" |         :is-edit="isEditPen" | ||||||
|       @success="handlePenSuccess" |         @success="handlePenSuccess" | ||||||
|       @cancel="penDialogVisible = false" |         @cancel="penDialogVisible = false" | ||||||
|     /> |     /> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script> | <script> | ||||||
| import { getPigHouses, deletePigHouse } from '@/api/pigHouse.js'; | import {getPigHouses, deletePigHouse} from '@/api/pigHouse.js'; | ||||||
| import { getPens, deletePen } from '@/api/pen.js'; | import {getPens, deletePen} from '@/api/pen.js'; | ||||||
| import { getPigBatches } from '@/api/pigBatch.js'; | import {getPigBatches} from '@/api/pigBatch.js'; | ||||||
| import PigHouseList from '@/components/PigHouseList.vue'; | import PigHouseList from '@/components/PigHouseList.vue'; | ||||||
| import PigHouseForm from '@/components/PigHouseForm.vue'; | import PigHouseForm from '@/components/PigHouseForm.vue'; | ||||||
| import PenForm from '@/components/PenForm.vue'; | import PenForm from '@/components/PenForm.vue'; | ||||||
| import { Refresh } from '@element-plus/icons-vue'; | import {Refresh} from '@element-plus/icons-vue'; | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|   name: 'PigFarmManagementView', |   name: 'PigFarmManagementView', | ||||||
| @@ -136,7 +139,7 @@ export default { | |||||||
|       houses.forEach(house => { |       houses.forEach(house => { | ||||||
|         // 确保保留 isExpanded 状态 |         // 确保保留 isExpanded 状态 | ||||||
|         const existingHouse = this.pigHousesData.find(h => h.id === house.id); |         const existingHouse = this.pigHousesData.find(h => h.id === house.id); | ||||||
|         houseMap.set(house.id, { ...house, pens: [], isExpanded: existingHouse ? existingHouse.isExpanded : false }); |         houseMap.set(house.id, {...house, pens: [], isExpanded: existingHouse ? existingHouse.isExpanded : false}); | ||||||
|       }); |       }); | ||||||
|  |  | ||||||
|       for (const pen of pens) { |       for (const pen of pens) { | ||||||
| @@ -157,7 +160,7 @@ export default { | |||||||
|       this.houseDialogVisible = true; |       this.houseDialogVisible = true; | ||||||
|     }, |     }, | ||||||
|     handleEditHouse(house) { |     handleEditHouse(house) { | ||||||
|       this.currentHouse = { ...house }; |       this.currentHouse = {...house}; | ||||||
|       this.isEditHouse = true; |       this.isEditHouse = true; | ||||||
|       this.houseDialogVisible = true; |       this.houseDialogVisible = true; | ||||||
|     }, |     }, | ||||||
| @@ -187,23 +190,23 @@ export default { | |||||||
|         if (index !== -1) { |         if (index !== -1) { | ||||||
|           // 保留 pens 和 isExpanded 状态 |           // 保留 pens 和 isExpanded 状态 | ||||||
|           const existingHouse = this.pigHousesData[index]; |           const existingHouse = this.pigHousesData[index]; | ||||||
|           this.pigHousesData[index] = { ...newHouseData, pens: existingHouse.pens, isExpanded: existingHouse.isExpanded }; |           this.pigHousesData[index] = {...newHouseData, pens: existingHouse.pens, isExpanded: existingHouse.isExpanded}; | ||||||
|         } |         } | ||||||
|         this.$message.success('猪舍更新成功'); |         this.$message.success('猪舍更新成功'); | ||||||
|       } else { |       } else { | ||||||
|         // 添加新猪舍 |         // 添加新猪舍 | ||||||
|         this.pigHousesData.push({ ...newHouseData, pens: [], isExpanded: false }); |         this.pigHousesData.push({...newHouseData, pens: [], isExpanded: false}); | ||||||
|         this.$message.success('猪舍添加成功'); |         this.$message.success('猪舍添加成功'); | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     // --- 猪栏操作 --- |     // --- 猪栏操作 --- | ||||||
|     handleAddPen(house) { |     handleAddPen(house) { | ||||||
|       this.currentPen = { house_id: house.id }; |       this.currentPen = {house_id: house.id}; | ||||||
|       this.isEditPen = false; |       this.isEditPen = false; | ||||||
|       this.penDialogVisible = true; |       this.penDialogVisible = true; | ||||||
|     }, |     }, | ||||||
|     handleEditPen(pen) { |     handleEditPen(pen) { | ||||||
|       this.currentPen = { ...pen }; |       this.currentPen = {...pen}; | ||||||
|       this.isEditPen = true; |       this.isEditPen = true; | ||||||
|       this.penDialogVisible = true; |       this.penDialogVisible = true; | ||||||
|     }, |     }, | ||||||
| @@ -251,6 +254,12 @@ export default { | |||||||
|           this.$message.success('猪栏添加成功'); |           this.$message.success('猪栏添加成功'); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  |     }, | ||||||
|  |     handleToggleHouseExpand(houseId) { | ||||||
|  |       const house = this.pigHousesData.find(h => h.id === houseId); | ||||||
|  |       if (house) { | ||||||
|  |         house.isExpanded = !house.isExpanded; | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @@ -312,6 +321,7 @@ export default { | |||||||
|   .pig-farm-management { |   .pig-farm-management { | ||||||
|     padding: 10px; |     padding: 10px; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   .card-header { |   .card-header { | ||||||
|     flex-direction: column; |     flex-direction: column; | ||||||
|     gap: 15px; |     gap: 15px; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user