在Ant Design Vue(v1.7.8)a-table组件中实现余额自动计算

2023-12-25 14:42:09

一、目标

在Ant Design Vue <a-table>表格中实现余额自动计算,公式为:剩余量 = 库存量 - 消耗量

二、二次开发基础

现有一个使用Ant Design Vue <a-table>表格的开源项目,原始表格有“消耗量”列,且带输入框,数据双向绑定

三、项目结构

stock\Stock.vue ———— 父组件 内容是库存清单

stock\StockAdd.vue ———— 已开发的入库物品列表 可以参考

stock\StockOut.vue ———— 需要二次开发的组件 内容是出库物品列表

四、功能描述

原始功能:在父组件中选择要出库的物品,点击出库,弹出出库物品列表,填写消耗量并提交,然后回到库存清单,库存量变为原库存量减去消耗量后的剩余量

?修改后功能:在弹出的物品列表中添加库存量、剩余量两列只读数据,填写消耗量时,剩余量会随之变化,满足剩余量 = 库存量 - 消耗量。

?五、遇到的问题

出库物品列表StockOut.vue中<a-table>表格的出库数据,来自传入参数,是从父组件库存清单表中提取的。因为库存清单表中没有消耗量和剩余量数据列,传递过来的对象数组中不含这两个数据项。需要通过map函数遍历数据数组,为每个对象添加 key、consumption、balance 属性,否则剩余量不能一直跟随消耗量变化(只能变化一次)。

this.dataList = this.stockoutData.map(item => {
    return {
        ...item,
        key: item.id, // 加入父组件库存列表中不存在的key属性,使用 ID 值作为 key
        consumption: 0, // 加入父组件库存列表中不存在的“消耗量”列
        balance: item.amount // 加入父组件库存列表中不存在的“剩余量”列
    }
})

其中,dataList是StockOut.vue本地数组,stockoutData是StockOut.vue组件参数,值由父组件传入。

以下是StockOut.vue的参数定义:

  props: {
    stockoutVisiable: {
      default: false
    },
    stockoutData: {
      type: Array
    }
  },

以下是Stock.vue中参数传递的代码:

    <stock-out
      @close="handleStockoutClose"
      @success="handleStockoutSuccess"
      :stockoutData="stockout.data"
      :stockoutVisiable="stockout.visiable">
    </stock-out>

入参stockoutData被赋值为stockout.data,而stockout.data来自所选的行数据this.selectedRows:

    // “出库”按键的响应方法
    outOfWarehouse () {
      if (!this.selectedRowKeys.length) {
        this.$message.warning('请选择需要出库的物品')
        return
      }
      let goods = this.selectedRows
      let amt = false
      let warningwords = '某个物品'
      goods.forEach(item => {
        item.max = item.amount
        if (item.amount === 0) {
          amt = true
          warningwords = item.name
        }
      })
      if (amt) {
        this.$message.warning(`${warningwords}没有库存!`)
        return
      }
      this.stockout.data = JSON.parse(JSON.stringify(goods))
      this.stockout.visiable = true
    },

this.selectedRows的赋值在onSelectChange()函数中进行,onSelectChange()被设为<a-table>组件的响应函数。当选中每行前面的复选框时,this.selectedRows就会同步赋值为所选的行的数据。

<a-table ref="TableInfo"
               :columns="columns"
               :rowKey="record => record.id"
               :dataSource="dataSource"
               :pagination="pagination"
               :loading="loading"
               :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
               :scroll="{ x: 900 }"
               @change="handleTableChange">


......

    onSelectChange (selectedRowKeys, selectedRows) {
      selectedRows.forEach(item => {
        if (item.amount === 0) {
          this.$message.warning(`${item.name}没有库存!`)
          return false
        }
      })
      this.selectedRowKeys = selectedRowKeys
      this.selectedRows = selectedRows
    },

由于<a-table>组件是封装好的,想通过老办法console.log()看<a-table>内部的变量值得改源码,读懂源码的难度很高,而通过vue的谷歌浏览器插件Vue.js devtools查看<a-table>内部的变量值就非常简单了。

?六、源码

stock\Stock.vue ———— 父组件 内容是库存清单

