uniapp/vue如何实现一个子表单及子表单作用

简介: uniapp/vue如何实现一个子表单及子表单作用

子表单是一个辅助表单或一个表,它允许在主表单中添加多个行式项目,以处理与主记录相关联的多个辅助项目或数据。子表单在多种应用场景中发挥着重要作用,特别是在需要处理一对多关系的数据时。

以下是对子表单的详细解析:


定义与特点

  • 定义:子表单是一个插入到主表单中的表单,用于在主表单中显示与主记录相关联的多个辅助记录或数据项。
  • 特点:
  • 提高表单的灵活性和信息的详细程度。
  • 适用于1:N(一对多)的数据场景。
  • 可以包含多种字段类型,如文本框、日期时间、单选框等。


应用场景

  1. 销售部门:
  • 子表单可用于使联系人详细信息与客户相关联。
  • 在销售订单中,子表单可以记录与主产品相关联的配件信息,如配件名称、价格、数量等。
  1. 人力资源管理:
  • 子表单可用于管理员工的多个联系人信息、工作经历、培训历史等。
  • 在员工信息表单中,子表单可以记录员工的工作经历、培训记录、证书等详细信息。
  1. 财务管理:
  • 在报销表单中,子表单可以详细记录每次报销包含的多个报销项目信息。
  1. 库存管理:
  • 出库单、入库单中的商品明细可以用子表单记录,根据实际需要录入的数据新增条数。


功能与优势

  • 数据录入:支持多种字段类型,方便用户录入复杂数据。
  • 数据管理:可以有效地处理复杂的数据关系,提高数据录入的准确性和效率。
  • 数据联动:当其他表单字段与子表单字段相关时,可以设置联动,实现数据的自动填充。
  • 批量操作:支持子表信息的批量导入和导出,提高数据处理效率。


创建与配置

子表单的创建和配置通常依赖于具体的软件或平台。以下是一些通用的步骤:

选择主表单

首先确定主表单,往主表单拖入相关表单输入字段并设置其属性,如字段类型、名称、是否必填等。


添加子表单

往主表单中添加子表单组件,并设置其属性,如字段类型、名称、是否必填等。

配置子表单

在子表单字段中配置需要显示的辅助记录或数据项,如配件名称、价格、数量等。


扩展样式设置

对整个子表单进行外边距设置、边框、圆角等设置

导出源码

点击保存源码至本地,本地可以快速进行调试子表单效果。


本地开发运行效果

保存源码至本地后,会生成uniapp、vue相关子表单源码,此时我们可以快速看见效果.

操作按钮位置设置

自定义操作按钮

支持自定义扩展按钮,可以根据生成上面点击事件拷贝出来,然后自定义操作按钮事件。

子表单代码生成器举例

<template>
  <view class="container container21094">
    <u-form :model="form" :rules="formRules" :errorType="['message', 'toast']" ref="formRef" class="flex diygw-form diygw-col-24">
      <u-form-item class="diygw-col-24" label="标题" prop="input">
        <u-input :focus="formData.inputFocus" placeholder="请输入提示信息" v-model="form.input"></u-input>
      </u-form-item>
      <u-form-item class="diygw-col-24" label="标题" prop="input1">
        <u-input :focus="formData.input1Focus" placeholder="请输入提示信息" v-model="form.input1"></u-input>
      </u-form-item>
      <view class="flex flex-wrap diygw-col-24 subform-clz">
        <view class="diygw-col-24" v-for="(subformItem, subformIndex) in form.subform" :key="subformIndex">
          <u-form class="diygw-col-24" :model="form.subform[subformIndex]" :errorType="['message', 'toast']" ref="subformRef" :rules="subformItemRules">
            <text class="diygw-col-24 text-clz"> 子表单 </text>
            <u-form-item class="diygw-col-24" label="标题" prop="input3">
              <u-input :focus="formData.subformItemDatas[subformIndex].input3Focus" placeholder="请输入提示信息" v-model="subformItem.input3"></u-input>
            </u-form-item>
          </u-form>
          <view class="formsubformtools flex justify-end">
            <button @tap="upSubformItem" :data-index="subformIndex" class="diygw-btn flex-sub radius margin-xs">
              <text class="button-icon diy-icon-fold"></text>
            </button>
            <button @tap="downSubformItem" :data-index="subformIndex" class="diygw-btn flex-sub radius margin-xs">
              <text class="button-icon diy-icon-unfold"></text>
            </button>
            <button @tap="addSubformItem" :data-index="subformIndex" class="diygw-btn flex-sub radius margin-xs">
              <text class="button-icon diy-icon-add"></text>
            </button>
            <button @tap="delSubformItem" :data-index="subformIndex" class="diygw-btn flex-sub radius margin-xs">
              <text class="button-icon diy-icon-close"></text>
            </button>
          </view>
        </view>
        <view class="padding-xs diygw-col-24">
          <button @tap="addSubformItem" class="diygw-btn diygw-col-24 radius" style="background: #07c160; color: #fff">新增</button>
        </view>
      </view>
    </u-form>
    <view class="clearfix"></view>
  </view>
