index.vue 15 KB

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