diff --git a/dsite/settings_default.py b/dsite/settings_default.py index f2065ab..2495fb8 100644 --- a/dsite/settings_default.py +++ b/dsite/settings_default.py @@ -27,7 +27,6 @@ DEBUG = True ALLOWED_HOSTS = [] - # Application definition INSTALLED_APPS = [ diff --git a/frontend/src/components/input_recipe.vue b/frontend/src/components/input_recipe.vue index dda6ea6..7dafe3b 100644 --- a/frontend/src/components/input_recipe.vue +++ b/frontend/src/components/input_recipe.vue @@ -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(); diff --git a/frontend/src/components/recipe-mobile/recipe-edit.vue b/frontend/src/components/recipe-mobile/recipe-edit.vue index 3a8bd98..5502ca9 100644 --- a/frontend/src/components/recipe-mobile/recipe-edit.vue +++ b/frontend/src/components/recipe-mobile/recipe-edit.vue @@ -42,6 +42,57 @@ type="textarea" /> + + + + + + + +
+ + + 添加食材 + + +
+ + + +
@@ -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; }, }, }; diff --git a/frontend/src/views/recipe-mobile/RecipeDetail.vue b/frontend/src/views/recipe-mobile/RecipeDetail.vue index e26ec75..b58be04 100644 --- a/frontend/src/views/recipe-mobile/RecipeDetail.vue +++ b/frontend/src/views/recipe-mobile/RecipeDetail.vue @@ -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)); }, }; diff --git a/frontend/src/views/recipeDetail.vue b/frontend/src/views/recipeDetail.vue index 4489ce3..e66c809 100644 --- a/frontend/src/views/recipeDetail.vue +++ b/frontend/src/views/recipeDetail.vue @@ -2,12 +2,8 @@ - - 首页 - - - 每周菜谱 - + 首页 + 每周菜谱 {{ recipe.name }} @@ -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: { diff --git a/recipe/serializers.py b/recipe/serializers.py index 92d89a2..784d918 100644 --- a/recipe/serializers.py +++ b/recipe/serializers.py @@ -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: diff --git a/recipe/views.py b/recipe/views.py index 3739297..57d316d 100644 --- a/recipe/views.py +++ b/recipe/views.py @@ -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) diff --git a/utils/depoly_notify.py b/utils/depoly_notify.py index deda3ac..de3c9d0 100755 --- a/utils/depoly_notify.py +++ b/utils/depoly_notify.py @@ -10,7 +10,6 @@ reload(sys) import utils.lark import git -import ipdb if __name__ == '__main__': # def notify():