GenerateFormItem.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  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.trim="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.trim="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.trim="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. controls-position="right"
  143. />
  144. </template>
  145. <template v-if="element.type === 'radio'">
  146. <el-radio-group
  147. v-model="data"
  148. :style="{ width: element.options.width }"
  149. :disabled="disabled || element.options.disabled"
  150. >
  151. <el-radio
  152. v-for="item of element.options.remote
  153. ? element.options.remoteOptions
  154. : element.options.options"
  155. :key="item.value"
  156. :label="item.value"
  157. :style="{
  158. display: element.options.inline ? 'inline-block' : 'block'
  159. }"
  160. >
  161. {{ element.options.showLabel ? item.label : item.value }}
  162. </el-radio>
  163. </el-radio-group>
  164. </template>
  165. <template v-if="element.type === 'checkbox'">
  166. <el-checkbox-group
  167. v-model="data"
  168. :style="{ width: element.options.width }"
  169. :disabled="disabled || element.options.disabled"
  170. >
  171. <el-checkbox
  172. v-for="item of element.options.remote
  173. ? element.options.remoteOptions
  174. : element.options.options"
  175. :key="item.value"
  176. :label="item.value"
  177. :style="{
  178. display: element.options.inline ? 'inline-block' : 'block'
  179. }"
  180. >
  181. {{ element.options.showLabel ? item.label : item.value }}
  182. </el-checkbox>
  183. </el-checkbox-group>
  184. </template>
  185. <template v-if="element.type === 'time'">
  186. <el-config-provider :locale="zhCn">
  187. <el-time-picker
  188. v-model="data"
  189. :placeholder="element.options.placeholder"
  190. :readonly="element.options.readonly"
  191. :editable="element.options.editable"
  192. :clearable="element.options.clearable"
  193. :format="element.options.format"
  194. :disabled="disabled || element.options.disabled"
  195. :style="{ width: element.options.width }"
  196. />
  197. </el-config-provider>
  198. </template>
  199. <template v-if="element.type === 'date'">
  200. <el-config-provider :locale="zhCn">
  201. <el-date-picker
  202. v-model="data"
  203. :placeholder="element.options.placeholder"
  204. :readonly="element.options.readonly"
  205. :editable="element.options.editable"
  206. :clearable="element.options.clearable"
  207. :format="element.options.format"
  208. :disabled="disabled || element.options.disabled"
  209. :style="{ width: element.options.width }"
  210. />
  211. </el-config-provider>
  212. </template>
  213. <template v-if="element.type === 'rate'">
  214. <el-rate
  215. v-model="data"
  216. :max="element.options.max"
  217. :allow-half="element.options.allowHalf"
  218. :disabled="disabled || element.options.disabled"
  219. />
  220. </template>
  221. <template v-if="element.type === 'select'">
  222. <el-select
  223. v-model="data"
  224. :multiple="element.options.multiple"
  225. :placeholder="element.options.placeholder"
  226. :clearable="element.options.clearable"
  227. :filterable="element.options.filterable"
  228. :disabled="disabled || element.options.disabled"
  229. :style="{ width: element.options.width }"
  230. >
  231. <el-option
  232. v-for="item of element.options.remote
  233. ? element.options.remoteOptions
  234. : element.options.options"
  235. :key="item.value"
  236. :value="item.value"
  237. :label="element.options.showLabel ? item.label : item.value"
  238. />
  239. </el-select>
  240. </template>
  241. <template v-if="element.type === 'switch'">
  242. <el-switch
  243. v-model="data"
  244. :active-text="element.options.activeText"
  245. :inactive-text="element.options.inactiveText"
  246. :disabled="disabled || element.options.disabled"
  247. />
  248. </template>
  249. <template v-if="element.type === 'slider'">
  250. <el-slider
  251. v-model="data"
  252. :min="element.options.min"
  253. :max="element.options.max"
  254. :step="element.options.step"
  255. :range="element.options.range"
  256. :disabled="disabled || element.options.disabled"
  257. :style="{ width: element.options.width }"
  258. />
  259. </template>
  260. <template v-if="element.type == 'text'">
  261. <span>{{ element.options.defaultValue }}</span>
  262. </template>
  263. <template v-if="element.type === 'img-upload'">
  264. <el-upload
  265. :name="element.options.file"
  266. :action="element.options.action"
  267. :accept="element.options.accept"
  268. :list-type="element.options.listType"
  269. :multiple="element.options.multiple"
  270. :limit="element.options.limit"
  271. :disabled="disabled || element.options.disabled"
  272. :on-success="handleUploadSuccess"
  273. >
  274. <template v-if="element.options.listType === 'picture-card'">
  275. <el-image
  276. v-if="element.options.defaultValue?.length"
  277. style=" width: 100%;height: 100%;"
  278. :preview-src-list="[
  279. '/api/sys/common/static/' + element.options.defaultValue
  280. ]"
  281. :src="'/api/sys/common/static/' + element.options.defaultValue"
  282. />
  283. <i v-else class="custom:insert" />
  284. </template>
  285. <el-button v-else>
  286. <i class="custom:img-upload mr-2" />点击上传
  287. </el-button>
  288. </el-upload>
  289. </template>
  290. <template v-if="element.type === 'download'" #label="{ label }">
  291. <a
  292. :href="`/api/sys/common/static/${element.options.defaultValue}?inline=1`"
  293. style="color: #606266;"
  294. target="_blank"
  295. >
  296. {{ label }}
  297. </a>
  298. </template>
  299. <template v-if="element.type === 'download'">
  300. <el-button
  301. style="margin-top: -4px;"
  302. type="text"
  303. @click="download(element.options.defaultValue, element.label)"
  304. >
  305. 下载
  306. </el-button>
  307. </template>
  308. <template v-if="element.type === 'cascader'">
  309. <el-cascader
  310. v-model="data"
  311. :options="element.options.remoteOptions"
  312. :placeholder="element.options.placeholder"
  313. :filterable="element.options.filterable"
  314. :clearable="element.options.clearable"
  315. :disabled="disabled || element.options.disabled"
  316. :style="{ width: element.options.width }"
  317. />
  318. </template>
  319. </el-form-item>
  320. </template>
  321. <script lang="ts" setup>
  322. import type { WidgetForm } from '@/config'
  323. import zhCn from "element-plus/es/locale/lang/zh-cn";
  324. const props = defineProps<{
  325. config: WidgetForm['config']
  326. element: any
  327. model: any
  328. updatedModel: any
  329. disabled: boolean
  330. request?: Function
  331. }>()
  332. const originData = props.model[props.element.model]
  333. const data = computed({
  334. get: () => props.model[props.element.model],
  335. set: (val) => {
  336. // eslint-disable-next-line vue/no-mutating-props
  337. props.model[props.element.model] = val
  338. if (JSON.stringify(originData) === JSON.stringify(val)) {
  339. Reflect.deleteProperty(props.updatedModel, props.element.model)
  340. }
  341. else {
  342. // eslint-disable-next-line vue/no-mutating-props
  343. props.updatedModel[props.element.model] = val
  344. }
  345. },
  346. })
  347. const handleUploadSuccess = (_res: any, _file: any, fileList: any[]) => {
  348. data.value = fileList
  349. }
  350. async function download(defaultValue: string, label: string) {
  351. const a = document.createElement('a')
  352. if (!props.request) return
  353. a.href = await props
  354. .request({
  355. url: `/sys/common/static/${defaultValue}`,
  356. responseType: 'blob',
  357. })
  358. .then((i: any) => {
  359. if (i.size === 0) return ''
  360. return URL.createObjectURL(i)
  361. })
  362. a.download = `${label}.${defaultValue.split('.')[1]}`
  363. a.click()
  364. }
  365. </script>
  366. <style scoped>
  367. :deep(.el-upload--picture-card) {
  368. width: 134px;
  369. height: 134px;
  370. }
  371. </style>