配方管理界面
This commit is contained in:
40
src/components/feed/RecipeTable.vue
Normal file
40
src/components/feed/RecipeTable.vue
Normal 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>
|
||||
@@ -109,6 +109,12 @@
|
||||
</el-icon>
|
||||
<template #title>品种管理</template>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/feed/recipes">
|
||||
<el-icon>
|
||||
<Tickets/>
|
||||
</el-icon>
|
||||
<template #title>配方管理</template>
|
||||
</el-menu-item>
|
||||
|
||||
</el-sub-menu>
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ import RawMaterialList from '../views/feed/RawMaterialList.vue';
|
||||
import NutrientList from '../views/feed/NutrientList.vue'; // 修正拼写错误
|
||||
import PigAgeStageList from '../views/feed/PigAgeStageList.vue'; // 导入 PigAgeStageList 组件
|
||||
import PigBreedList from '../views/feed/PigBreedList.vue'; // 导入 PigBreedList 组件
|
||||
import RecipeList from '../views/feed/RecipeList.vue';
|
||||
|
||||
|
||||
const routes = [
|
||||
{path: '/', component: Home, meta: {requiresAuth: true, title: '系统首页'}},
|
||||
@@ -42,6 +44,8 @@ const routes = [
|
||||
{path: '/feed/nutrients', component: NutrientList, 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/recipes', component: RecipeList, 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/notifications', component: NotificationLogView, meta: {requiresAuth: true, title: '通知记录'}},
|
||||
|
||||
166
src/views/feed/RecipeList.vue
Normal file
166
src/views/feed/RecipeList.vue
Normal 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>
|
||||
Reference in New Issue
Block a user