草庐IT

Uniapp微信小程序实现简易生成表单生成器

阿里爸爸首席执行官 2023-12-06 原文

在开发一些填报小程序,一些小型办公小程序的时候,难免会遇到较多的需要填写的表单信息,纯手撸表单耗时耗力。

TIP:类似于这种十种类型的表单,每种类型的表单并不一样


下面将分为三个部分

一、创建对应类型表单的结构体

下面是新建商机的表单结构体
字段详情看注释

//新建商机
export function Oppor() {
	return [{
			label: '客户名称', //表单label文字
			key: 'customer', //表单对应的字段属性名
			name: 'customername', //下拉选项中文名的属性名
			id: 'customerid', //下拉选项的id属性名
			formType: 'select',//表单类型 默认为单行文本
			remoteName: 'getCustomerName',//下拉框远程方法
			required: true,//必填校验
		}, {
			label: '商机名称',
			key: 'opportunityname',
			required: true,
		},
		{
			label: '客户对接人',
			key: 'customerdock',
			required: true,
		},
		{
			label: '预计金额',
			key: 'estimatedamount',
			unitName: '元',
			required: true,
		},
		{
			label: '商机描述',
			key: 'opportunitydescribe',
			formType: 'textarea',
			required: true,
		},
		{
			label: '工时',
			key: 'workhour',
			unitName: '时', //表单内容单位
			required: true,
		}
	]
}

二、对应的表单生成器模板

formProps就是上面的表单结构体
submitForm是保存事件(如有想法可改为插槽)
注意!!! 因为uniapp不支持通过props传子组件Function
所以remoteFun对应表单的远程方法,将通过另一种形式传递,并将修改uni-data-select组件的内部方法,实现远程调用接口。

	<DailyFormTemplate ref="dailyFormTemplate" @submitForm="submitForm"  :formProps="formProp"></DailyFormTemplate>

//js部分
//对应的远程方法
import {getProductLine,getCustomerName,getOpportunityName,getProjectName,getProductByProject,getProductByProductLine} from '@/http/api.js'
export default {
		components:{
			DailyFormTemplate
		},
		data() {
			return {
			//我们需要将remoteFun传进子组件DailyFormTemplate ,表单生成模板中
				remoteFun:{
				//标题一中remoteName绑定的对应的方法名
					getCustomerName,
				}
			}
		},
		mounted(){
		//我们需要将remoteFun传进子组件DailyFormTemplate ,表单生成模板中,初始化方法将remoteFun传入
			this.setRemote();
		},
		methods:{
		setRemote(){
			//将remoteFun传入,通过调用dailyFormTemplate里面定义的setRemote方法
		 	this.$refs.dailyFormTemplate.setRemote(this.remoteFun)
			},
		}
}

三、生成器模板代码

注意!!! 需要注意的是当前并不能直接使用远程方法,因为uni-data-select组件并不支持远程方法渲染,会导致数据无法回显,需要注意第四阶段进入uni-data-select组件修改

<template>
	<view class="continer">
		<uni-forms ref="form" :modelValue="form" :rules="rules">
			<view class="form_element" v-for="(item,index) in formProps" :key="index">

				<view class="form_title">
					<span v-if="item.required" class="is-required">*</span>
					{{item.label}}
				</view>
				<view v-if="!item.formType">
					<uni-forms-item :required="item.required?item.required:false" :name="item.key">
						<view class="input_box">
							<input :ref="item.key" class="uni-input formInput" v-model="form[item.key]"
								:placeholder="'请填写'+item.label" />
							<view class="unit" v-if="item.unitName">{{item.unitName}}</view>
						</view>
					</uni-forms-item>
				</view>
				<view v-if="item.formType==='select'">
					<uni-forms-item :required="item.required?item.required:false" :name="item.key">

						<uni-data-select :ref="item.key" v-model="form[item.key]" :getObjectParam="getObjectParam"
							:placeholder="'请选择'+item.label" @change="onchange($event,item)">
						</uni-data-select>
					</uni-forms-item>
					<!-- <input class="uni-input formInput" v-model="form[item.key]" :placeholder="'请填写'+item.label" /> -->
				</view>
				<view v-if="item.formType==='textarea'">
					<uni-forms-item :required="item.required?item.required:false" :name="item.key">

						<uni-easyinput :ref="item.key" type="textarea" :maxlength="-1" placeholderStyle="fontSize:28upx"
							v-model="form[item.key]" :placeholder="'请填写'+item.label" />
					</uni-forms-item>
					<!-- <input class="uni-input formInput" v-model="form[item.key]" :placeholder="'请填写'+item.label" /> -->
				</view>
			</view>
		</uni-forms>
	</view>
</template>

