hookehuyr

Merge branch 'feature/组件数据结构调整' into develop

......@@ -2,7 +2,7 @@
* @Author: hookehuyr hookehuyr@gmail.com
* @Date: 2022-05-26 23:52:36
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-12-09 14:20:44
* @LastEditTime: 2022-12-28 11:02:30
* @FilePath: /data-table/src/App.vue
* @Description:
-->
......@@ -76,16 +76,7 @@ onMounted(async () => {
const { data } = await getFormSettingAPI({ form_code: code });
const form_setting = {};
if (data.length) {
data[0].property_list.forEach((prop) => {
const key = prop["property_code"];
const obj = {
[key]:
prop["setting_value"].length > 1
? prop["setting_value"]
: prop["setting_value"][0],
};
Object.assign(form_setting, obj, data[0]['extend']);
});
Object.assign(form_setting, data[0]['property_list'], data[0]['extend']);
}
// 缓存表单设置
store.changeFormSetting(form_setting);
......
/*
* @Date: 2022-06-17 14:54:29
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-12-06 11:22:36
* @LastEditTime: 2022-12-16 15:57:01
* @FilePath: /data-table/src/api/form.js
* @Description: 表单接口
*/
......@@ -9,7 +9,7 @@ import { fn, fetch } from '@/api/fn';
const Api = {
FORM_ADD: '/srv/?a=add_form',
FORM_QUERY: '/srv/?a=query_form',
FORM_QUERY: '/srv/?a=query_form_all_field',
ADD_FORM_FIELD: '/srv/?a=add_form_field',
ADD_FORM_SETTING: '/srv/?a=add_form_setting',
QUERY_FORM_SETTING: '/srv/?a=query_form_setting',
......
<!--
* @Date: 2022-08-30 14:32:11
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-12-08 14:57:16
* @LastEditTime: 2022-12-29 15:42:46
* @FilePath: /data-table/src/components/AreaPickerField/index.vue
* @Description: 省市区选择控件
-->
<template>
<div class="area-picker-field">
<div v-if="HideShow" class="area-picker-field">
<div class="label">{{ item.component_props.label }}<span v-if="item.component_props.required">&nbsp;*</span></div>
<van-field
name="ignore"
......@@ -22,7 +22,7 @@
<van-field
name="ignore"
v-model="address"
:placeholder="item.component_props.placeholder"
placeholder="请填写详细地址"
@blur="onBlur"
:rules="item.rules"
:border="false"
......@@ -54,7 +54,10 @@ import { areaList } from "@vant/area-data";
const props = defineProps({
item: Object,
});
// 隐藏显示
const HideShow = computed(() => {
return !props.item.component_props.disabled
})
const emit = defineEmits(["active"]);
const show_empty = ref(false);
......
<!--
* @Date: 2022-08-30 11:34:19
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-11-21 14:42:00
* @LastEditTime: 2022-12-29 11:34:14
* @FilePath: /data-table/src/components/CheckboxField/index.vue
* @Description: 多项选择控件
-->
<template>
<div class="checkbox-field-page">
<div v-if="HideShow" class="checkbox-field-page">
<div class="label">
{{ item.component_props.label }}
<span v-if="item.component_props.required" style="color: red">&nbsp;*</span>
......@@ -14,6 +14,9 @@
(最多可选数:&nbsp;{{ item.component_props.max }})
</span>
</div>
<div v-if="item.component_props.note" class="note">
{{ item.component_props.note }}
</div>
<van-field :name="item.key" :rules="item.rules" :border="false">
<template #input>
<van-checkbox-group
......@@ -24,13 +27,13 @@
>
<van-checkbox
v-for="x in item.component_props.options"
:key="index"
:name="x"
:key="x.value"
:name="x.value"
icon-size="1rem"
shape="square"
:checked-color="themeVars.radioColor"
style="margin-bottom: 0.25rem"
>{{ x }}</van-checkbox
>{{ x.title }}</van-checkbox
>
</van-checkbox-group>
</template>
......@@ -52,6 +55,10 @@ onMounted(() => {
// 默认值为数组
props.item.value = [];
});
// 隐藏显示
const HideShow = computed(() => {
return !props.item.component_props.disabled
})
</script>
<style lang="less" scoped>
......@@ -61,6 +68,12 @@ onMounted(() => {
font-size: 0.9rem;
font-weight: bold;
}
.note {
font-size: 0.9rem;
margin-left: 1rem;
color: gray;
padding-bottom: 0.5rem
}
}
:deep(.van-checkbox) {
......
<!--
* @Date: 2022-08-31 11:45:30
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-11-21 14:43:16
* @LastEditTime: 2022-12-29 11:45:54
* @FilePath: /data-table/src/components/DatePickerField/index.vue
* @Description: 日期选择组件
-->
<template>
<div class="date-picker-field">
<div v-if="HideShow" class="date-picker-field">
<div class="label">
{{ item.component_props.label }}
<span v-if="item.component_props.required">&nbsp;*</span>
......@@ -17,17 +17,17 @@
readonly
:name="item.key"
:required="item.component_props.required"
:placeholder="item.component_props.placeholder"
:rules="item.rules"
@click="showPicker = true"
disabled="item.component_props.readonly"
:placeholder="item.component_props.placeholder ? item.component_props.placeholder : '请选择日期'"
:rules="rules"
@click="onTap"
:border="false"
/>
<van-popup v-model:show="showPicker" position="bottom">
<van-date-picker
v-model="currentDate"
:title="item.component_props.title"
:min-date="item.component_props.min_date"
:max-date="item.component_props.max_date"
:columns-type="item.component_props.columns_type"
title="日期选择"
:columns-type="columns_type"
@confirm="onConfirm"
@cancel="showPicker = false"
/>
......@@ -41,24 +41,69 @@ import dayjs from "dayjs";
const props = defineProps({
item: Object,
});
// 隐藏显示
const HideShow = computed(() => {
return !props.item.component_props.disabled
})
const showPicker = ref(false);
const currentDate = ref([]);
const readonly = props.item.component_props.readonly;
const onTap = () => {
if (readonly) return false; // 如果为只读,不能设置
showPicker.value = true
}
const onConfirm = ({ selectedValues, selectedOptions }) => {
props.item.value = selectedValues[0] + "-" + selectedValues[1];
props.item.value = selectedValues.join("-");
showPicker.value = false;
};
const columns_type = ref([]);
const date_format = props.item.component_props.data_dateformat; // YYYY-MM=年月,YYYY-MM-DD=年月日
onMounted(() => {
currentDate.value = props.item.value.split("-");
switch (date_format) {
case "YYYY-MM":
columns_type.value = ['year', 'month']
break;
case "YYYY-MM-DD":
columns_type.value = ['year', 'month', 'day']
break;
}
});
const required = props.item.component_props.required;
const data_minvalue = props.item.component_props.data_minvalue;
const data_maxvalue = props.item.component_props.data_maxvalue;
const validator = (val) => {
if (required && !val) {
return false;
} else if (val && data_minvalue && val < data_minvalue) {
return false;
} else if (val && data_maxvalue && val > data_maxvalue) {
return false;
} else {
return true;
}
};
// 错误提示文案
const validatorMessage = (val, rule) => {
if (required && !val) {
return "必填项不能为空";
} else if (val && data_minvalue && val < data_minvalue) {
return "最小可选:" + data_minvalue;
} else if (val && data_maxvalue && val > data_maxvalue) {
return "最大可选:" + data_maxvalue;
}
};
const rules = [{ validator, message: validatorMessage }];
</script>
<style lang="less" scoped>
.date-picker-field {
margin: 1rem;
.label {
padding: 1rem 1rem 0 1rem;
// padding: 1rem 1rem 0 1rem;
font-size: 0.9rem;
font-weight: bold;
......@@ -67,4 +112,11 @@ onMounted(() => {
}
}
}
:deep(.van-cell--clickable) {
border: 1px solid #eaeaea;
border-radius: 0.25rem;
padding: 0.25rem 0.5rem;
margin-top: 0.5rem;
}
</style>
......
<!--
* @Date: 2022-09-08 15:02:45
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-11-21 14:47:52
* @LastEditTime: 2022-12-29 11:44:54
* @FilePath: /data-table/src/components/DateTimePickerField/index.vue
* @Description: 日期时间选择器
-->
<template>
<div class="datetime-picker">
<div v-if="HideShow" class="datetime-picker">
<div class="label">
{{ item.component_props.label }}
<span v-if="item.component_props.required">&nbsp;*</span>
......@@ -17,22 +17,21 @@
readonly
:name="item.key"
:required="item.component_props.required"
:placeholder="item.component_props.placeholder"
:rules="item.rules"
@click="showPicker = true"
disabled="item.component_props.readonly"
:placeholder="item.component_props.placeholder ? item.component_props.placeholder : '请选择日期时间'"
:rules="rules"
@click="onTap"
:border="false"
/>
<van-popup v-model:show="showPicker" position="bottom">
<van-picker-group
:title="item.component_props.title"
title="请选择日期时间"
:tabs="['选择日期', '选择时间']"
@confirm="onConfirm"
@cancel="onCancel"
>
<van-date-picker
v-model="currentDate"
:min-date="item.component_props.min_date"
/>
<van-time-picker v-model="currentTime" />
<van-date-picker v-model="currentDate" :columns-type="columns_date_type" />
<van-time-picker v-model="currentTime" :columns-type="columns_time_type" />
</van-picker-group>
</van-popup>
</div>
......@@ -45,8 +44,17 @@ import dayjs from "dayjs";
const props = defineProps({
item: Object,
});
// 隐藏显示
const HideShow = computed(() => {
return !props.item.component_props.disabled
})
const showPicker = ref(false);
const readonly = props.item.component_props.readonly;
const onTap = () => {
if (readonly) return false; // 如果为只读,不能设置
showPicker.value = true
}
const currentDate = ref([]);
const currentTime = ref([]);
......@@ -58,18 +66,72 @@ const onCancel = () => {
showPicker.value = false;
};
const columns_date_type = ref([]);
const columns_time_type = ref([]);
const date_format = props.item.component_props.data_dateformat;
onMounted(() => {
// 获取值定位显示
const datetime = props.item.value.split(" ");
currentDate.value = datetime[0]?.split("-");
currentTime.value = datetime[1]?.split(":");
// YYYY=年,YYYY-MM=年月,YYYY-MM-DD=年月日,YYYY-MM-DD HH=年月日时,YYYY-MM-DD HH:mm=年月日时分,YYYY-MM-DD HH:mm:ss=年月日时分秒
switch (date_format) {
case "YYYY":
columns_date_type.value = ['year']
break;
case "YYYY-MM":
columns_date_type.value = ['year', 'month']
break;
case "YYYY-MM-DD":
columns_date_type.value = ['year', 'month', 'day']
break;
case "YYYY-MM-DD HH":
columns_date_type.value = ['year', 'month', 'day']
columns_time_type.value = ['hour']
break;
case "YYYY-MM-DD HH:mm":
columns_date_type.value = ['year', 'month', 'day']
columns_time_type.value = ['hour', 'minute']
break;
case "YYYY-MM-DD HH:mm:ss":
columns_date_type.value = ['year', 'month', 'day']
columns_time_type.value = ['hour', 'minute', 'second']
break;
}
});
const required = props.item.component_props.required;
const data_minvalue = props.item.component_props.data_minvalue;
const data_maxvalue = props.item.component_props.data_maxvalue;
const validator = (val) => {
if (required && !val) {
return false;
} else if (val && data_minvalue && val < data_minvalue) {
return false;
} else if (val && data_maxvalue && val > data_maxvalue) {
return false;
} else {
return true;
}
};
// 错误提示文案
const validatorMessage = (val, rule) => {
if (required && !val) {
return "必填项不能为空";
} else if (val && data_minvalue && val < data_minvalue) {
return "最小可选:" + data_minvalue;
} else if (val && data_maxvalue && val > data_maxvalue) {
return "最大可选:" + data_maxvalue;
}
};
const rules = [{ validator, message: validatorMessage }];
</script>
<style lang="less" scoped>
.datetime-picker {
margin: 1rem;
.label {
padding: 1rem 1rem 0 1rem;
// padding: 1rem 1rem 0 1rem;
font-size: 0.9rem;
font-weight: bold;
......@@ -78,4 +140,11 @@ onMounted(() => {
}
}
}
:deep(.van-cell--clickable) {
border: 1px solid #eaeaea;
border-radius: 0.25rem;
padding: 0.25rem 0.5rem;
margin-top: 0.5rem;
}
</style>
......
<!--
* @Date: 2022-08-29 14:31:20
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-11-21 16:08:20
* @LastEditTime: 2022-12-22 13:17:34
* @FilePath: /data-table/src/components/EmailField/index.vue
* @Description: 邮箱输入框
-->
<template>
<div class="text-field-page">
<div v-if="HideShow" class="text-field-page">
<div class="label">
{{ item.component_props.label
}}<span v-if="item.component_props.required">&nbsp;*</span>
......@@ -18,6 +18,7 @@
:placeholder="item.component_props.placeholder"
:rules="rules"
:required="item.component_props.required"
disabled="item.component_props.readonly"
clearable
/>
</div>
......@@ -27,16 +28,29 @@
const props = defineProps({
item: Object,
});
// 隐藏显示
const HideShow = computed(() => {
return !props.item.component_props.disabled
})
const required = props.item.component_props.required;
const validator = (val) => {
if (!props.item.component_props.required) {
// 非必填
return true;
if (required && !val) {
return false;
} else if (val && !/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/.test(val)) {
return false;
} else {
return /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/.test(val);
return true;
}
};
// 错误提示文案
const validatorMessage = (val, rule) => {
if (required && !val) {
return "必填项不能为空";
} else if (val && !/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/.test(val)) { // 小于最小值
return "请输入正确邮箱";
}
};
const rules = [{ validator, message: "请输入正确邮箱" }];
const rules = [{ validator, message: validatorMessage }];
</script>
<style lang="less" scoped>
......
<!--
* @Date: 2022-08-31 16:16:49
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-11-21 14:54:30
* @FilePath: /data-table/src/components/ImageUploaderField/index.vue
* @LastEditTime: 2022-12-30 16:53:12
* @FilePath: /data-table/src/components/FileUploaderField/index.vue
* @Description: 文件上传控件
-->
<template>
<div class="file-uploader-field">
<div v-if="HideShow" class="file-uploader-field">
<div class="label">
{{ item.component_props.label
}}<span v-if="item.component_props.required">&nbsp;*</span>
</div>
<div
v-if="item.component_props.note"
style="font-size: 0.9rem; margin-left: 1rem; color: gray; padding-bottom: 0.5rem"
style="font-size: 0.9rem; margin-left: 1rem; color: gray; padding-bottom: 0.5rem; padding-top: 0.25rem;"
>
{{ item.component_props.note }}
</div>
<div>
<p
v-for="file in fileList"
v-for="(file, index) in fileList"
:key="index"
style="padding-left: 1rem; margin-bottom: 0.5rem"
>
<span style="font-size: 1rem">{{ file.filename }}</span
>&nbsp;&nbsp;
<span style="color: #e32525; font-size: 0.85rem" @click="beforeDelete(file)"
>移除</span
>
<p style="font-size: 1rem; word-break: break-all; margin-right: 0.75rem;">
<span>{{ index + 1 }}.&nbsp;{{ file.filename }}&nbsp;&nbsp;{{ (file.size / 1024 / 1024).toFixed(2) }}MB</span>
&nbsp;&nbsp;
<span style="color: #e32525; font-size: 0.85rem" @click="beforeDelete(file)">移除</span>
</p>
</p>
</div>
<div style="padding: 1rem">
......@@ -38,6 +38,7 @@
:before-read="beforeRead"
:after-read="afterRead"
:before-delete="beforeDelete"
:multiple="item.component_props.max_size > 1"
>
<van-button icon="plus" type="primary">上传文件</van-button>
</van-uploader>
......@@ -80,6 +81,10 @@ const $route = useRoute();
const props = defineProps({
item: Object,
});
// 隐藏显示
const HideShow = computed(() => {
return !props.item.component_props.disabled
})
const emit = defineEmits(["active"]);
const show_empty = ref(false);
......@@ -104,16 +109,21 @@ const beforeRead = (file) => {
// (item) => `video/${item}`
// );
let flag = true;
if (file.length + 1 > props.item.component_props.max_count) {
// 数量限制
flag = false;
showToast(`最大上传数量为${props.item.component_props.max_count}个`);
}
if (fileList.value.length + 1 > props.item.component_props.max_count) {
// 数量限制
flag = false;
showToast(`最大上传数量为${props.item.component_props.max_count}个`);
}
if (file.size > props.item.component_props.max_size) {
if ((file.size / 1024 / 1024).toFixed(2) > props.item.component_props.max_size) {
// 体积限制
flag = false;
showToast(
`最大文件体积为${(props.item.component_props.max_size / 1024 / 1024).toFixed(2)}MB`
`最大文件体积为${props.item.component_props.max_size}MB`
);
}
// if (_.isArray(file)) {
......@@ -151,6 +161,7 @@ const afterRead = async (files) => {
// meta_id: imgUrl.meta_id,
filename: files.file.name,
url: imgUrl.src,
size: files.file.size
// isImage: true,
});
loading.value = false;
......@@ -249,6 +260,7 @@ var muliUpload = async (files) => {
// meta_id: res.meta_id,
filename: item.file.name,
url: res.src,
size: files.file.size
// isImage: true,
});
loading.value = false;
......@@ -258,8 +270,9 @@ var muliUpload = async (files) => {
// 生成数据库真实文件地址
const uploadQiniu = async (file, token, name, md5) => {
let suffix = /\.[^\.]+$/.exec(name); // 获取后缀
// let affix = uuidv4();
let fileName = `uploadForm/${formCode}/${md5}.${name.split(".")[1]}`;
let fileName = `uploadForm/${formCode}/${md5}${suffix}`;
let formData = new FormData();
formData.append("file", file); // 通过append向form对象添加数据
formData.append("token", token);
......
<!--
* @Date: 2022-09-14 14:44:30
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-11-21 16:00:36
* @LastEditTime: 2022-12-29 11:32:10
* @FilePath: /data-table/src/components/IdentityField/index.vue
* @Description: 身份证输入控件
-->
<template>
<div class="identity-page">
<div v-if="HideShow" class="identity-page">
<div class="label">
{{ item.component_props.label
}}<span v-if="item.component_props.required">&nbsp;*</span>
</div>
<!-- <div v-if="item.component_props.readonly" style="padding: 0.5rem 1rem;">{{ item.value }}</div> -->
<van-field
v-model="item.value"
:id="item.name"
......@@ -18,6 +19,7 @@
:placeholder="item.component_props.placeholder"
:rules="rules"
:required="item.component_props.required"
:disabled="item.component_props.readonly"
readonly
@touchstart.stop="openKeyboard($event)"
:border="false"
......@@ -43,7 +45,10 @@ import { storeToRefs, mainStore } from "@/utils/generatePackage";
const props = defineProps({
item: Object,
});
// 隐藏显示
const HideShow = computed(() => {
return !props.item.component_props.disabled
})
const show = ref(false);
let content = "";
......@@ -63,8 +68,9 @@ watch(
}
}
);
const readonly = props.item.component_props.readonly;
const openKeyboard = (e) => {
if (readonly) return false; // 如果为只读,不能设置
// // 键盘上移动
// const target_to_view_height = window.innerHeight - e.target.getBoundingClientRect().y; // 元素到适口高度
// const target_top = document.body.scrollHeight - $(e.target).offset().top; // 元素到正文高度
......@@ -106,19 +112,21 @@ const blurKeyboard = () => {
// 校验函数返回 true 表示校验通过,false 表示不通过
// 身份证号码为15位或者18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X
const required = props.item.component_props.required;
const validator = (val) => {
if (!props.item.component_props.required) {
// 非必填
return true;
if (required && !val) {
return false;
} else if (val && !/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(val)) {
return false;
} else {
return /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(val);
return true;
}
};
// 错误提示文案
const validatorMessage = (val, rule) => {
if (!val) {
if (required && !val) {
return "身份证号码不能为空";
} else if (!/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(val)) {
} else if (val && !/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(val)) {
return "请输入正确身份证号码";
}
};
......
<!--
* @Date: 2022-08-31 16:16:49
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-11-21 14:54:30
* @LastEditTime: 2022-12-30 10:31:02
* @FilePath: /data-table/src/components/ImageUploaderField/index.vue
* @Description: 图片上传控件
-->
<template>
<div class="image-uploader-field">
<div v-if="HideShow" class="image-uploader-field">
<div class="label">
{{ item.component_props.label
}}<span v-if="item.component_props.required">&nbsp;*</span>
</div>
<div
v-if="item.component_props.note"
style="font-size: 0.9rem; margin-left: 1rem; color: gray; padding-bottom: 0.5rem; padding-top: 0.25rem;"
>
{{ item.component_props.note }}
</div>
<div style="padding: 1rem">
<van-uploader
:name="item.name"
......@@ -19,7 +25,7 @@
:after-read="afterRead"
:before-delete="beforeDelete"
v-model="fileList"
:multiple="item.component_props.multiple"
:multiple="item.component_props.max_size > 1"
/>
</div>
<div class="type-text">上传类型:&nbsp;{{ type_text }}</div>
......@@ -60,6 +66,10 @@ const $route = useRoute();
const props = defineProps({
item: Object,
});
// 隐藏显示
const HideShow = computed(() => {
return !props.item.component_props.disabled
})
const emit = defineEmits(["active"]);
const show_empty = ref(false);
......@@ -111,13 +121,11 @@ const beforeRead = (file) => {
flag = false;
showToast(`最大上传数量为${props.item.component_props.max_count}张`);
}
if (file.size > props.item.component_props.max_size) {
if ((file.size / 1024 / 1024).toFixed(2) > props.item.component_props.max_size) {
// 体积限制
flag = false;
showToast(
`最大文件体积为${(props.item.component_props.max_size / 1024 / 1024).toFixed(
2
)}MB`
`最大文件体积为${props.item.component_props.max_size}MB`
);
}
}
......@@ -259,10 +267,20 @@ var muliUpload = async (files) => {
}
};
const getType = (file, name) => {
var index1 = name.lastIndexOf(".");
var index2 = file.length;
var type = file.substring(index1, index2).toUpperCase();
return type;
}
// 生成数据库真实图片地址
const uploadQiniu = async (file, token, name, md5) => {
let suffix = /\.[^\.]+$/.exec(name); // 获取后缀
// let affix = uuidv4();
let fileName = `uploadForm/${formCode}/${md5}.${name.split(".")[1]}`;
let fileName = `uploadForm/${formCode}/${md5}${suffix}`;
let formData = new FormData();
formData.append("file", file); // 通过append向form对象添加数据
formData.append("token", token);
......
<!--
* @Date: 2022-08-30 11:34:19
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-11-24 14:33:47
* @FilePath: /data-table/src/components/RuleField/index.vue
* @LastEditTime: 2022-12-30 17:17:26
* @FilePath: /data-table/src/components/MultiRuleField/index.vue
* @Description: 多选规则确认控件
-->
<template>
<div class="multi-rule-field-page">
<div class="label">
{{ item.component_props.label
}}<span v-if="item.component_props.required">&nbsp;*</span>(最少选{{
item.component_props.count
}}项)
<div v-if="HideShow" class="multi-rule-field-page">
<div class="label"> {{ item.component_props.label }}<span v-if="item.component_props.required" class="required">&nbsp;*</span>
<span v-if="item.component_props.min_count" style="color: #999; font-size: 0.85rem;">(最少选{{ item.component_props.min_count }}项)</span>
</div>
<van-field :name="item.key" :rules="rules" :border="false" style="padding-bottom: 0">
<template #input>
<van-checkbox-group v-model="item.value" style="width: 100%">
<template v-for="(rule, idx) in item.component_props.rules" :key="idx">
<template v-for="(rule, idx) in item.component_props.options" :key="idx">
<div class="multi-rule-field-box">
<van-checkbox
:name="idx"
:name="rule.value"
shape="square"
:checked-color="themeVars.radioColor"
>{{ rule.rule_desc }}</van-checkbox
>{{ rule.title }}</van-checkbox
>
<div class="rule-box" @click="showRule(rule)">
{{ rule.rule_link }}&nbsp;>>
<div class="van-multi-ellipsis--l3 rule-desc-text">{{ rule.desc_text }}</div>
<div v-if="rule.desc_type === 'text'" class="rule-box" @click="showRule(rule)">
{{ rule.desc_btn_name }}&nbsp;>>
</div>
<div v-if="rule.desc_type === 'url'" class="rule-box" @click="showUrl(rule)">
{{ rule.desc_btn_name }}&nbsp;<van-icon name="link-o" />
</div>
</div>
</template>
......@@ -56,7 +57,10 @@ import $ from "jquery";
const props = defineProps({
item: Object,
});
// 隐藏显示
const HideShow = computed(() => {
return !props.item.component_props.disabled
})
// TAG: 自定义主题颜色
const themeVars = {
radioColor: styleColor.baseColor,
......@@ -68,28 +72,39 @@ const show = ref(false);
const checked = ref([]);
const showRule = (rule) => {
show.value = true;
rule_content.value = rule.rule_content;
rule.desc_text = rule.desc_text.replace(/\\n/g, "<br>")
rule_content.value = rule.desc_text;
};
const closeRule = () => {
show.value = false;
rule_content.value = "";
};
const showUrl = (rule) => {
location.href = rule.desc_url
}
const rule_content = ref("");
const required = props.item.component_props.required;
const min_count = props.item.component_props.min_count;
const max_count = props.item.component_props.max_count;
const validator = (val) => {
if (!props.item.component_props.required) {
// 非必填
return true;
if (required && !val.length) {
return false;
} else if (min_count && props.item.value.length < min_count) {
return false;
} else if (max_count && props.item.value.length > max_count) {
return false;
} else {
return props.item.value.length >= props.item.component_props.count ? true : false;
return true;
}
};
// 错误提示文案
const validatorMessage = (val, rule) => {
if (!val) {
if (required && !val.length) {
return "选择项不能为空";
} else if (props.item.value.length < props.item.component_props.count) {
return `最少选择${props.item.component_props.count}项`;
} else if (min_count && props.item.value.length < min_count) {
return `最少选择${min_count}项`;
} else if (max_count && props.item.value.length > max_count) {
return `最多选择${max_count}项`;
}
};
const rules = [{ validator, message: validatorMessage }];
......@@ -101,10 +116,15 @@ const rules = [{ validator, message: validatorMessage }];
padding: 1rem 1rem 0 1rem;
font-size: 0.9rem;
font-weight: bold;
span {
span.required {
color: red;
}
}
.rule-desc-text {
margin: 0.35rem 0.5rem 0.5rem 1.75rem;
font-size: 0.8rem;
color: #808080;
}
.rule-box {
font-size: 0.85rem;
margin-left: 1.8rem;
......
<!--
* @Date: 2022-09-14 14:44:30
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-11-18 13:50:50
* @LastEditTime: 2022-12-29 11:29:46
* @FilePath: /data-table/src/components/NumberField/index.vue
* @Description: 数字输入框
-->
<template>
<div class="number-page">
<div v-if="HideShow" class="number-page">
<div class="label">
{{ item.component_props.label }}
<span v-if="item.component_props.required">&nbsp;*</span>
......@@ -16,8 +16,9 @@
:id="item.name"
:name="item.name"
:placeholder="item.component_props.placeholder"
:rules="item.rules"
:rules="rules"
:required="item.component_props.required"
disabled="item.component_props.readonly"
readonly
@touchstart.stop="showKeyboard($event)"
:border="false"
......@@ -52,6 +53,10 @@ import { storeToRefs, mainStore } from "@/utils/generatePackage";
const props = defineProps({
item: Object,
});
// 隐藏显示
const HideShow = computed(() => {
return !props.item.component_props.disabled
})
let content = "";
const store = mainStore();
......@@ -65,19 +70,20 @@ watch(
if (v !== props.item.name) {
// 还原border颜色
$(`#${props.item.name}`).parent().css("border-color", "#eaeaea");
if (props.item.component_props.type === "decimal") {
// 显示小数键盘
showDecimal.value = false;
} else {
if (props.item.component_props.max_fraction_count === 0) {
// 显示整数键盘
showInteger.value = false;
} else {
// 显示小数键盘
showDecimal.value = false;
}
document.getElementById("app").style.paddingBottom = "0";
}
}
);
const readonly = props.item.component_props.readonly;
const showKeyboard = (e) => {
if (readonly) return false; // 如果为只读,不能设置
// 键盘上移动
const target_to_view_height =
window.innerHeight - e.target.getBoundingClientRect().bottom; // 元素到适口高度
......@@ -99,24 +105,24 @@ const showKeyboard = (e) => {
// TAG: 自定义主题颜色
content.css("border-color", "#c2915f");
setTimeout(() => {
if (props.item.component_props.type === "decimal") {
// 显示小数键盘
showDecimal.value = true;
} else {
if (props.item.component_props.max_fraction_count === 0) {
// 显示整数键盘
showInteger.value = true;
} else {
// 显示小数键盘
showDecimal.value = true;
}
}, 300);
// 记录点击field名
store.changeFieldName(props.item.name);
};
const blurKeyboard = () => {
if (props.item.component_props.type === "decimal") {
// 显示小数键盘
showDecimal.value = false;
} else {
if (props.item.component_props.max_fraction_count === 0) {
// 显示整数键盘
showInteger.value = false;
} else {
// 显示小数键盘
showDecimal.value = false;
}
document.getElementById("app").style.paddingBottom = "0";
// 还原border颜色
......@@ -126,25 +132,38 @@ const blurKeyboard = () => {
const showDecimal = ref(false);
const showInteger = ref(false);
// // 校验函数返回 true 表示校验通过,false 表示不通过
// // 身份证号码为15位或者18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X
// const validator = (val) => {
// if (!props.item.component_props.required) {
// // 非必填
// return true;
// } else {
// return /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(val);
// }
// };
// // 错误提示文案
// const validatorMessage = (val, rule) => {
// if (!val) {
// return "身份证号码不能为空";
// } else if (!/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(val)) {
// return "请输入正确身份证号码";
// }
// };
// const rules = [{ validator, message: validatorMessage }];
// 校验函数返回 true 表示校验通过,false 表示不通过
const required = props.item.component_props.required;
const min = props.item.component_props.min;
const max = props.item.component_props.max;
const max_count = props.item.component_props.max_fraction_count; // 保留小数个数 null=不限,0=没有小数,大于0=最多只能输入的小数个数
const reg = new RegExp("^([0-9]+)(\\.(\\d){" + max_count +"," + max_count +"})$", "g");
const validator = (val) => {
if (required && !val) { // 必填
return false;
} else if (val && min && (val < min)) { // 小于最小值
return false;
} else if (val && max && (val > max)) { // 大于最大值
return false;
} else if (val && max_count && !reg.test(val)) { // 不符合保留小数个数
return false;
} else {
return true;
}
};
// 错误提示文案
const validatorMessage = (val, rule) => {
if (required && !val) {
return "必填项不能为空";
} else if (val && min && (val < min)) { // 小于最小值
return "最小值为" + min;
} else if (val && max && (val > max)) { // 大于最大值
return "最大值为" + max;
} else if (val && max_count && !reg.test(val)) { // 不符合保留小数个数
return "保留小数点后" + max_count + "位";
}
};
const rules = [{ validator, message: validatorMessage }];
const onInput = (value) => {};
const onDelete = () => {};
......
<!--
* @Date: 2022-09-02 10:46:03
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-12-09 13:34:21
* @LastEditTime: 2022-12-29 11:39:40
* @FilePath: /data-table/src/components/PhoneField/index.vue
* @Description: 手机输入框
-->
<template>
<div class="phone-field-page">
<div v-if="HideShow" class="phone-field-page">
<div class="label">
{{ item.component_props.label }}
<span v-if="item.component_props.required">&nbsp;*</span>
......@@ -20,6 +20,7 @@
:placeholder="item.component_props.placeholder ? item.component_props.placeholder : '请输入手机号码'"
:rules="rules"
:required="item.component_props.required"
disabled="item.component_props.readonly"
:readonly="readonly"
@touchstart.stop="openKeyboard($event)"
:border="false"
......@@ -57,7 +58,10 @@ import { storeToRefs, mainStore } from "@/utils/generatePackage";
const props = defineProps({
item: Object,
});
// 隐藏显示
const HideShow = computed(() => {
return !props.item.component_props.disabled
})
// web端判断
const readonly = computed(() => wxInfo().isMobile);
// 打开短信验证模式
......@@ -65,18 +69,19 @@ const is_sms = ref(false);
// 校验函数返回 true 表示校验通过,false 表示不通过
const validator = (val) => {
if (!props.item.component_props.required) {
// 非必填
return true;
if (props.item.component_props.required && !val) {
return false;
} else if (val && !/1\d{10}/.test(val)) {
return false;
} else {
return /1\d{10}/.test(val);
return true;
}
};
// 错误提示文案
const validatorMessage = (val, rule) => {
if (!val) {
if (props.item.component_props.required && !val) {
return "手机号码不能为空";
} else if (!/1\d{10}/.test(val)) {
} else if (val && !/1\d{10}/.test(val)) {
return "请输入正确手机号码";
}
};
......@@ -103,6 +108,7 @@ watch(
);
const openKeyboard = (e) => {
if (props.item.component_props.readonly) return false; // 如果为只读,不能设置
// 键盘上移动
const target_to_view_height =
window.innerHeight - e.target.getBoundingClientRect().bottom; // 元素到适口高度
......
<!--
* @Date: 2022-08-30 13:46:51
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-08-30 14:23:32
* @LastEditTime: 2022-12-21 11:25:55
* @FilePath: /data-table/src/components/PickerField/index.vue
* @Description: 单列选择器组件
-->
<template>
<div class="picker-field-page">
<div v-if="HideShow" class="picker-field-page">
<div class="label">
{{ item.component_props.label
}}<span v-if="item.component_props.required">&nbsp;*</span>
......@@ -20,6 +20,7 @@
:placeholder="item.component_props.placeholder"
:rules="item.rules"
@click="showPicker = true"
:border="false"
/>
<van-popup v-model:show="showPicker" position="bottom">
<van-picker
......@@ -37,12 +38,12 @@ const props = defineProps({
});
onMounted(() => {
props.item.component_props.options = props.item.component_props.options.map((opt) => {
return {
text: opt,
value: opt,
};
});
// props.item.component_props.options = props.item.component_props.options.map((opt) => {
// return {
// text: opt,
// value: opt,
// };
// });
});
const selectedValues = ref("");
......@@ -52,12 +53,17 @@ const onConfirm = ({ selectedOptions }) => {
props.item.value = selectedOptions[0]?.value;
showPicker.value = false;
};
// 隐藏显示
const HideShow = computed(() => {
return !props.item.component_props.disabled
})
</script>
<style lang="less" scoped>
.picker-field-page {
margin: 1rem;
.label {
padding: 1rem 1rem 0 1rem;
// padding: 1rem 1rem 0 0;
font-size: 0.9rem;
font-weight: bold;
......@@ -66,4 +72,11 @@ const onConfirm = ({ selectedOptions }) => {
}
}
}
:deep(.van-cell--clickable) {
border: 1px solid #eaeaea;
border-radius: 0.25rem;
padding: 0.25rem 0.5rem;
margin-top: 0.5rem;
}
</style>
......
<!--
* @Date: 2022-08-30 11:34:19
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-12-09 15:54:52
* @LastEditTime: 2022-12-29 11:14:20
* @FilePath: /data-table/src/components/RadioField/index.vue
* @Description: 单项选择控件
-->
<template>
<div class="radio-field-page">
<div v-if="HideShow" class="radio-field-page">
<div class="label">
{{ item.component_props.label
}}<span v-if="item.component_props.required">&nbsp;*</span>
</div>
<div
v-if="item.component_props.note"
style="font-size: 0.9rem; margin-left: 1rem; color: gray; margin-top: 0.25rem;"
>
<div v-if="item.component_props.note" class="note">
{{ item.component_props.note }}
</div>
<van-field :name="item.key" :rules="item.rules">
......@@ -26,12 +23,12 @@
>
<van-radio
v-for="x in item.component_props.options"
:key="index"
:name="x"
:key="x.value"
:name="x.value"
icon-size="1rem"
:checked-color="themeVars.radioColor"
style="margin-bottom: 0.25rem"
>{{ x }}</van-radio
>{{ x.title }}</van-radio
>
</van-radio-group>
</template>
......@@ -50,6 +47,10 @@ const props = defineProps({
const themeVars = {
radioColor: styleColor.baseColor,
};
// 隐藏显示
const HideShow = computed(() => {
return !props.item.component_props.disabled
})
</script>
<style lang="less" scoped>
......@@ -62,6 +63,12 @@ const themeVars = {
color: red;
}
}
.note {
font-size: 0.9rem;
margin-left: 1rem;
color: gray;
padding-bottom: 0.5rem
}
}
:deep(.van-radio) {
......
<!--
* @Date: 2022-09-08 15:47:54
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-11-21 15:16:10
* @LastEditTime: 2022-12-28 18:51:11
* @FilePath: /data-table/src/components/RatePickerField/index.vue
* @Description: 评分选择控件
-->
<template>
<div class="rate-field">
<div v-if="HideShow" class="rate-field">
<div class="label">
{{ item.component_props.label
}}<span v-if="item.component_props.required">&nbsp;*</span>
</div>
<van-rate
v-model="rate_value"
:count="item.component_props.count"
:count="item.component_props.data_length"
:readonly="item.component_props.readonly"
:color="styleColor.baseColor"
@change="onChange"
style="padding: 1rem"
......@@ -35,9 +36,13 @@ import { styleColor } from "@/constant.js";
const props = defineProps({
item: Object,
});
// 隐藏显示
const HideShow = computed(() => {
return !props.item.component_props.disabled
})
const emit = defineEmits(["active"]);
const show_empty = ref(false);
const rate_value = ref(0);
const rate_value = ref(props.item.component_props.default);
const onChange = (value) => {
props.item.value = { key: props.item.key, value, type: "rate" };
......
<!--
* @Date: 2022-08-29 14:31:20
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-12-09 15:33:56
* @LastEditTime: 2022-12-29 11:13:58
* @FilePath: /data-table/src/components/TextField/index.vue
* @Description: 单行文本输入框
-->
<template>
<div class="text-field-page">
<div v-if="HideShow" class="text-field-page">
<div class="label">
{{ item.component_props.label
}}<span v-if="item.component_props.required">&nbsp;*</span>
......@@ -29,6 +29,10 @@
const props = defineProps({
item: Object,
});
// 隐藏显示
const HideShow = computed(() => {
return !props.item.component_props.disabled
})
</script>
<style lang="less" scoped>
......
<!--
* @Date: 2022-08-29 14:31:20
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-12-09 15:37:59
* @LastEditTime: 2022-12-29 11:25:54
* @FilePath: /data-table/src/components/TextareaField/index.vue
* @Description: 多行文本输入框
-->
<template>
<div class="textarea-field-page">
<div v-if="HideShow" class="textarea-field-page">
<div class="label">
{{ item.component_props.label
}}<span v-if="item.component_props.required">&nbsp;*</span>
......@@ -18,10 +18,11 @@
:placeholder="item.component_props.placeholder ? item.component_props.placeholder : '请输入'"
:rules="item.rules"
:required="item.component_props.required"
:readonly="item.component_props.readonly"
:rows="item.component_props.rows"
autosize
:maxlength="item.component_props.maxlength"
show-word-limit
:maxlength="item.component_props.maxlength ? item.component_props.maxlength : null"
:show-word-limit="item.component_props.maxlength"
/>
</div>
</template>
......@@ -30,6 +31,10 @@
const props = defineProps({
item: Object,
});
// 隐藏显示
const HideShow = computed(() => {
return !props.item.component_props.disabled
})
</script>
<style lang="less" scoped>
......
<!--
* @Date: 2022-08-31 11:45:30
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-11-21 15:21:56
* @LastEditTime: 2022-12-29 11:46:19
* @FilePath: /data-table/src/components/TimePickerField/index.vue
* @Description: 时间选择组件
-->
<template>
<div class="time-picker-field">
<div v-if="HideShow" class="time-picker-field">
<div class="label">
{{ item.component_props.label
}}<span v-if="item.component_props.required">&nbsp;*</span>
......@@ -17,15 +17,17 @@
readonly
:name="item.key"
:required="item.component_props.required"
:placeholder="item.component_props.placeholder"
:rules="item.rules"
@click="showPicker = true"
disabled="item.component_props.readonly"
:placeholder="item.component_props.placeholder ? item.component_props.placeholder : '请选择时间'"
:rules="rules"
@click="onTap"
:border="false"
/>
<van-popup v-model:show="showPicker" position="bottom">
<van-time-picker
v-model="currentTime"
:title="item.component_props.title"
:columns-type="item.component_props.columns_type"
title="请选择时间"
:columns-type="columns_type"
@confirm="onConfirm"
@cancel="showPicker = false"
/>
......@@ -39,24 +41,70 @@ import dayjs from "dayjs";
const props = defineProps({
item: Object,
});
// 隐藏显示
const HideShow = computed(() => {
return !props.item.component_props.disabled
})
const showPicker = ref(false);
const currentTime = ref([]);
const readonly = props.item.component_props.readonly;
const onTap = () => {
if (readonly) return false; // 如果为只读,不能设置
showPicker.value = true
}
const onConfirm = ({ selectedValues, selectedOptions }) => {
props.item.value = selectedValues[0] + ":" + selectedValues[1];
props.item.value = selectedValues.join(":");
showPicker.value = false;
};
const columns_type = ref([]);
const date_format = props.item.component_props.data_dateformat; // HH:mm=时分,HH:mm:ss=时分秒
onMounted(() => {
currentTime.value = props.item.value.split(":");
switch (date_format) {
case "HH:mm":
columns_type.value = ['hour', 'minute']
break;
case "HH:mm:ss":
columns_type.value = ['hour', 'minute', 'second']
break;
}
});
const required = props.item.component_props.required;
const data_minvalue = props.item.component_props.data_minvalue;
const data_maxvalue = props.item.component_props.data_maxvalue;
const validator = (val) => {
if (required && !val) {
return false;
} else if (val && data_minvalue && val < data_minvalue) {
return false;
} else if (val && data_maxvalue && val > data_maxvalue) {
return false;
} else {
return true;
}
};
// 错误提示文案
const validatorMessage = (val, rule) => {
if (required && !val) {
return "必填项不能为空";
} else if (val && data_minvalue && val < data_minvalue) {
return "最小可选:" + data_minvalue;
} else if (val && data_maxvalue && val > data_maxvalue) {
return "最大可选:" + data_maxvalue;
}
};
const rules = [{ validator, message: validatorMessage }];
</script>
<style lang="less" scoped>
.time-picker-field {
margin: 1rem;
.label {
padding: 1rem 1rem 0 1rem;
// padding: 1rem 1rem 0 1rem;
font-size: 0.9rem;
font-weight: bold;
......@@ -65,4 +113,11 @@ onMounted(() => {
}
}
}
:deep(.van-cell--clickable) {
border: 1px solid #eaeaea;
border-radius: 0.25rem;
padding: 0.25rem 0.5rem;
margin-top: 0.5rem;
}
</style>
......
......@@ -30,11 +30,11 @@ import ButtonField from '@/components/ButtonField/index.vue'
/**
* 生成自定义组件类型
* @param {*} data
* @type text 单行文本 TextField
* @type input 单行文本 TextField
* @type textarea 多行文本 TextareaField
* @type radio 单项选择 RadioField
* @type checkbox 多项选择 CheckboxField
* @type picker 单列选择器 PickerField
* @type select 单列选择器 PickerField
* @type area_picker 地址选择器 AreaPickerField
* @type date_picker 日期选择器 DatePickerField
* @type time_picker 时间选择器 TimePickerField
......@@ -60,102 +60,102 @@ export function createComponentType(data) {
if (item.component_props.required) {
item.rules = [{ required: true, message: item.placeholder ? item.placeholder : '必填项不能为空' }]
}
if (item.component_props.name === 'text') {
if (item.component_props.tag === 'input') {
item.type = 'text';
item.name = item.key;
item.component = TextField;
}
if (item.component_props.name === 'textarea') {
if (item.component_props.tag === 'textarea') {
item.type = 'textarea';
item.name = item.key;
// item.rows = 10;
item.autosize = true;
item.component = TextareaField;
}
if (item.component_props.name === 'number') {
if (item.component_props.tag === 'number') {
item.name = item.key;
item.component = NumberField;
}
if (item.component_props.name === 'radio') {
if (item.component_props.tag === 'radio') {
item.component = RadioField;
}
if (item.component_props.name === 'checkbox') {
if (item.component_props.tag === 'checkbox') {
item.component = CheckboxField;
}
if (item.component_props.name === 'picker') {
if (item.component_props.tag === 'select') {
item.component = PickerField;
}
if (item.component_props.name === 'area_picker') {
if (item.component_props.tag === 'address') {
item.component = AreaPickerField;
}
if (item.component_props.name === 'date_picker') {
if (item.component_props.tag === 'date') {
item.component = DatePickerField;
}
if (item.component_props.name === 'time_picker') {
if (item.component_props.tag === 'time') {
item.component = TimePickerField;
}
if (item.component_props.name === 'datetime_picker') {
if (item.component_props.tag === 'datetime') {
item.component = DateTimePickerField;
}
if (item.component_props.name === 'image_uploader') {
if (item.component_props.tag === 'image_uploader') {
item.component = ImageUploaderField;
}
if (item.component_props.name === 'file_uploader') {
if (item.component_props.tag === 'file_uploader') {
item.component = FileUploaderField;
}
if (item.component_props.name === 'phone') {
if (item.component_props.tag === 'phone') {
item.name = item.key;
item.component = PhoneField;
}
if (item.component_props.name === 'email') {
if (item.component_props.tag === 'email') {
item.name = item.key;
item.component = EmailField;
}
if (item.component_props.name === 'sign') {
if (item.component_props.tag === 'sign') {
item.name = item.key;
item.component = SignField;
}
if (item.component_props.name === 'rate_picker') {
if (item.component_props.tag === 'rate') {
item.name = item.key;
item.component = RatePickerField;
}
if (item.component_props.name === 'calendar') {
if (item.component_props.tag === 'calendar') {
item.name = item.key;
item.component = CalendarField;
}
if (item.component_props.name === 'id_code') {
if (item.component_props.tag === 'id_card') {
item.name = item.key;
item.component = IdentityField;
}
if (item.component_props.name === 'desc') {
if (item.component_props.tag === 'desc') {
item.name = item.key;
item.component = DesField;
}
if (item.component_props.name === 'divider') {
if (item.component_props.tag === 'divider') {
item.name = item.key;
item.component = DividerField;
}
if (item.component_props.name === 'video') {
if (item.component_props.tag === 'video') {
item.name = item.key;
item.component = VideoField;
}
if (item.component_props.name === 'marquee') {
if (item.component_props.tag === 'marquee') {
item.name = item.key;
item.component = MarqueeField;
}
if (item.component_props.name === 'contact') {
if (item.component_props.tag === 'contact') {
item.name = item.key;
item.component = ContactField;
}
if (item.component_props.name === 'rule') {
if (item.component_props.tag === 'rule') {
item.name = item.key;
item.component = RuleField;
}
if (item.component_props.name === 'button') {
if (item.component_props.tag === 'button') {
item.name = item.key;
item.component = ButtonField;
}
if (item.component_props.name === 'multi_rule') {
if (item.component_props.tag === 'multi_rule') {
item.name = item.key;
item.value = [];
item.component = MultiRuleField;
......
<!--
* @Date: 2022-07-18 10:22:22
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-12-09 15:25:00
* @LastEditTime: 2022-12-28 10:46:29
* @FilePath: /data-table/src/views/index.vue
* @Description: 首页
-->
......@@ -13,7 +13,7 @@
scrollable
mode="closeable"
/>
<div class="table-box" :style="{ margin: is_pc ? '1rem 0' : '1rem'}">
<div class="table-box" :style="{ margin: is_pc ? '1rem 0' : '1rem', overflow: 'auto'}">
<van-image
v-if="PHeader.type === '单张图'"
width="100%"
......@@ -31,7 +31,7 @@
<div v-if="PHeader.label" class="table-title">{{ PHeader.label }}</div>
<div v-if="PHeader.description" class="table-desc" v-html="PHeader.description" />
<van-config-provider :theme-vars="themeVars">
<van-form @submit="onSubmit">
<van-form @submit="onSubmit" scroll-to-error="true">
<van-cell-group :border="false">
<component
v-for="(item, index) in formData"
......@@ -122,40 +122,11 @@ const model = $route.query.model;
const formatData = (data) => {
const arr = [];
data.forEach((field) => {
const { interaction_type, data_type, field_id, field_name, ...component_props } = field;
// 生成组件属性
const component_props = {
name: field.component_code,
};
if (field.component_type === "h5edit") {
// 编辑组件
field.property_list.forEach((prop) => {
const key = prop["property_code"];
const obj = {
[key]:
prop["setting_value"].length > 1
? prop["setting_value"]
: prop["setting_value"][0],
};
Object.assign(component_props, obj);
});
} else {
// 展示组件
field.property_list.forEach((prop) => {
const key = prop["property_code"];
const obj = {
[key]:
key !== 'label'
? prop["setting_value"]
: prop["setting_value"][0],
};
Object.assign(component_props, obj);
});
}
// 绑定组件名称标识
const temp = {
key: field.field_name,
key: field_name,
value: component_props.default ? component_props.default : "",
component: field.component_code,
component_props,
};
arr.push(temp);
......@@ -173,19 +144,19 @@ const rate_picker = ref([]);
// 动态绑定ref数据
const setRefMap = (el, item) => {
if (el) {
if (item.component_props.name === "area_picker") {
if (item.component_props.tag === "area_picker") {
area_picker.value.push(el);
}
if (item.component_props.name === "image_uploader") {
if (item.component_props.tag === "image_uploader") {
image_uploader.value.push(el);
}
if (item.component_props.name === "file_uploader") {
if (item.component_props.tag === "file_uploader") {
file_uploader.value.push(el);
}
if (item.component_props.name === "sign") {
if (item.component_props.tag === "sign") {
sign.value.push(el);
}
if (item.component_props.name === "rate_picker") {
if (item.component_props.tag === "rate_picker") {
rate_picker.value.push(el);
}
}
......@@ -201,27 +172,20 @@ onMounted(async () => {
.querySelector("body")
.setAttribute("style", `background-color: ${styleColor.backgroundColor}`);
const { data } = await queryFormAPI({ form_code: $route.query.code });
const form_data = data[0];
const form_data = data;
// 表单网页标题
useTitle(form_data.name);
// 重构数据结构
let page_header = {};
let page_commit = {};
let page_form = [];
form_data.field_list.forEach((element) => {
if (element.component_code === "page_header") {
if (element.tag === "page_header") {
// 页眉组件
const list = element.property_list;
list.forEach((ele) => {
page_header[ele["property_code"]] =
ele.setting_value.length > 1 ? ele.setting_value : ele.setting_value[0];
});
} else if (element.component_code === "page_commit") {
page_header = element;
} else if (element.tag === "page_commit") {
// 提交按钮
const list = element.property_list;
list.forEach((ele) => {
page_commit[ele["property_code"]] =
ele.setting_value.length > 1 ? ele.setting_value : ele.setting_value[0];
});
page_commit = element;
} else {
page_form.push(element);
}
......@@ -248,21 +212,22 @@ onMounted(async () => {
};
}
formData.value = formatData(page_form);
// mockData.value = [
// {
// key: "",
// value: "",
// component: "",
// component_props: {
// name: "multi_rule",
// label: "同意活动规则之后才可提交",
// required: "1",
// count: "2",
// },
// },
// ];
mockData.value = [
{
key: "111",
value: "",
component: "",
component_props: {
name: "datetime",
tag: "datetime",
label: "时间日期",
data_dateformat: "YYYY-MM-DD HH:mm:ss",
required: true,
},
},
];
// 生成自定义组件
// createComponentType(mockData.value);
createComponentType(mockData.value);
createComponentType(formData.value);
// 过期时间显示
notice_text.value = `表单报名将在 ${formSetting.value.sjsj_end_time} 后结束`;
......@@ -290,16 +255,7 @@ const checkUserSubscribe = async () => {
const { data } = await getFormSettingAPI({ form_code: code });
const form_setting = {};
if (data.length) {
data[0].property_list.forEach((prop) => {
const key = prop["property_code"];
const obj = {
[key]:
prop["setting_value"].length > 1
? prop["setting_value"]
: prop["setting_value"][0],
};
Object.assign(form_setting, obj, data[0]['extend']);
});
Object.assign(form_setting, data[0]['property_list'], data[0]['extend']);
}
// 判断是否需要关注公众号, 弹出二维码识别
if (form_setting.wxzq_must_follow && form_setting.x_field_weixin_subscribe) {
......