<template>
  <a-card :bordered="false" class="card-area">
    <div :class="advanced ? 'search' : null">
      <!-- 搜索区域 -->
      <a-form layout="horizontal">
        <a-row :gutter="15">
          <div :class="advanced ? null: 'fold'">
            <a-col :md="6" :sm="24">
              <a-form-item
                label="物品名称"
                :labelCol="{span: 4}"
                :wrapperCol="{span: 18, offset: 2}">
                <a-input v-model="queryParams.name"/>
              </a-form-item>
            </a-col>
            <a-col :md="6" :sm="24">
              <a-form-item
                label="物品型号"
                :labelCol="{span: 4}"
                :wrapperCol="{span: 18, offset: 2}">
                <a-input v-model="queryParams.type"/>
              </a-form-item>
            </a-col>
            <a-col :md="6" :sm="24">
              <a-form-item
                label="物品类型"
                :labelCol="{span: 4}"
                :wrapperCol="{span: 18, offset: 2}">
                <a-select v-model="queryParams.typeId" style="width: 100%" allowClear>
                  <a-select-option v-for="(item, index) in consumableType" :value="item.id" :key="index">{{ item.name }}</a-select-option>
                </a-select>
              </a-form-item>
            </a-col>
          </div>
          <span style="float: right; margin-top: 3px;">
            <a-button type="primary" @click="search">查询</a-button>
            <a-button style="margin-left: 8px" @click="reset">重置</a-button>
          </span>
        </a-row>
      </a-form>
    </div>
    <div>
      <div class="operator">
        <a-button type="primary" ghost @click="warehouse">入库</a-button>
        <a-button type="primary" ghost @click="outOfWarehouse">出库</a-button>
        <!--<a-button @click="batchDelete">删除</a-button>-->
      </div>
      <!-- 表格区域  -->
      <a-table ref="TableInfo"
               :columns="columns"
               :rowKey="record => record.id"
               :dataSource="dataSource"
               :pagination="pagination"
               :loading="loading"
               :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
               :scroll="{ x: 900 }"
               @change="handleTableChange">
        <template slot="titleShow" slot-scope="text, record">
          <template>
            <a-badge status="processing"/>
            <a-tooltip>
              <template slot="title">
                {{ record.title }}
              </template>
              {{ record.title.slice(0, 8) }} ...
            </a-tooltip>
          </template>
        </template>
        <template slot="contentShow" slot-scope="text, record">
          <template>
            <a-tooltip>
              <template slot="title">
                {{ record.content }}
              </template>
              {{ record.content.slice(0, 30) }} ...
            </a-tooltip>
          </template>
        </template>
        <template slot="operation" slot-scope="text, record">
          <a-icon type="setting" theme="twoTone" twoToneColor="#4a9ff5" @click="edit(record)" title="修 改"></a-icon>
        </template>
      </a-table>
    </div>
    <!-- v-if="stockadd.visiable" StockAdd.vue中的a-drawer 有显示属性:visible="show"  不需要再使用v-if控制其是否显示   -->
    <stock-add
      @close="handleStockAddClose"
      @success="handleStockAddSuccess"
      :stockAddVisiable="stockadd.visiable">
    </stock-add>
    <stock-out
      @close="handleStockoutClose"
      @success="handleStockoutSuccess"
      :stockoutData="stockout.data"
      :stockoutVisiable="stockout.visiable">
    </stock-out>
  </a-card>
</template>

<script>
import RangeDate from '@/components/datetime/RangeDate'
import {mapState} from 'vuex'
import StockOut from './StockOut'
import StockAdd from './StockAdd'
import moment from 'moment'
moment.locale('zh-cn')

