无法读取Vue JS中未定义的属性'reduce'

时间:2020-01-24 08:59:36

标签: laravel vue.js nuxt.js

我想获取数据进行编辑时出现vue.js问题,并且出现以下错误:

无法读取未定义的属性'reduce'

但是当我使用console.log时,数据是正确的。我尝试花更多时间在代码上更改this.$set(this.$data, "form", res.returnsale)中的fetchRuturn,然后出现此错误。

<template>
  <v-app>
<v-card class="mx-5 my-5">
  <div class="teal darken-1">
    <v-card-title class="white--text">Edit​ Return Sale</v-card-title>
  </div>
  <v-divider></v-divider>
  <div class="px-5">
    <p class="caption font-italic pt-5">The field labels marked with * are required input fields.</p>
    <v-row>
      <v-col md="6" cols="12">
        <label for="reference_no" class="font-weight-bold">Reference No</label>
        <v-text-field solo outlined dense v-model="form.reference_no"></v-text-field>
      </v-col>
      <v-col md="6" cols="12">
        <label class="font-weight-bold">Location*</label>
        <v-autocomplete item-value="address" item-text="address" solo outlined dense label="Business Location"
          return-object v-model="form.location" :items="locations"></v-autocomplete>
      </v-col>
      <v-col md="6" cols="12">
        <label class="font-weight-bold">Supplier</label>
        <v-autocomplete :items="suppliers" item-text="name" item-value="name" solo outlined dense return-object
          v-model="form.supplier" label="Select Supplier"></v-autocomplete>
      </v-col>
      <v-col md="6" cols="12">
        <label class="font-weight-bold">Account</label>
        <v-autocomplete :items="accounts" item-text="name" item-value="name" solo outlined dense return-object
          v-model="form.account" label="Select Account"></v-autocomplete>
      </v-col>

      <v-col cols="12">
        <label class="font-weight-bold">Select Product</label>
        <div>
          <v-autocomplete dense solo item-text="name" item-value="name" return-object :items="products"
            @input="addTocart"></v-autocomplete>
        </div>
      </v-col>
    </v-row>
    <div>
      <label class="font-weight-bold mb-3">Product Table</label>
      <table class="tableReturn">
        <thead>
          <tr class="tableReturn--header">
            <td>Name</td>
            <td>Code</td>
            <td>Quantity</td>
            <td>Unit Price</td>
            <td>Discount</td>
            <td>Total</td>
            <td>Actions</td>
          </tr>
        </thead>
        <tbody>
          <tr class="tableReturn--td" v-for="(item, index) in form.items" :key="index">
            <td>{{item.name}}</td>
            <td>{{item.code}}</td>
            <td>
              <input type="number" class="table-quantity" v-model="form.items[index].quantity" />
            </td>
            <td>
              <input type="number" class="table-quantity" v-model="form.items[index].unit_price"
                placeholder="0.00" />
            </td>
            <td>
              <input type="number" class="table-quantity" v-model="form.items[index].discount" placeholder="0.00" />
            </td>
            <td>USD {{ discountedPrice(item) | formatMoney }}</td>
            <td>
              <v-btn small color="red" outlined @click="removeItem(index)">
                <v-icon>mdi-delete</v-icon>
              </v-btn>
            </td>
          </tr>
          <tr>
            <td class="py-5" colspan="2">Total</td>
            <td colspan="3">{{ Qty }}</td>
            <td>USD {{ Total | formatMoney }}</td>
          </tr>
        </tbody>
      </table>
    </div>

    <v-row>
      <v-col md="6" cols="12">
        <div class="d-flex flex-column mb-5">
          <label for="" class="font-weight-bold">Return Note</label>
          <textarea cols="30" rows="5" class="textarea" v-model="form.return_des"></textarea>
        </div>
      </v-col>
      <v-col md="6" cols="12">
        <div class="d-flex flex-column mb-5">
          <label for="" class="font-weight-bold">Staff Note</label>
          <textarea cols="30" rows="5" class="textarea" v-model="form.staff_des"></textarea>
        </div>
      </v-col>
    </v-row>
  </div>
  <v-btn @click.prevent="updateReturn" class="blue mx-5 darken-2 mb-5 grey--text text--lighten-4">
    <v-icon>mdi-check</v-icon>Update
  </v-btn>
</v-card>
  </v-app>
</template>

