Toggle navigation
Toggle navigation
This project
Loading...
Sign in
Hooke
/
data-table
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Graphs
Network
Create a new issue
Commits
Issue Boards
Authored by
hookehuyr
2022-12-30 21:12:09 +0800
Browse Files
Options
Browse Files
Download
Plain Diff
Commit
d6b98a181b78706572651be92f40d342722ce460
d6b98a18
2 parents
10055536
9868f3a8
Merge branch 'feature/组件数据结构调整' into develop
Show whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
566 additions
and
295 deletions
src/App.vue
src/api/form.js
src/components/AreaPickerField/index.vue
src/components/CheckboxField/index.vue
src/components/DatePickerField/index.vue
src/components/DateTimePickerField/index.vue
src/components/EmailField/index.vue
src/components/FileUploaderField/index.vue
src/components/IdentityField/index.vue
src/components/ImageUploaderField/index.vue
src/components/MultiRuleField/index.vue
src/components/NumberField/index.vue
src/components/PhoneField/index.vue
src/components/PickerField/index.vue
src/components/RadioField/index.vue
src/components/RatePickerField/index.vue
src/components/TextField/index.vue
src/components/TextareaField/index.vue
src/components/TimePickerField/index.vue
src/hooks/useComponentType.js
src/views/index.vue
src/App.vue
View file @
d6b98a1
...
...
@@ -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);
...
...
src/api/form.js
View file @
d6b98a1
/*
* @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'
,
...
...
src/components/AreaPickerField/index.vue
View file @
d6b98a1
<!--
* @Date: 2022-08-30 14:32:11
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-12-
08 14:57:1
6
* @LastEditTime: 2022-12-
29 15:42:4
6
* @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"> *</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);
...
...
src/components/CheckboxField/index.vue
View file @
d6b98a1
<!--
* @Date: 2022-08-30 11:34:19
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-1
1-21 14:42:00
* @LastEditTime: 2022-1
2-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"> *</span>
...
...
@@ -14,6 +14,9 @@
(最多可选数: {{ 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) {
...
...
src/components/DatePickerField/index.vue
View file @
d6b98a1
<!--
* @Date: 2022-08-31 11:45:30
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-1
1-21 14:43:16
* @LastEditTime: 2022-1
2-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"> *</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>
...
...
src/components/DateTimePickerField/index.vue
View file @
d6b98a1
<!--
* @Date: 2022-09-08 15:02:45
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-1
1-21 14:47:52
* @LastEditTime: 2022-1
2-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"> *</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>
...
...
src/components/EmailField/index.vue
View file @
d6b98a1
<!--
* @Date: 2022-08-29 14:31:20
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-1
1-21 16:08:20
* @LastEditTime: 2022-1
2-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"> *</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>
...
...
src/components/FileUploaderField/index.vue
View file @
d6b98a1
<!--
* @Date: 2022-08-31 16:16:49
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-1
1-21 14:54:30
* @FilePath: /data-table/src/components/
Imag
eUploaderField/index.vue
* @LastEditTime: 2022-1
2-30 16:53:12
* @FilePath: /data-table/src/components/
Fil
eUploaderField/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"> *</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
>
<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 }}. {{ file.filename }} {{ (file.size / 1024 / 1024).toFixed(2) }}MB</span>
<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);
...
...
src/components/IdentityField/index.vue
View file @
d6b98a1
<!--
* @Date: 2022-09-14 14:44:30
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-1
1-21 16:00:36
* @LastEditTime: 2022-1
2-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"> *</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 "请输入正确身份证号码";
}
};
...
...
src/components/ImageUploaderField/index.vue
View file @
d6b98a1
<!--
* @Date: 2022-08-31 16:16:49
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-1
1-21 14:54:30
* @LastEditTime: 2022-1
2-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"> *</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.m
ultiple
"
:multiple="item.component_props.m
ax_size > 1
"
/>
</div>
<div class="type-text">上传类型: {{ 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);
...
...
src/components/MultiRuleField/index.vue
View file @
d6b98a1
<!--
* @Date: 2022-08-30 11:34:19
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-1
1-24 14:33:47
* @FilePath: /data-table/src/components/RuleField/index.vue
* @LastEditTime: 2022-1
2-30 17:17:26
* @FilePath: /data-table/src/components/
Multi
RuleField/index.vue
* @Description: 多选规则确认控件
-->
<template>
<div class="multi-rule-field-page">
<div class="label">
{{ item.component_props.label
}}<span v-if="item.component_props.required"> *</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"> *</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.
rule
s" :key="idx">
<template v-for="(rule, idx) in item.component_props.
option
s" :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 }} >>
<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 }} >>
</div>
<div v-if="rule.desc_type === 'url'" class="rule-box" @click="showUrl(rule)">
{{ rule.desc_btn_name }} <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 : fals
e;
return
tru
e;
}
};
// 错误提示文案
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;
...
...
src/components/NumberField/index.vue
View file @
d6b98a1
<!--
* @Date: 2022-09-14 14:44:30
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-1
1-18 13:50:50
* @LastEditTime: 2022-1
2-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"> *</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 = () => {};
...
...
src/components/PhoneField/index.vue
View file @
d6b98a1
<!--
* @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"> *</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; // 元素到适口高度
...
...
src/components/PickerField/index.vue
View file @
d6b98a1
<!--
* @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"> *</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>
...
...
src/components/RadioField/index.vue
View file @
d6b98a1
<!--
* @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"> *</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) {
...
...
src/components/RatePickerField/index.vue
View file @
d6b98a1
<!--
* @Date: 2022-09-08 15:47:54
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-1
1-21 15:16:10
* @LastEditTime: 2022-1
2-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"> *</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" };
...
...
src/components/TextField/index.vue
View file @
d6b98a1
<!--
* @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"> *</span>
...
...
@@ -29,6 +29,10 @@
const props = defineProps({
item: Object,
});
// 隐藏显示
const HideShow = computed(() => {
return !props.item.component_props.disabled
})
</script>
<style lang="less" scoped>
...
...
src/components/TextareaField/index.vue
View file @
d6b98a1
<!--
* @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"> *</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>
...
...
src/components/TimePickerField/index.vue
View file @
d6b98a1
<!--
* @Date: 2022-08-31 11:45:30
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-1
1-21 15:21:56
* @LastEditTime: 2022-1
2-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"> *</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>
...
...
src/hooks/useComponentType.js
View file @
d6b98a1
...
...
@@ -30,11 +30,11 @@ import ButtonField from '@/components/ButtonField/index.vue'
/**
* 生成自定义组件类型
* @param {*} data
* @type
tex
t 单行文本 TextField
* @type
inpu
t 单行文本 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
===
'tex
t'
)
{
if
(
item
.
component_props
.
tag
===
'inpu
t'
)
{
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
;
...
...
src/views/index.vue
View file @
d6b98a1
<!--
* @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) {
...
...
Please
register
or
login
to post a comment