byForm.vue 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. <template>
  2. <div class="by-form">
  3. <el-descriptions v-if="attrs.showType=='desc'" :title="attrs.title" :column="attrs.itemCount" :border="attrs.border" :direction="attrs.direction"
  4. :size="attrs.size?attrs.size:'medium'" :colon="attrs.colon">
  5. <template v-for="(itemChild,index) of columns">
  6. <el-descriptions-item :label="item.label" v-for="(item,_ind) of itemChild" :span="item.colspan" :key="index+'-'+_ind">
  7. <slot v-if="item.descSlot" :name='item.prop+"_desc"' :value='value'></slot>
  8. <template v-else>{{value[item.prop]?value[item.prop]:'--'}}</template>
  9. </el-descriptions-item>
  10. </template>
  11. </el-descriptions>
  12. <el-form class="byForm"
  13. v-else
  14. :style="{ height: attrs.height ? attrs.height + 'px' : 'auto' }"
  15. :model="value"
  16. ref="byForm"
  17. :validate-on-rule-change="false"
  18. :size="attrs.size ? attrs.size : 'small'"
  19. :inline-message="true"
  20. v-bind="$attrs"
  21. :disabled="attrs.disabled"
  22. :label-width="attrs.labelWidth"
  23. :rules="attrs.readonly?{}:attrs.rules"
  24. :label-position="attrs.labelPosition ? attrs.labelPosition : ''">
  25. <el-row class="form-row" v-for="(itemChild,index) of columns" :key="index">
  26. <el-col v-for="(item,_ind) of itemChild" :span="item.span" :key="'itemChild'+_ind">
  27. <el-form-item class="by-form-item"
  28. :label="item.label"
  29. :rules="attrs.readonly?[]:item.rules"
  30. :prop="item.prop"
  31. :required="item.required"
  32. :error="item.error"
  33. :size="item.size"
  34. :label-width="item.labelWidth?item.labelWidth:'100px'">
  35. <component v-bind:is="item.component"
  36. class="form-comp"
  37. :propConfig="item.compConfig"
  38. :ref="item.prop+suffixCode"
  39. :parentValue="value"
  40. :propValue="value[item.prop]"
  41. @onChange="onChange($event,item)"
  42. v-bind="$attrs"
  43. v-on="$listeners"
  44. />
  45. <slot v-if="item.slot" :name='item.prop' :value='value'></slot>
  46. <!-- <slot :[item.prop]="value" ></slot> -->
  47. <div class="readonly-cover" v-if="attrs.readonly"></div>
  48. </el-form-item>
  49. </el-col>
  50. </el-row>
  51. </el-form>
  52. <!-- <el-button @click="getValueData">获取数据</el-button> -->
  53. </div>
  54. </template>
  55. <script lang="ts">
  56. /*
  57. 基础配置
  58. config:{
  59. attr:{
  60. showType: '' //展示形式
  61. title:'' //标题(desc的时候用)
  62. itemCount:'' //每行展示几列(desc的时候用)
  63. border:true/false //是否有边框(desc的时候用)
  64. direction: vertical / horizontal 排列的方向(desc的时候用)
  65. colon:true/false //是否显示冒号 (desc的时候用)
  66. disabled:true/false //表单禁用
  67. readonly:true/false //表单只读
  68. size:medium / small / mini, //表单域下组件的尺寸,
  69. height:'', //高度
  70. labelPosition: right/left/top //标签位置
  71. labelWidth: '' //标签的宽度
  72. rules:[] //验证规则
  73. },
  74. columns: [[{ //表单列
  75. span:'' //分栏,
  76. label:'' //标签
  77. prop:'' //字段
  78. labelWidth:'' 标签的的宽度
  79. rule:{} //验证规则
  80. size:medium / small / mini //表单域下组件的尺寸,
  81. component:'' //组件
  82. compConfig:{} //组件配置
  83. slot:true/false //插槽
  84. colspan:‘’ //在itemCount的基础上 列的数量(desc的时候用)
  85. descSlot:true/false //插槽(desc的时候用)
  86. }]]
  87. request:{
  88. url:'',
  89. method:'',
  90. headers:{},
  91. data:{}
  92. }
  93. }
  94. */
  95. import { Component, Prop, Vue, Watch } from "vue-property-decorator";
  96. import VueViews from '@/benyun/compVue/VueViews'
  97. @Component
  98. export default class ByForm extends VueViews {
  99. value:any={}
  100. suffixCode="--comp"
  101. get columns(){
  102. let columns:Array<any> = this.config?.columns ? this.config.columns : []
  103. //分栏设置
  104. if(columns.length > 0){
  105. for (const itemChild of columns) {
  106. let spans = 24
  107. let n = itemChild.length
  108. for(const item of itemChild){
  109. if (item && ((Number(item.span) > 0 && Number(item.span) <= 24))) {
  110. spans = spans - Number(item.span)
  111. n--;
  112. }
  113. }
  114. for(const item of itemChild){
  115. if (Number(item.span) > 0 && Number(item.span) <= 24) {
  116. item.span = Number(item.span)
  117. } else {
  118. item.span = spans / n
  119. }
  120. }
  121. }
  122. }
  123. return columns
  124. }
  125. created(){
  126. if(this.propConfig){
  127. this.setConfig(this.propConfig)
  128. }
  129. }
  130. mounted(){
  131. if(this.attrs.data){
  132. this.setValue(this.attrs.data);
  133. }
  134. }
  135. getValueData(){
  136. console.log('表单数据',this.value)
  137. }
  138. //设置数据
  139. setValue(data:any){
  140. if(data){
  141. this.value = (this as any).$lodash.cloneDeep(data);
  142. }else{
  143. this.value = {};
  144. }
  145. this.$nextTick(()=>{
  146. this.setChildrenComValue();
  147. })
  148. this.$forceUpdate();
  149. }
  150. clearValue(){
  151. this.value = {};
  152. this.clearChildrenComp();
  153. this.defaultHandle();
  154. }
  155. //获取数据
  156. getValue(){
  157. return (this as any).$lodash.cloneDeep(this.value);
  158. }
  159. setConfigAfter(){
  160. if(this.columns.length > 0){
  161. for(const itemData of this.columns){
  162. for(const item of itemData){
  163. if(this.$refs[item.prop+this.suffixCode] && (this.$refs[item.prop+this.suffixCode] as any)[0] && (this.$refs[item.prop+this.suffixCode] as any)[0].setConfig){
  164. (this.$refs[item.prop+this.suffixCode] as any)[0].setConfig(item.compConfig)
  165. }
  166. }
  167. }
  168. }
  169. }
  170. //清除下级组件组件值
  171. clearChildrenComp(){
  172. for(const key in this.$refs){
  173. if(key.indexOf(this.suffixCode) >= 0 && (this as any).$refs[key][0] && (this as any).$refs[key][0].clearValue){
  174. (this as any).$refs[key][0].clearValue()
  175. }
  176. }
  177. }
  178. //下级组件默认值
  179. defaultHandle(){
  180. for(const key in this.$refs){
  181. if(key.indexOf(this.suffixCode) >= 0 && (this as any).$refs[key][0] && (this as any).$refs[key][0].defaultHandle){
  182. (this as any).$refs[key][0].defaultHandle()
  183. }
  184. }
  185. }
  186. //设置下级组件值
  187. setChildrenComValue(){
  188. for(const key in (this as any).$refs){
  189. if(key.indexOf(this.suffixCode) >= 0 && (this as any).$refs[key] && (this as any).$refs[key][0] && (this as any).$refs[key][0].setValue){
  190. const code = key.split(this.suffixCode)[0];
  191. if(this.value){
  192. (this as any).$refs[key][0].setValue(this.value[code])
  193. }else{
  194. (this as any).$refs[key][0].setValue(null)
  195. }
  196. }
  197. }
  198. }
  199. //表单数据变化
  200. onChange(v:any,config:any){
  201. let code = config.prop;
  202. if (v && (v as any).constructor === Object){
  203. for(const key in v){
  204. this.changeSetValue(key,v[key])
  205. }
  206. }else{
  207. this.changeSetValue(code,v)
  208. }
  209. if((this as any).$refs.byForm){
  210. (this as any).$refs.byForm.validateField(code);
  211. }
  212. this.$emit('formChange',{value:v,code:code})
  213. }
  214. changeSetValue(code:string,v:any){
  215. if(this.value[code]){
  216. this.value[code] = v;
  217. }else{
  218. Vue.set(this.value, code, v);
  219. }
  220. }
  221. //表单验证
  222. validate(parames?:any):Promise<any>{
  223. return new Promise((resolve:Function, reject:Function) => {
  224. if(!this.$refs.byForm){
  225. resolve(true)
  226. }
  227. (this as any).$refs.byForm.validate((valid:any) => {
  228. if (valid) {
  229. resolve(true)
  230. } else {
  231. if(!parames || !parames.noMsg){
  232. (this as any).$message({
  233. message: '验证未通过,请检查!',
  234. type: 'warning',
  235. })
  236. }
  237. reject()
  238. }
  239. });
  240. })
  241. }
  242. //清除过滤提示
  243. clearValidate(){
  244. if(this.$refs.byForm){
  245. (this.$refs.byForm as any).clearValidate();
  246. }
  247. }
  248. }
  249. </script>
  250. <style lang="scss" scoped>
  251. .by-form{
  252. width: 100%;
  253. .form-comp{
  254. width: 100%;
  255. }
  256. .readonly-cover{
  257. position: absolute;
  258. height: 100%;
  259. width: 100%;
  260. left: 0;
  261. top: 0;
  262. }
  263. }
  264. </style>
  265. <style lang="scss">
  266. .by-form-item{
  267. margin-bottom: 10px !important;
  268. }
  269. </style>