Javascript v-model未使用vuejs中的开关和选择下拉菜单更改数据

Javascript v-model未使用vuejs中的开关和选择下拉菜单更改数据,javascript,php,laravel,vue.js,axios,Javascript,Php,Laravel,Vue.js,Axios,在laravel和vue的帮助下,我正在用crud生成器制作一个动态管理面板 我有一个从API异步加载数据的表。在我的表格中有一个is_特色列,我想成为一个开关。这样,用户就可以从表格页面更改值,而不是转到编辑页面 要生成整个表,有一个配置对象,其中包含要显示的字段以及该字段的类型和其他元数据。在配置对象中,有一个名为prerender的字段,负责预渲染需要调用其他API的字段或一些可编辑字段,如选择下拉列表或开关 要使开关和选择字段工作,我有一个名为fieldData的空对象。 当找到类型为t

在laravel和vue的帮助下,我正在用crud生成器制作一个动态管理面板

我有一个从API异步加载数据的表。在我的表格中有一个is_特色列,我想成为一个开关。这样,用户就可以从表格页面更改值,而不是转到编辑页面

要生成整个表,有一个配置对象,其中包含要显示的字段以及该字段的类型和其他元数据。在配置对象中,有一个名为
prerender
的字段,负责预渲染需要调用其他API的字段或一些可编辑字段,如选择下拉列表或开关

要使开关和选择字段工作,我有一个名为
fieldData
的空对象。 当找到类型为
type:boolean
prerender:true
的字段时,我的代码将以field.name作为字段数据中的属性名称初始化属性,并用该字段名称下的相应值填充该属性

this.fieldData[field.name] = {};
this.tableData.forEach(
   data => (this.fieldData[field.name][data.id] = data[field.name])
);
但开关和选择按钮在此不起作用

所以我需要帮助

这是我的全部代码供参考

<template>
  <div class="app-container">
    <el-row :gutter="20" style="display: flex; align-items: center;">
      <el-col :span="10">
        <h1 style="text-transform: capatilize;">{{ resourceName }}</h1>
      </el-col>
      <el-col :span="14" style="display: flex; justify-content: flex-end; align-items: center">
        <el-input
          v-model="navigation.search"
          placeholder="Search anything here"
          prefix-icon="el-icon-search"
          style="width: 300px; margin: 0 10px;"
          @keydown.enter.native="handleGlobalSearch"
        />
        <FilterPannel
          style="margin: 0 10px"
          :filter-pannel-obj="filterPannelObj"
          @set-filter="handleFilterVals"
          @reset-filter="getTableData({})"
        />
        <Import
          :url="`/api/${resourceName}/upload`"
          @import-success="handleImportSucces"
          @import-error="handleImportError"
        />
        <Export :url="`/api/${resourceName}/export`" :selected-ids="selected.map(el => el.id)" />
        <el-button
          type="info"
          icon="el-icon-delete"
          @click="$refs['table'].clearSelection()"
        >Clear Selection</el-button>
        <el-button type="danger" icon="el-icon-delete" @click="handleMultipleDelete">Delete Selected</el-button>
      </el-col>
    </el-row>
    <el-row>
      <el-table
        ref="table"
        v-loading="loading.tableData"
        :data="tableData"
        border
        :row-key="getRowKeys"
        @sort-change="handleSortChange"
        @selection-change="handleSelectionChange"
      >
        <el-table-column type="selection" label="Selection" reserve-selection />
        <el-table-column label="Actions" width="200">
          <template slot-scope="scope">
            <div style="display: flex; justify-content: space-around;">
              <el-button
                icon="el-icon-view"
                type="primary"
                circle
                @click="$router.push(`/${resourceName}/view/${scope.row.id}`)"
              />
              <el-button
                icon="el-icon-edit"
                type="success"
                circle
                @click="$router.push(`/${resourceName}/edit/${scope.row.id}`)"
              />
              <el-button
                icon="el-icon-delete"
                type="danger"
                circle
                @click="handleDeleteClick(scope.row.id)"
              />
            </div>
          </template>
        </el-table-column>
        <el-table-column
          v-for="field in fieldsToShow"
          :key="field.name"
          :prop="field.name"
          :label="field.name.replace('_',' ')"
          sortable="custom"
        >
          <template slot-scope="scope">
            <div
              v-if="field.type=='multilangtext'"
              class="cell"
            >{{ JSON.parse(scope.row[field.name])[$store.state.app.language] }}</div>
            <div v-if="field.type=='text'" class="cell">{{ scope.row[field.name] }}</div>
            <el-tag v-if="field.type=='tag'">{{ scope.row.type }}</el-tag>
            <img v-if="field.type=='image'" :src="scope.row.icon" width="100px" height="100px" />
            <div v-if="field.type=='oneFrom'" class="cell">
              <el-tag
                :key="scope.row[field.name]"
              >{{field.multilang ? scope.row[field.name][$store.state.app.language] : scope.row[field.name]}}</el-tag>
            </div>
            <div v-if="field.type=='manyFrom'" class="cell">
              <el-tag
                style="margin: 5px"
                v-for="(item, index) in scope.row[field.name]"
                :key="`${field.multilang ? item[$store.state.app.language] : item}+${index}`"
              >{{field.multilang ? item[$store.state.app.language] : item}}</el-tag>
            </div>
            <div v-if="field.type=='boolean'" class="cell">
              {{scope.row.id}} =>
              {{field.name}} =>>
              {{scope.row[field.name]}} =>>>
              {{fieldData[field.name][scope.row.id]}}
              <el-switch
                :key="`switch${scope.row.id}`"
                v-model="fieldData[field.name][scope.row.id]"
                :active-value="1"
                :inactive-value="0"
              ></el-switch>
            </div>
            <div v-if="field.type=='select'" class="cell">
              <el-select :key="`select${scope.row.id}`" v-model="fieldData[field.name][scope.row.id]" placeholder="Select">
                <el-option
                  v-for="item in field.options"
                  :key="item"
                  :label="item"
                  :value="item"
                ></el-option>
              </el-select>
            </div>
          </template>
        </el-table-column>
      </el-table>
    </el-row>
    <el-row>
      <pagination
        style="padding: 0;"
        :total="paginationData.total"
        :page.sync="paginationData.current_page"
        :limit.sync="paginationData.per_page"
        @pagination="handlePagination"
      />
    </el-row>
  </div>