<script>
  import Vue from "vue";

  let numeral = require('numeral');

  Vue.filter('formatMoney', function (value) {
return numeral(value).format('00,00.00')
  });

  export default {

name: "editReturn",

created() {

  this.fetchReturn();
  this.fetchLocation();
  this.fetchSupplier();
  this.fetchAccount();
  this.fetchProduct();

},

data() {
  return {
    form: {
      items: []
    },
    suppliers: [],
    locations: [],
    products: [],
    returnsale: [],
    accounts: []
  };
},

computed: {
  Qty() {
    return this.form.items.reduce((total, item) => {
      return total + Number(item.quantity);
    }, 0);
  },

  Total() {
    return this.form.items.reduce((total, item) => {
      let subtotal = (item.unit_price - (item.unit_price * item.discount) / 100) *
        item.quantity
      return total + subtotal;
    }, 0);
  }
},

methods: {
  discountedPrice(product) {
    return (
      (product.unit_price -
        (product.unit_price * product.discount) / 100) *
      product.quantity
    );
  },

  fetchLocation() {
    this.$axios.$get(`api/location`)
      .then(res => {
        // this.locations = res.locations.data;
        this.$set(this.$data, "locations", res.locations.data);
        console.log(res);
      })
      .catch(err => {
        console.log(err.response);
      });
  },

  fetchSupplier() {
    this.$axios.$get(`api/supplier`)
      .then(res => {
        this.$set(this.$data, "suppliers", res.suppliers.data);
        console.log(res);
      })
      .catch(err => {
        console.log(err.response);
      });
  },

  fetchAccount() {
    this.$axios.$get(`api/account`)
      .then(res => {
        this.$set(this.$data, "accounts", res.accounts);
        console.log(res)
      })
      .catch(err => {
        console.log(err.response);
      });
  },

  fetchProduct() {
    this.$axios
      .$get(`/api/product`)
      .then(res => {
        this.$set(this.$data, "products", res.products.data);
        console.log(res);
      })
      .catch(err => {
        console.log(err);
      });
  },

  fetchReturn() {
    this.$axios
      .$get(`api/return-sale/` + this.$route.params.id)
      .then(res => {
        this.$set(this.$data, "form", res.returnsale);
        console.log(res);

        for (let i in this.form.items) {
          Vue.set(this.form.items[i], 'quantity', this.form.items[i].pivot.quantity);
          Vue.set(this.form.items[i], 'unit_price', this.form.items[i].pivot.unit_price);
          Vue.set(this.form.items[i], 'discount', this.form.items[i].pivot.discount);
        }
      })
      .catch(err => {
        console.log(res.response);
      });
  },

  updateReturn() {
    this.$axios
      .$patch(`api/return-sale/` + this.form.id, {

        location: this.form.location,
        products: this.form.products,
        supplier: this.form.supplier,
        account: this.form.account,
        return_des: this.form.return_des,
        staff_des: this.form.staff_des,

      })
      .then(res => {
        this.returnsale = res.data;
        // this.$set(this.$data, "returnsale", res.data);
        this.$set(this.$data, "returnsale", res.returnsale);
        this.$router.push(`/return/return-sale/view`);
        console.log(res);
      })
      .catch(err => {
        console.log(err.response);
      });
  },

  addTocart(item) {
    if (this.form.items.includes(item)) {
      alert("already there");
    } else {
      this.form.items.push(item);
    }
    Vue.set(item, 'quantity', 1);
    Vue.set(item, 'discount', 1);
  },

  removeItem(index) {
    this.form.items.splice(index, 1);
  }
}
  };
</script>

<style lang="scss">
  .textarea {
border: 1px solid rgba(0, 0, 0, 0.125);
outline: 1px solid #461577;
  }

  .tableReturn {
width: 100%;
margin-top: 10px;
border-collapse: collapse;

&--header {
  font-weight: 500;
  text-align: left;
  border-bottom: 1px solid rgba(0, 0, 0, 0.125);
}

&--td {
  border-bottom: 1px solid rgba(0, 0, 0, 0.125);
}
  }

  .table-quantity {
border: 1px solid rgba(0, 0, 0, 0.125);
padding: 5px 10px 5px 10px;
margin-top: 5px;
margin-bottom: 5px;
  }
</style>

enter image description here

1 个答案:

答案 0 :(得分:1)

尝试一下

