byForm.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. <template>
  2. <div class="by-form">
  3. <el-form class="byForm"
  4. :style="{ height: attrs.height ? attrs.height + 'px' : 'auto' }"
  5. :model="value"
  6. ref="byForm"
  7. :validate-on-rule-change="false"
  8. :size="attrs.size ? attrs.size : 'small'"
  9. :inline-message="true"
  10. v-bind="$attrs"
  11. :disabled="attrs.disabled"
  12. :label-width="attrs.labelWidth"
  13. :rules="attrs.readonly?[]:attrs.rules"
  14. :label-position="attrs.labelPosition ? attrs.labelPosition : ''">
  15. <el-row class="form-row" v-for="(itemChild,index) of columns" :key="index">
  16. <el-col v-for="(item,_ind) of itemChild" :span="item.span" :key="'itemChild'+_ind">
  17. <el-form-item class="by-form-item"
  18. :label="item.label"
  19. :rules="attrs.readonly?[]:item.rules"
  20. :prop="item.prop"
  21. :required="item.required"
  22. :error="item.error"
  23. :size="item.size"
  24. :label-width="item.labelWidth?item.labelWidth:'100px'">
  25. <component v-bind:is="item.component"
  26. class="form-comp"
  27. :propConfig="item.compConfig"
  28. :ref="item.prop+'Comp'"
  29. :propValue="value[item.prop]"
  30. @onChange="onChange($event,item)"
  31. v-bind="$attrs"
  32. v-on="$listeners"
  33. />
  34. <slot v-if="item.slot" :name='item.prop' :value='value'></slot>
  35. <!-- <slot :[item.prop]="value" ></slot> -->
  36. <div class="readonly-cover" v-if="attrs.readonly"></div>
  37. </el-form-item>
  38. </el-col>
  39. </el-row>
  40. </el-form>
  41. </div>
  42. </template>
  43. <script lang="ts">
  44. /*
  45. 基础配置
  46. config:{
  47. attr:{
  48. disabled:true/false //表单禁用
  49. readonly:true/false //表单只读
  50. size:medium / small / mini, //表单域下组件的尺寸,
  51. height:'', //高度
  52. labelPosition: right/left/top //标签位置
  53. labelWidth: '' //标签的宽度
  54. rules:[] //验证规则
  55. },
  56. columns: [[{ //表单列
  57. span:'' //分栏,
  58. label:'' //标签
  59. prop:'' //字段
  60. labelWidth:'' 标签的的宽度
  61. rule:{} //验证规则
  62. size:medium / small / mini //表单域下组件的尺寸,
  63. component:'' //组件
  64. compConfig:{} //组件配置
  65. }]]
  66. request:{
  67. url:'',
  68. method:'',
  69. headers:{},
  70. data:{}
  71. }
  72. }
  73. */
  74. import { Component, Prop, Vue, Watch } from "vue-property-decorator";
  75. import VueViews from '@/benyun/compVue/VueViews'
  76. @Component
  77. export default class ByForm extends VueViews {
  78. value:any={}
  79. get columns(){
  80. let columns:Array<any> = this.config?.columns ? this.config.columns : []
  81. //分栏设置
  82. if(columns.length > 0){
  83. for (const itemChild of columns) {
  84. let spans = 24
  85. let n = itemChild.length
  86. for(const item of itemChild){
  87. if (item && ((Number(item.span) > 0 && Number(item.span) <= 24))) {
  88. spans = spans - Number(item.span)
  89. n--;
  90. }
  91. }
  92. for(const item of itemChild){
  93. if (Number(item.span) > 0 && Number(item.span) <= 24) {
  94. item.span = Number(item.span)
  95. } else {
  96. item.span = spans / n
  97. }
  98. }
  99. }
  100. }
  101. return columns
  102. }
  103. created(){
  104. if(this.propConfig){
  105. this.setConfig(this.propConfig)
  106. }
  107. }
  108. mounted(){}
  109. //设置数据
  110. setValue(data:any){
  111. this.clearChildrenComp();
  112. if(data){
  113. this.value = (this as any).$lodash.cloneDeep(data);
  114. }else{
  115. this.value = {};
  116. }
  117. this.setChildrenComValue();
  118. }
  119. //获取数据
  120. getValue(){
  121. return (this as any).$lodash.cloneDeep(this.value);
  122. }
  123. setConfigAfter(){
  124. if(this.columns.length > 0){
  125. for(const itemData of this.columns){
  126. for(const item of itemData){
  127. if(this.$refs[item.prop+'Comp'] && (this.$refs[item.prop+'Comp'] as any)[0] && (this.$refs[item.prop+'Comp'] as any)[0].setConfig){
  128. (this.$refs[item.prop+'Comp'] as any)[0].setConfig(item.compConfig)
  129. }
  130. }
  131. }
  132. }
  133. }
  134. //清除下级组件组件值
  135. clearChildrenComp(){
  136. for(const key in this.$refs){
  137. if(key.indexOf('Comp') >= 0 && (this as any).$refs[key][0] && (this as any).$refs[key][0].clearValue){
  138. (this as any).$refs[key][0].clearValue()
  139. }
  140. }
  141. }
  142. //设置下级组件值
  143. setChildrenComValue(){
  144. if(this.value){
  145. for(const key in this.value){
  146. const code = key +'Comp';
  147. if((this as any).$refs[code] && (this as any).$refs[code][0] && (this as any).$refs[code][0].setValue){
  148. (this as any).$refs[code][0].setValue(this.value[key])
  149. }
  150. }
  151. }
  152. }
  153. //表单数据变化
  154. onChange(v:any,config:any){
  155. let code = config.prop;
  156. if (v && (v as any).constructor === Object){
  157. for(const key in v){
  158. this.changeSetValue(key,v[key])
  159. }
  160. }else{
  161. this.changeSetValue(code,v)
  162. }
  163. this.$emit('formChange',{value:v,code:code})
  164. }
  165. changeSetValue(code:string,v:any){
  166. if(this.value[code]){
  167. this.value[code] = v;
  168. }else{
  169. Vue.set(this.value, code, v);
  170. }
  171. }
  172. //表单验证
  173. validate(parames?:any):Promise<any>{
  174. return new Promise((resolve:Function, reject:Function) => {
  175. (this as any).$refs.byForm.validate((valid:any) => {
  176. if (valid) {
  177. resolve(true)
  178. } else {
  179. if(!parames || !parames.noMsg){
  180. (this as any).$message({
  181. message: '验证未通过,请检查!',
  182. type: 'warning',
  183. })
  184. }
  185. reject()
  186. }
  187. });
  188. })
  189. }
  190. }
  191. </script>
  192. <style lang="scss" scoped>
  193. .by-form{
  194. width: 100%;
  195. .form-comp{
  196. width: 100%;
  197. }
  198. .readonly-cover{
  199. position: absolute;
  200. height: 100%;
  201. width: 100%;
  202. left: 0;
  203. top: 0;
  204. }
  205. }
  206. </style>
  207. <style lang="scss">
  208. .by-form-item{
  209. margin-bottom: 10px !important;
  210. }
  211. </style>