</template>

<script>
import Pagination from '@/components/Pagination';
import FilterPannel from '@/components/FilterPannel';
import Export from './components/Export'; // ? not needed
import Import from './components/Import';
import axios from 'axios';
import Resource from '@/api/resource';
const resourceName = 'coupons';
const ResourceApi = new Resource(resourceName);

export default {
  name: 'CategoryList',
  components: {
    Pagination,
    FilterPannel,
    Export,
    Import,
  },
  data() {
    return {
      resourceName: resourceName,
      language: 'en',
      tableData: [],
      fieldData: {},
      fieldsToShow: [
        { name: 'title', type: 'multilangtext' },
        // { name: 'description', type: 'multilangtext' },
        { name: 'code', type: 'text' },
        // { name: 'expiry_date', type: 'text' },
        { name: 'type', type: 'tag' },
        {
          name: 'store_id',
          type: 'oneFrom',
          url: '/api/stores/',
          foreignKey: 'store_id',
          attrName: 'name',
          multilang: true,
          prerender: true,
        },
        {
          name: 'tags',
          type: 'manyFrom',
          url: '/api/tags?idsarr=',
          foreignKey: 'tags',
          attrName: 'name',
          multilang: true,
          prerender: true,
        },
        {
          name: 'brands',
          type: 'manyFrom',
          url: '/api/brands?idsarr=',
          foreignKey: 'brands',
          attrName: 'name',
          multilang: true,
          prerender: true,
        },
        // { name: 'brands', type: 'text' },
        { name: 'is_featured', type: 'boolean', prerender: true },
        {
          name: 'status',
          type: 'select',
          options: ['publish', 'draft', 'trash'],
          prerender: true,
        },
      ],
      paginationData: {
        current_page: 0,
        last_page: 0,
        per_page: 0,
        total: 0,
      },
      navigation: {
        page: 1,
        limit: 10,
        sort: '',
        'sort-order': 'asc',
        filters: '',
        search: '',
      },
      filters: '',
      selected: [], // ? for selection
      loading: {
        tableData: false,
      },
      allData: [],
      filterPannelObj: {
        title: {
          default: '',
          type: 'Input',
          label: 'Title',
        },
        description: {
          default: '',
          type: 'Input',
          label: 'Description',
        },
        promo_text: {
          default: '',
          type: 'Input',
          label: 'Promo Text',
        },
        type: {
          default: [],
          type: 'checkbox',
          label: 'Type',
          src: [
            { value: 'coupon', label: 'Coupon' },
            { value: 'offer', label: 'Offer' },
          ],
        },
        code: {
          default: '',
          type: 'Input',
          label: 'Code',
        },
        store_id: {
          default: [],
          type: 'select',
          label: 'Store',
          src: [],
          multiple: true,
        },
        brands: {
          default: [],
          type: 'select',
          label: 'Brands',
          src: [],
          multiple: true,
        },
        tags: {
          default: [],
          type: 'select',
          label: 'Tags',
          src: [],
          multiple: true,
        },
        cats: {
          default: [],
          type: 'select',
          label: 'Categories',
          src: [],
          multiple: true,
        },
      },
    };
  },
  watch: {
    async 'navigation.search'(newVal, oldVal) {
      await this.handleGlobalSearch();
    },
  },
  async created() {
    await this.getTableData({});
    this.allData = await ResourceApi.list({ limit: -1 });

    // to fill filter dialog selects
    // To get brands
    this.filterPannelObj.brands.src = (await axios.get(
      `/api/brands?limit=-1`
    )).data.map(({ name, id }) => ({
      label: JSON.parse(name)[this.$store.state.app.language],
      value: id,
    }));
    // To get tags
    this.filterPannelObj.tags.src = (await axios.get(
      `/api/tags?limit=-1`
    )).data.map(({ name, id }) => ({
      label: JSON.parse(name)[this.$store.state.app.language],
      value: id,
    }));
    // To get categories
    this.filterPannelObj.cats.src = (await axios.get(
      `/api/categories?limit=-1`
    )).data.map(({ name, id }) => ({
      label: JSON.parse(name)[this.$store.state.app.language],
      value: id,
    }));
    // To get stores
    this.filterPannelObj.store_id.src = (await axios.get(
      `/api/stores?limit=-1`
    )).data.map(({ name, id }) => ({
      label: JSON.parse(name)[this.$store.state.app.language],
      value: id,
    }));
  },
  methods: {
    printScope(x) {
      console.log('TCL: printScope -> x', x);
    },
    async getTableData(query) {
      this.loading.tableData = true;
      const responseData = await ResourceApi.list(query);
      this.tableData = responseData.data;
      this.paginationData = this.pick(
        ['current_page', 'last_page', 'per_page', 'total'],
        responseData
      );
      Object.keys(this.paginationData).forEach(
        key => (this.paginationData[key] = parseInt(this.paginationData[key]))
      );
      await this.handlePrerender();
      this.loading.tableData = false;
    },
    async handlePrerender() {
      this.fieldsToShow.forEach(async field => {
        if (field.prerender) {
          switch (field.type) {
            case 'oneFrom': {
              await this.setRelatedFieldName(field);
              break;
            }
            case 'manyFrom': {
              await this.setRelatedFieldName(field);
              break;
            }
            case 'boolean': {
              this.fieldData[field.name] = {};
              this.tableData.forEach(
                data => (this.fieldData[field.name][data.id] = data[field.name])
              );
              break;
            }
            case 'select': {
              this.fieldData[field.name] = {};
              this.tableData.forEach(
                data => (this.fieldData[field.name][data.id] = data[field.name])
              );
              break;
            }
          }
        }
      });
    },
    // utils
    pick(propsArr, srcObj) {
      return Object.keys(srcObj).reduce((obj, k) => {
        if (propsArr.includes(k)) {
          obj[k] = srcObj[k];
        }
        return obj;
      }, {});
    },
    // ? remember to refactor the parameter id
    async setRelatedFieldName({
      name,
      type,
      url,
      foreignKey,
      attrName,
      multilang,
    }) {
      this.tableData.forEach(async data => {
        if (type === 'oneFrom') {
          data[name] = (await axios.get(`${url}${data[foreignKey]}`)).data[
            attrName
          ];
          if (multilang) {
            data[name] = JSON.parse(data[name]);
          }
        } else if (type === 'manyFrom') {
          data[name] = (await axios.get(`${url}${data[foreignKey]}`)).data.map(
            idata => (multilang ? JSON.parse(idata[attrName]) : idata[attrName])
          );
        }
      });
    },
    // Sort
    async handleSortChange(change) {
      this.navigation.sort = change.prop;
      if (change.order === 'ascending') {
        this.navigation['sort-order'] = 'asc';
      } else if (change.order === 'descending') {
        this.navigation['sort-order'] = 'desc';
      }
      await this.getTableData(this.navigation);
    },
    // Pagination
    async handlePagination(obj) {
      // obj page obj containing {page: ..., limit: ...}
      this.navigation.page = obj.page;
      this.navigation.limit = obj.limit;
      await this.getTableData(this.navigation);
    },
    // Global Search
    async handleGlobalSearch() {
      await this.getTableData(this.navigation);
    },
    // ? Skipped for now
    // Filters
    async handleFilterVals(filterparams) {
      console.log('TCL: handleFilterVals -> filterparams', filterparams);
      this.navigation.filters = JSON.stringify(filterparams.filters);
      this.navigation.sort = filterparams.sort.field;
      this.navigation.sort = 'name';
      this.navigation['sort-order'] = filterparams.sort.asc ? 'asc' : 'desc';
      await this.getTableData(this.navigation);
    },
    async handleDeleteClick(id) {
      ResourceApi.destroy(id)
        .then(res => {
          this.$message.success('Delete Successfully');
          this.getTableData({ page: this.paginationData.current_page });
        })
        .error(err => {
          this.$message.error(err);
        });
    },
    // Selection methods
    handleSelectionChange(selection) {
      this.selected = selection;
    },
    getRowKeys(row) {
      return row.id;
    },
    // Multiple Delete
    handleMultipleDelete() {
      axios
        .delete(
          `/api/${this.resourceName}/delete-multiple?ids=${this.selected
            .map(item => item.id)
            .join(',')}`
        )
        .then(async () => {
          this.$message.success('Records deleted successfully');
          await this.getTableData({ page: this.paginationData.current_page });
          if (this.tableData.length === 0) {
            await this.getTableData({
              page: this.paginationData.current_page,
            });
          }
          this.$refs.table.clearSelection();
        })
        .catch();
    },
    // Import Events
    handleImportSucces() {
      this.$message.success('New Data Imported');
      this.getTableData({});
    },
    handleImportError(err) {
      this.$message.error('There were some errors. CHK console');
      console.log(err);
    },
  },
};
</script>

