index.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. <template>
  2. <div class="by-form">
  3. <el-form
  4. :model="formData"
  5. :label-width="formOption.labelWidth"
  6. :inline="formOption.inline || false"
  7. :rules="rules"
  8. :labelPosition="formOption.labelPosition || 'top'"
  9. ref="byForm"
  10. :disabled="formOption.disabled || false">
  11. <el-form-item
  12. :label="i.label"
  13. v-for="i in formConfig"
  14. :key="i.model"
  15. :prop="i.prop"
  16. v-show="i.isShow || i.isShow == undefined"
  17. :style="
  18. i.type == 'title' ? 'width:100%' : i.itemWidth ? 'width:' + i.itemWidth + '%' : formOption.itemWidth ? 'width:' + formOption.itemWidth + '%' : '100%'
  19. "
  20. :class="i.type == 'json' ? (i.isHide ? 'by-form-json dn' : 'by-form-json') : i.isHide ? 'dn' : ''">
  21. <el-input
  22. v-if="i.type == 'input'"
  23. v-model="formData[i.prop]"
  24. :placeholder="i.placeholder || $t('common.pleaseEnter')"
  25. @input="(e) => commonsEmit(e, i)"
  26. @change="(e) => commonsEmitChange(e, i)"
  27. :type="i.itemType ? i.itemType : 'text'"
  28. :disabled="i.disabled ? i.disabled : false"
  29. :max="i.max"
  30. :min="i.min"
  31. :maxlength="i.maxlength"
  32. :readonly="i.readonly ? i.readonly : false"
  33. :style="i.style" />
  34. <el-input
  35. v-if="i.type == 'selectInput'"
  36. v-model="formData[i.prop]"
  37. :placeholder="i.placeholder || $t('common.pleaseEnter')"
  38. @input="(e) => commonsEmit(e, i)"
  39. :type="i.itemType ? i.itemType : 'text'"
  40. :disabled="i.disabled ? i.disabled : false"
  41. :max="i.max"
  42. :min="i.min"
  43. :maxlength="i.maxlength"
  44. :readonly="i.readonly ? i.readonly : false">
  45. <template #prepend>
  46. <el-select
  47. v-model="formData[i.selectProp]"
  48. :placeholder="i.selectPlaceholder || $t('common.pleaseSelect')"
  49. @change="(e) => commonsEmit(e, i)"
  50. :disabled="i.disabled ? i.disabled : false"
  51. :readonly="i.readonly ? i.readonly : false"
  52. style="width: 80px">
  53. <el-option :label="j.title || j.name || j.label" :value="j.id || j.value" v-for="j in i.data" :key="j.id"> </el-option>
  54. </el-select>
  55. </template>
  56. </el-input>
  57. <el-select
  58. v-model="formData[i.prop]"
  59. :multiple="i.multiple || false"
  60. v-else-if="i.type == 'select'"
  61. :placeholder="i.placeholder || $t('common.pleaseSelect')"
  62. @change="(e) => commonsEmit(e, i)"
  63. :disabled="i.disabled ? i.disabled : false"
  64. :clearable="i.clearable ? i.clearable : false"
  65. :filterable="i.filterable ? true : false"
  66. :style="i.style"
  67. :readonly="i.readonly ? i.readonly : false"
  68. style="width: 100%">
  69. <el-option :label="j.dictValue || j.title || j.name || j.label" :value="j.dictKey || j.id || j.value" v-for="j in i.data" :key="j.id"> </el-option>
  70. </el-select>
  71. <el-tree-select
  72. v-model="formData[i.prop]"
  73. v-else-if="i.type == 'treeSelect'"
  74. :data="i.data"
  75. :readonly="i.readonly ? i.readonly : false"
  76. :props="{
  77. value: i.propsTreeValue || 'id',
  78. label: i.propsTreeLabel || 'label',
  79. children: i.propsTreeChildren || 'children',
  80. }"
  81. value-key="id"
  82. :placeholder="i.placeholder || $t('common.pleaseSelect')"
  83. :disabled="i.disabled ? i.disabled : false"
  84. check-strictly
  85. :style="i.style"
  86. style="width: 100%" />
  87. <el-date-picker
  88. v-model="formData[i.prop]"
  89. :readonly="i.readonly ? i.readonly : false"
  90. v-else-if="i.type == 'date'"
  91. :type="i.itemType"
  92. :placeholder="i.placeholder || $t('common.pleaseSelectTime')"
  93. @change="(e) => commonsEmit(e, i)"
  94. :disabled="i.disabled ? i.disabled : false"
  95. :format="i.format ? i.format : dateFormatInit(i.itemType)"
  96. :value-format="i.format ? i.format : dateFormatInit(i.itemType)"
  97. style="width: 100%" />
  98. <el-switch
  99. :disabled="i.disabled ? i.disabled : false"
  100. v-else-if="i.type == 'switch'"
  101. :readonly="i.readonly ? i.readonly : false"
  102. v-model="formData[i.prop]" />
  103. <el-checkbox-group
  104. v-else-if="i.type == 'checkbox'"
  105. v-model="formData[i.prop]"
  106. :readonly="i.readonly ? i.readonly : false"
  107. :disabled="i.disabled ? i.disabled : false">
  108. <el-checkbox v-for="j in i.data" :key="j.id || j.value" :label="j.id || j.value" name="type">
  109. {{ j.name || j.label }}
  110. </el-checkbox>
  111. </el-checkbox-group>
  112. <el-radio-group
  113. v-else-if="i.type == 'radio'"
  114. v-model="formData[i.prop]"
  115. :readonly="i.readonly ? i.readonly : false"
  116. :disabled="i.disabled ? i.disabled : false">
  117. <el-radio :border="i.border ? i.border : false" v-for="j in i.data" :key="j.id || j.value" :label="j.id || j.value" name="type">
  118. {{ j.name || j.label }}
  119. </el-radio>
  120. </el-radio-group>
  121. <el-input-number
  122. v-else-if="i.type == 'number'"
  123. v-model="formData[i.prop]"
  124. :readonly="i.readonly ? i.readonly : false"
  125. :placeholder="i.placeholder || $t('common.pleaseEnter')"
  126. @change="(e) => commonsEmit(e, i)"
  127. :disabled="i.disabled ? i.disabled : false"
  128. :min="i.min ? i.min : 0"
  129. :max="i.max ? i.max : 9999999999"
  130. :step="i.step ? i.step : 1"
  131. :precision="i.precision !== '' ? i.precision : 2"
  132. :controls="i.controls === false ? false : true"
  133. :style="i.style"
  134. onmousewheel="return false;">
  135. </el-input-number>
  136. <el-tree
  137. v-else-if="i.type == 'tree'"
  138. :data="i.data"
  139. :props="i.props"
  140. :readonly="i.readonly ? i.readonly : false"
  141. :show-checkbox="i.showCheckbox || true">
  142. </el-tree>
  143. <el-cascader
  144. v-else-if="i.type == 'cascader'"
  145. :options="i.data"
  146. :props="i.props"
  147. :readonly="i.readonly ? i.readonly : false"
  148. :placeholder="i.placeholder || $t('common.pleaseSelect')"
  149. @change="(e) => commonsEmit(e, i)"
  150. :disabled="i.disabled ? i.disabled : false"
  151. :style="i.style">
  152. </el-cascader>
  153. <div class="form-title" v-else-if="i.type == 'title'">
  154. {{ i.title }}
  155. </div>
  156. <slot :name="i.slotName" v-else-if="i.type == 'slot'"> {{ i.slotName }}插槽占位符 </slot>
  157. <div class="upload" v-else-if="i.type == 'upload'">
  158. <el-upload
  159. v-model="formData[i.prop]"
  160. action="https://winfaster.obs.cn-south-1.myhuaweicloud.com"
  161. :data="uploadData"
  162. list-type="picture-card"
  163. :on-remove="handleRemove"
  164. :on-success="handleSuccess"
  165. :before-upload="handleBeforeUpload">
  166. <el-icon><Plus /></el-icon>
  167. </el-upload>
  168. </div>
  169. <div v-else-if="i.type == 'table'" class="by-form-table" style="width: 100%">
  170. <el-table :data="formData[i.prop]" style="width: 100%">
  171. <el-table-column :prop="j.prop" :label="j.label" :width="i.width" v-for="(j, jindex) in i.column">
  172. <template #default="scope" v-if="j.type">
  173. <component
  174. @change="(e) => formTableChange(e, scope, j)"
  175. v-model="scope.row[j.prop]"
  176. :is="formTableObj[j.type]"
  177. :placeholder="j.placeholder || $t('common.pleaseEnter')"
  178. :type="j.type == 'number' ? 'number' : 'text'">
  179. <el-option :label="n.title || n.name || n.label" :value="n.id || n.value" v-for="n in j.data" :key="n.id" v-if="j.type == 'select'">
  180. </el-option>
  181. </component>
  182. </template>
  183. </el-table-column>
  184. </el-table>
  185. </div>
  186. <div v-else-if="i.type == 'json'">
  187. <byForm :formConfig="i.json" :formOption="formOption" v-model="formData[i.prop]" ref="byform" :rules="rules"> </byForm>
  188. </div>
  189. </el-form-item>
  190. </el-form>
  191. </div>
  192. </template>
  193. <script>
  194. export default {
  195. name: "byForm",
  196. };
  197. </script>
  198. <script setup>
  199. defineProps({
  200. modelValue: {
  201. type: Object,
  202. default: false,
  203. },
  204. formConfig: {
  205. type: Array,
  206. default: false,
  207. },
  208. disabled: {
  209. type: Boolean,
  210. default: false,
  211. },
  212. formOption: {
  213. type: Object,
  214. default: false,
  215. },
  216. rules: {
  217. type: Object,
  218. default: false,
  219. },
  220. });
  221. const formTableChange = (e, scope, column) => {
  222. if (column.fn) {
  223. column.fn(e, scope);
  224. }
  225. };
  226. const formTableObj = {
  227. number: "el-input",
  228. text: "el-input",
  229. select: "el-select",
  230. input: "el-input",
  231. };
  232. const fileList = ref([]);
  233. const fileListCopy = ref([]);
  234. const uploadData = ref({});
  235. //文件上传相关方法
  236. const handleSuccess = (res, file, files) => {
  237. emit("update:modelValue", formData.value);
  238. };
  239. const handleRemove = (file) => {
  240. const index = fileListCopy.value.findIndex((x) => x.uid === file.uid || x.id === file.id);
  241. fileListCopy.value.splice(index, 1);
  242. };
  243. const handleBeforeUpload = async (file) => {
  244. const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
  245. uploadData.value = res.uploadBody;
  246. fileListCopy.value.push({
  247. id: res.id,
  248. fileName: res.fileName,
  249. path: res.fileUrl,
  250. url: res.fileUrl,
  251. uid: file.uid,
  252. });
  253. };
  254. const { proxy } = getCurrentInstance();
  255. const emit = defineEmits(["update:modelValue"]);
  256. const formData = computed(() => {
  257. return proxy.modelValue;
  258. });
  259. const commonsEmit = (prop, item) => {
  260. if (item.fn) {
  261. item.fn(prop);
  262. }
  263. emit("update:modelValue", formData.value);
  264. };
  265. const commonsEmitChange = (prop, item) => {
  266. if (item.type == "input") {
  267. formData.value[item.prop] = prop.trim();
  268. }
  269. if (item.fn) {
  270. item.fn(prop);
  271. }
  272. emit("update:modelValue", formData.value);
  273. };
  274. const loadInit = () => {
  275. const v = this;
  276. for (let i = 0; i < proxy.formConfig.length; i++) {
  277. const element = proxy.formConfig[i];
  278. if (element.isLoad) {
  279. commonGetdata(element.isLoad, i);
  280. }
  281. }
  282. };
  283. const dateFormatInit = (itemType) => {
  284. const formatObj = {
  285. year: "YYYY",
  286. month: "YYYY-MM",
  287. date: "YYYY-MM-DD HH:mm:ss",
  288. dates: "YYYY-MM-DD",
  289. datetime: "YYYY-MM-DD HH:mm:ss",
  290. monthrange: "YYYY-MM-DD HH:mm:ss",
  291. datetimerange: "YYYY-MM-DD HH:mm:ss",
  292. daterange: "YYYY-MM-DD HH:mm:ss",
  293. };
  294. return formatObj[itemType];
  295. };
  296. //公用递归,保证key,val统一
  297. const commonRecursive = (arr, labelKey, labelVal, childrenName) => {
  298. for (let i = 0; i < arr.length; i++) {
  299. if (labelKey == "stringArray") {
  300. arr[i] = {
  301. label: arr[i],
  302. value: arr[i],
  303. id: arr[i],
  304. title: arr[i],
  305. };
  306. } else {
  307. arr[i].title = arr[i].label = arr[i][labelKey];
  308. arr[i].id = arr[i].value = arr[i][labelVal];
  309. }
  310. if (childrenName) {
  311. arr[i].children = arr[i][childrenName];
  312. }
  313. arr[i].checked = false;
  314. typeof arr[i][labelVal] == String ? (arr[i].key = arr[i][labelVal]) : (arr[i].key = JSON.stringify(arr[i][labelVal]));
  315. if (childrenName) {
  316. this.commonRecursive(arr[i][childrenName], labelKey, labelVal, childrenName);
  317. }
  318. }
  319. };
  320. //请求form表单所需数据字典
  321. const commonGetdata = (isLoad, i) => {
  322. proxy[isLoad.method](isLoad.url, isLoad.req).then((message) => {
  323. if (getFormat(isLoad.resUrl, message) == undefined) {
  324. console.log("请查看isLoad配置是否正确url:" + isLoad.url);
  325. return;
  326. }
  327. proxy.formConfig[i].data = getFormat(isLoad.resUrl, message);
  328. if (isLoad.labelKey) {
  329. commonRecursive(proxy.formConfig[i].data, isLoad.labelKey, isLoad.labelVal, isLoad.childrenName);
  330. }
  331. });
  332. };
  333. //根据resurl获取数据
  334. const getFormat = (formatStr, props) => {
  335. if (!formatStr) return props;
  336. return formatStr.split(".").reduce((total, cur) => (!total ? "" : total[cur]), props);
  337. };
  338. //初始化所有表单
  339. const formDataInit = () => {
  340. var map = {
  341. input: "",
  342. radio: null,
  343. select: null,
  344. checkbox: [],
  345. date: "",
  346. datetime: "",
  347. daterange: [],
  348. datetimerange: [],
  349. year: null,
  350. month: null,
  351. switch: false,
  352. inputNumber: 0,
  353. cascader: [],
  354. Solt: null,
  355. Transfer: [],
  356. Upload: { path: null, id: null, name: null },
  357. password: "",
  358. treeSelect: "",
  359. json: {},
  360. };
  361. const formDataCopy = { ...formData.value };
  362. for (let i = 0; i < proxy.formConfig.length; i++) {
  363. const element = proxy.formConfig[i];
  364. if (formDataCopy[element.prop] || element.type === "slot") {
  365. continue;
  366. }
  367. if (map[element.itemType] != undefined) {
  368. formData.value[element.prop] = map[element.itemType];
  369. } else {
  370. formData.value[element.prop] = element.multiple ? [] : map[element.type];
  371. }
  372. }
  373. emit("update:modelValue", formData.value);
  374. };
  375. const handleSubmit = async (onSubmit) => {
  376. try {
  377. const flag = await proxy.$refs["byForm"].validate();
  378. if (flag) {
  379. const form = { ...formData.value };
  380. proxy.formConfig.map((item) => {
  381. if (item.type == "json") {
  382. form[item.prop] = JSON.stringify(form[item.prop]);
  383. }
  384. });
  385. emit("update:modelValue", form);
  386. onSubmit();
  387. return true;
  388. }
  389. } catch (err) {
  390. console.log("请检查表单!", err);
  391. return false;
  392. }
  393. };
  394. const byform = ref(null); // 延迟使用,因为还没有返回跟挂载
  395. onMounted(() => {});
  396. defineExpose({
  397. handleSubmit,
  398. });
  399. formDataInit();
  400. loadInit();
  401. </script>
  402. <style>
  403. .form-title {
  404. font-size: 14px;
  405. font-weight: bold;
  406. color: #6c88f1;
  407. width: 120px;
  408. border-bottom: 1px solid #6c88f1;
  409. }
  410. .by-form .el-form--inline .el-form-item {
  411. margin-right: 0px;
  412. box-sizing: border-box;
  413. }
  414. .by-form .el-form--inline > .el-form-item {
  415. padding: 0 10px;
  416. }
  417. /* .el-form--inline.el-form--label-top{
  418. justify-content: space-between;
  419. } */
  420. .dn {
  421. display: none !important;
  422. }
  423. .by-form-json .by-form .el-form .el-form-item {
  424. margin-bottom: 18px;
  425. }
  426. .by-form-json {
  427. padding: 0px !important;
  428. }
  429. </style>