subform.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. <template>
  2. <div class="oSubform" :class="[preview ? '' : 'o-unit']" v-if="widget.type == 'subform'">
  3. <!-- <input type="text" :name="widget.model" v-model="dataModel"> -->
  4. <!-- <van-field type="hidden" :name="widget.model" v-model="dataModel" /> -->
  5. <van-cell v-if="!preview" style="padding-bottom: 5px;" :title="(widget.name || '子表单')" :border="false"></van-cell>
  6. <div v-for="(child, iChild) in columns" :key="iChild" :class="preview ? 'previewSection' : null">
  7. <van-cell v-if="preview" class="previewTitle" :title="(widget.name || '子表单') + `${iChild + 1}`" :border="false"></van-cell>
  8. <span v-if="columns.length > 1 && !preview" class="delete">
  9. <span @click="onDelete(child, iChild)">删除</span>
  10. </span>
  11. <div v-if="child.list && child.list.length > 0" :class="[preview ? null : 'van-hairline--bottom']">
  12. <div v-for="(item, index) in child.list" :key="'o' + index">
  13. <template v-if="item.type == 'input' && !item.hidden">
  14. <o-input :widget="item" :fileCheck="fileCheck" :preview="preview" :value="defaultValue ? defaultValue[iChild] : null" />
  15. </template>
  16. <template v-if="item.type == 'textarea' && !item.hidden">
  17. <o-textarea :widget="item" :fileCheck="fileCheck" :preview="preview" :value="defaultValue ? defaultValue[iChild] : null" />
  18. </template>
  19. <template v-if="item.type == 'number' && !item.hidden">
  20. <o-number :widget="item" :fileCheck="fileCheck" :preview="preview" :value="defaultValue ? defaultValue[iChild] : null" />
  21. </template>
  22. <template v-if="item.type == 'radio' && !item.hidden">
  23. <o-radio :widget="item" :fileCheck="fileCheck" :preview="preview" :value="defaultValue ? defaultValue[iChild] : null" />
  24. </template>
  25. <template v-if="item.type == 'checkbox' && !item.hidden">
  26. <o-checkbox :widget="item" :fileCheck="fileCheck" :preview="preview" :value="defaultValue ? defaultValue[iChild] : null" />
  27. </template>
  28. <template v-if="item.type == 'date' && !item.hidden">
  29. <o-date :widget="item" :fileCheck="fileCheck" :preview="preview" :value="defaultValue ? defaultValue[iChild] : null" />
  30. </template>
  31. <template v-if="item.type == 'rate' && !item.hidden">
  32. <o-rate :widget="item" :fileCheck="fileCheck" :preview="preview" :value="defaultValue ? defaultValue[iChild] : null" />
  33. </template>
  34. <template v-if="item.type == 'select' && !item.hidden">
  35. <o-select :widget="item" :fileCheck="fileCheck" @relationFormChange="relationFormChange" :preview="preview" :value="defaultValue ? defaultValue[iChild] : null" />
  36. </template>
  37. <template v-if="item.type == 'organ' && !item.hidden">
  38. <o-organ :widget="item" :fileCheck="fileCheck" :preview="preview" :value="defaultValue ? defaultValue[iChild] : null" />
  39. </template>
  40. <template v-if="item.type == 'school' && !item.hidden">
  41. <o-school :widget="item" :fileCheck="fileCheck" :preview="preview" :value="defaultValue ? defaultValue[iChild] : null" />
  42. </template>
  43. <template v-if="item.type == 'text' && !item.hidden">
  44. <o-text :widget="item" :fileCheck="fileCheck" :preview="preview" :value="defaultValue ? defaultValue[iChild] : null" />
  45. </template>
  46. <template v-if="item.type == 'imgupload' && !item.hidden">
  47. <o-img-upload :widget="item" :fileCheck="fileCheck" :preview="preview" :value="defaultValue ? defaultValue[iChild] : null" />
  48. </template>
  49. <template v-if="item.type == 'file' && !item.hidden">
  50. <o-file-upload :widget="item" :fileCheck="fileCheck" @fileCheckRequired="fileCheckRequired" :preview="preview" :value="defaultValue ? defaultValue[iChild] : null" />
  51. </template>
  52. <template v-if="item.type == 'divider' && !item.hidden">
  53. <o-divider :widget="item" :fileCheck="fileCheck" :preview="preview" :value="defaultValue ? defaultValue[iChild] : null" />
  54. </template>
  55. <template v-if="item.type == 'cascader' && !item.hidden">
  56. <o-cascader :widget="item" :fileCheck="fileCheck" :preview="preview" :value="defaultValue ? defaultValue[iChild] : null" />
  57. </template>
  58. <!-- <template v-if="item.type == 'subform'">
  59. <o-subform :widget="item" />
  60. </template> -->
  61. </div>
  62. </div>
  63. </div>
  64. <div class="addItem" @click="addItem" v-if="!preview">
  65. <van-icon name="plus" /> 添加
  66. </div>
  67. </div>
  68. </template>
  69. <script>
  70. import OInput from './input'
  71. import OTextarea from './textarea'
  72. import ONumber from './number'
  73. import ORadio from './radio'
  74. import OCheckbox from './checkbox'
  75. import ODate from './date'
  76. import ORate from './rate'
  77. import OSelect from './select'
  78. import OOrgan from './organ'
  79. import OSchool from './school'
  80. import OText from './text'
  81. import OImgUpload from './imgFile'
  82. import OFileUpload from './fileUpload'
  83. import ODivider from './divider'
  84. import OCascader from './cascader'
  85. export default {
  86. name: 'oSubform',
  87. components: {OInput, OTextarea, ONumber, ORadio, OCheckbox, ODate, ORate, OSelect, OOrgan, OSchool, OText, OImgUpload, OFileUpload, ODivider, OCascader },
  88. props: ['widget', 'value', 'preview', 'fileCheck'],
  89. data() {
  90. return {
  91. columns: [],
  92. tempColumns: [],
  93. models: {},
  94. defaultValue: null,
  95. }
  96. },
  97. mounted() {
  98. this.__init()
  99. },
  100. methods: {
  101. __init() {
  102. // 初始化参数
  103. this.columns = []
  104. this.tempColumns = []
  105. const columns = this.widget.columns || []
  106. let arr = {
  107. list: []
  108. }
  109. columns.forEach(item => {
  110. if(item.list?.length > 0) {
  111. item.list.forEach(child => {
  112. child.originModel = child.model
  113. child.model = this.widget.model + '.' + child.model + '.0'
  114. })
  115. arr.list.push(...item.list)
  116. }
  117. });
  118. this.columns.push(arr)
  119. this.tempColumns.push(arr)
  120. if(this.value) {
  121. const widget = this.widget
  122. const model = widget.originModel || widget.model
  123. for(let v in this.value) {
  124. if(v == model) {
  125. this.defaultValue = this.value[v]
  126. }
  127. }
  128. }
  129. // 对比值跟表单对比
  130. if(this.defaultValue) {
  131. let arrDiff = this.defaultValue.length - this.columns?.length
  132. if(arrDiff > 0) {
  133. for(let i = 0; i < arrDiff; i++) {
  134. this.addItem()
  135. }
  136. }
  137. }
  138. },
  139. reSetFormData() {
  140. this.columns = []
  141. const columns = this.widget.columns || []
  142. let arr = {
  143. list: []
  144. }
  145. columns.forEach(item => {
  146. if(item.list?.length > 0) {
  147. arr.list.push(...item.list)
  148. }
  149. });
  150. this.columns.push(arr)
  151. },
  152. addItem() {
  153. // 添加组件
  154. // console.log(this.tempColumns)
  155. let tempColumns = JSON.parse(JSON.stringify(this.tempColumns))
  156. tempColumns.forEach(item => {
  157. if(item.list?.length > 0) {
  158. item.list.forEach(child => {
  159. let model = child.model.split('.')
  160. model.pop()
  161. model = model.join('.')
  162. child.model = model + '.' + this.columns.length
  163. })
  164. }
  165. })
  166. this.columns.push(...tempColumns)
  167. },
  168. onDelete(child, index) {
  169. this.$dialog.confirm({
  170. message: `你确定要删除吗?`,
  171. }).then(() => {
  172. // on confirm
  173. if (index !== -1) {
  174. this.columns.splice(index, 1)
  175. }
  176. })
  177. },
  178. relationFormChange(value) { // 是否隐藏对应表单
  179. this.$emit('relationFormChange', value)
  180. },
  181. fileCheckRequired(value) { // 退费模板上传附件
  182. this.$emit('fileCheckRequired', value)
  183. },
  184. },
  185. computed: {
  186. options() {
  187. return this.widget.options || {}
  188. },
  189. // columns() {
  190. // return this.widget.columns || []
  191. // }
  192. },
  193. watch: {
  194. // dataModel: {
  195. // deep: true,
  196. // handler(newValue) {
  197. // if (newValue !== undefined && newValue !== null) {
  198. // }
  199. // }
  200. // },
  201. // value: {
  202. // deep: true,
  203. // handler(val) {
  204. // this.models = { ...this.models, ...val }
  205. // }
  206. // }
  207. }
  208. }
  209. </script>
  210. <style lang='less' scoped>
  211. .o-unit {
  212. margin-bottom: 12px;
  213. }
  214. .oSubform {
  215. .delete {
  216. color: #01C1B5;
  217. font-size: 0.14rem;
  218. padding: 0.05rem 0.1rem 0;
  219. display: block;
  220. text-align: right;
  221. }
  222. .o-unit {
  223. margin-bottom: 0;
  224. position: relative;
  225. &::after {
  226. position: absolute;
  227. box-sizing: border-box;
  228. content: ' ';
  229. pointer-events: none;
  230. right: 16px;
  231. bottom: 0;
  232. left: 16px;
  233. border-bottom: 1px solid #ebedf0;
  234. -webkit-transform: scaleY(0.5);
  235. transform: scaleY(0.5);
  236. }
  237. }
  238. /deep/.van-field {
  239. padding: 12px 16px;
  240. line-height: 1.3;
  241. display: flex;
  242. font-size: 16px;
  243. }
  244. .addItem {
  245. display: flex;
  246. align-items: center;
  247. justify-content: center;
  248. background: #fff;
  249. padding: .1rem;
  250. color: #01C1B5;
  251. /deep/.van-icon {
  252. font-size: .16rem;
  253. padding-right: .03rem;
  254. }
  255. }
  256. .previewSection {
  257. padding: 0 .16rem;
  258. .previewTitle {
  259. padding: 0 .1rem;
  260. margin-top: .1rem;
  261. background: #f5f5f5;
  262. color: #808080;
  263. }
  264. }
  265. }
  266. </style>