支持修改营养元素
This commit is contained in:
139
src/components/feed/NutrientEditor.vue
Normal file
139
src/components/feed/NutrientEditor.vue
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
<template>
|
||||||
|
<div class="nutrient-editor">
|
||||||
|
<el-form label-width="100px">
|
||||||
|
<el-form-item v-for="(nutrient, index) in localNutrients" :key="index" :label="nutrient.nutrient_name">
|
||||||
|
<el-input-number v-model="nutrient.value" :min="0" controls-position="right" style="width: 150px;"></el-input-number>
|
||||||
|
<el-button type="danger" @click="removeNutrient(index)" style="margin-left: 10px;">
|
||||||
|
<el-icon><Delete /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<div class="add-nutrient-section">
|
||||||
|
<el-select v-model="newNutrientId" placeholder="选择要添加的营养素" filterable>
|
||||||
|
<el-option v-for="item in availableNutrients" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
||||||
|
</el-select>
|
||||||
|
<el-button type="primary" @click="addNutrient" style="margin-left: 10px;">添加</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button @click="handleCancel">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleSave">保存</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref, watch, onMounted } from 'vue';
|
||||||
|
import { FeedApi } from '../../api/feed';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
import { Delete } from '@element-plus/icons-vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'NutrientEditor',
|
||||||
|
components: {
|
||||||
|
Delete,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
initialData: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
emits: ['save', 'cancel'],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const localNutrients = ref([]);
|
||||||
|
const availableNutrients = ref([]);
|
||||||
|
const newNutrientId = ref(null);
|
||||||
|
|
||||||
|
// 监听 initialData 的变化,深拷贝以避免直接修改 props
|
||||||
|
watch(() => props.initialData, (newData) => {
|
||||||
|
if (newData && newData.raw_material_nutrients) {
|
||||||
|
localNutrients.value = JSON.parse(JSON.stringify(newData.raw_material_nutrients));
|
||||||
|
} else {
|
||||||
|
localNutrients.value = [];
|
||||||
|
}
|
||||||
|
}, { immediate: true, deep: true });
|
||||||
|
|
||||||
|
// 获取所有可用的营养素列表
|
||||||
|
const fetchAllNutrients = async () => {
|
||||||
|
try {
|
||||||
|
// 通常我们会获取一个完整的、未分页的列表用于选择
|
||||||
|
const response = await FeedApi.getNutrients({ page_size: 999 });
|
||||||
|
if (response.data) {
|
||||||
|
availableNutrients.value = response.data.list;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('获取营养素列表失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeNutrient = (index) => {
|
||||||
|
localNutrients.value.splice(index, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addNutrient = () => {
|
||||||
|
if (!newNutrientId.value) {
|
||||||
|
ElMessage.warning('请先选择一个营养素');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const nutrientExists = localNutrients.value.some(n => n.nutrient_id === newNutrientId.value);
|
||||||
|
if (nutrientExists) {
|
||||||
|
ElMessage.warning('该营养素已存在');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const nutrientToAdd = availableNutrients.value.find(n => n.id === newNutrientId.value);
|
||||||
|
if (nutrientToAdd) {
|
||||||
|
localNutrients.value.push({
|
||||||
|
nutrient_id: nutrientToAdd.id,
|
||||||
|
nutrient_name: nutrientToAdd.name,
|
||||||
|
value: 0, // 默认值为0
|
||||||
|
});
|
||||||
|
newNutrientId.value = null; // 重置选择
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSave = () => {
|
||||||
|
// 构造符合 API 要求的数据格式
|
||||||
|
const nutrientsToSave = localNutrients.value.map(n => ({
|
||||||
|
nutrient_id: n.nutrient_id,
|
||||||
|
value: n.value,
|
||||||
|
}));
|
||||||
|
emit('save', { nutrients: nutrientsToSave });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
emit('cancel');
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchAllNutrients();
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
localNutrients,
|
||||||
|
availableNutrients,
|
||||||
|
newNutrientId,
|
||||||
|
removeNutrient,
|
||||||
|
addNutrient,
|
||||||
|
handleSave,
|
||||||
|
handleCancel,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.nutrient-editor {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.add-nutrient-section {
|
||||||
|
margin-top: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.dialog-footer {
|
||||||
|
margin-top: 30px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -35,6 +35,7 @@
|
|||||||
<el-table-column label="操作">
|
<el-table-column label="操作">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button size="small" @click="handleEdit(scope.row)">编辑</el-button>
|
<el-button size="small" @click="handleEdit(scope.row)">编辑</el-button>
|
||||||
|
<el-button size="small" type="warning" @click="handleEditNutrients(scope.row)">修改营养成分</el-button>
|
||||||
<el-button size="small" type="danger" @click="handleDelete(scope.row)">删除</el-button>
|
<el-button size="small" type="danger" @click="handleDelete(scope.row)">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -60,7 +61,7 @@ import {ElMessageBox, ElMessage} from 'element-plus';
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'RawMaterialTable',
|
name: 'RawMaterialTable',
|
||||||
emits: ['edit'], // 声明触发的事件
|
emits: ['edit', 'edit-nutrients'], // 声明触发的事件
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const tableData = ref([]);
|
const tableData = ref([]);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
@@ -160,6 +161,10 @@ export default {
|
|||||||
emit('edit', row); // 触发 edit 事件,并传递当前行数据
|
emit('edit', row); // 触发 edit 事件,并传递当前行数据
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleEditNutrients = (row) => {
|
||||||
|
emit('edit-nutrients', row); // 触发 edit-nutrients 事件
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchRawMaterials();
|
fetchRawMaterials();
|
||||||
});
|
});
|
||||||
@@ -177,6 +182,7 @@ export default {
|
|||||||
handleExpandChange,
|
handleExpandChange,
|
||||||
handleEdit,
|
handleEdit,
|
||||||
handleDelete,
|
handleDelete,
|
||||||
|
handleEditNutrients,
|
||||||
fetchRawMaterials, // 将方法暴露出去
|
fetchRawMaterials, // 将方法暴露出去
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -12,8 +12,7 @@
|
|||||||
<el-button type="primary" @click="handleAddRawMaterial">添加原料</el-button>
|
<el-button type="primary" @click="handleAddRawMaterial">添加原料</el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<!-- 确保只有一个 raw-material-table 实例,并正确绑定事件 -->
|
<raw-material-table ref="rawMaterialTableRef" @edit="handleEdit" @edit-nutrients="handleEditNutrients"></raw-material-table>
|
||||||
<raw-material-table ref="rawMaterialTableRef" @edit="handleEdit"></raw-material-table>
|
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<!-- 添加/编辑原料弹窗 -->
|
<!-- 添加/编辑原料弹窗 -->
|
||||||
@@ -24,7 +23,6 @@
|
|||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
@close="handleCancel"
|
@close="handleCancel"
|
||||||
>
|
>
|
||||||
<!-- 只有在弹窗显示时才渲染表单组件,并传递编辑状态和初始数据 -->
|
|
||||||
<raw-material-form
|
<raw-material-form
|
||||||
v-if="showDialog"
|
v-if="showDialog"
|
||||||
ref="rawMaterialFormRef"
|
ref="rawMaterialFormRef"
|
||||||
@@ -34,15 +32,32 @@
|
|||||||
@cancel="handleCancel"
|
@cancel="handleCancel"
|
||||||
></raw-material-form>
|
></raw-material-form>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 修改营养成分弹窗 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="showNutrientDialog"
|
||||||
|
title="修改营养成分"
|
||||||
|
width="600px"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
@close="handleNutrientCancel"
|
||||||
|
>
|
||||||
|
<nutrient-editor
|
||||||
|
v-if="showNutrientDialog"
|
||||||
|
:initialData="currentNutrientEditData"
|
||||||
|
@save="handleNutrientSubmit"
|
||||||
|
@cancel="handleNutrientCancel"
|
||||||
|
></nutrient-editor>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { ref, nextTick } from 'vue'; // 导入 nextTick
|
import { ref, nextTick } from 'vue';
|
||||||
import { Refresh } from '@element-plus/icons-vue';
|
import { Refresh } from '@element-plus/icons-vue';
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import RawMaterialTable from '../../components/feed/RawMaterialTable.vue';
|
import RawMaterialTable from '../../components/feed/RawMaterialTable.vue';
|
||||||
import RawMaterialForm from '../../components/feed/RawMaterialForm.vue';
|
import RawMaterialForm from '../../components/feed/RawMaterialForm.vue';
|
||||||
|
import NutrientEditor from '../../components/feed/NutrientEditor.vue'; // 导入新组件
|
||||||
import { FeedApi } from '../../api/feed';
|
import { FeedApi } from '../../api/feed';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -51,66 +66,63 @@ export default {
|
|||||||
RawMaterialTable,
|
RawMaterialTable,
|
||||||
Refresh,
|
Refresh,
|
||||||
RawMaterialForm,
|
RawMaterialForm,
|
||||||
|
NutrientEditor, // 注册新组件
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const rawMaterialTableRef = ref(null);
|
const rawMaterialTableRef = ref(null);
|
||||||
const rawMaterialFormRef = ref(null); // 用于引用 RawMaterialForm 组件
|
const rawMaterialFormRef = ref(null);
|
||||||
const showDialog = ref(false);
|
const showDialog = ref(false);
|
||||||
const isEditMode = ref(false); // 标识当前是新增模式还是编辑模式
|
const isEditMode = ref(false);
|
||||||
const currentEditData = ref(null); // 存储当前正在编辑的原料数据
|
const currentEditData = ref(null);
|
||||||
const formTitle = ref('添加原料');
|
const formTitle = ref('添加原料');
|
||||||
|
|
||||||
|
// 用于营养成分编辑弹窗
|
||||||
|
const showNutrientDialog = ref(false);
|
||||||
|
const currentNutrientEditData = ref(null);
|
||||||
|
|
||||||
const refreshList = () => {
|
const refreshList = () => {
|
||||||
if (rawMaterialTableRef.value) {
|
if (rawMaterialTableRef.value) {
|
||||||
rawMaterialTableRef.value.fetchRawMaterials();
|
rawMaterialTableRef.value.fetchRawMaterials();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理添加原料按钮点击事件
|
|
||||||
const handleAddRawMaterial = () => {
|
const handleAddRawMaterial = () => {
|
||||||
formTitle.value = '添加原料';
|
formTitle.value = '添加原料';
|
||||||
isEditMode.value = false; // 新增模式
|
isEditMode.value = false;
|
||||||
currentEditData.value = null; // 清空编辑数据
|
currentEditData.value = null;
|
||||||
showDialog.value = true;
|
showDialog.value = true;
|
||||||
// 在 nextTick 中执行,确保 DOM 更新完成,表单组件被渲染后才调用 resetForm
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
rawMaterialFormRef.value?.resetForm();
|
rawMaterialFormRef.value?.resetForm();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理编辑按钮点击事件
|
|
||||||
const handleEdit = (row) => {
|
const handleEdit = (row) => {
|
||||||
formTitle.value = '编辑原料';
|
formTitle.value = '编辑原料';
|
||||||
isEditMode.value = true; // 编辑模式
|
isEditMode.value = true;
|
||||||
currentEditData.value = { ...row }; // 存储当前编辑数据,进行深拷贝
|
currentEditData.value = { ...row };
|
||||||
showDialog.value = true;
|
showDialog.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理表单提交
|
|
||||||
const handleSubmit = async (formData) => {
|
const handleSubmit = async (formData) => {
|
||||||
try {
|
try {
|
||||||
let message = '';
|
let message = '';
|
||||||
if (isEditMode.value) {
|
if (isEditMode.value) {
|
||||||
// 编辑模式
|
|
||||||
await FeedApi.updateRawMaterial(currentEditData.value.id, formData);
|
await FeedApi.updateRawMaterial(currentEditData.value.id, formData);
|
||||||
message = '原料更新成功';
|
message = '原料更新成功';
|
||||||
} else {
|
} else {
|
||||||
// 新增模式
|
|
||||||
await FeedApi.createRawMaterial(formData);
|
await FeedApi.createRawMaterial(formData);
|
||||||
message = '原料添加成功';
|
message = '原料添加成功';
|
||||||
}
|
}
|
||||||
ElMessage.success(message);
|
ElMessage.success(message);
|
||||||
refreshList(); // 刷新列表
|
refreshList();
|
||||||
showDialog.value = false; // 关闭弹窗
|
showDialog.value = false;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('操作失败: ' + (error.message || '未知错误'));
|
ElMessage.error('操作失败: ' + (error.message || '未知错误'));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理弹窗取消或关闭
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
showDialog.value = false;
|
showDialog.value = false;
|
||||||
// 关闭弹窗时重置表单和编辑状态
|
|
||||||
if (rawMaterialFormRef.value) {
|
if (rawMaterialFormRef.value) {
|
||||||
rawMaterialFormRef.value.resetForm();
|
rawMaterialFormRef.value.resetForm();
|
||||||
}
|
}
|
||||||
@@ -118,6 +130,29 @@ export default {
|
|||||||
currentEditData.value = null;
|
currentEditData.value = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleEditNutrients = (row) => {
|
||||||
|
currentNutrientEditData.value = { ...row };
|
||||||
|
showNutrientDialog.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理营养成分保存
|
||||||
|
const handleNutrientSubmit = async (data) => {
|
||||||
|
try {
|
||||||
|
await FeedApi.updateRawMaterialNutrients(currentNutrientEditData.value.id, data);
|
||||||
|
ElMessage.success('营养成分更新成功');
|
||||||
|
showNutrientDialog.value = false;
|
||||||
|
refreshList(); // 刷新列表以显示最新数据
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('保存失败: ' + (error.message || '未知错误'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理营养成分弹窗取消
|
||||||
|
const handleNutrientCancel = () => {
|
||||||
|
showNutrientDialog.value = false;
|
||||||
|
currentNutrientEditData.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
rawMaterialTableRef,
|
rawMaterialTableRef,
|
||||||
rawMaterialFormRef,
|
rawMaterialFormRef,
|
||||||
@@ -130,6 +165,12 @@ export default {
|
|||||||
handleEdit,
|
handleEdit,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
handleCancel,
|
handleCancel,
|
||||||
|
// 营养成分编辑
|
||||||
|
showNutrientDialog,
|
||||||
|
currentNutrientEditData,
|
||||||
|
handleEditNutrients,
|
||||||
|
handleNutrientSubmit,
|
||||||
|
handleNutrientCancel,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user