</template>
 
<script>
  export default {
    data() {
      return {
        //用户全局信息
        userInfo: {},
        //页面传参
        globalOption: {},
        //自定义全局变量
        globalData: { logintype: '0', agree: '0' },
        subformItemData: {
          input3Focus: false
        },
        subformItem: {
          input3: ''
        },
        form: {
          input: '',
          input1: '',
          subform: []
        },
        formRules: {},
        subformItemRules: {},
        formData: {
          inputFocus: false,
          input1Focus: false,
          subformItemDatas: []
        }
      };
    },
    onShow() {
      this.setCurrentPage(this);
    },
    onLoad(option) {
      this.setCurrentPage(this);
      if (option) {
        this.setData({
          globalOption: this.getOption(option)
        });
      }
 
      this.init();
    },
    onReady() {
      this.$refs.formRef?.setRules(this.formRules);
      this.initSubformData();
    },
    methods: {
      async init() {
        await this.initResetform();
      }, //初始化显示子表单数据条数
      initSubformData() {
        for (let i = 0; i < 1; i++) {
          this.form.subform.push(JSON.parse(JSON.stringify(this.subformItem)));
          this.formData.subformItemDatas.push(JSON.parse(JSON.stringify(this.subformItemData)));
        }
        this.initSubformValid();
      },
      //子表单验证
      initSubformValid() {
        this.$nextTick(() => {
          this.$refs['subformRef']?.forEach((subform) => {
            subform.setRules(this.subformItemRules);
          });
        });
      },
      //上移子表单
      upSubformItem(evt) {
        let { index } = evt.currentTarget.dataset;
        if (index == 0) {
          this.navigateTo({
            type: 'tip',
            tip: '已经是第一个'
          });
          return false;
        }
        this.form.subform[index] = this.form.subform.splice(index - 1, 1, this.form.subform[index])[0];
        this.formData.subformItemDatas[index] = this.formData.subformItemDatas.splice(index - 1, 1, this.formData.subformItemDatas[index])[0];
        this.initSubformValid();
      },
      //下移子表单
      downSubformItem(evt) {
        let { index } = evt.currentTarget.dataset;
        if (index == this.form.subform.length - 1) {
          this.navigateTo({
            type: 'tip',
            tip: '已经是最后一个'
          });
          return false;
        }
        this.form.subform[index] = this.form.subform.splice(index + 1, 1, this.form.subform[index])[0];
        this.formData.subformItemDatas[index] = this.formData.subformItemDatas.splice(index + 1, 1, this.formData.subformItemDatas[index])[0];
        this.initSubformValid();
      },
      //删除子表单
      delSubformItem(evt) {
        let { index } = evt.currentTarget.dataset;
        this.form.subform.splice(index, 1);
        this.formData.subformItemDatas.splice(index, 1);
        this.initSubformValid();
      },
      //增加子表单
      addSubformItem() {
        this.form.subform.push(JSON.parse(JSON.stringify(this.subformItem)));
        this.formData.subformItemDatas.push(JSON.parse(JSON.stringify(this.subformItemData)));
        this.initSubformValid();
      },
      //验证所有的子表单
      checkSubformValid() {
        let flag = true;
        this.$refs['subformRef']?.forEach((subform) => {
          subform.validate((valid) => {
            if (!valid) {
              flag = false;
              return false;
            }
          });
        });
        return flag;
      },
      initResetform() {
        this.initform = JSON.stringify(this.form);
      },
      resetForm() {
        this.form = JSON.parse(this.initform);
      },
 
      async submitForm(e) {
        this.$refs.formRef?.setRules(this.formRules);
 
        this.initSubformValid();
        this.$nextTick(async () => {
          let subformvalid = await this.checkSubformValid();
          let valid = await this.$refs.formRef.validate();
          if (valid && subformvalid) {
            //保存数据
            let param = this.form;
            let header = {
              'Content-Type': 'application/json'
            };
            let url = '';
            if (!url) {
              this.showToast('请先配置表单提交地址', 'none');
              return false;
            }
 
            let res = await this.$http.post(url, param, header, 'json');
 
            if (res.code == 200) {
              this.showToast(res.msg, 'success');
            } else {
              this.showModal(res.msg, '提示', false);
            }
          } else {
            console.log('验证失败');
          }
        });
      }
    }
  };
