WidgetFormItem.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. <script lang="ts" setup>
  2. import Draggable from 'vuedraggable'
  3. import { cloneWidget } from '@/components/ComponentGroup.vue'
  4. const { element, index, list, ...props } = defineProps<{
  5. list: any
  6. element: any
  7. index: number
  8. selectWidget: any
  9. }>()
  10. defineEmits(['itemClick', 'delete', 'update:selectWidget'])
  11. let selectWidget = $(useVModel(props, 'selectWidget'))
  12. const handleCopyClick = () => {
  13. list.splice(index + 1, 0, cloneWidget(list[index]))
  14. selectWidget = list[index + 1]
  15. }
  16. const handleDeleteClick = () => {
  17. list.splice(index, 1)
  18. selectWidget = list[list.length === index ? (index - 1) : index]
  19. }
  20. </script>
  21. <template>
  22. <div
  23. class="widget-view"
  24. :class="{ active: selectWidget?.key === element.key ,col:element.type === 'grid'}"
  25. :style="element.type === 'grid'?`gap: ${element.options.gutter}px; align-items: ${element.options.align};`:''"
  26. @click.stop="selectWidget=element"
  27. >
  28. <template v-if="element.type === 'grid'">
  29. <Draggable
  30. v-for="(col, key) of element.columns"
  31. :key="key"
  32. class="bg-white min-h-12 border border-dashed border-gray-300"
  33. :style="`grid-column: span ${col.span}`"
  34. item-key="key"
  35. handle="[cursor-move]"
  36. :animation="200"
  37. group="form-design"
  38. :no-transition-on-drag="true"
  39. :list="col.list"
  40. @add="selectWidget=col.list[$event.newIndex]"
  41. >
  42. <template #item="{ element: colElement, index: colIndex }">
  43. <WidgetFormItem
  44. v-model:selectWidget="selectWidget"
  45. :element="colElement"
  46. :list="col.list"
  47. :index="colIndex"
  48. />
  49. </template>
  50. </Draggable>
  51. </template>
  52. <el-table
  53. v-else-if="element.type === 'table'"
  54. class="w-0 flex-1"
  55. border
  56. :data="element.options.defaultValue"
  57. >
  58. <el-table-column
  59. v-for="i in element.columns"
  60. :key="i.prop"
  61. :header-align="element.options.align"
  62. :align="element.options.align"
  63. v-bind="i"
  64. />
  65. </el-table>
  66. <el-divider v-else-if="element.type === 'divider'" class="pb-0" :data="element.options.defaultValue" content-position="left">
  67. {{ element.label }}
  68. </el-divider>
  69. <el-form-item
  70. v-else-if="element"
  71. :key="element.key"
  72. :label="element.label"
  73. :label-width="element.labelWidth"
  74. :rules="element.options.rules"
  75. >
  76. <template v-if="element.type === 'input'">
  77. <el-input
  78. readonly
  79. :model-value="element.options.defaultValue"
  80. :style="{ width: element.options.width }"
  81. :placeholder="element.options.placeholder"
  82. :maxlength="parseInt(element.options.maxlength)"
  83. :clearable="element.options.clearable"
  84. :disabled="element.options.disabled"
  85. >
  86. <template v-if="element.options.prefix" #prefix>
  87. {{ element.options.prefix }}
  88. </template>
  89. <template v-if="element.options.suffix" #suffix>
  90. {{ element.options.suffix }}
  91. </template>
  92. <template v-if="element.options.prepend" #prepend>
  93. {{ element.options.prepend }}
  94. </template>
  95. <template v-if="element.options.append" #append>
  96. {{ element.options.append }}
  97. </template>
  98. </el-input>
  99. </template>
  100. <template v-if="element.type === 'password'">
  101. <el-input
  102. readonly
  103. :model-value="element.options.defaultValue"
  104. :style="{ width: element.options.width }"
  105. :placeholder="element.options.placeholder"
  106. :maxlength="parseInt(element.options.maxlength)"
  107. :clearable="element.options.clearable"
  108. :disabled="element.options.disabled"
  109. :show-password="element.options.showPassword"
  110. >
  111. <template v-if="element.options.prefix" #prefix>
  112. {{ element.options.prefix }}
  113. </template>
  114. <template v-if="element.options.suffix" #suffix>
  115. {{ element.options.suffix }}
  116. </template>
  117. <template v-if="element.options.prepend" #prepend>
  118. {{ element.options.prepend }}
  119. </template>
  120. <template v-if="element.options.append" #append>
  121. {{ element.options.append }}
  122. </template>
  123. </el-input>
  124. </template>
  125. <template v-if="element.type === 'textarea'">
  126. <el-input
  127. type="textarea"
  128. resize="none"
  129. readonly
  130. :rows="element.options.rows"
  131. :model-value="element.options.defaultValue"
  132. :style="{ width: element.options.width }"
  133. :placeholder="element.options.placeholder"
  134. :maxlength="parseInt(element.options.maxlength)"
  135. :show-word-limit="element.options.showWordLimit"
  136. :autosize="element.options.autosize"
  137. :clearable="element.options.clearable"
  138. :disabled="element.options.disabled"
  139. />
  140. </template>
  141. <template v-if="element.type === 'number'">
  142. <el-input-number
  143. :model-value="element.options.defaultValue"
  144. :style="{ width: element.options.width }"
  145. :max="element.options.max"
  146. :min="element.options.min"
  147. :disabled="element.options.disabled"
  148. controls-position="right"
  149. />
  150. </template>
  151. <template v-if="element.type === 'radio'">
  152. <el-radio-group
  153. :model-value="element.options.defaultValue"
  154. :style="{ width: element.options.width }"
  155. :disabled="element.options.disabled"
  156. >
  157. <el-radio
  158. v-for="item of element.options.options"
  159. :key="item.value"
  160. :label="item.value"
  161. :style="{
  162. display: element.options.inline ? 'inline-block' : 'block'
  163. }"
  164. >
  165. {{ element.options.showLabel ? item.label : item.value }}
  166. </el-radio>
  167. </el-radio-group>
  168. </template>
  169. <template v-if="element.type === 'checkbox'">
  170. <el-checkbox-group
  171. :model-value="element.options.defaultValue"
  172. :style="{ width: element.options.width }"
  173. :disabled="element.options.disabled"
  174. >
  175. <el-checkbox
  176. v-for="item of element.options.options"
  177. :key="item.value"
  178. :label="item.value"
  179. :style="{
  180. display: element.options.inline ? 'inline-block' : 'block'
  181. }"
  182. >
  183. {{ element.options.showLabel ? item.label : item.value }}
  184. </el-checkbox>
  185. </el-checkbox-group>
  186. </template>
  187. <template v-if="element.type === 'time'">
  188. <el-time-picker
  189. :model-value="element.options.defaultValue"
  190. :placeholder="element.options.placeholder"
  191. :readonly="element.options.readonly"
  192. :editable="element.options.editable"
  193. :clearable="element.options.clearable"
  194. :format="element.options.format"
  195. :disabled="element.options.disabled"
  196. :style="{ width: element.options.width }"
  197. />
  198. </template>
  199. <template v-if="element.type === 'date'">
  200. <el-date-picker
  201. :model-value="element.options.defaultValue"
  202. :placeholder="element.options.placeholder"
  203. :readonly="element.options.readonly"
  204. :editable="element.options.editable"
  205. :clearable="element.options.clearable"
  206. :format="element.options.format"
  207. :disabled="element.options.disabled"
  208. :style="{ width: element.options.width }"
  209. />
  210. </template>
  211. <template v-if="element.type === 'rate'">
  212. <el-rate
  213. :model-value="element.options.defaultValue"
  214. :max="element.options.max"
  215. :allow-half="element.options.allowHalf"
  216. :disabled="element.options.disabled"
  217. />
  218. </template>
  219. <template v-if="element.type === 'select'">
  220. <el-select
  221. :model-value="element.options.defaultValue"
  222. :multiple="element.options.multiple"
  223. :placeholder="element.options.placeholder"
  224. :clearable="element.options.clearable"
  225. :filterable="element.options.filterable"
  226. :disabled="element.options.disabled"
  227. :style="{ width: element.options.width }"
  228. >
  229. <el-option
  230. v-for="item of element.options.options"
  231. :key="item.value"
  232. :value="item.value"
  233. :label="element.options.showLabel ? item.label : item.value"
  234. />
  235. </el-select>
  236. </template>
  237. <template v-if="element.type === 'switch'">
  238. <el-switch
  239. :model-value="element.options.defaultValue"
  240. :active-text="element.options.activeText"
  241. :inactive-text="element.options.inactiveText"
  242. :disabled="element.options.disabled"
  243. />
  244. </template>
  245. <template v-if="element.type === 'slider'">
  246. <el-slider
  247. :model-value="element.options.defaultValue"
  248. :min="element.options.min"
  249. :max="element.options.max"
  250. :step="element.options.step"
  251. :range="element.options.range"
  252. :disabled="element.options.disabled"
  253. :style="{ width: element.options.width }"
  254. />
  255. </template>
  256. <template v-if="element.type == 'text'">
  257. <span>{{ element.options.defaultValue }}</span>
  258. </template>
  259. <template v-if="element.type === 'img-upload'">
  260. <el-upload
  261. :name="element.options.file"
  262. :action="element.options.action"
  263. :accept="element.options.accept"
  264. :list-type="element.options.listType"
  265. :multiple="element.options.multiple"
  266. :limit="element.options.limit"
  267. :disabled="element.options.disabled"
  268. >
  269. <template v-if="element.options.listType === 'picture-card'">
  270. <el-image
  271. v-if="element.options.defaultValue?.length"
  272. style="width: 100%; height: 100%;"
  273. :preview-src-list="[
  274. '/api/sys/common/static/' + element.options.defaultValue
  275. ]"
  276. :src="'/api/sys/common/static/' + element.options.defaultValue"
  277. />
  278. <i v-else class="custom:insert" />
  279. </template>
  280. <el-button v-else>
  281. <i icon-class="custom:img-upload" style="margin-right: 10px;" />
  282. 点击上传
  283. </el-button>
  284. </el-upload>
  285. </template>
  286. <template v-if="element.type === 'download'">
  287. <el-button type="text" style="margin-top: -4px;">
  288. 下载
  289. </el-button>
  290. </template>
  291. <template v-if="element.type === 'cascader'">
  292. <el-cascader
  293. :model-value="element.options.defaultValue"
  294. :options="element.options.remoteOptions"
  295. :placeholder="element.options.placeholder"
  296. :filterable="element.options.filterable"
  297. :clearable="element.options.clearable"
  298. :disabled="element.options.disabled"
  299. :style="{ width: element.options.width }"
  300. />
  301. </template>
  302. </el-form-item>
  303. <template v-if="selectWidget?.key === element.key">
  304. <div absolute z-10 left-0 top="-.5" bg-blue-500 text-white p=".5 l-0 t-0" cursor-move :class="{'bg-yellow-500':element.type === 'grid'}">
  305. <i class="eva:move-outline" text-lg />
  306. </div>
  307. <div absolute z-10 right-0 bottom="-0.5" bg-blue-500 flex gap-1 p="1 r-.5" text-white cursor-pointer :class="{'bg-yellow-500':element.type === 'grid'}">
  308. <i class="fa6-regular:clone" @click.stop="handleCopyClick()" v-if="false" />
  309. <i class="fa6-regular:trash-can" @click.stop="handleDeleteClick()" v-if="!element.allDisable" />
  310. </div>
  311. </template>
  312. </div>
  313. </template>