hookehuyr

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

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