RightPanel.vue 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906
  1. <template>
  2. <div class="right-board">
  3. <el-tabs v-model="currentTab" stretch class="center-tabs">
  4. <el-tab-pane label="组件属性" name="field" />
  5. <el-tab-pane label="表单属性" name="form" />
  6. </el-tabs>
  7. <div class="field-box">
  8. <a class="document-link" target="_blank" :href="documentLink" title="查看组件文档">
  9. <el-icon>
  10. <Link />
  11. </el-icon>
  12. </a>
  13. <el-scrollbar class="right-scrollbar">
  14. <!-- 组件属性 -->
  15. <el-form v-show="currentTab === 'field' && showField" size="default" label-width="90px" label-position="top"
  16. style="">
  17. <el-form-item v-if="activeData.changeTag" label="组件类型">
  18. <el-select v-model="activeData.tagIcon" placeholder="请选择组件类型" :style="{ width: '100%' }" @change="tagChange">
  19. <el-option-group v-for="group in tagList" :key="group.label" :label="group.label">
  20. <el-option v-for="item in group.options" :key="item.label" :label="item.label" :value="item.tagIcon">
  21. <svg-icon class="node-icon" :icon-class="item.tagIcon" style="margin-right: 10px;" />
  22. <span> {{ item.label }}</span>
  23. </el-option>
  24. </el-option-group>
  25. </el-select>
  26. </el-form-item>
  27. <el-form-item v-if="activeData.vModel !== undefined" label="字段名">
  28. <el-input v-model="activeData.vModel" placeholder="请输入字段名(v-model)" />
  29. </el-form-item>
  30. <el-form-item v-if="activeData.componentName !== undefined" label="组件名">
  31. {{ activeData.componentName }}
  32. </el-form-item>
  33. <el-form-item v-if="activeData.label !== undefined" label="标题">
  34. <el-input v-model="activeData.label" placeholder="请输入标题" />
  35. </el-form-item>
  36. <el-form-item v-if="activeData.placeholder !== undefined" label="占位提示">
  37. <el-input v-model="activeData.placeholder" placeholder="请输入占位提示" />
  38. </el-form-item>
  39. <el-form-item v-if="activeData['start-placeholder'] !== undefined" label="开始占位">
  40. <el-input v-model="activeData['start-placeholder']" placeholder="请输入占位提示" />
  41. </el-form-item>
  42. <el-form-item v-if="activeData['end-placeholder'] !== undefined" label="结束占位">
  43. <el-input v-model="activeData['end-placeholder']" placeholder="请输入占位提示" />
  44. </el-form-item>
  45. <el-form-item v-if="activeData.span !== undefined" label="表单栅格">
  46. <el-slider v-model="activeData.span" :max="24" :min="1" :marks="{ 12: '' }" @change="spanChange" />
  47. </el-form-item>
  48. <el-form-item v-if="activeData.layout === 'rowFormItem'" label="栅格间隔">
  49. <el-input-number v-model="activeData.gutter" :min="0" placeholder="栅格间隔" />
  50. </el-form-item>
  51. <el-form-item v-if="activeData.justify !== undefined" label="水平排列">
  52. <el-select v-model="activeData.justify" placeholder="请选择水平排列" :style="{ width: '100%' }">
  53. <el-option v-for="(item, index) in justifyOptions" :key="index" :label="item.label" :value="item.value" />
  54. </el-select>
  55. </el-form-item>
  56. <el-form-item v-if="activeData.align !== undefined" label="垂直排列">
  57. <el-radio-group v-model="activeData.align">
  58. <el-radio-button label="top" />
  59. <el-radio-button label="middle" />
  60. <el-radio-button label="bottom" />
  61. </el-radio-group>
  62. </el-form-item>
  63. <el-form-item v-if="activeData.labelWidth !== undefined" label="标签宽度">
  64. <el-input v-model.number="activeData.labelWidth" type="number" placeholder="请输入标签宽度" />
  65. </el-form-item>
  66. <el-form-item v-if="activeData.style && activeData.style.width !== undefined" label="组件宽度">
  67. <el-input v-model="activeData.style.width" placeholder="请输入组件宽度" clearable />
  68. </el-form-item>
  69. <el-form-item v-if="activeData.vModel !== undefined" label="默认值">
  70. <el-input :value="setDefaultValue(activeData.defaultValue)" placeholder="请输入默认值"
  71. @input="onDefaultValueInput" />
  72. </el-form-item>
  73. <el-form-item v-if="activeData.tag === 'el-checkbox-group'" label="至少应选">
  74. <el-input-number :value="activeData.min" :min="0" placeholder="至少应选"
  75. @input="$set(activeData, 'min', $event ? $event : undefined)" />
  76. </el-form-item>
  77. <el-form-item v-if="activeData.tag === 'el-checkbox-group'" label="最多可选">
  78. <el-input-number :value="activeData.max" :min="0" placeholder="最多可选"
  79. @input="$set(activeData, 'max', $event ? $event : undefined)" />
  80. </el-form-item>
  81. <el-form-item v-if="activeData.prepend !== undefined" label="前缀">
  82. <el-input v-model="activeData.prepend" placeholder="请输入前缀" />
  83. </el-form-item>
  84. <el-form-item v-if="activeData.append !== undefined" label="后缀">
  85. <el-input v-model="activeData.append" placeholder="请输入后缀" />
  86. </el-form-item>
  87. <el-form-item v-if="activeData['prefix-icon'] !== undefined" label="前图标">
  88. <el-input v-model="activeData['prefix-icon']" placeholder="请输入前图标名称">
  89. <template #append>
  90. <el-button icon="Pointer" @click="openIconsDialog('prefix-icon')">
  91. 选择
  92. </el-button>
  93. </template>
  94. </el-input>
  95. </el-form-item>
  96. <el-form-item v-if="activeData['suffix-icon'] !== undefined" label="后图标">
  97. <el-input v-model="activeData['suffix-icon']" placeholder="请输入后图标名称">
  98. <template #append>
  99. <el-button icon="Pointer" @click="openIconsDialog('suffix-icon')">
  100. 选择
  101. </el-button>
  102. </template>
  103. </el-input>
  104. </el-form-item>
  105. <el-form-item v-if="activeData.tag === 'el-cascader'" label="选项分隔符">
  106. <el-input v-model="activeData.separator" placeholder="请输入选项分隔符" />
  107. </el-form-item>
  108. <el-form-item v-if="activeData.autosize !== undefined" label="最小行数">
  109. <el-input-number v-model="activeData.autosize.minRows" :min="1" placeholder="最小行数" />
  110. </el-form-item>
  111. <el-form-item v-if="activeData.autosize !== undefined" label="最大行数">
  112. <el-input-number v-model="activeData.autosize.maxRows" :min="1" placeholder="最大行数" />
  113. </el-form-item>
  114. <el-form-item v-if="activeData.min !== undefined" label="最小值">
  115. <el-input-number v-model="activeData.min" placeholder="最小值" />
  116. </el-form-item>
  117. <el-form-item v-if="activeData.max !== undefined" label="最大值">
  118. <el-input-number v-model="activeData.max" placeholder="最大值" />
  119. </el-form-item>
  120. <el-form-item v-if="activeData.step !== undefined" label="步长">
  121. <el-input-number v-model="activeData.step" placeholder="步数" />
  122. </el-form-item>
  123. <el-form-item v-if="activeData.tag === 'el-input-number'" label="精度">
  124. <el-input-number v-model="activeData.precision" :min="0" placeholder="精度" />
  125. </el-form-item>
  126. <el-form-item v-if="activeData.tag === 'el-input-number'" label="按钮位置">
  127. <el-radio-group v-model="activeData['controls-position']">
  128. <el-radio-button label="">
  129. 默认
  130. </el-radio-button>
  131. <el-radio-button label="right">
  132. 右侧
  133. </el-radio-button>
  134. </el-radio-group>
  135. </el-form-item>
  136. <el-form-item v-if="activeData.maxlength !== undefined" label="最多输入">
  137. <el-input v-model="activeData.maxlength" placeholder="请输入字符长度">
  138. <template slot="append">
  139. 个字符
  140. </template>
  141. </el-input>
  142. </el-form-item>
  143. <el-form-item v-if="activeData['active-text'] !== undefined" label="开启提示">
  144. <el-input v-model="activeData['active-text']" placeholder="请输入开启提示" />
  145. </el-form-item>
  146. <el-form-item v-if="activeData['inactive-text'] !== undefined" label="关闭提示">
  147. <el-input v-model="activeData['inactive-text']" placeholder="请输入关闭提示" />
  148. </el-form-item>
  149. <el-form-item v-if="activeData['active-value'] !== undefined" label="开启值">
  150. <el-input :value="setDefaultValue(activeData['active-value'])" placeholder="请输入开启值"
  151. @input="onSwitchValueInput($event, 'active-value')" />
  152. </el-form-item>
  153. <el-form-item v-if="activeData['inactive-value'] !== undefined" label="关闭值">
  154. <el-input :value="setDefaultValue(activeData['inactive-value'])" placeholder="请输入关闭值"
  155. @input="onSwitchValueInput($event, 'inactive-value')" />
  156. </el-form-item>
  157. <el-form-item v-if="activeData.type !== undefined && 'el-date-picker' === activeData.tag" label="时间类型">
  158. <el-select v-model="activeData.type" placeholder="请选择时间类型" :style="{ width: '100%' }"
  159. @change="dateTypeChange">
  160. <el-option v-for="(item, index) in dateOptions" :key="index" :label="item.label" :value="item.value" />
  161. </el-select>
  162. </el-form-item>
  163. <el-form-item v-if="activeData.name !== undefined" label="文件字段名">
  164. <el-input v-model="activeData.name" placeholder="请输入上传文件字段名" />
  165. </el-form-item>
  166. <el-form-item v-if="activeData.accept !== undefined" label="文件类型">
  167. <el-select v-model="activeData.accept" placeholder="请选择文件类型" :style="{ width: '100%' }" clearable>
  168. <el-option label="图片" value="image/*" />
  169. <el-option label="视频" value="video/*" />
  170. <el-option label="音频" value="audio/*" />
  171. <el-option label="excel" value=".xls,.xlsx" />
  172. <el-option label="word" value=".doc,.docx" />
  173. <el-option label="pdf" value=".pdf" />
  174. <el-option label="txt" value=".txt" />
  175. </el-select>
  176. </el-form-item>
  177. <el-form-item v-if="activeData.fileSize !== undefined" label="文件大小">
  178. <el-input v-model.number="activeData.fileSize" placeholder="请输入文件大小">
  179. <el-select slot="append" v-model="activeData.sizeUnit" :style="{ width: '66px' }">
  180. <el-option label="KB" value="KB" />
  181. <el-option label="MB" value="MB" />
  182. <el-option label="GB" value="GB" />
  183. </el-select>
  184. </el-input>
  185. </el-form-item>
  186. <el-form-item v-if="activeData.action !== undefined" label="上传地址">
  187. <el-input v-model="activeData.action" placeholder="请输入上传地址" clearable />
  188. </el-form-item>
  189. <el-form-item v-if="activeData['list-type'] !== undefined" label="列表类型">
  190. <el-radio-group v-model="activeData['list-type']" size="small">
  191. <el-radio-button label="text">
  192. text
  193. </el-radio-button>
  194. <el-radio-button label="picture">
  195. picture
  196. </el-radio-button>
  197. <el-radio-button label="picture-card">
  198. picture-card
  199. </el-radio-button>
  200. </el-radio-group>
  201. </el-form-item>
  202. <el-form-item v-if="activeData.buttonText !== undefined" v-show="'picture-card' !== activeData['list-type']"
  203. label="按钮文字">
  204. <el-input v-model="activeData.buttonText" placeholder="请输入按钮文字" />
  205. </el-form-item>
  206. <el-form-item v-if="activeData['range-separator'] !== undefined" label="分隔符">
  207. <el-input v-model="activeData['range-separator']" placeholder="请输入分隔符" />
  208. </el-form-item>
  209. <el-form-item v-if="activeData['picker-options'] !== undefined" label="时间段">
  210. <el-input v-model="activeData['picker-options'].selectableRange" placeholder="请输入时间段" />
  211. </el-form-item>
  212. <el-form-item v-if="activeData.format !== undefined" label="时间格式">
  213. <el-input :value="activeData.format" placeholder="请输入时间格式" @input="setTimeValue($event)" />
  214. </el-form-item>
  215. <template v-if="['el-checkbox-group', 'el-radio-group', 'el-select'].indexOf(activeData.tag) > -1">
  216. <el-divider>选项</el-divider>
  217. <draggable :list="activeData.options" :animation="340" group="selectItem" handle=".option-drag"
  218. item-key="label">
  219. <template #item="{ element, index }">
  220. <div :key="index" class="select-item">
  221. <div class="select-line-icon option-drag">
  222. <i class="el-icon-s-operation" />
  223. </div>
  224. <el-input v-model="element.label" placeholder="选项名" size="small" />
  225. <el-input placeholder="选项值" size="small" :value="element.value"
  226. @input="setOptionValue(element, $event)" />
  227. <div class="close-btn select-line-icon" @click="activeData.options.splice(index, 1)">
  228. <el-icon>
  229. <Remove />
  230. </el-icon>
  231. </div>
  232. </div>
  233. </template>
  234. </draggable>
  235. <div>
  236. <el-button icon="CirclePlus" style="margin-left: 8px; margin-top: 10px;" text bg type="primary"
  237. @click="addSelectItem">
  238. 添加选项
  239. </el-button>
  240. </div>
  241. <el-divider />
  242. </template>
  243. <template v-if="['el-cascader'].indexOf(activeData.tag) > -1">
  244. <el-divider>选项</el-divider>
  245. <el-form-item label="数据类型">
  246. <el-radio-group v-model="activeData.dataType" size="small">
  247. <el-radio-button label="dynamic">
  248. 动态数据
  249. </el-radio-button>
  250. <el-radio-button label="static">
  251. 静态数据
  252. </el-radio-button>
  253. </el-radio-group>
  254. </el-form-item>
  255. <template v-if="activeData.dataType === 'dynamic'">
  256. <el-form-item label="标签键名">
  257. <el-input v-model="activeData.labelKey" placeholder="请输入标签键名" />
  258. </el-form-item>
  259. <el-form-item label="值键名">
  260. <el-input v-model="activeData.valueKey" placeholder="请输入值键名" />
  261. </el-form-item>
  262. <el-form-item label="子级键名">
  263. <el-input v-model="activeData.childrenKey" placeholder="请输入子级键名" />
  264. </el-form-item>
  265. </template>
  266. <el-tree v-if="activeData.dataType === 'static'" draggable :data="activeData.options" node-key="id"
  267. :expand-on-click-node="false" :render-content="renderContent" />
  268. <div v-if="activeData.dataType === 'static'">
  269. <el-button icon="CirclePlus" style="margin-left: 0; margin-top: 10px;" type="primary" text bg
  270. @click="addTreeItem">
  271. 添加父级
  272. </el-button>
  273. </div>
  274. <el-divider />
  275. </template>
  276. <el-form-item v-if="activeData.optionType !== undefined" label="选项样式">
  277. <el-radio-group v-model="activeData.optionType">
  278. <el-radio-button label="default">
  279. 默认
  280. </el-radio-button>
  281. <el-radio-button label="button">
  282. 按钮
  283. </el-radio-button>
  284. </el-radio-group>
  285. </el-form-item>
  286. <el-form-item v-if="activeData['active-color'] !== undefined" label="开启颜色">
  287. <el-color-picker v-model="activeData['active-color']" />
  288. </el-form-item>
  289. <el-form-item v-if="activeData['inactive-color'] !== undefined" label="关闭颜色">
  290. <el-color-picker v-model="activeData['inactive-color']" />
  291. </el-form-item>
  292. <el-form-item v-if="activeData['allow-half'] !== undefined" label="允许半选">
  293. <el-switch v-model="activeData['allow-half']" />
  294. </el-form-item>
  295. <el-form-item v-if="activeData['show-text'] !== undefined" label="辅助文字">
  296. <el-switch v-model="activeData['show-text']" @change="rateTextChange" />
  297. </el-form-item>
  298. <el-form-item v-if="activeData['show-score'] !== undefined" label="显示分数">
  299. <el-switch v-model="activeData['show-score']" @change="rateScoreChange" />
  300. </el-form-item>
  301. <el-form-item v-if="activeData['show-stops'] !== undefined" label="显示间断点">
  302. <el-switch v-model="activeData['show-stops']" />
  303. </el-form-item>
  304. <el-form-item v-if="activeData.range !== undefined" label="范围选择">
  305. <el-switch v-model="activeData.range" @change="rangeChange" />
  306. </el-form-item>
  307. <el-form-item v-if="activeData.border !== undefined && activeData.optionType === 'default'" label="是否带边框">
  308. <el-switch v-model="activeData.border" />
  309. </el-form-item>
  310. <el-form-item v-if="activeData.tag === 'el-color-picker'" label="颜色格式">
  311. <el-select v-model="activeData['color-format']" placeholder="请选择颜色格式" :style="{ width: '100%' }"
  312. @change="colorFormatChange">
  313. <el-option v-for="(item, index) in colorFormatOptions" :key="index" :label="item.label"
  314. :value="item.value" />
  315. </el-select>
  316. </el-form-item>
  317. <el-form-item v-if="activeData.size !== undefined &&
  318. (activeData.optionType === 'button' ||
  319. activeData.border ||
  320. activeData.tag === 'el-color-picker')" label="选项尺寸">
  321. <el-radio-group v-model="activeData.size">
  322. <el-radio-button label="large">
  323. 较大
  324. </el-radio-button>
  325. <el-radio-button label="default">
  326. 默认
  327. </el-radio-button>
  328. <el-radio-button label="small">
  329. 较小
  330. </el-radio-button>
  331. </el-radio-group>
  332. </el-form-item>
  333. <el-form-item v-if="activeData['show-word-limit'] !== undefined" label="输入统计">
  334. <el-switch v-model="activeData['show-word-limit']" />
  335. </el-form-item>
  336. <el-form-item v-if="activeData.tag === 'el-input-number'" label="严格步数">
  337. <el-switch v-model="activeData['step-strictly']" />
  338. </el-form-item>
  339. <el-form-item v-if="activeData.tag === 'el-cascader'" label="是否多选">
  340. <el-switch v-model="activeData.props.props.multiple" />
  341. </el-form-item>
  342. <el-form-item v-if="activeData.tag === 'el-cascader'" label="展示全路径">
  343. <el-switch v-model="activeData['show-all-levels']" />
  344. </el-form-item>
  345. <el-form-item v-if="activeData.tag === 'el-cascader'" label="可否筛选">
  346. <el-switch v-model="activeData.filterable" />
  347. </el-form-item>
  348. <el-form-item v-if="activeData.clearable !== undefined" label="能否清空">
  349. <el-switch v-model="activeData.clearable" />
  350. </el-form-item>
  351. <el-form-item v-if="activeData.showTip !== undefined" label="显示提示">
  352. <el-switch v-model="activeData.showTip" />
  353. </el-form-item>
  354. <el-form-item v-if="activeData.multiple !== undefined" label="多选文件">
  355. <el-switch v-model="activeData.multiple" />
  356. </el-form-item>
  357. <el-form-item v-if="activeData['auto-upload'] !== undefined" label="自动上传">
  358. <el-switch v-model="activeData['auto-upload']" />
  359. </el-form-item>
  360. <el-form-item v-if="activeData.readonly !== undefined" label="是否只读">
  361. <el-switch v-model="activeData.readonly" />
  362. </el-form-item>
  363. <el-form-item v-if="activeData.disabled !== undefined" label="是否禁用">
  364. <el-switch v-model="activeData.disabled" />
  365. </el-form-item>
  366. <el-form-item v-if="activeData.tag === 'el-select'" label="是否可搜索">
  367. <el-switch v-model="activeData.filterable" />
  368. </el-form-item>
  369. <el-form-item v-if="activeData.tag === 'el-select'" label="是否多选">
  370. <el-switch v-model="activeData.multiple" @change="multipleChange" />
  371. </el-form-item>
  372. <el-form-item v-if="activeData.required !== undefined" label="是否必填">
  373. <el-switch v-model="activeData.required" />
  374. </el-form-item>
  375. <template v-if="activeData.layoutTree">
  376. <el-divider>布局结构树</el-divider>
  377. <el-tree :data="[activeData]" :props="layoutTreeProps" node-key="renderKey" default-expand-all draggable>
  378. <template #default="{ node, data }">
  379. <span class="node-label">
  380. <svg-icon class="node-icon" :icon-class="data.tagIcon" style="margin-right: 5px;" />
  381. {{ node.label }}
  382. </span>
  383. </template>
  384. </el-tree>
  385. </template>
  386. <template v-if="activeData.layout === 'colFormItem'">
  387. <el-divider>正则校验</el-divider>
  388. <div v-for="(item, index) in activeData.regList" :key="index" class="reg-item">
  389. <span class="close-btn" @click="activeData.regList.splice(index, 1)">
  390. <el-icon>
  391. <Close />
  392. </el-icon>
  393. </span>
  394. <el-form-item label="表达式">
  395. <el-input v-model="item.pattern" placeholder="请输入正则" />
  396. </el-form-item>
  397. <el-form-item label="错误提示" style="margin-bottom:0">
  398. <el-input v-model="item.message" placeholder="请输入错误提示" />
  399. </el-form-item>
  400. </div>
  401. <div>
  402. <el-button icon="CirclePlus" style="margin-left: 0; margin-top: 10px;" type="primary" text bg
  403. @click="addReg">
  404. 添加规则
  405. </el-button>
  406. </div>
  407. </template>
  408. </el-form>
  409. <!-- 表单属性 -->
  410. <el-form v-show="currentTab === 'form'" label-width="90px" label-position="top">
  411. <el-form-item label="表单名">
  412. <el-input v-model="formConf.formRef" placeholder="请输入表单名(ref)" />
  413. </el-form-item>
  414. <el-form-item label="表单模型">
  415. <el-input v-model="formConf.formModel" placeholder="请输入数据模型" />
  416. </el-form-item>
  417. <el-form-item label="校验模型">
  418. <el-input v-model="formConf.formRules" placeholder="请输入校验模型" />
  419. </el-form-item>
  420. <el-form-item label="表单尺寸">
  421. <el-radio-group v-model="formConf.size">
  422. <el-radio-button label="large" value="较大" />
  423. <el-radio-button label="default" value="默认" />
  424. <el-radio-button label="small" value="较小" />
  425. </el-radio-group>
  426. </el-form-item>
  427. <el-form-item label="标签对齐">
  428. <el-radio-group v-model="formConf.labelPosition">
  429. <el-radio-button label="left" value="左对齐" />
  430. <el-radio-button label="right" value="右对齐" />
  431. <el-radio-button label="top" value="顶部对齐" />
  432. </el-radio-group>
  433. </el-form-item>
  434. <el-form-item label="标签宽度">
  435. <el-input-number v-model="formConf.labelWidth" placeholder="标签宽度" />
  436. </el-form-item>
  437. <el-form-item label="栅格间隔">
  438. <el-input-number v-model="formConf.gutter" :min="0" placeholder="栅格间隔" />
  439. </el-form-item>
  440. <el-form-item label="禁用表单">
  441. <el-switch v-model="formConf.disabled" />
  442. </el-form-item>
  443. <el-form-item label="表单按钮">
  444. <el-switch v-model="formConf.formBtns" />
  445. </el-form-item>
  446. <el-form-item label="显示未选中组件边框">
  447. <el-switch v-model="formConf.unFocusedComponentBorder" />
  448. </el-form-item>
  449. </el-form>
  450. </el-scrollbar>
  451. </div>
  452. <icons-dialog v-model="iconsVisible" :current="activeData[currentIconModel]" @select="setIcon" />
  453. <treeNode-dialog v-model="dialogVisible" @commit="addNode" />
  454. </div>
  455. </template>
  456. <script setup>
  457. import draggable from "vuedraggable/dist/vuedraggable.common"
  458. import { isNumberStr } from '@/utils/index'
  459. import IconsDialog from './IconsDialog'
  460. import TreeNodeDialog from './TreeNodeDialog'
  461. import { inputComponents, selectComponents } from '@/utils/generator/config'
  462. const { proxy } = getCurrentInstance()
  463. const dateTimeFormat = {
  464. date: 'YYYY-MM-DD',
  465. week: 'YYYY 第 ww 周',
  466. month: 'YYYY-MM',
  467. year: 'YYYY',
  468. datetime: 'YYYY-MM-DD HH:mm:ss',
  469. daterange: 'YYYY-MM-DD',
  470. monthrange: 'YYYY-MM',
  471. datetimerange: 'YYYY-MM-DD HH:mm:ss'
  472. }
  473. const props = defineProps({
  474. showField: Boolean,
  475. activeData: Object,
  476. formConf: Object
  477. })
  478. const data = reactive({
  479. currentTab: 'field',
  480. currentNode: null,
  481. dialogVisible: false,
  482. iconsVisible: false,
  483. currentIconModel: null,
  484. dateTypeOptions: [
  485. {
  486. label: '日(date)',
  487. value: 'date'
  488. },
  489. {
  490. label: '周(week)',
  491. value: 'week'
  492. },
  493. {
  494. label: '月(month)',
  495. value: 'month'
  496. },
  497. {
  498. label: '年(year)',
  499. value: 'year'
  500. },
  501. {
  502. label: '日期时间(datetime)',
  503. value: 'datetime'
  504. }
  505. ],
  506. dateRangeTypeOptions: [
  507. {
  508. label: '日期范围(daterange)',
  509. value: 'daterange'
  510. },
  511. {
  512. label: '月范围(monthrange)',
  513. value: 'monthrange'
  514. },
  515. {
  516. label: '日期时间范围(datetimerange)',
  517. value: 'datetimerange'
  518. }
  519. ],
  520. colorFormatOptions: [
  521. {
  522. label: 'hex',
  523. value: 'hex'
  524. },
  525. {
  526. label: 'rgb',
  527. value: 'rgb'
  528. },
  529. {
  530. label: 'rgba',
  531. value: 'rgba'
  532. },
  533. {
  534. label: 'hsv',
  535. value: 'hsv'
  536. },
  537. {
  538. label: 'hsl',
  539. value: 'hsl'
  540. }
  541. ],
  542. justifyOptions: [
  543. {
  544. label: 'start',
  545. value: 'start'
  546. },
  547. {
  548. label: 'end',
  549. value: 'end'
  550. },
  551. {
  552. label: 'center',
  553. value: 'center'
  554. },
  555. {
  556. label: 'space-around',
  557. value: 'space-around'
  558. },
  559. {
  560. label: 'space-between',
  561. value: 'space-between'
  562. }
  563. ],
  564. layoutTreeProps: {
  565. label(data, node) {
  566. return data.componentName || `${data.label}: ${data.vModel}`
  567. }
  568. }
  569. })
  570. const { currentTab, currentNode, dialogVisible, iconsVisible, currentIconModel, dateTypeOptions, dateRangeTypeOptions, colorFormatOptions, justifyOptions, layoutTreeProps } = toRefs(data)
  571. const documentLink = computed(() => props.activeData.document || 'https://element-plus.org/zh-CN/guide/installation')
  572. const dateOptions = computed(() => {
  573. if (props.activeData.type !== undefined && props.activeData.tag === 'el-date-picker') {
  574. if (props.activeData['start-placeholder'] === undefined) {
  575. return dateTypeOptions.value
  576. }
  577. return dateRangeTypeOptions.value
  578. }
  579. return []
  580. })
  581. const tagList = ref([
  582. {
  583. label: '输入型组件',
  584. options: inputComponents
  585. },
  586. {
  587. label: '选择型组件',
  588. options: selectComponents
  589. }
  590. ])
  591. const emit = defineEmits(['tag-change'])
  592. function addReg() {
  593. props.activeData.regList.push({
  594. pattern: '',
  595. message: ''
  596. })
  597. }
  598. function addSelectItem() {
  599. props.activeData.options.push({
  600. label: '',
  601. value: ''
  602. })
  603. }
  604. function addTreeItem() {
  605. ++proxy.idGlobal
  606. dialogVisible.value = true
  607. currentNode.value = props.activeData.options
  608. }
  609. function renderContent(h, { node, data, store }) {
  610. return h('div', {
  611. class: "custom-tree-node"
  612. }, [
  613. h('span', node.label),
  614. h('span', {
  615. class: "node-operation"
  616. }, [
  617. h(resolveComponent('el-link'), {
  618. type: "primary",
  619. icon: "Plus",
  620. underline: false,
  621. onClick: () => {
  622. append(data)
  623. }
  624. }),
  625. h(resolveComponent('el-link'), {
  626. type: "danger",
  627. icon: "Delete",
  628. underline: false,
  629. style: "margin-left: 5px;",
  630. onClick: () => {
  631. remove(node, data)
  632. }
  633. })
  634. ])
  635. ])
  636. }
  637. function append(data) {
  638. if (!data.children) {
  639. data.children = []
  640. }
  641. dialogVisible.value = true
  642. currentNode.value = data.children
  643. }
  644. function remove(node, data) {
  645. const { parent } = node
  646. const children = parent.data.children || parent.data
  647. const index = children.findIndex(d => d.id === data.id)
  648. children.splice(index, 1)
  649. }
  650. function addNode(data) {
  651. currentNode.value.push(data)
  652. }
  653. function setOptionValue(item, val) {
  654. item.value = isNumberStr(val) ? +val : val
  655. }
  656. function setDefaultValue(val) {
  657. if (Array.isArray(val)) {
  658. return val.join(',')
  659. }
  660. if (['string', 'number'].indexOf(val) > -1) {
  661. return val
  662. }
  663. if (typeof val === 'boolean') {
  664. return `${val}`
  665. }
  666. return val
  667. }
  668. function onDefaultValueInput(str) {
  669. if (Array.isArray(props.activeData.defaultValue)) {
  670. // 数组
  671. props.activeData.defaultValue = str.split(',').map(val => (isNumberStr(val) ? +val : val))
  672. } else if (['true', 'false'].indexOf(str) > -1) {
  673. // 布尔
  674. props.activeData.defaultValue = JSON.parse(str)
  675. } else {
  676. // 字符串和数字
  677. props.activeData.defaultValue = isNumberStr(str) ? +str : str
  678. }
  679. }
  680. function onSwitchValueInput(val, name) {
  681. if (['true', 'false'].indexOf(val) > -1) {
  682. props.activeData[name] = JSON.parse(val)
  683. } else {
  684. props.activeData[name] = isNumberStr(val) ? +val : val
  685. }
  686. }
  687. function setTimeValue(val, type) {
  688. const valueFormat = type === 'week' ? dateTimeFormat.date : val
  689. props.activeData.defaultValue = null
  690. props.activeData['value-format'] = valueFormat
  691. props.activeData.format = val
  692. }
  693. function spanChange(val) {
  694. props.formConf.span = val
  695. }
  696. function multipleChange(val) {
  697. props.activeData.defaultValue = val ? [] : ''
  698. }
  699. function dateTypeChange(val) {
  700. setTimeValue(dateTimeFormat[val], val)
  701. }
  702. function rangeChange(val) {
  703. props.activeData.defaultValue = val ? [props.activeData.min, props.activeData.max] : props.activeData.min
  704. }
  705. function rateTextChange(val) {
  706. if (val) props.activeData['show-score'] = false
  707. }
  708. function rateScoreChange(val) {
  709. if (val) props.activeData['show-text'] = false
  710. }
  711. function colorFormatChange(val) {
  712. props.activeData.defaultValue = null
  713. props.activeData['show-alpha'] = val.indexOf('a') > -1
  714. props.activeData.renderKey = +new Date() // 更新renderKey,重新渲染该组件
  715. }
  716. function openIconsDialog(model) {
  717. iconsVisible.value = true
  718. currentIconModel.value = model
  719. }
  720. function setIcon(val) {
  721. props.activeData[currentIconModel.value] = val
  722. }
  723. function tagChange(tagIcon) {
  724. let target = inputComponents.find(item => item.tagIcon === tagIcon)
  725. if (!target) target = selectComponents.find(item => item.tagIcon === tagIcon)
  726. emit('tag-change', target)
  727. }
  728. </script>
  729. <style lang="scss" scoped>
  730. .right-board {
  731. width: 350px;
  732. position: absolute;
  733. right: 0;
  734. top: 0;
  735. padding-top: 3px;
  736. &:deep() {
  737. .el-tabs__header {
  738. margin: 0;
  739. }
  740. .el-input-group__append .el-button {
  741. display: inline-flex;
  742. }
  743. }
  744. .field-box {
  745. position: relative;
  746. height: calc(100vh - 50px - 40px - 42px);
  747. box-sizing: border-box;
  748. overflow: hidden;
  749. }
  750. .el-scrollbar {
  751. height: 100%;
  752. &:deep() {
  753. .el-scrollbar__view {
  754. padding: 30px 20px;
  755. }
  756. }
  757. }
  758. }
  759. .reg-item {
  760. padding: 12px 6px;
  761. background: var(--el-border-color-extra-light);
  762. position: relative;
  763. border-radius: 4px;
  764. .close-btn {
  765. position: absolute;
  766. right: -6px;
  767. top: -6px;
  768. display: flex;
  769. align-items: center;
  770. justify-content: center;
  771. width: 16px;
  772. height: 16px;
  773. line-height: 16px;
  774. background: rgba(0, 0, 0, .2);
  775. border-radius: 50%;
  776. color: #fff;
  777. z-index: 1;
  778. cursor: pointer;
  779. font-size: 12px;
  780. }
  781. }
  782. .select-item {
  783. display: flex;
  784. border: 1px dashed #fff;
  785. box-sizing: border-box;
  786. & .close-btn {
  787. cursor: pointer;
  788. color: #f56c6c;
  789. }
  790. & .el-input+.el-input {
  791. margin-left: 4px;
  792. }
  793. }
  794. .select-item+.select-item {
  795. margin-top: 4px;
  796. }
  797. .select-item.sortable-chosen {
  798. border: 1px dashed #409eff;
  799. }
  800. .select-line-icon {
  801. line-height: 32px;
  802. font-size: 22px;
  803. padding: 0 4px;
  804. color: #777;
  805. }
  806. .option-drag {
  807. cursor: move;
  808. }
  809. .time-range {
  810. .el-date-editor {
  811. width: 227px;
  812. }
  813. :deep() {
  814. .el-icon-time {
  815. display: none;
  816. }
  817. }
  818. }
  819. .document-link {
  820. position: absolute;
  821. display: flex;
  822. width: 26px;
  823. height: 26px;
  824. top: 0;
  825. left: 0;
  826. cursor: pointer;
  827. background: #409eff;
  828. z-index: 1;
  829. border-radius: 0 0 6px 0;
  830. justify-content: center;
  831. align-items: center;
  832. color: #fff;
  833. font-size: 18px;
  834. }
  835. .node-label {
  836. font-size: 14px;
  837. }
  838. .node-icon {
  839. color: #bebfc3;
  840. }
  841. .custom-tree-node {
  842. flex: 1;
  843. display: flex;
  844. align-items: center;
  845. justify-content: space-between;
  846. font-size: 14px;
  847. padding-right: 8px;
  848. }
  849. </style>