export default {
  name: 'Stock',
  components: {StockOut, StockAdd, RangeDate},
  data () {
    return {
      advanced: false,
      stockadd: {
        visiable: false
      },
      stockout: {
        visiable: false,
        data: null
      },
      requestEdit: {
        visiable: false
      },
      queryParams: {},
      filteredInfo: null,
      sortedInfo: null,
      paginationInfo: null,
      dataSource: [],
      selectedRowKeys: [],
      selectedRows: [],
      loading: false,
      pagination: {
        pageSizeOptions: ['10', '20', '30', '40', '100'],
        defaultCurrent: 1,
        defaultPageSize: 10,
        showQuickJumper: true,
        showSizeChanger: true,
        showTotal: (total, range) => `显示 ${range[0]} ~ ${range[1]} 条记录,共 ${total} 条记录`
      },
      consumableType: []
    }
  },
  computed: {
    ...mapState({
      currentUser: state => state.account.user
    }),
    columns () {
      return [{
        title: 'ID',
        dataIndex: 'id'
      }, {
        title: '物品名称',
        dataIndex: 'name'
      }, {
        title: '型号',
        dataIndex: 'type',
        customRender: (text, row, index) => {
          if (text !== null) {
            return text
          } else {
            return '- -'
          }
        }
      }, {
        title: '物品数量',
        dataIndex: 'amount',
        customRender: (text, row, index) => {
          if (text !== null) {
            return text
          } else {
            return '- -'
          }
        }
      }, {
        title: '单位',
        dataIndex: 'unit',
        customRender: (text, row, index) => {
          if (text !== null) {
            return text
          } else {
            return '- -'
          }
        }
      }, {
        title: '单价',
        dataIndex: 'price',
        customRender: (text, row, index) => {
          if (text !== null) {
            return '¥' + text.toFixed(2)
          } else {
            return '- -'
          }
        }
      }, {
        title: '总价',
        dataIndex: 'allPrice',
        customRender: (text, row, index) => {
          return '¥' + (row.price * row.amount).toFixed(2)
        }
      }, {
        title: '物品类型',
        dataIndex: 'consumableType',
        customRender: (text, row, index) => {
          if (text !== null) {
            return <a-tag>{text}</a-tag>
          } else {
            return '- -'
          }
        }
      }, {
        title: '备注',
        dataIndex: 'content',
        customRender: (text, row, index) => {
          if (text !== null) {
            return text
          } else {
            return '- -'
          }
        }
      }, {
        title: '入库时间',
        dataIndex: 'createDate',
        customRender: (text, row, index) => {
          if (text !== null) {
            return text
          } else {
            return '- -'
          }
        }
      }]
    }
  },
  mounted () {
    this.fetch()
    this.getConsumableType()
  },
  methods: {
    getConsumableType () {
      this.$get('/cos/consumable-type/list').then((r) => {
        this.consumableType = r.data.data
      })
    },
    onSelectChange (selectedRowKeys, selectedRows) {
      selectedRows.forEach(item => {
        if (item.amount === 0) {
          this.$message.warning(`${item.name}没有库存!`)
          return false
        }
      })
      this.selectedRowKeys = selectedRowKeys
      this.selectedRows = selectedRows
    },
    toggleAdvanced () {
      this.advanced = !this.advanced
    },
    // “入库”按键响应
    warehouse () {
      this.stockadd.visiable = true
    },
    // “出库”按键的响应方法
    outOfWarehouse () {
      if (!this.selectedRowKeys.length) {
        this.$message.warning('请选择需要出库的物品')
        return
      }
      let goods = this.selectedRows
      let amt = false
      let warningwords = '某个物品'
      goods.forEach(item => {
        item.max = item.amount
        if (item.amount === 0) {
          amt = true
          warningwords = item.name
        }
      })
      if (amt) {
        this.$message.warning(`${warningwords}没有库存!`)
        return
      }
      this.stockout.data = JSON.parse(JSON.stringify(goods))
      this.stockout.visiable = true
    },
    handleStockAddClose () {
      this.stockadd.visiable = false
    },
    handleStockAddSuccess () {
      this.stockadd.visiable = false
      this.$message.success('入库成功')
      this.search()
    },
    handleStockoutClose () {
      this.stockout.visiable = false
    },
    handleStockoutSuccess () {
      this.stockout.visiable = false
      this.selectedRows = []
      this.selectedRowKeys = []
      this.$message.success('出库成功')
      this.search()
    },
    handleDeptChange (value) {
      this.queryParams.deptId = value || ''
    },
    batchDelete () {
      if (!this.selectedRowKeys.length) {
        this.$message.warning('请选择需要删除的记录')
        return
      }
      let that = this
      this.$confirm({
        title: '确定删除所选中的记录?',
        content: '当您点击确定按钮后,这些记录将会被彻底删除',
        centered: true,
        onOk () {
          let ids = that.selectedRowKeys.join(',')
          that.$delete('/cos/request-type/' + ids).then(() => {
            that.$message.success('删除成功')
            that.selectedRowKeys = []
            that.selectedRows = []
            that.search()
          })
        },
        onCancel () {
          that.selectedRowKeys = []
          that.selectedRows = []
        }
      })
    },
    search () {
      let {sortedInfo, filteredInfo} = this
      let sortField, sortOrder
      // 获取当前列的排序和列的过滤规则
      if (sortedInfo) {
        sortField = sortedInfo.field
        sortOrder = sortedInfo.order
      }
      this.fetch({
        sortField: sortField,
        sortOrder: sortOrder,
        ...this.queryParams,
        ...filteredInfo
      })
    },
    reset () {
      // 取消选中
      this.selectedRowKeys = []
      // 重置分页
      this.$refs.TableInfo.pagination.current = this.pagination.defaultCurrent
      if (this.paginationInfo) {
        this.paginationInfo.current = this.pagination.defaultCurrent
        this.paginationInfo.pageSize = this.pagination.defaultPageSize
      }
      // 重置列过滤器规则
      this.filteredInfo = null
      // 重置列排序规则
      this.sortedInfo = null
      // 重置查询参数
      this.queryParams = {}
      this.fetch()
    },
    handleTableChange (pagination, filters, sorter) {
      // 将这三个参数赋值给Vue data,用于后续使用
      this.paginationInfo = pagination
      this.filteredInfo = filters
      this.sortedInfo = sorter

      this.fetch({
        sortField: sorter.field,
        sortOrder: sorter.order,
        ...this.queryParams,
        ...filters
      })
    },
    fetch (params = {}) {
      // 显示loading
      this.loading = true
      if (this.paginationInfo) {
        // 如果分页信息不为空,则设置表格当前第几页,每页条数,并设置查询分页参数
        this.$refs.TableInfo.pagination.current = this.paginationInfo.current
        this.$refs.TableInfo.pagination.pageSize = this.paginationInfo.pageSize
        params.size = this.paginationInfo.pageSize
        params.current = this.paginationInfo.current
      } else {
        // 如果分页信息为空,则设置为默认值
        params.size = this.pagination.defaultPageSize
        params.current = this.pagination.defaultCurrent
      }
      if (params.typeId === undefined) {
        delete params.typeId
      }
      this.$get('/cos/stock-info/page', {
        ...params
      }).then((r) => {
        let data = r.data.data
        const pagination = {...this.pagination}
        pagination.total = data.total
        this.dataSource = data.records
        this.pagination = pagination
        // 数据加载完毕,关闭loading
        this.loading = false
      })
    }
  },
  watch: {}
}
</script>
<style lang="less" scoped>
@import "../../../../static/less/Common";
</style>