<script>
	import formTypeMap from '../js/RelationClass.js'
	export default {
		props: {
			formProps: {
				type: Array,
				default: () => []
			},


		},
		computed: {
			reData: {
				get() {
					return function(val) {
						const that = this;
						if (this.remote) {
							return that.remote[val]();
						}
						return []

					}
				},
				set() {}

			},
		},
		data() {
			return {
				getObjectParam: {
					text: 'text',
					value: 'value'
				},
				remoteObj: {
					remoteOption: []
				},
				remote: null,
				form: {},
				// 校验规则
				rules: {},
			}
		},
		mounted() {

			this.setRules();

		},
		options: {
			styleIsolation: 'shared'
		},
		methods: {
			initSelect() {
				this.formProps.forEach(async item => {
					if (item.remoteName) {
						this.$refs[item.key][0].setMixinDatacomResData(this.remote[item.remoteName]())
					}

				})

			},
			setRemote(param) {
				this.remote = param
				
				this.initSelect();
			},
			async getRemoteFun(val) {
				let arr = await this.remote[val]()
				console.log(arr)
				return arr
			},
			setRules() {
				this.rules = {}
				this.formProps.forEach(item => {
					if (item.required) {
						this.rules[item.key] = {
							rules: [{
								required: true,
								errorMessage: `${item.label}不能为空`
							}]
						}
					}
				})
			},
			onchange(param, item) {
				// console.log(param,item)
				//判断该表单是否有关联操作
				if (item.relationForm) {

					item.relationForm.forEach(temp => {
						// formTypeMap.forEach(ftype=>{
						// 	if(ftype.type ===item.formType){
						// 		ftype.feedbackType(temp.type);
						// 	}
						// })
						if (item.formType === 'select') {
							//如果是下拉框
							if (temp.type === 'reload') {
								//重新加载
								let dataArr = []
								if (temp.searchParam) {
									temp.searchParam.forEach(ele => {

										dataArr.push({
											field: ele.field,
											operator: ele.operator,
											value: ele.fieldParam === 'id' ? param.value : param
												.text
										});
									})
								}
								//清除关联表单的内容
								this.$refs[temp.key][0].clearCurrent()
								this.$refs[temp.key][0].setMixinDatacomResData(this.remote[temp.event](dataArr))
							}

						}

					})
				}


			},
			validateForm() {
				let self = this;
				self.$refs.form.validate().then(res => {
					self.$emit("submitForm", res)

				}).catch(err => {
					console.log(err)
				})
			}
		}
	}
</script>

<style scoped>
	.continer {
		width: 100%;
		height: 100%;
	}

	.form_element {
		width: calc(100% - 40upx);
		padding: 20upx;
		border-bottom: 1px solid #ccc;
	}

	.form_title {
		width: 100%;
		font-weight: 800;
		font-size: 32upx;

	}

	.input_box {
		display: flex;
		align-items: center;
	}

	.unit {
		margin-right: 20upx;
	}

	/* ::v-deep .uni-section .uni-section-header__content {
		font-weight: 800;
	
	}
	
	::v-deep .uni-section .uni-section-header {
		padding: 0;
	} */
	::v-deep .uni-input {
		padding: 20upx 0 0 0;

	}

	::v-deep .uni-select {
		border: none;
		padding: 20upx 0 0 0;
	}

	::v-deep .uni-forms-item__label {
		display: none;
	}

	::v-deep .is-input-border {
		border: none;
		padding: 20upx 0 0 0;
	}

	::v-deep .input-padding {
		padding: 0;
	}

	::v-deep .uni-easyinput__content-textarea {}

	::v-deep .uni-textare {}

	.is-required {
		color: #dd524d;
		font-weight: bold;
		margin-right: 10upx;
	}
</style>

四、进入uni-data-select组件,添加一个支持远程接口的方法

//在methods中新增一个自定义方法,通过第三阶段initSelect的方法中调用,将对应的Promise对象传入,来修改组件的数据
	setMixinDatacomResData(param){
				param.then(res=>{
					this.mixinDatacomResData = res;
				})
				
			}

效果图

五、进阶表单——关联关系

由一个表单影响其他表单的操作-------关联表单关系
我们要回到第一部分,对应类型表单的结构体
例如下图,我们需要在项目名称下拉发生change的时候,改变产品名称表单的数据,需要通过relationForm数组绑定(可绑定多个)
relationForm的
key:代表对应受到影响的表单key,
type:受影响类型,
event:绑定受到影响后需要执行的远程方法,
searchParam:为调用方法需要传递的部分参数

