GenerateFormItem.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. <template>
  2. <div
  3. v-if="element.type === 'grid'"
  4. grid="~ cols-24"
  5. :style="`gap: ${element.options.gutter}px; align-items: ${element.options.align};`"
  6. >
  7. <div
  8. v-for="(col, colIndex) of element.columns"
  9. :key="colIndex"
  10. :style="`grid-column: span ${col.span}`"
  11. >
  12. <GenerateFormItem
  13. v-for="colItem of col.list"
  14. :key="colItem.key"
  15. :request="request"
  16. :model="model"
  17. :updated-model="updatedModel"
  18. :element="colItem"
  19. :config="config"
  20. :disabled="disabled"
  21. />
  22. </div>
  23. </div>
  24. <el-table
  25. v-else-if="element.type === 'table'"
  26. border
  27. class="mb-4.5"
  28. :data="element.options.defaultValue"
  29. >
  30. <el-table-column
  31. v-for="i in element.columns"
  32. :key="i.prop"
  33. :align="element.options.align"
  34. v-bind="i"
  35. />
  36. </el-table>
  37. <el-divider
  38. v-else-if="element.type === 'divider'"
  39. :data="element.options.defaultValue"
  40. content-position="left"
  41. >
  42. {{ element.label }}
  43. </el-divider>
  44. <el-form-item
  45. v-else-if="element"
  46. :key="element.key"
  47. :label="element.label"
  48. :prop="element.model"
  49. :style="
  50. element.type === 'download' ? 'display:inline-flex;margin-right:40px' : ''
  51. "
  52. :label-width="element.labelWidth"
  53. >
  54. <template v-if="element.type === 'input'">
  55. <el-input
  56. v-model="data"
  57. :style="{ width: element.options.width }"
  58. :placeholder="element.options.placeholder"
  59. :maxlength="parseInt(element.options.maxlength)"
  60. :clearable="element.options.clearable"
  61. :readonly="element.options.readonly"
  62. :disabled="disabled || element.options.disabled"
  63. >
  64. <template v-if="element.options.prefix" #prefix>
  65. {{
  66. element.options.prefix
  67. }}
  68. </template>
  69. <template v-if="element.options.suffix" #suffix>
  70. {{
  71. element.options.suffix
  72. }}
  73. </template>
  74. <template v-if="element.options.prepend" #prepend>
  75. {{
  76. element.options.prepend
  77. }}
  78. </template>
  79. <template v-if="element.options.append" #append>
  80. {{
  81. element.options.append
  82. }}
  83. </template>
  84. </el-input>
  85. </template>
  86. <template v-if="element.type === 'password'">
  87. <el-input
  88. v-model="data"
  89. :style="{ width: element.options.width }"
  90. :placeholder="element.options.placeholder"
  91. :maxlength="parseInt(element.options.maxlength)"
  92. :clearable="element.options.clearable"
  93. :disabled="disabled || element.options.disabled"
  94. :readonly="element.options.readonly"
  95. :show-password="element.options.showPassword"
  96. >
  97. <template v-if="element.options.prefix" #prefix>
  98. {{
  99. element.options.prefix
  100. }}
  101. </template>
  102. <template v-if="element.options.suffix" #suffix>
  103. {{
  104. element.options.suffix
  105. }}
  106. </template>
  107. <template v-if="element.options.prepend" #prepend>
  108. {{
  109. element.options.prepend
  110. }}
  111. </template>
  112. <template v-if="element.options.append" #append>
  113. {{
  114. element.options.append
  115. }}
  116. </template>
  117. </el-input>
  118. </template>
  119. <template v-if="element.type === 'textarea'">
  120. <el-input
  121. v-model="data"
  122. type="textarea"
  123. resize="none"
  124. :rows="element.options.rows"
  125. :style="{ width: element.options.width }"
  126. :placeholder="element.options.placeholder"
  127. :maxlength="parseInt(element.options.maxlength)"
  128. :show-word-limit="element.options.showWordLimit"
  129. :autosize="element.options.autosize"
  130. :clearable="element.options.clearable"
  131. :readonly="element.options.readonly"
  132. :disabled="disabled || element.options.disabled"
  133. />
  134. </template>
  135. <template v-if="element.type === 'number'">
  136. <el-input-number
  137. v-model="data"
  138. :style="{ width: element.options.width }"
  139. :max="element.options.max"
  140. :min="element.options.min"
  141. :disabled="disabled || element.options.disabled"
  142. />
  143. </template>
  144. <template v-if="element.type === 'radio'">
  145. <el-radio-group
  146. v-model="data"
  147. :style="{ width: element.options.width }"
  148. :disabled="disabled || element.options.disabled"
  149. >
  150. <el-radio
  151. v-for="item of element.options.remote
  152. ? element.options.remoteOptions
  153. : element.options.options"
  154. :key="item.value"
  155. :label="item.value"
  156. :style="{
  157. display: element.options.inline ? 'inline-block' : 'block'
  158. }"
  159. >
  160. {{ element.options.showLabel ? item.label : item.value }}
  161. </el-radio>
  162. </el-radio-group>
  163. </template>
  164. <template v-if="element.type === 'checkbox'">
  165. <el-checkbox-group
  166. v-model="data"
  167. :style="{ width: element.options.width }"
  168. :disabled="disabled || element.options.disabled"
  169. >
  170. <el-checkbox
  171. v-for="item of element.options.remote
  172. ? element.options.remoteOptions
  173. : element.options.options"
  174. :key="item.value"
  175. :label="item.value"
  176. :style="{
  177. display: element.options.inline ? 'inline-block' : 'block'
  178. }"
  179. >
  180. {{ element.options.showLabel ? item.label : item.value }}
  181. </el-checkbox>
  182. </el-checkbox-group>
  183. </template>
  184. <template v-if="element.type === 'time'">
  185. <el-time-picker
  186. v-model="data"
  187. :placeholder="element.options.placeholder"
  188. :readonly="element.options.readonly"
  189. :editable="element.options.editable"
  190. :clearable="element.options.clearable"
  191. :format="element.options.format"
  192. :disabled="disabled || element.options.disabled"
  193. :style="{ width: element.options.width }"
  194. />
  195. </template>
  196. <template v-if="element.type === 'date'">
  197. <el-date-picker
  198. v-model="data"
  199. :placeholder="element.options.placeholder"
  200. :readonly="element.options.readonly"
  201. :editable="element.options.editable"
  202. :clearable="element.options.clearable"
  203. :format="element.options.format"
  204. :disabled="disabled || element.options.disabled"
  205. :style="{ width: element.options.width }"
  206. />
  207. </template>
  208. <template v-if="element.type === 'rate'">
  209. <el-rate
  210. v-model="data"
  211. :max="element.options.max"
  212. :allow-half="element.options.allowHalf"
  213. :disabled="disabled || element.options.disabled"
  214. />
  215. </template>
  216. <template v-if="element.type === 'select'">
  217. <el-select
  218. v-model="data"
  219. :multiple="element.options.multiple"
  220. :placeholder="element.options.placeholder"
  221. :clearable="element.options.clearable"
  222. :filterable="element.options.filterable"
  223. :disabled="disabled || element.options.disabled"
  224. :style="{ width: element.options.width }"
  225. >
  226. <el-option
  227. v-for="item of element.options.remote
  228. ? element.options.remoteOptions
  229. : element.options.options"
  230. :key="item.value"
  231. :value="item.value"
  232. :label="element.options.showLabel ? item.label : item.value"
  233. />
  234. </el-select>
  235. </template>
  236. <template v-if="element.type === 'switch'">
  237. <el-switch
  238. v-model="data"
  239. :active-text="element.options.activeText"
  240. :inactive-text="element.options.inactiveText"
  241. :disabled="disabled || element.options.disabled"
  242. />
  243. </template>
  244. <template v-if="element.type === 'slider'">
  245. <el-slider
  246. v-model="data"
  247. :min="element.options.min"
  248. :max="element.options.max"
  249. :step="element.options.step"
  250. :range="element.options.range"
  251. :disabled="disabled || element.options.disabled"
  252. :style="{ width: element.options.width }"
  253. />
  254. </template>
  255. <template v-if="element.type == 'text'">
  256. <span>{{ element.options.defaultValue }}</span>
  257. </template>
  258. <template v-if="element.type === 'img-upload'">
  259. <el-upload
  260. :name="element.options.file"
  261. :action="element.options.action"
  262. :accept="element.options.accept"
  263. :list-type="element.options.listType"
  264. :multiple="element.options.multiple"
  265. :limit="element.options.limit"
  266. :disabled="disabled || element.options.disabled"
  267. :on-success="handleUploadSuccess"
  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 class="custom:img-upload mr-2" />点击上传
  282. </el-button>
  283. </el-upload>
  284. </template>
  285. <template v-if="element.type === 'download'" #label="{ label }">
  286. <a
  287. :href="`/api/sys/common/static/${element.options.defaultValue}?inline=1`"
  288. style="color: #606266;"
  289. target="_blank"
  290. >
  291. {{ label }}
  292. </a>
  293. </template>
  294. <template v-if="element.type === 'download'">
  295. <el-button
  296. style="margin-top: -4px;"
  297. type="text"
  298. @click="download(element.options.defaultValue, element.label)"
  299. >
  300. 下载
  301. </el-button>
  302. </template>
  303. <template v-if="element.type === 'cascader'">
  304. <el-cascader
  305. v-model="data"
  306. :options="element.options.remoteOptions"
  307. :placeholder="element.options.placeholder"
  308. :filterable="element.options.filterable"
  309. :clearable="element.options.clearable"
  310. :disabled="disabled || element.options.disabled"
  311. :style="{ width: element.options.width }"
  312. />
  313. </template>
  314. </el-form-item>
  315. </template>
  316. <script lang="ts" setup>
  317. import type { WidgetForm } from '@/config'
  318. const props = defineProps<{
  319. config: WidgetForm['config']
  320. element: any
  321. model: any
  322. updatedModel: any
  323. disabled: boolean
  324. request?: Function
  325. }>()
  326. const originData = props.model[props.element.model]
  327. const data = computed({
  328. get: () => props.model[props.element.model],
  329. set: (val) => {
  330. // eslint-disable-next-line vue/no-mutating-props
  331. props.model[props.element.model] = val
  332. if (JSON.stringify(originData) === JSON.stringify(val)) {
  333. Reflect.deleteProperty(props.updatedModel, props.element.model)
  334. }
  335. else {
  336. // eslint-disable-next-line vue/no-mutating-props
  337. props.updatedModel[props.element.model] = val
  338. }
  339. },
  340. })
  341. const handleUploadSuccess = (_res: any, _file: any, fileList: any[]) => {
  342. data.value = fileList
  343. }
  344. async function download(defaultValue: string, label: string) {
  345. const a = document.createElement('a')
  346. if (!props.request) return
  347. a.href = await props
  348. .request({
  349. url: `/sys/common/static/${defaultValue}`,
  350. responseType: 'blob',
  351. })
  352. .then((i: any) => {
  353. if (i.size === 0) return ''
  354. return URL.createObjectURL(i)
  355. })
  356. a.download = `${label}.${defaultValue.split('.')[1]}`
  357. a.click()
  358. }
  359. </script>
  360. <style scoped>
  361. :deep(.el-upload--picture-card) {
  362. width: 134px;
  363. height: 134px;
  364. }
  365. </style>