我添加了一张支票if (this.form.hasOwnProperty("items")) 如果形式有价值,那么只有它才能发挥作用

<template>
  <v-app>
    <v-card class="mx-5 my-5">
      <div class="teal darken-1">
        <v-card-title class="white--text">Edit​ Return Sale</v-card-title>
      </div>
      <v-divider></v-divider>
      <div class="px-5">
        <p
          class="caption font-italic pt-5"
        >The field labels marked with * are required input fields.</p>
        <v-row>
          <v-col md="6" cols="12">
            <label for="reference_no" class="font-weight-bold">Reference No</label>
            <v-text-field solo outlined dense v-model="form.reference_no"></v-text-field>
          </v-col>
          <v-col md="6" cols="12">
            <label class="font-weight-bold">Location*</label>
            <v-autocomplete
              item-value="address"
              item-text="address"
              solo
              outlined
              dense
              label="Business Location"
              return-object
              v-model="form.location"
              :items="locations"
            ></v-autocomplete>
          </v-col>
          <v-col md="6" cols="12">
            <label class="font-weight-bold">Supplier</label>
            <v-autocomplete
              :items="suppliers"
              item-text="name"
              item-value="name"
              solo
              outlined
              dense
              return-object
              v-model="form.supplier"
              label="Select Supplier"
            ></v-autocomplete>
          </v-col>
          <v-col md="6" cols="12">
            <label class="font-weight-bold">Account</label>
            <v-autocomplete
              :items="accounts"
              item-text="name"
              item-value="name"
              solo
              outlined
              dense
              return-object
              v-model="form.account"
              label="Select Account"
            ></v-autocomplete>
          </v-col>

          <v-col cols="12">
            <label class="font-weight-bold">Select Product</label>
            <div>
              <v-autocomplete
                dense
                solo
                item-text="name"
                item-value="name"
                return-object
                :items="products"
                @input="addTocart"
              ></v-autocomplete>
            </div>
          </v-col>
        </v-row>
        <div>
          <label class="font-weight-bold mb-3">Product Table</label>
          <table class="tableReturn">
            <thead>
              <tr class="tableReturn--header">
                <td>Name</td>
                <td>Code</td>
                <td>Quantity</td>
                <td>Unit Price</td>
                <td>Discount</td>
                <td>Total</td>
                <td>Actions</td>
              </tr>
            </thead>
            <tbody>
              <tr class="tableReturn--td" v-for="(item, index) in form.items" :key="index">
                <td>{{item.name}}</td>
                <td>{{item.code}}</td>
                <td>
                  <input type="number" class="table-quantity" v-model="form.items[index].quantity" />
                </td>
                <td>
                  <input
                    type="number"
                    class="table-quantity"
                    v-model="form.items[index].unit_price"
                    placeholder="0.00"
                  />
                </td>
                <td>
                  <input
                    type="number"
                    class="table-quantity"
                    v-model="form.items[index].discount"
                    placeholder="0.00"
                  />
                </td>
                <td>USD {{ discountedPrice(item) | formatMoney }}</td>
                <td>
                  <v-btn small color="red" outlined @click="removeItem(index)">
                    <v-icon>mdi-delete</v-icon>
                  </v-btn>
                </td>
              </tr>
              <tr>
                <td class="py-5" colspan="2">Total</td>
                <td colspan="3">{{ Qty }}</td>
                <td>USD {{ Total | formatMoney }}</td>
              </tr>
            </tbody>
          </table>
        </div>

        <v-row>
          <v-col md="6" cols="12">
            <div class="d-flex flex-column mb-5">
              <label for class="font-weight-bold">Return Note</label>
              <textarea cols="30" rows="5" class="textarea" v-model="form.return_des"></textarea>
            </div>
          </v-col>
          <v-col md="6" cols="12">
            <div class="d-flex flex-column mb-5">
              <label for class="font-weight-bold">Staff Note</label>
              <textarea cols="30" rows="5" class="textarea" v-model="form.staff_des"></textarea>
            </div>
          </v-col>
        </v-row>
      </div>
      <v-btn
        @click.prevent="updateReturn"
        class="blue mx-5 darken-2 mb-5 grey--text text--lighten-4"
      >
        <v-icon>mdi-check</v-icon>Update
      </v-btn>
    </v-card>
  </v-app>
</template>

<script>
import Vue from "vue";

let numeral = require("numeral");

