vue3【组件封装】超级表单 S-form.vue

最终效果

在这里插入图片描述
在这里插入图片描述

代码实现

components/SUI/S-form.vue

<script lang="ts" setup>
import type { FormInstance } from "element-plus";// 使用索引签名定义对象类型
type GenericObject = {[key: string]: any;
};const props = defineProps<{Model?: GenericObject;disabled?: boolean;hideHandle?: boolean;saveAPI?: string;saveOK?: () => void;local_save?: (formData: GenericObject) => void;cancel?: () => void;colNum?: number;action?: string;PageConfig?: GenericObject;
}>();const formData = defineModel<GenericObject>({});const formItemConfigList = computed(() => {let result: any = [];if (props.Model) {for (const [key, value] of Object.entries(props.Model)) {let temp_value = JSON.parse(JSON.stringify(value));// 解析 -- 必填if ("require" in temp_value && temp_value.require) {if ("formRules" in temp_value &&temp_value.formRules &&Array.isArray(temp_value.formRules)) {temp_value.formRules.push({required: true,message: "请输入" + temp_value.label,});} else {temp_value.formRules = [{required: true,message: "请输入" + temp_value.label,},];}}result.push({prop: key,...(temp_value as object),});}}return result;
});const group_formItemConfigList_Obj = computed(() => {let result: any = {};if (props.PageConfig && props.PageConfig.formGrouped) {let final_formItemConfigList: any[] = [];formItemConfigList.value.forEach((formItemConfig: any) => {if (!(formItemConfig.formHide &&(formItemConfig.formHide === "all" ||(Array.isArray(formItemConfig.formHide) &&formItemConfig.formHide.includes(props.action))))) {final_formItemConfigList.push(formItemConfig);}});result = groupBy(final_formItemConfigList,"group",props.PageConfig.groupName_default);}return result;
});const activeGroups: string[] = Object.keys(group_formItemConfigList_Obj.value);const pageData = reactive<{localFomrData: GenericObject;
}>({localFomrData: formData.value || {},
});const { localFomrData } = toRefs(pageData);const formRef = ref<FormInstance>();const callbackMessage = ref({show: false,valid: true,content: "",
});// 按钮 -- 保存
const submitForm = (formEl: FormInstance | undefined) => {if (!formEl) return;formEl.validate(async (valid) => {if (valid) {if (props.local_save) {props.local_save(pageData.localFomrData);return;}try {await $fetch(`/api${props.saveAPI}`, {body: pageData.localFomrData,method: "POST",});callbackMessage.value = {show: true,valid: true,content: "操作成功",};if (props.saveOK) {props.saveOK();}} catch (e: any) {callbackMessage.value = {show: true,valid: false,content: e.data.message,};}} else {console.log("提交报错!");}});
};// 将方法暴露给父组件
defineExpose({submitForm,localFomrData,formRef,
});
</script>
<template><div class="relative mt-10"><el-scrollbar max-height="460px" class="px10"><el-formref="formRef":inline="true":model="localFomrData":disabled="props.disabled"><el-collapsev-if="props.PageConfig && props.PageConfig.formGrouped"v-model="activeGroups"><el-collapse-item:name="group"v-for="(formItemConfigList, group) in group_formItemConfigList_Obj":key="group"><template #title><div class="font-bold text-14px">{{ group }}</div></template><S-formRow:formItemConfigList="formItemConfigList":colNum="props.colNum":action="props.action"v-model="localFomrData":disabled="props.disabled"><templatev-for="formItemConfig in formItemConfigList.filter((item:any) => item.type === 'custom')":key="formItemConfig.prop"#[formItemConfig.prop]><slot :name="formItemConfig.prop" /></template></S-formRow></el-collapse-item></el-collapse><S-formRowv-else:formItemConfigList="formItemConfigList":colNum="props.colNum":action="props.action":disabled="props.disabled"v-model="localFomrData"><templatev-for="formItemConfig in formItemConfigList.filter((item:any) => item.type === 'custom')":key="formItemConfig.prop"#[formItemConfig.prop]><slot :name="formItemConfig.prop" /></template></S-formRow></el-form></el-scrollbar><div class="flex justify-center p4" v-if="!props.disabled && !hideHandle"><el-button @click="props.cancel">取消</el-button><el-button type="primary" @click="submitForm(formRef)">保存</el-button></div><S-msgWin :msg="callbackMessage" /></div>
</template>

components/SUI/S-formRow.vue

<script lang="ts" setup>
import { ref, onMounted } from "vue";
import { defineAsyncComponent } from "vue";const props = defineProps<{formItemConfigList: any;colNum?: number;action?: string;disabled?: boolean;
}>();const localFomrData = defineModel<any>({});// 标记客户端环境
const isClient = ref(false);// 动态导入组件,禁用SSR
const AvatarCropper = defineAsyncComponent({loader: () => import("~/components/SUI/S-avatar.vue"),suspensible: false, // 关键:禁止在服务端渲染该组件,使用 suspensible 替代 ssr
});onMounted(() => {isClient.value = true; // 确保在客户端挂载后才显示组件
});
</script>
<template><el-row :sapn="24"><template v-for="formItemConfig in formItemConfigList"><el-colv-if="!(formItemConfig.formHide &&(formItemConfig.formHide === 'all' ||(Array.isArray(formItemConfig.formHide) &&formItemConfig.formHide.includes(props.action))))":span="formItemConfig.span || (props.colNum && 24 / props.colNum) || 12":key="formItemConfig.prop"><el-form-item:label="formItemConfig.label":label-width="160":rules="formItemConfig.formRules":prop="formItemConfig.prop"><el-date-pickerv-if="formItemConfig.type === 'date'"v-model="localFomrData[formItemConfig.prop as string]"type="date"placeholder="选择日期"v-bind="formItemConfig"/><el-input-numberv-else-if="formItemConfig.type === 'number'"v-model="localFomrData[formItemConfig.prop as string]"v-bind="formItemConfig"controls-position="right"class="w-220px!"><template #suffix><span>{{ formItemConfig.unit }}</span></template></el-input-number><el-switchv-else-if="formItemConfig.type === 'switch'"v-model="localFomrData[formItemConfig.prop as string]"v-bind="formItemConfig"class="w-220px!"/><el-selectv-else-if="formItemConfig.type === 'select'"v-model="localFomrData[formItemConfig.prop as string]"filterableclearable:multiple="formItemConfig.multSelect"class="w-220px!"placeholder=""><el-optionv-for="item in formItemConfig.options || []":key="item.value":label="item.label":value="item.value"/></el-select><el-tree-selectv-else-if="formItemConfig.type === 'treeSelect'"v-model="localFomrData[formItemConfig.prop as string]":data="formItemConfig.treeData":render-after-expand="false"class="w-220px!"filterableclearable:node-key="formItemConfig.key"default-expand-all/><AvatarCropperv-else-if="isClient && formItemConfig.type === 'avatar'":disabled="(formItemConfig.formDisable &&formItemConfig.formDisable.includes(props.action)) ||props.disabled"v-model="localFomrData[formItemConfig.prop as string]"/><template v-else-if="formItemConfig.type === 'custom'"><slot :name="formItemConfig.prop" /></template><el-inputv-elsev-model="localFomrData[formItemConfig.prop as string]"v-bind="formItemConfig"class="w-220px!":type="formItemConfig.type || 'text'":disabled="formItemConfig.formDisable &&formItemConfig.formDisable.includes(props.action)":autosize="formItemConfig.autosize || { minRows: 2, maxRows: 4 }"show-word-limit/></el-form-item></el-col></template></el-row>
</template>

相关组件

头像 S-avatar.vue

https://blog.csdn.net/weixin_41192489/article/details/149716009

消息弹窗 S-msgWin.vue

https://blog.csdn.net/weixin_41192489/article/details/149717948

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/91211.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/91211.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android Studio Memory Monitor内存分析核心指标详解

Depth、Native Size、Shallow Size、Retained Size 解析 一、指标定义与对比指标定义计算逻辑重要性Shallow Size对象自身实例占用的内存基本类型字段大小 引用指针 内存对齐对象的基础内存成本Retained Size回收该对象可释放的总内存量&#xff08;含所有依赖对象&#xff0…

vue中使用wavesurfer.js绘制波形图和频谱图(支持.pcm)

新的实现方式&#xff1a;vue使用Canvas绘制频谱图 安装wavesurfer.js npm install wavesurfer.js第一版&#xff1a; 组件特点&#xff1a; 一次性加载好所有的数据&#xff1b; <template><div class"audio-visualizer-container"><div class&…

go mod教程、go module

什么是go mod go mod 是go语言的包管理工具&#xff0c;类似java 的maven&#xff0c;go mod的出现可以告别goPath&#xff0c;使用go module来管理项目&#xff0c;有了go mod账号就不需要非得把项目放到gopath/src目录下了&#xff0c;你可以在磁盘的任何位置新建一个项目 go…

150-SWT-MCNN-BiGRU-Attention分类预测模型等!

150-SWT-MCNN-BiGRU-Attention分类预测模型!基于多尺度卷积神经网络(MCNN)双向长短期记忆网络(BiGRU)注意力机制(Attention)的分类预测模型&#xff0c;matlab代码&#xff0c;直接运行使用&#xff01;1、模型介绍&#xff1a;针对传统方法在噪声环境下诊断精度低的问题&#…

MySQL数据一致性与主从延迟深度解析:从内核机制到生产实践

在高并发分布式系统中&#xff0c;数据一致性与复制延迟如同硬币的两面。本文深入剖析MySQL持久化机制与主从同步原理&#xff0c;并提供可落地的调优方案。一、数据持久化核心机制&#xff1a;双日志协同 1. Redo Log&#xff1a;崩溃恢复的生命线刷新策略&#xff08;innodb_…

【I】题目解析

目录 单选题 多选题 判断题 单选题 1.reg[7:0]A; A2hFF;则A&#xff08;&#xff09; A.8b11111110 B.8b03 C.8b00000011 D.8b11111111 C 2hFF实际上等效于2位二进制2b11&#xff0c;赋值给8位寄存器A之后&#xff0c;低位赋值&#xff0c;高位补0 A8b00000011 AMD FPG…

《Foundation 面板:设计、功能与最佳实践解析》

《Foundation 面板:设计、功能与最佳实践解析》 引言 在当今数字化时代,用户界面(UI)设计的重要性不言而喻。其中,Foundation 面板作为一种流行的前端框架,因其灵活性和高效性而被众多开发者所青睐。本文将深入解析 Foundation 面板的设计理念、功能特点以及最佳实践,…

React服务端渲染 Next 使用详解

1. Next.js 概述 Next.js 是一个基于 React 的开源框架&#xff0c;专注于服务器端渲染&#xff08;SSR&#xff09;和静态站点生成&#xff08;SSG&#xff09;&#xff0c;提供开箱即用的 SSR 功能&#xff0c;简化 React 应用的开发与部署。 2. Next.js 的核心特性 SSR 支…

Deforum Stable Diffusion,轻松实现AI视频生成自由!

摘要&#xff1a; 你是否曾被那些充满想象力、画面流畅的AI视频所震撼&#xff1f;你是否也想亲手创造出属于自己的AI动画&#xff1f;本文将为你提供一份“保姆级”的详尽教程&#xff0c;从环境配置到参数调整&#xff0c;一步步带你复现强大的Deforum Stable Diffusion模型&…

不同环境安装配置redis

不同环境安装配置redis windows 环境安装redis redis所有下载地址 windows版本redis下载&#xff08;GitHub&#xff09;&#xff1a; https://github.com/tporadowski/redis/releases &#xff08;推荐使用&#xff09;https://github.com/MicrosoftArchive/redis/releases]官…

汇川Easy系列PLC算法系列(回溯法ST语言实现)

Easy系列PLC 3次多项式轨迹插补算法 Easy系列PLC 3次多项式轨迹插补算法(完整ST代码)_plc连续插补算法-CSDN博客文章浏览阅读122次。INbExecuteBOOLOFFOFF不保持1INrStartPosREAL0.0000000.000000不保持起始位置unit2INrEndPosREAL0.0000000.000000不保持结束位置unit3INrStar…

Linux C:构造数据类型

目录 一、结构体&#xff08;struct&#xff09; 1.1类型定义 1.2 结构体变量定义 1.3 结构体元素初始化 1.4 结构体成员访问 1.5 结构体的存储&#xff08;内存对齐&#xff09; 1.6 结构体传参 本文主要记录了C语言中构造数据类型部分的内容&#xff0c;今天暂时只写了…

Python:self

在Python面向对象编程中&#xff0c;self是一个指向类实例自身的引用参数&#xff1a;‌1. 本质与作用‌‌身份标识‌&#xff1a;self是类实例化后对象的"身份证"&#xff0c;代表当前实例本身&#xff0c;用于区分不同实例的属性和方法‌‌自动传递‌&#xff1a;调…

【SpringMVC】SpringMVC的概念、创建及相关配置

什么是SpringMVC 概述 中文翻译版&#xff1a;Servlet 栈的 Web 应用 Spring MVC是Spring Framework的一部分&#xff0c;是基于Java实现MVC的轻量级Web框架。 查看官方文档&#xff1a;https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/web.h…

浅谈存储过程

问题引入 面试的时候有时候会问到知不知道存储过程&#xff0c;用没用过&#xff1f; 是什么 存储过程&#xff08;Stored Procedure&#xff09;是在大型数据库系统中&#xff0c;一组为了完成特定功能的SQL 语句集&#xff0c;它存储在数据库中&#xff0c;一次编译后永久…

maven optional 功能详解

前言 最近参与了一个项目,使用maven管理依赖.项目拆分了很多模块.然后交个多个团队各自开发.最后在一个项目骨架中,把各自的模块引入进来,一起启动. 后来随着项目的深入.引入的jar包变多.发现 jar包太多,编译太慢, 打包之后的war包非常大.这种情况就可以使用optional来优化什么…

Python基础--Day04--流程控制语句

流程控制语句是计算机编程中用于控制程序执行流程的语句。它们允许根据条件来控制代码的执行顺序和逻辑&#xff0c;从而使程序能够根据不同的情况做出不同的决策。流程控制实现了更复杂和灵活的编程逻辑。 顺序语句 顺序语句是按照编写的顺序依次执行程序中的代码。代码会按照…

【同济大学】双速率自动驾驶架构LeAD:端到端+LLM,CARLA实测93%路线完成率,性能SOTA!

近年来&#xff0c;随着端到端的技术快速发展将自动驾驶带到了一个新高度&#xff0c;并且取得了非常亮眼的成绩。由于感知限制和极端长尾场景下训练数据覆盖不足&#xff0c;模型在高密度复杂交通场景下和不规则交通情况下的处理能力不足&#xff0c;导致在开放道路上大规模部…

github与git新手教程(快速访问github)

0 序言 作为一个开发者&#xff0c;你必须知道github和git是什么&#xff0c;怎么使用。 github是一个存储代码等资源的远程仓库&#xff0c;一个大型项目往往需要很多人共同协作开发&#xff0c;而大家如何协同开发的进度与分工等要求需要有一个统一开放保存代码的平台。git…

Windows环境下安装Python和PyCharm

可以只安装PyCharm吗&#xff1f;不可以&#xff01;&#xff01;&#xff01; 开发Python应用程序需要同时安装Python和PyCharm。Python是一种编程语言&#xff0c;PyCharm是一个专门为Python开发设计的集成开发环境&#xff0c;提供丰富的功能以简化编码过程。 一、前期准备…