stock\StockAdd.vue ———— 已开发的入库物品列表 可以参考

<template>
  <a-drawer
    title="物品入库"
    :maskClosable="false"
    placement="right"
    :closable="false"
    :visible="show"
    :width="1200"
    @close="onClose"
    style="height: calc(100% - 55px);overflow: auto;padding-bottom: 53px;"
  >
    <a-form :form="form" layout="horizontal">
      <a-row :gutter="32">
        <a-col :span="12">
          <a-form-item label='保管人' v-bind="formItemLayout">
            <a-input v-decorator="[
            'custodian',
            { rules: [{ required: true, message: '请输入保管人!' }] }
            ]"/>
          </a-form-item>
        </a-col>
        <a-col :span="12">
          <a-form-item label='入库人' v-bind="formItemLayout">
            <a-input v-decorator="[
            'putUser',
            { rules: [{ required: true, message: '请输入入库人!' }] }
            ]"/>
          </a-form-item>
        </a-col>
        <a-col :span="24">
          <a-form-item label='备注消息' v-bind="formItemLayout">
            <a-textarea :rows="4" v-decorator="[
            'content',
             { rules: [{ required: true, message: '请输入名称!' }] }
            ]"/>
          </a-form-item>
        </a-col>
        <a-col :span="24">
          <a-table :columns="columns" :data-source="dataList">
            <template slot="nameShow" slot-scope="text, record">
              <a-input v-model="record.name"></a-input>
            </template>
            <template slot="typeShow" slot-scope="text, record">
              <a-input v-model="record.type"></a-input>
            </template>
            <template slot="typeIdShow" slot-scope="text, record">
              <a-select v-model="record.typeId" style="width: 100%">
                <a-select-option v-for="(item, index) in consumableType" :value="item.id" :key="index">{{ item.name }}</a-select-option>
              </a-select>
            </template>
            <template slot="unitShow" slot-scope="text, record">
              <a-input v-model="record.unit"></a-input>
            </template>
            <template slot="amountShow" slot-scope="text, record">
              <a-input-number v-model="record.amount" :min="1" :step="1" :precision="2" @change="handleChange(record)"/>
            </template>
            <template slot="consumptionShow" slot-scope="text, record">
              <a-input-number v-model="record.consumption" :min="0" :max="record.amount" :step="1" :precision="2" @change="handleChange(record)"/>
            </template>
            <template slot="priceShow" slot-scope="text, record">
              <a-input-number v-model="record.price" :min="0"/>
            </template>
          </a-table>
          <a-button @click="dataAdd" type="primary" ghost size="large" style="margin-top: 10px;width: 100%">
            新增物品
          </a-button>
        </a-col>
      </a-row>
    </a-form>
    <div class="drawer-bootom-button">
      <a-popconfirm title="确定放弃编辑?" @confirm="onClose" okText="确定" cancelText="取消">
        <a-button style="margin-right: .8rem">取消</a-button>
      </a-popconfirm>
      <a-button @click="handleSubmit" type="primary" :loading="loading">提交</a-button>
    </div>
  </a-drawer>