//产品交付
export function BusinessDailyProduct() {
	return [{
			label: '项目名称',
			key: 'project',
			name: 'projectname', //下拉选项中文名的属性名
			id: 'projectid', //下拉选项的id属性名
			remoteName: 'getProjectName',
			formType: 'select',
			relationForm:[{key:'product',type:'reload',event:'getProductByProject',searchParam:[{fieldParam:'id', field:'projectid',operator:'eq',value:''}]}], //关联表单及其触发事件绑定
			required: true,
		}, {
			label: '产品名称',
			formType: 'select',
			key: 'product',
			name: 'productname', //下拉选项中文名的属性名
			id: 'productid', //下拉选项的id属性名
			// remoteName: 'getProductByProject',
			required: true,
		}, {
			label: '工时',
			key: 'workhour',
			unitName: '时',
			required: true,
		},
		{
			label: '工作内容',
			key: 'workcontent',
			formType: 'textarea',
			required: true,
		}, {
			label: '存在问题',
			key: 'existproblem',
			formType: 'textarea',
			required: true,
		},

	]
}


//对应的受影响的远程方法----上面的event
//根据项目获取对应的产品
export async function getProductByProject(searchCondition) {

	let res = await request({
		url: '/business/product/manage/list',
		method: 'post',
		data: new SearchCondition({searchCondition,}),

	})
	let arr = res.data.data.list.map(item => ({
		text: item.productname,
		value: item.id,
		...item
	}))

	return await arr;

}

下班了!,再见!!!!,下回聊

有关Uniapp微信小程序实现简易生成表单生成器的更多相关文章

  1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  2. ruby-on-rails - Rails 编辑表单不显示嵌套项 - 2

    我得到了一个包含嵌套链接的表单。编辑时链接字段为空的问题。这是我的表格:Editingkategori{:action=>'update',:id=>@konkurrancer.id})do|f|%>'Trackingurl',:style=>'width:500;'%>'Editkonkurrence'%>|我的konkurrencer模型:has_one:link我的链接模型:classLink我的konkurrancer编辑操作:defedit@konkurrancer=Konkurrancer.find(params[:id])@konkurrancer.link_attrib

  3. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  4. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

  5. ruby - 如何在 Rails 4 中使用表单对象之前的验证回调? - 2

    我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser

  6. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  7. ruby-on-rails - Ruby on Rails - 为文本区域和图片生成列 - 2

    我是Rails的新手,所以请原谅简单的问题。我正在为一家公司创建一个网站。那家公司想在网站上展示它的客户。我想让客户自己管理这个。我正在为“客户”生成一个表格,我想要的三列是:公司名称、公司描述和Logo。对于名称,我使用的是name:string但不确定如何在脚本/生成脚手架终端命令中最好地创建描述列(因为我打算将其设置为文本区域)和图片。我怀疑描述(我想成为一个文本区域)应该仍然是描述:字符串,然后以实际形式进行调整。不确定如何处理图片字段。那么……说来话长:我在脚手架命令中输入什么来生成描述和图片列? 最佳答案 对于“文本”数

  8. ruby-on-rails - 如何生成传递一些自定义参数的 `link_to` URL? - 2

    我正在使用RubyonRails3.0.9,我想生成一个传递一些自定义参数的link_toURL。也就是说,有一个articles_path(www.my_web_site_name.com/articles)我想生成如下内容:link_to'Samplelinktitle',...#HereIshouldimplementthecode#=>'http://www.my_web_site_name.com/articles?param1=value1¶m2=value2&...我如何编写link_to语句“alàRubyonRailsWay”以实现该目的?如果我想通过传递一些

  9. ruby-on-rails - 如何在 Rails 3 中创建自定义脚手架生成器? - 2

    有这些railscast。http://railscasts.com/episodes/218-making-generators-in-rails-3有了这个,你就会知道如何创建样式表和脚手架生成器。http://railscasts.com/episodes/216-generators-in-rails-3通过这个,您可以了解如何添加一些文件来修改脚手架View。我想把两者结合起来。我想创建一个生成器,它也可以创建脚手架View。有点像RyanBates漂亮的生成器或web_app_themegem(https://github.com/pilu/web-app-theme)。我

  10. 报告回顾丨模型进化狂飙,DetectGPT能否识别最新模型生成结果? - 2

    导读语言模型给我们的生产生活带来了极大便利,但同时不少人也利用他们从事作弊工作。如何规避这些难辨真伪的文字所产生的负面影响也成为一大难题。在3月9日智源Live第33期活动「DetectGPT:判断文本是否为机器生成的工具」中,主讲人Eric为我们讲解了DetectGPT工作背后的思路——一种基于概率曲率检测的用于检测模型生成文本的工具,它可以帮助我们更好地分辨文章的来源和可信度,对保护信息真实、防止欺诈等方面具有重要意义。本次报告主要围绕其功能,实现和效果等展开。(文末点击“阅读原文”,查看活动回放。)Ericmitchell斯坦福大学计算机系四年级博士生,由ChelseaFinn和Chri

随机推荐