feat(recipe edit page): 菜谱编辑页增加添加食材功能

菜谱编辑页增加添加食材功能

Signed-off-by: Ching <loooching@gmail.com>
This commit is contained in:
Ching 2022-02-13 18:01:51 +08:00
parent 54819c6861
commit 1c424275f1
8 changed files with 175 additions and 39 deletions

View File

@ -27,7 +27,6 @@ DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [

View File

@ -138,7 +138,7 @@ export default {
});
} else {
axios
.put(config.publicPath + '/recipe/recipe/' + recipe_id, data)
.put(config.publicPath + '/recipe/recipe/' + recipe_id + '/', data)
.then(function () {
ElMessage({
message: '修改成功.',
@ -152,7 +152,7 @@ export default {
},
onSubmitDelete(recipe_id) {
axios
.delete(config.publicPath + '/recipe/recipe/' + recipe_id)
.delete(config.publicPath + '/recipe/recipe/' + recipe_id + '/')
.then(function () {
ElMessage.error('删除成功.');
location.reload();

View File

@ -42,6 +42,57 @@
type="textarea"
/>
</van-cell-group>
<van-cell-group
class="recipe-create"
inset
border
v-if="form.recipe_ingredients && form.recipe_ingredients.length > 0"
title="数量为 0 的食材将被删除"
>
<van-cell
v-bind:title="recipe_ingredient.ingredient.name"
v-for="recipe_ingredient in form.recipe_ingredients"
:key="recipe_ingredient.id"
>
<template #value>
<van-stepper
v-model.number="recipe_ingredient.quantity"
default-value="recipe_ingredient.quantity"
:decimal-length="1"
allow-empty="true"
min="0"
/>
{{ recipe_ingredient.ingredient.unit }}
</template>
</van-cell>
</van-cell-group>
<div class="recipe-create">
<van-row gutter="20">
<van-col span="24">
<van-button
icon="plus"
type="primary"
plain
round
hairline
class="submit-button"
@click="showIngredientPicker = true"
>添加食材</van-button
>
</van-col>
</van-row>
</div>
<van-popup v-model:show="showIngredientPicker" round position="bottom">
<van-picker
:columns="ingredient_columns"
:columns-field-names="customFieldName"
@cancel="showIngredientPicker = false"
@confirm="onConfirmIngredient"
/>
</van-popup>
<div class="recipe-create">
<van-row gutter="20">
<van-col span="8" v-if="recipe_id">
@ -93,6 +144,7 @@ import {
Form,
Field,
CellGroup,
Cell,
Radio,
RadioGroup,
Rate,
@ -100,11 +152,15 @@ import {
Toast,
Col,
Row,
Stepper,
Popup,
Picker,
} from 'vant';
import axios from 'axios';
import config from '@/config/index';
import router from '@/router/index';
import constants from '@/utils/constants.js';
import { ref } from 'vue';
export default {
props: ['recipe_'],
@ -118,14 +174,23 @@ export default {
[Form.name]: Form,
[Field.name]: Field,
[CellGroup.name]: CellGroup,
[Cell.name]: Cell,
[Radio.name]: Radio,
[RadioGroup.name]: RadioGroup,
[Rate.name]: Rate,
[Button.name]: Button,
[Col.name]: Col,
[Row.name]: Row,
[Stepper.name]: Stepper,
[Popup.name]: Popup,
[Picker.name]: Picker,
},
data() {
const customFieldName = {
text: 'name',
};
const showIngredientPicker = ref(false);
return {
form: {
name: null,
@ -133,12 +198,18 @@ export default {
rate: 0,
difficulty: 0,
note: null,
recipe_ingredients: null,
},
loading: false,
recipe_id: null,
ingredient_columns: null,
customFieldName,
showIngredientPicker,
};
},
mounted() {},
mounted() {
this.getIngredients();
},
methods: {
onSubmit(recipe_id) {
if (!this.form.name) {
@ -153,6 +224,9 @@ export default {
difficulty: this.form.difficulty,
rate: this.form.rate,
note: this.form.note ? this.form.note : null,
recipe_ingredients: this.form.recipe_ingredients
? this.form.recipe_ingredients
: [],
};
if (!recipe_id) {
axios
@ -161,14 +235,19 @@ export default {
(response) => (response, router.push({ name: 'RecipeMobileHome' }))
);
} else {
axios.put(config.publicPath + '/recipe/recipe/' + recipe_id, data).then(
(Toast.success({
message: '修改成功',
forbidClick: true,
duration: 500,
}),
(this.loading = false))
);
axios
.put(config.publicPath + '/recipe/recipe/' + recipe_id + '/', data)
.then(
(response) => (
response,
Toast.success({
message: '修改成功',
forbidClick: true,
duration: 500,
}),
(this.loading = false)
)
);
}
},
onSubmitDelete(recipe_id) {
@ -176,14 +255,56 @@ export default {
return;
}
this.loading = true;
axios.delete(config.publicPath + '/recipe/recipe/' + recipe_id).then(
(Toast.success({
message: '删除成功',
axios
.delete(config.publicPath + '/recipe/recipe/' + recipe_id + '/')
.then(
(Toast.success({
message: '删除成功',
forbidClick: true,
duration: 500,
}),
(this.loading = false))
);
},
getIngredients() {
axios.get(config.publicPath + '/recipe/ingredient/').then((response) => {
(this.ingredient_columns = response.data['results']),
console.log('ingredient_columns', this.ingredient_columns);
});
},
onConfirmIngredient(value) {
var exists = false;
this.showIngredientPicker = false;
if (this.form.recipe_ingredients === null) {
this.form.recipe_ingredients = [];
}
for (let i = 0; i < this.form.recipe_ingredients.length; i++) {
if (this.form.recipe_ingredients[i].ingredient.id == value.id) {
exists = true;
break;
}
}
if (exists) {
Toast.fail({
message: '该食材已存在',
forbidClick: true,
duration: 500,
}),
(this.loading = false))
);
duration: 800,
});
} else {
this.form.recipe_ingredients.push({
id: 0,
ingredient: {
id: value.id,
name: value.name,
unit: value.unit,
}, //
});
}
},
onChangeIngredientQuantity(value) {
console.log('onChangeIngredientQuantity', value);
console.log('recipe ingerdients ', this.form.recipe_ingredients);
// this.form.recipe_ingredients[value.index].quantity = value.quantity;
},
},
};

View File

@ -21,7 +21,7 @@ export default {
},
mounted() {
axios
.get(config.publicPath + '/recipe/recipe/' + this.$route.params.id)
.get(config.publicPath + '/recipe/recipe/' + this.$route.params.id + '/')
.then((response) => (this.recipe = response.data));
},
};

View File

@ -2,12 +2,8 @@
<el-container>
<el-header>
<el-menu mode="horizontal" default-active="#" router>
<el-menu-item index="/">
首页
</el-menu-item>
<el-menu-item index="/week-recipe/">
每周菜谱
</el-menu-item>
<el-menu-item index="/"> 首页 </el-menu-item>
<el-menu-item index="/week-recipe/"> 每周菜谱 </el-menu-item>
<el-menu-item index="#">
{{ recipe.name }}
</el-menu-item>
@ -33,7 +29,7 @@ import config from '@/config/index';
export default {
name: 'RecipeDetail',
components: { input_recipe },
data: function() {
data: function () {
return {
recipe: {},
constants: constants,
@ -41,7 +37,7 @@ export default {
},
mounted() {
axios
.get(config.publicPath + '/recipe/recipe/' + this.$route.params.id)
.get(config.publicPath + '/recipe/recipe/' + this.$route.params.id + '/')
.then((response) => (this.recipe = response.data));
},
methods: {

View File

@ -5,6 +5,8 @@ from utils import const
class IngredientSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(read_only=True)
class Meta:
model = recipe.models.Ingredient
fields = '__all__'
@ -28,16 +30,7 @@ class RecipeIngredientSerializer(serializers.ModelSerializer):
class RecipeSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(read_only=True)
recipe_ingredients = RecipeIngredientSerializer(many=True)
def update(self, instance, validated_data):
if 'recipe_ingredients' in validated_data:
recipe_ingredients = validated_data.pop('recipe_ingredients')
if recipe_ingredients:
for recipe_ingredient in recipe_ingredients:
recipe_ingredient['recipe'] = instance
RecipeIngredientSerializer.update(recipe_ingredient)
return super().update(instance, validated_data)
recipe_ingredients = RecipeIngredientSerializer(many=True, read_only=True)
def create(self, validated_data):
if 'recipe_ingredients' in validated_data:

View File

@ -25,6 +25,34 @@ class RecipeAPI(viewsets.ModelViewSet):
instance.status = const.RECIPE_STATUS_DELETED
instance.save(update_fields=['status'])
def perform_update(self, serializer):
instance = self.get_object()
if 'recipe_ingredients' in self.request.data:
recipe_ingredients = self.request.data.pop('recipe_ingredients')
if recipe_ingredients:
for recipe_ingredient in recipe_ingredients:
# 没有 id 则新增食材
if not recipe_ingredient['id'] and recipe_ingredient['quantity']:
ingredient = recipe.models.Ingredient.objects.get(id=recipe_ingredient['ingredient']['id'])
del recipe_ingredient['ingredient']
del recipe_ingredient['id']
recipe.models.RecipeIngredient.objects.create(
recipe=instance, ingredient=ingredient, **recipe_ingredient
)
# 有 id 没数量则删除食材
elif recipe_ingredient['id'] and not recipe_ingredient['quantity']:
recipe.models.RecipeIngredient.objects.filter(id=recipe_ingredient['id']).update(
status=const.INGREDIENT_STATUS_DELETED
)
# 有 id 有数量则更新食材
elif recipe_ingredient['id'] and recipe_ingredient['quantity']:
del recipe_ingredient['ingredient']
recipe.models.RecipeIngredient.objects.filter(id=recipe_ingredient['id']).update(
**recipe_ingredient
)
return super().perform_update(serializer)
def list(self, request, *args, **kwargs):
self.queryset = recipe.models.Recipe.objects.exclude(status=const.RECIPE_STATUS_DELETED)
return super().list(request, *args, **kwargs)

View File

@ -10,7 +10,6 @@ reload(sys)
import utils.lark
import git
import ipdb
if __name__ == '__main__':
# def notify():