</template>

<script>
import {mapState} from 'vuex'
const formItemLayout = {
  labelCol: { span: 24 },
  wrapperCol: { span: 24 }
}
export default {
  name: 'stockAdd',
  props: {
    stockAddVisiable: {
      default: false
    }
  },
  computed: {
    ...mapState({
      currentUser: state => state.account.user
    }),
    show: {
      get: function () {
        return this.stockAddVisiable
      },
      set: function () {
      }
    },
    columns () {
      return [{
        title: '序号',
        dataIndex: 'key'
      }, {
        title: '物品名称',
        dataIndex: 'name',
        scopedSlots: {customRender: 'nameShow'}
      }, {
        title: '所属类型',
        dataIndex: 'typeId',
        width: 200,
        scopedSlots: {customRender: 'typeIdShow'}
      }, {
        title: '型号',
        dataIndex: 'type',
        scopedSlots: {customRender: 'typeShow'}
      }, {
        title: '采购量',
        dataIndex: 'amount',
        scopedSlots: {customRender: 'amountShow'}
      }, {
        title: '消耗量',
        dataIndex: 'consumption',
        scopedSlots: {customRender: 'consumptionShow'}
      }, {
        title: '剩余量',
        dataIndex: 'balance'
      }, {
        title: '单位',
        dataIndex: 'unit',
        scopedSlots: {customRender: 'unitShow'}
      }, {
        title: '单价',
        dataIndex: 'price',
        scopedSlots: {customRender: 'priceShow'}
      }]
    }
  },
  mounted () {
    this.getConsumableType()
  },
  data () {
    return {
      dataList: [],
      formItemLayout,
      form: this.$form.createForm(this),
      loading: false,
      consumableType: [],
      keynumber: 1
    }
  },
  methods: {
    getConsumableType () {
      this.$get('/cos/consumable-type/list').then((r) => {
        this.consumableType = r.data.data
      })
    },
    dataAdd () {
      this.dataList.push({key: this.keynumber++, name: '', type: '', typeId: '', unit: '', amount: 0, consumption: 0, balance: 0, price: 0})
    },
    reset () {
      this.loading = false
      this.form.resetFields()
    },
    onClose () {
      this.reset()
      this.$emit('close')
    },
    handleChange (record) {
      record.balance = (record.amount - record.consumption).toFixed(2)
    },
    handleSubmit () {
      let price = 0
      this.dataList.forEach(item => {
        price += item.price * item.amount
      })
      this.form.validateFields((err, values) => {
        values.price = price
        values.goods = JSON.stringify(this.dataList)
        if (!err) {
          this.loading = true
          this.$post('/cos/stock-info/put', {
            ...values
          }).then((r) => {
            this.reset()
            this.$emit('success')
          }).catch(() => {
            this.loading = false
          })
        }
      })
    }
  }
}
</script>

<style scoped>

</style>

stock\StockOut.vue ———— 需要二次开发的组件 内容是出库物品列表