Vue.filter("formatMoney", function(value) {
  return numeral(value).format("00,00.00");
});

export default {
  name: "editReturn",

  created() {
    this.fetchReturn();
    this.fetchLocation();
    this.fetchSupplier();
    this.fetchAccount();
    this.fetchProduct();
  },

  data() {
    return {
      form: {
        items: []
      },
      suppliers: [],
      locations: [],
      products: [],
      returnsale: [],
      accounts: []
    };
  },

  computed: {
    Qty() {
      if (this.form.hasOwnProperty("items")) {
        return this.form.items.reduce((total, item) => {
          return total + Number(item.quantity);
        }, 0);
      }
    },

    Total() {
      if (this.form.hasOwnProperty("items")) {
        return this.form.items.reduce((total, item) => {
          let subtotal =
            (item.unit_price - (item.unit_price * item.discount) / 100) *
            item.quantity;
          return total + subtotal;
        }, 0);
      }
    }
  },

  methods: {
    discountedPrice(product) {
      return (
        (product.unit_price - (product.unit_price * product.discount) / 100) *
        product.quantity
      );
    },

    fetchLocation() {
      this.$axios
        .$get(`api/location`)
        .then(res => {
          // this.locations = res.locations.data;
          this.$set(this.$data, "locations", res.locations.data);
          console.log(res);
        })
        .catch(err => {
          console.log(err.response);
        });
    },

    fetchSupplier() {
      this.$axios
        .$get(`api/supplier`)
        .then(res => {
          this.$set(this.$data, "suppliers", res.suppliers.data);
          console.log(res);
        })
        .catch(err => {
          console.log(err.response);
        });
    },

    fetchAccount() {
      this.$axios
        .$get(`api/account`)
        .then(res => {
          this.$set(this.$data, "accounts", res.accounts);
          console.log(res);
        })
        .catch(err => {
          console.log(err.response);
        });
    },

    fetchProduct() {
      this.$axios
        .$get(`/api/product`)
        .then(res => {
          this.$set(this.$data, "products", res.products.data);
          console.log(res);
        })
        .catch(err => {
          console.log(err);
        });
    },

    fetchReturn() {
      this.$axios
        .$get(`api/return-sale/` + this.$route.params.id)
        .then(res => {
          this.$set(this.$data, "form", res.returnsale);
          console.log(res);

          for (let i in this.form.items) {
            Vue.set(
              this.form.items[i],
              "quantity",
              this.form.items[i].pivot.quantity
            );
            Vue.set(
              this.form.items[i],
              "unit_price",
              this.form.items[i].pivot.unit_price
            );
            Vue.set(
              this.form.items[i],
              "discount",
              this.form.items[i].pivot.discount
            );
          }
        })
        .catch(err => {
          console.log(res.response);
        });
    },

    updateReturn() {
      this.$axios
        .$patch(`api/return-sale/` + this.form.id, {
          location: this.form.location,
          products: this.form.products,
          supplier: this.form.supplier,
          account: this.form.account,
          return_des: this.form.return_des,
          staff_des: this.form.staff_des
        })
        .then(res => {
          this.returnsale = res.data;
          // this.$set(this.$data, "returnsale", res.data);
          this.$set(this.$data, "returnsale", res.returnsale);
          this.$router.push(`/return/return-sale/view`);
          console.log(res);
        })
        .catch(err => {
          console.log(err.response);
        });
    },

    addTocart(item) {
      if (this.form.items.includes(item)) {
        alert("already there");
      } else {
        this.form.items.push(item);
      }
      Vue.set(item, "quantity", 1);
      Vue.set(item, "discount", 1);
    },

    removeItem(index) {
      this.form.items.splice(index, 1);
    }
  }
};
</script>

<style lang="scss">
.textarea {
  border: 1px solid rgba(0, 0, 0, 0.125);
  outline: 1px solid #461577;
}

.tableReturn {
  width: 100%;
  margin-top: 10px;
  border-collapse: collapse;
  &--header {
    font-weight: 500;
    text-align: left;
    border-bottom: 1px solid rgba(0, 0, 0, 0.125);
  }

  &--td {
    border-bottom: 1px solid rgba(0, 0, 0, 0.125);
  }
}

.table-quantity {
  border: 1px solid rgba(0, 0, 0, 0.125);
  padding: 5px 10px 5px 10px;
  margin-top: 5px;
  margin-bottom: 5px;
}
</style>