123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521 |
- <template>
- <div class="by-form">
- <el-form :model="formData" :label-width="formOption.labelWidth || '100px'" :inline="formOption.inline || false" :rules="rules"
- :labelPosition="formOption.labelPosition || 'right'" ref="byForm" :disabled="formOption.disabled || false">
- <template v-for="i in formConfig" :key="i.model">
- <el-form-item :label="i.label" :prop="i.prop" v-if="(Object.keys(i).length>0)&& (i.isShow || i.isShow == undefined)" :style="
- (i.type == 'title'||i.type == 'title1')
- ? 'width:100%'
- : i.itemWidth
- ? 'width:' + i.itemWidth + '%'
- : formOption.itemWidth
- ? 'width:' + formOption.itemWidth + '%'
- : '100%'
- " :class="
- (i.type == 'title'||i.type == 'title1')?
- 'formTitle'
- : ''
- ">
- <el-input v-if="i.type == 'input'" v-model="formData[i.prop]" :placeholder="i.placeholder || $t('common.pleaseEnter')"
- @input="(e) => commonsEmit(e, i)" @change="(e) => commonsEmitChange(e, i)" :type="i.itemType ? i.itemType : 'text'"
- :disabled="i.disabled ? i.disabled : false" :max="i.max" :min="i.min" :maxlength="i.maxlength"
- :readonly="i.readonly ? i.readonly : false" :style="i.style" />
- <el-input v-if="i.type == 'selectInput'" v-model="formData[i.prop]" :placeholder="i.placeholder || $t('common.pleaseEnter')"
- @input="(e) => commonsEmit(e, i)" :type="i.itemType ? i.itemType : 'text'" :disabled="i.disabled ? i.disabled : false"
- :max="i.max" :min="i.min" :maxlength="i.maxlength" :readonly="i.readonly ? i.readonly : false">
- <template #prepend>
- <el-select v-model="formData[i.selectProp]" :placeholder="i.selectPlaceholder || $t('common.pleaseSelect')"
- @change="(e) => commonsEmit(e, i)" :disabled="i.disabledSelect ? i.disabledSelect : false"
- :readonly="i.readonly ? i.readonly : false" style="width: 80px">
- <el-option :label="j.dictValue || j.name || j.label" :value="j.dictKey||j.id || j.value" v-for="j in i.data"
- :key="j.id || j.dictKey || j.value">
- </el-option>
- </el-select>
- </template>
- </el-input>
- <div v-else-if="i.type == 'text'">
- {{formData[i.prop]}}
- </div>
- <el-select v-model="formData[i.prop]" :multiple="i.multiple || false" v-else-if="i.type == 'select'"
- :placeholder="i.placeholder || $t('common.pleaseSelect')" @change="(e) => commonsEmit(e, i)"
- :disabled="i.disabled ? i.disabled : false" :clearable="i.clearable ? i.clearable : false"
- :filterable="i.filterable ? true : true" :style="i.style?i.style:{width:'100%'}" :readonly="i.readonly ? i.readonly : false">
- <el-option :label="j.dictValue || j.name || j.label" :value="j.dictKey||j.id || j.value" v-for="j in i.data"
- :key="j.id || j.dictKey || j.value" :disabled="j.disabled ?j.disabled:false ">
- </el-option>
- </el-select>
- <el-tree-select v-model="formData[i.prop]" :multiple="i.multiple || false" v-else-if="i.type == 'treeSelect'" :data="i.data"
- :readonly="i.readonly ? i.readonly : false" :props="{
- value: i.propsTreeValue || 'id',
- label: i.propsTreeLabel || 'label',
- children: i.propsTreeChildren || 'children',
- disabled:i.propsTreeDisabled || 'disabled'
- }" value-key="id" :filterable="i.filterable ? true : true" :clearable="i.clearable ? i.clearable : false"
- :placeholder="i.placeholder || $t('common.pleaseSelect')" :disabled="i.disabled ? i.disabled : false" check-strictly
- :style="i.style?i.style:{width:'100%'}" default-expand-all @change="(e) => commonsEmit(e, i)" />
- <el-date-picker v-model="formData[i.prop]" :readonly="i.readonly ? i.readonly : false" v-else-if="i.type == 'date'" :type="i.itemType"
- :placeholder="i.placeholder || $t('common.pleaseSelectTime')" @change="(e) => commonsEmit(e, i)"
- :disabled="i.disabled ? i.disabled : false" :format="i.format ? i.format : dateFormatInit(i.itemType)"
- :value-format="i.format ? i.format : dateFormatInit(i.itemType)" :style="i.style?i.style:{width:'100%'}"
- :disabled-date="i.disabledFn ? i.disabledFn :()=>false" />
- <el-switch :disabled="i.disabled ? i.disabled : false" v-else-if="i.type == 'switch'" :readonly="i.readonly ? i.readonly : false"
- v-model="formData[i.prop]" />
- <el-checkbox-group v-else-if="i.type == 'checkbox'" v-model="formData[i.prop]" :readonly="i.readonly ? i.readonly : false"
- :disabled="i.disabled ? i.disabled : false">
- <el-checkbox v-for="j in i.data" :key="j.id || j.value" :label="j.id || j.value" name="type">
- {{ j.name || j.label }}
- </el-checkbox>
- </el-checkbox-group>
- <el-radio-group v-else-if="i.type == 'radio'" v-model="formData[i.prop]" :readonly="i.readonly ? i.readonly : false"
- :disabled="i.disabled ? i.disabled : false" @change="(e) => commonsEmit(e, i)">
- <el-radio :border="i.border ? i.border : false" v-for="j in i.data" :key="j.id || j.value ||j.dictKey"
- :label="j.id ||j.dictKey || j.value" name="type">
- {{j.dictValue || j.name || j.label }}
- </el-radio>
- </el-radio-group>
- <el-input-number v-else-if="i.type == 'number'" v-model="formData[i.prop]" :readonly="i.readonly ? i.readonly : false"
- :placeholder="i.placeholder || $t('common.pleaseEnter')" @change="(e) => commonsEmit(e, i)"
- :disabled="i.disabled ? i.disabled : false" :min="i.min ? i.min : 0" :max="i.max ? i.max : 9999999999"
- :step="i.step ? i.step : 1" :precision="i.precision !== '' ? i.precision : 2"
- :controls="i.controls === false ? false : true" :style="i.style?i.style:{width:'100%'}" onmousewheel="return false;">
- </el-input-number>
- <el-tree v-else-if="i.type == 'tree'" :data="i.data" :props="i.props" :readonly="i.readonly ? i.readonly : false"
- :show-checkbox="i.showCheckbox || true">
- </el-tree>
- <el-cascader v-else-if="i.type == 'cascader'" :options="i.data" :props="i.props" :readonly="i.readonly ? i.readonly : false"
- :placeholder="i.placeholder || $t('common.pleaseSelect')" @change="(e) => commonsEmit(e, i)"
- :disabled="i.disabled ? i.disabled : false" :style="i.style">
- </el-cascader>
- <!-- <div class="form-title" v-else-if="i.type == 'title'">
- {{ i.title }}
- </div> -->
- <div v-else-if="i.type == 'title'" style="width:100%">
- <div v-if="i.haveLine" style="width:calc(100% + 80px);margin-left:-45px;background:#F0F2F5;height:15px"></div>
- <div :style="{marginTop:i.haveLine?'15px':''}" style="margin-left:-15px;">
- <TitleInfo :content="i.title"></TitleInfo>
- </div>
- </div>
- <div v-else-if="i.type == 'title1'" style="width:100%">
- <div>
- <TitleInfo :content="i.title"></TitleInfo>
- </div>
- </div>
- <slot :name="i.slotName" v-else-if="i.type == 'slot'">
- {{ i.slotName }}插槽占位符
- </slot>
- <div class="upload" v-else-if="i.type == 'upload'">
- <el-upload :file-list="formData[i.prop]?formData[i.prop]:[]" multiple :action="uploadUrl" :data="uploadData"
- :list-type="i.listType ? i.listType : 'text'" :accept="i.accept?i.accept :''" :limit="i.limit?i.limit:3"
- :before-upload="(file)=>handleBeforeUpload(file,i)" :on-success="()=>handleSuccess(i)"
- :on-remove="(file)=>handleRemove(file,i)" :on-exceed="()=>handleExceed(i)" :on-preview="onPreviewFile">
- <el-icon v-if="i.listType=='picture-card'">
- <Plus />
- </el-icon>
- <span v-else-if="formOption.disabled" style="color:#409EFF">已上传:</span>
- <el-button type="primary" plain v-else>点击上传</el-button>
- </el-upload>
- </div>
- <div class="upload" v-else-if="i.type == 'uploadImg'">
- <el-upload :action="uploadUrl" accept=".gif, .jpeg, .jpg, .png" :show-file-list="false" :data="uploadData"
- :before-upload="(file)=>handleBeforeUploadOne(file,i.prop,i.imgProp)" :on-success="()=>handleSuccessOne(i.imgProp)">
- <div v-loading="imgLoading">
- <img v-if="formData[i.imgProp]" :src="formData[i.imgProp]" class="picOne" />
- <el-icon v-else class="avatar-uploader-icon">
- <Plus />
- </el-icon>
- </div>
- </el-upload>
- </div>
- <div v-else-if="i.type == 'table'" class="by-form-table" style="width: 100%">
- <el-table :data="formData[i.prop]" style="width: 100%">
- <el-table-column :prop="j.prop" :label="j.label" :width="i.width" v-for="(j, jindex) in i.column">
- <template #default="scope" v-if="j.type">
- <component @change="(e) => formTableChange(e, scope, j)" v-model="scope.row[j.prop]" :is="formTableObj[j.type]"
- :placeholder="j.placeholder || $t('common.pleaseEnter')" :type="j.type == 'number' ? 'number' : 'text'">
- <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'">
- </el-option>
- </component>
- </template>
- </el-table-column>
- </el-table>
- </div>
- <!-- <div v-else-if="i.type == 'json'">
- <byForm :formConfig="i.json" :formOption="formOption" v-model="formData[i.prop]" ref="byform" :rules="rules">
- </byForm>
- </div> -->
- </el-form-item>
- </template>
- </el-form>
- </div>
- </template>
- <script>
- export default {
- name: "byForm",
- };
- </script>
- <script setup>
- import { set } from "@vueuse/shared";
- import { reactive } from "vue";
- import TitleInfo from "@/components/TitleInfo/index.vue";
- defineProps({
- modelValue: {
- type: Object,
- default: false,
- },
- formConfig: {
- type: Array,
- default: false,
- },
- disabled: {
- type: Boolean,
- default: false,
- },
- formOption: {
- type: Object,
- default: false,
- },
- rules: {
- type: Object,
- default: false,
- },
- });
- const formTableChange = (e, scope, column) => {
- if (column.fn) {
- column.fn(e, scope);
- }
- console.log(formData);
- console.log(e, scope);
- };
- const formTableObj = {
- number: "el-input",
- text: "el-input",
- select: "el-select",
- input: "el-input",
- };
- const fileList = ref([]);
- const fileListCopy = ref([]);
- const uploadData = ref({});
- const fileData = ref({});
- //文件上传相关方法
- const handleSuccess = (item) => {
- if (fileData.value && fileData.value.fileUrl) {
- formData.value[item.prop].push({
- id: fileData.value.id,
- fileName: fileData.value.fileName,
- name: fileData.value.fileName,
- url: fileData.value.fileUrl,
- fileUrl: fileData.value.fileUrl,
- });
- }
- emit("update:modelValue", formData.value);
- };
- const handleRemove = (file, item) => {
- let index = formData.value[item.prop].findIndex(
- (x) => x.id == file.id || x.id == file.raw.id
- );
- if (index > -1) {
- formData.value[item.prop].splice(index, 1);
- }
- };
- const handleBeforeUpload = async (file, item) => {
- fileData.value = {};
- const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
- file.id = res.id;
- file.fileUrl = res.fileUrl;
- uploadData.value = res.uploadBody;
- fileData.value = res;
- return true;
- };
- const handleExceed = (item) => {
- let limit = item.limit || 3;
- return proxy.msgTip(`上传文件数量不可大于${limit}`, 2);
- };
- const onPreviewFile = (file, a) => {
- if (file && file.fileUrl) {
- window.open(file.fileUrl, "_blank");
- } else {
- window.open(file.raw.fileUrl, "_blank");
- }
- };
- const imgLoading = ref(false);
- const handleBeforeUploadOne = async (file, prop, imgProp) => {
- imgLoading.value = true;
- fileData.value = {};
- const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
- uploadData.value = res.uploadBody;
- formData.value[prop] = [
- {
- id: res.id,
- fileName: res.fileName,
- fileUrl: res.fileUrl,
- },
- ];
- fileData.value = res;
- return true;
- };
- const handleSuccessOne = (imgProp) => {
- if (fileData.value && fileData.value.fileUrl) {
- formData.value[imgProp] = fileData.value.fileUrl;
- emit("update:modelValue", formData.value);
- }
- setTimeout(() => {
- imgLoading.value = false;
- }, 400);
- };
- const isInit = ref(false);
- const { proxy } = getCurrentInstance();
- const emit = defineEmits(["update:modelValue"]);
- const formData = computed(() => {
- return proxy.modelValue;
- });
- const formDataReset = ref({ ...proxy.modelValue });
- const commonsEmit = (prop, item) => {
- if (item.type == "input" && item.itemType == "number") {
- console.log(formData.value);
- }
- if (item.fn) {
- item.fn(prop);
- }
- emit("update:modelValue", formData.value);
- };
- const commonsEmitChange = (prop, item) => {
- if (item.type == "input") {
- formData.value[item.prop] = prop.trim();
- }
- if (item.fn) {
- item.fn(prop);
- }
- emit("update:modelValue", formData.value);
- };
- const loadInit = () => {
- const v = this;
- for (let i = 0; i < proxy.formConfig.length; i++) {
- const element = proxy.formConfig[i];
- if (element.isLoad) {
- commonGetdata(element.isLoad, i);
- }
- }
- };
- const dateFormatInit = (itemType) => {
- const formatObj = {
- year: "YYYY",
- month: "YYYY-MM",
- date: "YYYY-MM-DD",
- dates: "YYYY-MM-DD",
- datetime: "YYYY-MM-DD HH:mm:ss",
- monthrange: "YYYY-MM-DD HH:mm:ss",
- datetimerange: "YYYY-MM-DD HH:mm:ss",
- daterange: "YYYY-MM-DD HH:mm:ss",
- };
- return formatObj[itemType];
- };
- //公用递归,保证key,val统一
- const commonRecursive = (arr, labelKey, labelVal, childrenName) => {
- for (let i = 0; i < arr.length; i++) {
- if (labelKey == "stringArray") {
- arr[i] = {
- label: arr[i],
- value: arr[i],
- id: arr[i],
- title: arr[i],
- };
- } else {
- arr[i].title = arr[i].label = arr[i][labelKey];
- arr[i].id = arr[i].value = arr[i][labelVal];
- }
- if (childrenName) {
- arr[i].children = arr[i][childrenName];
- }
- arr[i].checked = false;
- typeof arr[i][labelVal] == String
- ? (arr[i].key = arr[i][labelVal])
- : (arr[i].key = JSON.stringify(arr[i][labelVal]));
- if (childrenName) {
- this.commonRecursive(
- arr[i][childrenName],
- labelKey,
- labelVal,
- childrenName
- );
- }
- }
- };
- //请求form表单所需数据字典
- const commonGetdata = (isLoad, i) => {
- proxy[isLoad.method](isLoad.url, isLoad.req).then((message) => {
- console.log(message);
- if (getFormat(isLoad.resUrl, message) == undefined) {
- console.log("请查看isLoad配置是否正确url:" + isLoad.url);
- return;
- }
- proxy.formConfig[i].data = getFormat(isLoad.resUrl, message);
- if (isLoad.labelKey) {
- commonRecursive(
- proxy.formConfig[i].data,
- isLoad.labelKey,
- isLoad.labelVal,
- isLoad.childrenName
- );
- }
- console.log(proxy.formConfig[i].data);
- });
- };
- //根据resurl获取数据
- const getFormat = (formatStr, props) => {
- if (!formatStr) return props;
- return formatStr
- .split(".")
- .reduce((total, cur) => (!total ? "" : total[cur]), props);
- };
- //初始化所有表单
- const formDataInit = () => {
- var map = {
- input: "",
- radio: null,
- select: null,
- checkbox: [],
- date: "",
- datetime: "",
- daterange: [],
- datetimerange: [],
- year: null,
- month: null,
- switch: false,
- inputNumber: 0,
- cascader: [],
- Solt: null,
- Transfer: [],
- Upload: { path: null, id: null, name: null },
- password: "",
- treeSelect: "",
- json: {},
- };
- const formDataCopy = { ...formData.value };
- for (let i = 0; i < proxy.formConfig.length; i++) {
- const element = proxy.formConfig[i];
- if (formDataCopy[element.prop] || element.type === "slot") {
- continue;
- }
- if (map[element.itemType] != undefined) {
- formData.value[element.prop] = map[element.itemType];
- } else {
- formData.value[element.prop] = element.multiple ? [] : map[element.type];
- }
- }
- emit("update:modelValue", formData.value);
- };
- const handleSubmit = async (onSubmit) => {
- try {
- const flag = await proxy.$refs["byForm"].validate();
- if (flag) {
- const form = { ...formData.value };
- proxy.formConfig.map((item) => {
- // if (item.type == "json") {
- // form[item.prop] = JSON.stringify(form[item.prop]);
- // }
- // if (item.type == 'input') {
- // form[item.prop] = form[item.prop].trim();
- // }
- });
- emit("update:modelValue", form);
- onSubmit();
- return true;
- } else {
- }
- } catch (err) {
- setTimeout(() => {
- const errorDiv = document.getElementsByClassName("is-error");
- if (errorDiv && errorDiv[0]) {
- errorDiv[0].scrollIntoView({
- behavior: "smooth",
- block: "center",
- inline: "nearest",
- });
- }
- }, 0);
- console.log("请检查表单!", err);
- return false;
- }
- };
- const byform = ref(null); // 延迟使用,因为还没有返回跟挂载
- onMounted(() => {});
- defineExpose({
- handleSubmit,
- });
- formDataInit();
- loadInit();
- </script>
- <style scope>
- .form-title {
- font-size: 14px;
- font-weight: bold;
- margin-top: 22px;
- color: #333333;
- }
- .by-form .el-form--inline .el-form-item {
- margin-right: 0px;
- box-sizing: border-box;
- }
- .by-form .el-form--inline > .el-form-item {
- padding: 0 10px 0 0px;
- }
- .by-form .el-form--inline .formTitle {
- padding: 0px !important;
- }
- /* .el-form--inline.el-form--label-top{
- justify-content: space-between;
- } */
- .dn {
- display: none !important;
- }
- /* .by-form-json .by-form .el-form .el-form-item {
- margin-bottom: 18px;
- } */
- /* .by-form-json {
- padding: 0px !important;
- } */
- .picOne {
- object-fit: contain;
- width: 80px;
- height: 80px;
- cursor: pointer;
- vertical-align: middle;
- }
- .el-icon.avatar-uploader-icon {
- font-size: 20px;
- color: #8c939d;
- width: 80px;
- height: 80px;
- text-align: center;
- border: 1px dashed var(--el-border-color);
- }
- </style>
|