<template>
  <a-drawer title="出库" :maskClosable="false" placement="right" :closable="false" :visible="show" :width="1200"
    @close="onClose" style="height: calc(100% - 55px);overflow: auto;padding-bottom: 53px;">
    <a-form :form="form" layout="vertical">
      <a-row :gutter="20">
        <a-col :span="12">
          <a-form-item label='出库对象' v-bind="formItemLayout">
            <a-select v-decorator="[
              'userId',
              { rules: [{ required: true, message: '请输入出库对象!' }] }
            ]" style="width: 100%">
              <a-select-option v-for="(item, index) in studentList" :value="item.id" :key="index">{{ item.name
              }}</a-select-option>
            </a-select>
          </a-form-item>
        </a-col>
        <a-col :span="12">
          <a-form-item label='保管员' v-bind="formItemLayout">
            <a-input v-decorator="[
              'custodian',
              { rules: [{ required: true, message: '请输入保管员!' }] }
            ]" />
          </a-form-item>
        </a-col>
        <a-col :span="12">
          <a-form-item label='经手人' v-bind="formItemLayout">
            <a-input v-decorator="[
              'handler',
              { rules: [{ required: true, message: '请输入经手人!' }] }
            ]" />
          </a-form-item>
        </a-col>
        <a-col :span="24">
          <a-table :columns="columns" :data-source="dataList">
            <template slot="nameShow" slot-scope="text, record">
              <a-input v-model="record.name"></a-input>
            </template>
            <template slot="typeShow" slot-scope="text, record">
              <a-input v-model="record.type"></a-input>
            </template>
            <template slot="typeIdShow" slot-scope="text, record">
              <a-select v-model="record.typeId" style="width: 100%">
                <a-select-option v-for="(item, index) in consumableType" :value="item.id" :key="index">{{ item.name
                }}</a-select-option>
              </a-select>
            </template>
            <template slot="unitShow" slot-scope="text, record">
              <a-input v-model="record.unit"></a-input>
            </template>
            <template slot="consumptionShow" slot-scope="text, record">
              <a-input-number v-model="record.consumption" :min="0" :max="record.amount" :step="1" :precision="2"
                @change="handleChange(record)" />
            </template>
            <template slot="priceShow" slot-scope="text, record">
              <a-input-number v-model="record.price" :min="1" />
            </template>
          </a-table>
        </a-col>
      </a-row>
    </a-form>
    <div class="drawer-bootom-button">
      <a-popconfirm title="确定放弃编辑?" @confirm="onClose" okText="确定" cancelText="取消">
        <a-button style="margin-right: .8rem">取消</a-button>
      </a-popconfirm>
      <a-button @click="handleSubmit" type="primary" :loading="loading">提交</a-button>
    </div>
  </a-drawer>
</template>

<script>
import { mapState } from 'vuex'
const formItemLayout = {
  labelCol: { span: 24 },
  wrapperCol: { span: 24 }
}
export default {
  name: 'StockOut',
  props: {
    stockoutVisiable: {
      default: false
    },
    stockoutData: {
      type: Array
    }
  },
  computed: {
    ...mapState({
      currentUser: state => state.account.user
    }),
    show: {
      get: function () {
        return this.stockoutVisiable
      },
      set: function () {
      }
    },
    columns () {
      return [{
        title: '序号',
        dataIndex: 'key'
      }, {
        title: '物品名称',
        dataIndex: 'name',
        scopedSlots: { customRender: 'nameShow' }
      }, {
        title: '型号',
        dataIndex: 'type',
        scopedSlots: { customRender: 'typeShow' }
      }, {
        title: '库存量',
        dataIndex: 'amount'
      }, {
        title: '消耗量',
        dataIndex: 'consumption',
        scopedSlots: { customRender: 'consumptionShow' }
      }, {
        title: '剩余量',
        dataIndex: 'balance'
      }, {
        title: '所属类型',
        dataIndex: 'typeId',
        width: 200,
        scopedSlots: { customRender: 'typeIdShow' }
      }, {
        title: '单位',
        dataIndex: 'unit',
        scopedSlots: { customRender: 'unitShow' }
      }, {
        title: '单价',
        dataIndex: 'price',
        scopedSlots: { customRender: 'priceShow' }
      }]
    }
  },
  data () {
    return {
      formItemLayout,
      form: this.$form.createForm(this),
      loading: false,
      dataList: [],
      consumableType: [],
      studentList: []
    }
  },
  watch: {
    stockoutVisiable: function (value) {
      if (value) {
        this.dataList = this.stockoutData.map(item => {
          return {
            ...item,
            key: item.id, // 加入父组件库存列表中不存在的key属性,使用 ID 值作为 key
            consumption: 0, // 加入父组件库存列表中不存在的“消耗量”列
            balance: item.amount // 加入父组件库存列表中不存在的“剩余量”列
          }
        })
      }
    }
  },
  mounted () {
    this.getConsumableType()
    this.getStudentList()
  },
  methods: {
    getStudentList () {
      this.$get('/cos/student-info/list').then((r) => {
        this.studentList = r.data.data
      })
    },
    getConsumableType () {
      this.$get('/cos/consumable-type/list').then((r) => {
        this.consumableType = r.data.data
      })
    },
    reset () {
      this.loading = false
      this.dataList = []
      this.form.resetFields()
    },
    onClose () {
      this.reset()
      this.$emit('close')
    },
    handleChange (record) {
      record.balance = (record.amount - record.consumption).toFixed(2)
    },
    handleSubmit () {
      if (this.dataList.length !== 0) {
        let price = 0
        this.dataList.forEach(item => {
          price += item.price * item.amount
        })
        this.form.validateFields((err, values) => {
          if (!err) {
            values.price = price
            values.goods = JSON.stringify(this.dataList)
            this.loading = true
            this.$post('/cos/stock-out/stockOut', {
              ...values
            }).then((r) => {
              this.reset()
              this.$emit('success')
            }).catch(() => {
              this.loading = false
            })
          }
        })
      } else {
        this.$message.warning('添加出库记录')
      }
    }
  }
}
</script>

