配方管理界面

This commit is contained in:
2025-11-24 14:15:54 +08:00
parent 3158115865
commit f209d131a9
4 changed files with 216 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
<template>
<el-table
:data="recipes"
style="width: 100%"
:fit="true"
table-layout="auto"
row-key="id"
:highlight-current-row="false"
:scrollbar-always-on="true"
>
<el-table-column prop="id" label="ID" min-width="80" />
<el-table-column prop="name" label="配方名" min-width="150" />
<el-table-column label="原料种类数" min-width="120">
<template #default="scope">
{{ scope.row.recipe_ingredients ? scope.row.recipe_ingredients.length : 0 }}
</template>
</el-table-column>
<el-table-column prop="description" label="配方简介" min-width="200" />
<el-table-column label="操作" min-width="150" align="center">
<template #default="scope">
<el-button size="small" @click="$emit('edit', scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="$emit('delete', scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</template>
<script>
export default {
name: 'RecipeTable',
props: {
recipes: {
type: Array,
required: true,
default: () => []
}
},
emits: ['edit', 'delete']
};
</script>

View File

@@ -109,6 +109,12 @@
</el-icon> </el-icon>
<template #title>品种管理</template> <template #title>品种管理</template>
</el-menu-item> </el-menu-item>
<el-menu-item index="/feed/recipes">
<el-icon>
<Tickets/>
</el-icon>
<template #title>配方管理</template>
</el-menu-item>
</el-sub-menu> </el-sub-menu>

View File

@@ -27,6 +27,8 @@ import RawMaterialList from '../views/feed/RawMaterialList.vue';
import NutrientList from '../views/feed/NutrientList.vue'; // 修正拼写错误 import NutrientList from '../views/feed/NutrientList.vue'; // 修正拼写错误
import PigAgeStageList from '../views/feed/PigAgeStageList.vue'; // 导入 PigAgeStageList 组件 import PigAgeStageList from '../views/feed/PigAgeStageList.vue'; // 导入 PigAgeStageList 组件
import PigBreedList from '../views/feed/PigBreedList.vue'; // 导入 PigBreedList 组件 import PigBreedList from '../views/feed/PigBreedList.vue'; // 导入 PigBreedList 组件
import RecipeList from '../views/feed/RecipeList.vue';
const routes = [ const routes = [
{path: '/', component: Home, meta: {requiresAuth: true, title: '系统首页'}}, {path: '/', component: Home, meta: {requiresAuth: true, title: '系统首页'}},
@@ -42,6 +44,8 @@ const routes = [
{path: '/feed/nutrients', component: NutrientList, meta: {requiresAuth: true, title: '营养管理'}}, {path: '/feed/nutrients', component: NutrientList, meta: {requiresAuth: true, title: '营养管理'}},
{path: '/feed/pig-age-stages', component: PigAgeStageList, meta: {requiresAuth: true, title: '年龄阶段管理'}}, // 添加年龄阶段管理路由 {path: '/feed/pig-age-stages', component: PigAgeStageList, meta: {requiresAuth: true, title: '年龄阶段管理'}}, // 添加年龄阶段管理路由
{path: '/feed/pig-breeds', component: PigBreedList, meta: {requiresAuth: true, title: '品种管理'}}, // 添加品种管理路由 {path: '/feed/pig-breeds', component: PigBreedList, meta: {requiresAuth: true, title: '品种管理'}}, // 添加品种管理路由
{path: '/feed/recipes', component: RecipeList, meta: {requiresAuth: true, title: '配方管理'}},
{path: '/monitor/device-command-logs', component: DeviceCommandLogView, meta: {requiresAuth: true, title: '设备命令日志'}}, {path: '/monitor/device-command-logs', component: DeviceCommandLogView, meta: {requiresAuth: true, title: '设备命令日志'}},
{path: '/monitor/medication-logs', component: MedicationLogsView, meta: {requiresAuth: true, title: '用药记录'}}, {path: '/monitor/medication-logs', component: MedicationLogsView, meta: {requiresAuth: true, title: '用药记录'}},
{path: '/monitor/notifications', component: NotificationLogView, meta: {requiresAuth: true, title: '通知记录'}}, {path: '/monitor/notifications', component: NotificationLogView, meta: {requiresAuth: true, title: '通知记录'}},

View File

@@ -0,0 +1,166 @@
<template>
<div class="recipe-list">
<el-card>
<template #header>
<div class="card-header">
<div class="title-container">
<h2 class="page-title">配方管理</h2>
<el-button type="text" @click="loadRecipes" class="refresh-btn" title="刷新配方列表">
<el-icon :size="20"><Refresh /></el-icon>
</el-button>
</div>
<el-button type="primary" @click="addRecipe">新增配方</el-button>
</div>
</template>
<!-- 加载状态 -->
<div v-if="loading" class="loading">
<el-skeleton animated />
</div>
<!-- 错误状态 -->
<div v-else-if="error" class="error">
<el-alert
title="获取配方数据失败"
:description="error"
type="error"
show-icon
closable
@close="error = null"
/>
<el-button type="primary" @click="loadRecipes" class="retry-btn">重新加载</el-button>
</div>
<!-- 配方列表 -->
<RecipeTable
v-else
:recipes="recipes"
@edit="editRecipe"
@delete="deleteRecipe"
/>
</el-card>
</div>
</template>
<script>
import { Refresh } from '@element-plus/icons-vue';
import { getRecipes, deleteRecipe as deleteRecipeApi } from '../../api/feed.js';
import RecipeTable from '../../components/feed/RecipeTable.vue';
import { ElMessage, ElMessageBox } from 'element-plus';
export default {
name: 'RecipeList',
components: {
RecipeTable,
Refresh
},
data() {
return {
recipes: [],
loading: false,
error: null,
};
},
async mounted() {
await this.loadRecipes();
},
methods: {
async loadRecipes() {
this.loading = true;
this.error = null;
try {
const response = await getRecipes();
this.recipes = response.data.list || [];
} catch (err) {
this.error = err.message || '未知错误';
console.error('加载配方列表失败:', err);
} finally {
this.loading = false;
}
},
addRecipe() {
console.log('addRecipe triggered');
// 后续将实现表单对话框
ElMessage.info('新增功能待实现');
},
editRecipe(recipe) {
console.log('editRecipe triggered for:', recipe);
// 后续将实现表单对话框
ElMessage.info('编辑功能待实现');
},
async deleteRecipe(recipe) {
try {
await ElMessageBox.confirm(
`确认删除配方 "${recipe.name}" 吗?`,
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
);
await deleteRecipeApi(recipe.id);
ElMessage.success('删除成功');
await this.loadRecipes();
} catch (err) {
if (err !== 'cancel') {
ElMessage.error('删除失败: ' + (err.message || '未知错误'));
}
}
},
}
};
</script>
<style scoped>
.recipe-list {
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 0;
}
.title-container {
display: flex;
align-items: center;
gap: 5px;
}
.page-title {
margin: 0;
font-size: 1.5rem;
font-weight: bold;
line-height: 1;
}
.refresh-btn {
color: black;
background-color: transparent;
padding: 0;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
border: none;
}
.loading {
padding: 20px 0;
}
.error {
padding: 20px 0;
text-align: center;
}
.retry-btn {
margin-top: 15px;
}
</style>