</script>
 
<style lang="scss" scoped>
  .subform-clz {
    margin-left: 10rpx;
    border: 2rpx solid #ac0a0a;
    border-bottom-left-radius: 12rpx;
    overflow: hidden;
    width: calc(100% - 10rpx - 10rpx) !important;
    border-top-left-radius: 12rpx;
    margin-top: 10rpx;
    border-top-right-radius: 12rpx;
    border-bottom-right-radius: 12rpx;
    margin-bottom: 10rpx;
    margin-right: 10rpx;
  }
  .formsubformtools {
    position: absolute;
    z-index: 1;
    right: 0rpx;
    top: 0rpx;
  }
  .formsubformtools .diygw-btn {
    padding: 5px;
    height: auto;
    flex: inherit;
    border-radius: 20px;
  }
  .text-clz {
    margin-left: 10rpx;
    padding-top: 10rpx;
    padding-left: 10rpx;
    width: calc(100% - 10rpx - 10rpx) !important;
    padding-bottom: 10rpx;
    margin-top: 10rpx;
    margin-bottom: 10rpx;
    margin-right: 10rpx;
    padding-right: 10rpx;
  }
  .container21094 {
  }
</style>

注意事项

在使用子表单时,需要注意数据的完整性和准确性,避免出现数据冗余或错误。

根据实际需求合理配置子表单的字段和关联关系,以提高数据处理的效率和准确性。

在进行批量操作时,如批量导入和导出,需要注意数据的格式和顺序,确保数据的正确性和完整性。

综上所述,子表单是一种重要的数据管理工具,能够有效地处理复杂的数据关系和提高数据处理的效率。在实际应用中,需要根据具体需求合理配置和使用子表单。

目录
相关文章
|
1天前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1506 1
|
28天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
4天前
|
人工智能 Rust Java
10月更文挑战赛火热启动,坚持热爱坚持创作!
开发者社区10月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
453 17
|
1天前
|
存储 SQL 关系型数据库
彻底搞懂InnoDB的MVCC多版本并发控制
本文详细介绍了InnoDB存储引擎中的两种并发控制方法:MVCC(多版本并发控制)和LBCC(基于锁的并发控制)。MVCC通过记录版本信息和使用快照读取机制,实现了高并发下的读写操作,而LBCC则通过加锁机制控制并发访问。文章深入探讨了MVCC的工作原理,包括插入、删除、修改流程及查询过程中的快照读取机制。通过多个案例演示了不同隔离级别下MVCC的具体表现,并解释了事务ID的分配和管理方式。最后,对比了四种隔离级别的性能特点,帮助读者理解如何根据具体需求选择合适的隔离级别以优化数据库性能。
176 0
|
7天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
20天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
8天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
392 3
|
6天前
|
存储 人工智能 搜索推荐
数据治理,是时候打破刻板印象了
瓴羊智能数据建设与治理产品Datapin全面升级,可演进扩展的数据架构体系为企业数据治理预留发展空间,推出敏捷版用以解决企业数据量不大但需构建数据的场景问题,基于大模型打造的DataAgent更是为企业用好数据资产提供了便利。
300 2
|
22天前
|
人工智能 IDE 程序员
期盼已久!通义灵码 AI 程序员开启邀测,全流程开发仅用几分钟
在云栖大会上,阿里云云原生应用平台负责人丁宇宣布,「通义灵码」完成全面升级,并正式发布 AI 程序员。
|
24天前
|
机器学习/深度学习 算法 大数据
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
2024“华为杯”数学建模竞赛,对ABCDEF每个题进行详细的分析,涵盖风电场功率优化、WLAN网络吞吐量、磁性元件损耗建模、地理环境问题、高速公路应急车道启用和X射线脉冲星建模等多领域问题,解析了问题类型、专业和技能的需要。
2603 22
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析