<style scoped></style>

七、新的疑问

?columns必须是计算属性吗

  computed: {
    ...mapState({
      currentUser: state => state.account.user
    }),
    show: {
      get: function () {
        return this.stockoutVisiable
      },
      set: function () {
      }
    },
    columns () {
      return [{
        title: '序号',
        dataIndex: 'key'
      }, {
        title: '物品名称',
        dataIndex: 'name',
        scopedSlots: { customRender: 'nameShow' }
      }, {
        title: '型号',
        dataIndex: 'type',
        scopedSlots: { customRender: 'typeShow' }
      }, {
        title: '库存量',
        dataIndex: 'amount'
      }, {
        title: '消耗量',
        dataIndex: 'consumption',
        scopedSlots: { customRender: 'consumptionShow' }
      }, {
        title: '剩余量',
        dataIndex: 'balance'
      }, {
        title: '所属类型',
        dataIndex: 'typeId',
        width: 200,
        scopedSlots: { customRender: 'typeIdShow' }
      }, {
        title: '单位',
        dataIndex: 'unit',
        scopedSlots: { customRender: 'unitShow' }
      }, {
        title: '单价',
        dataIndex: 'price',
        scopedSlots: { customRender: 'priceShow' }
      }]
    }
  },

如何将后台api数据中的id列转为antdesignvue中的key?

AI参考答案:

要将后台 API 数据中的 ID 列转换为 Ant Design Vue 中的 key,你可以按照以下步骤进行操作:

  1. 首先,确保你已经使用 Ant Design Vue 创建了表格或其他组件,需要将数据作为数据源进行渲染。

  2. 在获取到后台 API 数据后,遍历数据数组中的每个对象。

  3. 对于每个对象,将其 ID 值提取出来,并将其赋值给一个名为 "key" 的属性。

  4. 最后,将更新后的数据数组作为数据源传递给 Ant Design Vue 的组件进行渲染。

以下是一段示例代码,展示了如何将后台 API 数据中的 ID 列转换为 Ant Design Vue 中的 key:

// 假设你已经从后台 API 获取到了数据数组
const apiData = [
  { id: 1, name: 'John', age: 25 },
  { id: 2, name: 'Jane', age: 30 },
  // ...
];

// 遍历数据数组,为每个对象添加 key 属性
const transformedData = apiData.map(item => {
  return {
    ...item,
    key: item.id, // 使用 ID 值作为 key
  };
});

// 将更新后的数据传递给 Ant Design Vue 的组件进行渲染
<Table :dataSource="transformedData">
  <!-- 表格列配置 -->
  <a-table-column title="ID" dataIndex="id" key="id" />
  <a-table-column title="Name" dataIndex="name" key="name" />
  <a-table-column title="Age" dataIndex="age" key="age" />
  <!-- 更多列... -->
</Table>

文章来源:https://blog.csdn.net/qq_27361945/article/details/135195280
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。