feat(recipe edit page): 菜谱编辑页增加添加食材功能
菜谱编辑页增加添加食材功能 Signed-off-by: Ching <loooching@gmail.com>
This commit is contained in:
parent
54819c6861
commit
1c424275f1
@ -27,7 +27,6 @@ DEBUG = True
|
|||||||
|
|
||||||
ALLOWED_HOSTS = []
|
ALLOWED_HOSTS = []
|
||||||
|
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
|
|||||||
@ -138,7 +138,7 @@ export default {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
axios
|
axios
|
||||||
.put(config.publicPath + '/recipe/recipe/' + recipe_id, data)
|
.put(config.publicPath + '/recipe/recipe/' + recipe_id + '/', data)
|
||||||
.then(function () {
|
.then(function () {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: '修改成功.',
|
message: '修改成功.',
|
||||||
@ -152,7 +152,7 @@ export default {
|
|||||||
},
|
},
|
||||||
onSubmitDelete(recipe_id) {
|
onSubmitDelete(recipe_id) {
|
||||||
axios
|
axios
|
||||||
.delete(config.publicPath + '/recipe/recipe/' + recipe_id)
|
.delete(config.publicPath + '/recipe/recipe/' + recipe_id + '/')
|
||||||
.then(function () {
|
.then(function () {
|
||||||
ElMessage.error('删除成功.');
|
ElMessage.error('删除成功.');
|
||||||
location.reload();
|
location.reload();
|
||||||
|
|||||||
@ -42,6 +42,57 @@
|
|||||||
type="textarea"
|
type="textarea"
|
||||||
/>
|
/>
|
||||||
</van-cell-group>
|
</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">
|
<div class="recipe-create">
|
||||||
<van-row gutter="20">
|
<van-row gutter="20">
|
||||||
<van-col span="8" v-if="recipe_id">
|
<van-col span="8" v-if="recipe_id">
|
||||||
@ -93,6 +144,7 @@ import {
|
|||||||
Form,
|
Form,
|
||||||
Field,
|
Field,
|
||||||
CellGroup,
|
CellGroup,
|
||||||
|
Cell,
|
||||||
Radio,
|
Radio,
|
||||||
RadioGroup,
|
RadioGroup,
|
||||||
Rate,
|
Rate,
|
||||||
@ -100,11 +152,15 @@ import {
|
|||||||
Toast,
|
Toast,
|
||||||
Col,
|
Col,
|
||||||
Row,
|
Row,
|
||||||
|
Stepper,
|
||||||
|
Popup,
|
||||||
|
Picker,
|
||||||
} from 'vant';
|
} from 'vant';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import config from '@/config/index';
|
import config from '@/config/index';
|
||||||
import router from '@/router/index';
|
import router from '@/router/index';
|
||||||
import constants from '@/utils/constants.js';
|
import constants from '@/utils/constants.js';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['recipe_'],
|
props: ['recipe_'],
|
||||||
@ -118,14 +174,23 @@ export default {
|
|||||||
[Form.name]: Form,
|
[Form.name]: Form,
|
||||||
[Field.name]: Field,
|
[Field.name]: Field,
|
||||||
[CellGroup.name]: CellGroup,
|
[CellGroup.name]: CellGroup,
|
||||||
|
[Cell.name]: Cell,
|
||||||
[Radio.name]: Radio,
|
[Radio.name]: Radio,
|
||||||
[RadioGroup.name]: RadioGroup,
|
[RadioGroup.name]: RadioGroup,
|
||||||
[Rate.name]: Rate,
|
[Rate.name]: Rate,
|
||||||
[Button.name]: Button,
|
[Button.name]: Button,
|
||||||
[Col.name]: Col,
|
[Col.name]: Col,
|
||||||
[Row.name]: Row,
|
[Row.name]: Row,
|
||||||
|
[Stepper.name]: Stepper,
|
||||||
|
[Popup.name]: Popup,
|
||||||
|
[Picker.name]: Picker,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
const customFieldName = {
|
||||||
|
text: 'name',
|
||||||
|
};
|
||||||
|
const showIngredientPicker = ref(false);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
form: {
|
form: {
|
||||||
name: null,
|
name: null,
|
||||||
@ -133,12 +198,18 @@ export default {
|
|||||||
rate: 0,
|
rate: 0,
|
||||||
difficulty: 0,
|
difficulty: 0,
|
||||||
note: null,
|
note: null,
|
||||||
|
recipe_ingredients: null,
|
||||||
},
|
},
|
||||||
loading: false,
|
loading: false,
|
||||||
recipe_id: null,
|
recipe_id: null,
|
||||||
|
ingredient_columns: null,
|
||||||
|
customFieldName,
|
||||||
|
showIngredientPicker,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {},
|
mounted() {
|
||||||
|
this.getIngredients();
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onSubmit(recipe_id) {
|
onSubmit(recipe_id) {
|
||||||
if (!this.form.name) {
|
if (!this.form.name) {
|
||||||
@ -153,6 +224,9 @@ export default {
|
|||||||
difficulty: this.form.difficulty,
|
difficulty: this.form.difficulty,
|
||||||
rate: this.form.rate,
|
rate: this.form.rate,
|
||||||
note: this.form.note ? this.form.note : null,
|
note: this.form.note ? this.form.note : null,
|
||||||
|
recipe_ingredients: this.form.recipe_ingredients
|
||||||
|
? this.form.recipe_ingredients
|
||||||
|
: [],
|
||||||
};
|
};
|
||||||
if (!recipe_id) {
|
if (!recipe_id) {
|
||||||
axios
|
axios
|
||||||
@ -161,13 +235,18 @@ export default {
|
|||||||
(response) => (response, router.push({ name: 'RecipeMobileHome' }))
|
(response) => (response, router.push({ name: 'RecipeMobileHome' }))
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
axios.put(config.publicPath + '/recipe/recipe/' + recipe_id, data).then(
|
axios
|
||||||
(Toast.success({
|
.put(config.publicPath + '/recipe/recipe/' + recipe_id + '/', data)
|
||||||
|
.then(
|
||||||
|
(response) => (
|
||||||
|
response,
|
||||||
|
Toast.success({
|
||||||
message: '修改成功',
|
message: '修改成功',
|
||||||
forbidClick: true,
|
forbidClick: true,
|
||||||
duration: 500,
|
duration: 500,
|
||||||
}),
|
}),
|
||||||
(this.loading = false))
|
(this.loading = false)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -176,7 +255,9 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
axios.delete(config.publicPath + '/recipe/recipe/' + recipe_id).then(
|
axios
|
||||||
|
.delete(config.publicPath + '/recipe/recipe/' + recipe_id + '/')
|
||||||
|
.then(
|
||||||
(Toast.success({
|
(Toast.success({
|
||||||
message: '删除成功',
|
message: '删除成功',
|
||||||
forbidClick: true,
|
forbidClick: true,
|
||||||
@ -185,6 +266,46 @@ export default {
|
|||||||
(this.loading = false))
|
(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: 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;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -21,7 +21,7 @@ export default {
|
|||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
axios
|
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));
|
.then((response) => (this.recipe = response.data));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,12 +2,8 @@
|
|||||||
<el-container>
|
<el-container>
|
||||||
<el-header>
|
<el-header>
|
||||||
<el-menu mode="horizontal" default-active="#" router>
|
<el-menu mode="horizontal" default-active="#" router>
|
||||||
<el-menu-item index="/">
|
<el-menu-item index="/"> 首页 </el-menu-item>
|
||||||
首页
|
<el-menu-item index="/week-recipe/"> 每周菜谱 </el-menu-item>
|
||||||
</el-menu-item>
|
|
||||||
<el-menu-item index="/week-recipe/">
|
|
||||||
每周菜谱
|
|
||||||
</el-menu-item>
|
|
||||||
<el-menu-item index="#">
|
<el-menu-item index="#">
|
||||||
{{ recipe.name }}
|
{{ recipe.name }}
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
@ -41,7 +37,7 @@ export default {
|
|||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
axios
|
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));
|
.then((response) => (this.recipe = response.data));
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@ -5,6 +5,8 @@ from utils import const
|
|||||||
|
|
||||||
|
|
||||||
class IngredientSerializer(serializers.ModelSerializer):
|
class IngredientSerializer(serializers.ModelSerializer):
|
||||||
|
id = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = recipe.models.Ingredient
|
model = recipe.models.Ingredient
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
@ -28,16 +30,7 @@ class RecipeIngredientSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
class RecipeSerializer(serializers.ModelSerializer):
|
class RecipeSerializer(serializers.ModelSerializer):
|
||||||
id = serializers.IntegerField(read_only=True)
|
id = serializers.IntegerField(read_only=True)
|
||||||
recipe_ingredients = RecipeIngredientSerializer(many=True)
|
recipe_ingredients = RecipeIngredientSerializer(many=True, read_only=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)
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
if 'recipe_ingredients' in validated_data:
|
if 'recipe_ingredients' in validated_data:
|
||||||
|
|||||||
@ -25,6 +25,34 @@ class RecipeAPI(viewsets.ModelViewSet):
|
|||||||
instance.status = const.RECIPE_STATUS_DELETED
|
instance.status = const.RECIPE_STATUS_DELETED
|
||||||
instance.save(update_fields=['status'])
|
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):
|
def list(self, request, *args, **kwargs):
|
||||||
self.queryset = recipe.models.Recipe.objects.exclude(status=const.RECIPE_STATUS_DELETED)
|
self.queryset = recipe.models.Recipe.objects.exclude(status=const.RECIPE_STATUS_DELETED)
|
||||||
return super().list(request, *args, **kwargs)
|
return super().list(request, *args, **kwargs)
|
||||||
|
|||||||
@ -10,7 +10,6 @@ reload(sys)
|
|||||||
|
|
||||||
import utils.lark
|
import utils.lark
|
||||||
import git
|
import git
|
||||||
import ipdb
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# def notify():
|
# def notify():
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user