<style lang="scss" scoped>
</style>

{{resourceName}}
清晰选择
删除所选内容
{{JSON.parse(scope.row[field.name])[$store.state.app.language]}
{{scope.row[field.name]}
{{scope.row.type}
{{field.multilang?scope.row[field.name][$store.state.app.language]:scope.row[field.name]}
{{field.multilang?项[$store.state.app.language]:项}
{{scope.row.id}=>
{{field.name}}=>>
{{scope.row[field.name]}}=>>
{{fieldData[field.name][scope.row.id]}
从“@/components/Pagination”导入分页;
从“@/components/FilterPanel”导入FilterPanel;
从“./components/Export”导入导出;//?不需要
从“./components/import”导入;
从“axios”导入axios;
从“@/api/Resource”导入资源;
const resourceName=‘优惠券’;
const ResourceApi=新资源(resourceName);
导出默认值{
名称:'类别列表',
组成部分:{
标页码
过滤板,
出口,,
进口,,
},
数据(){
返回{
resourceName:resourceName,
语言:"en",,
tableData:[],
字段数据:{},
现场演示:[
{name:'title',键入:'multilangtext'},
//{name:'description',键入:'multilangtext'},
{name:'code',键入:'text'},
//{name:'expiration_date',键入:'text'},
{name:'type',type:'tag'},
{
名称:'store_id',
键入:“oneFrom”,
url:“/api/stores/”,
foreignKey:“存储\u id”,
attrName:'name',
是的,
预渲染:正确,
},
{
名称:'标签',
键入:“manyFrom”,
url:“/api/tags?idsarr=”,
外键:“标签”,
attrName:'name',
是的,
预渲染:正确,
},
{
名称:'品牌',
键入:“manyFrom”,
url:“/api/brands?idsarr=”,
外键:“品牌”,
attrName:'name',
是的,
预渲染:正确,
},
//{name:'brands',键入:'text'},
{name:'is_featured',type:'boolean',prerender:true},
{
名称:'状态',
键入:“选择”,
选项:[“发布”、“草稿”、“垃圾箱”],
预渲染:正确,
},
],
分页数据:{
当前页面:0,
最后一页:0,
每页:0,
总数:0,
},
导航:{
页码:1,
限额:10,
排序:“”,
“排序顺序”:“asc”,
筛选器:“”,
搜索:“”,
},
筛选器:“”,
已选择:[],/?供选择
装载:{
tableData:false,
},
所有数据:[],
FilterPanelobj:{
标题:{
默认值:“”,
键入:“输入”,
标签:“标题”,
},
说明:{
默认值:“”,
键入:“输入”,
标签:“说明”,
},
促销文本:{
默认值:“”,
键入:“输入”,
标签:“促销文本”,
},
类型:{
默认值:[],
键入:“复选框”,
标签:“类型”,
src:[
{值:'优惠券',标签:'优惠券'},
{值:'offer',标签:'offer'},
],
},
代码:{
默认值:“”,
键入:“输入”,
标签:“代码”,
},
门店标识:{
默认值:[],
键入:“选择”,
标签:'商店',
src:[],
多重:对,
},
品牌:{
默认值:[],
键入:“选择”,
标签:“品牌”,
src:[],
多重:对,
},
标签:{
默认值:[],
键入:“选择”,
标签:“标签”,
src:[],
多重:对,
},
猫:{
默认值:[],
键入:“选择”,
标签:“类别”,
src:[],
多重:对,
},
},
};
},
观察:{
异步“navigation.search”(newVal、oldVal){
等待此消息。handleGlobalSearch();
},
},
异步创建(){
等待这个.getTableData({});
this.allData=await ResourceApi.list({limit:-1});
//填补空缺
      this.fieldData[field.name] = {};
      self.$set(self.fieldData,field.name,{});
this.fieldData[field.name][data.id] = data[field.name] // to
//Replace
self.$set(self.fieldData[field.name],data.id, data[field.name]);