hookehuyr

✨ feat(多选规则控件): 样式和功能调整

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: 2023-02-10 14:41:52 4 + * @LastEditTime: 2023-04-04 15:00:16
5 - * @FilePath: /data-table/src/components/MultiRuleField/index.vue 5 + * @FilePath: /custom_form/src/components/MultiRuleField/index.vue
6 * @Description: 多选规则确认控件 6 * @Description: 多选规则确认控件
7 --> 7 -->
8 <template> 8 <template>
9 <div v-if="HideShow" class="multi-rule-field-page"> 9 <div v-if="HideShow" class="multi-rule-field-page">
10 <div class="label"> 10 <div class="label">
11 - <span v-if="item.component_props.required" class="required">&nbsp;*</span> 11 + <text v-if="item.component_props.required" class="required">&nbsp;*</text>
12 {{ item.component_props.label }} 12 {{ item.component_props.label }}
13 - <span v-if="item.component_props.min_count" style="color: #999; font-size: 0.85rem;">(最少选{{ item.component_props.min_count }}项)</span> 13 + <text v-if="item.component_props.min_count" style="color: #999; font-size: 13px;">(最少选{{ item.component_props.min_count }}项)</text>
14 </div> 14 </div>
15 - <van-field :name="item.key" :rules="rules" :border="false" style="padding-bottom: 0"> 15 + <nut-checkbox-group v-model="checkbox_value" style="width: 100%">
16 - <template #input> 16 + <template v-for="(rule, idx) in item.component_props.options" :key="idx">
17 - <van-checkbox-group v-model="item.value" style="width: 100%"> 17 + <div class="multi-rule-field-box">
18 - <template v-for="(rule, idx) in item.component_props.options" :key="idx"> 18 + <nut-checkbox @click="onClick(rule)" :label="rule.title">{{ rule.title }}</nut-checkbox>
19 - <div class="multi-rule-field-box"> 19 + <div class="multi-ellipsis--l3 rule-desc-text">{{ rule.desc_text }}</div>
20 - <van-checkbox 20 + <div v-if="rule.desc_type === 'text'" class="rule-box" @click="showRule(rule)">
21 - :name="rule.value" 21 + {{ rule.desc_btn_name }}&nbsp;>>
22 - shape="square" 22 + </div>
23 - :checked-color="themeVars.radioColor" 23 + <div v-if="rule.desc_type === 'url' && h5" class="rule-box" @click="showUrl(rule)">
24 - >{{ rule.title }}</van-checkbox 24 + {{ rule.desc_btn_name }}&nbsp;<Link size="12" />
25 - > 25 + </div>
26 - <div class="van-multi-ellipsis--l3 rule-desc-text">{{ rule.desc_text }}</div> 26 + </div>
27 - <div v-if="rule.desc_type === 'text'" class="rule-box" @click="showRule(rule)">
28 - {{ rule.desc_btn_name }}&nbsp;>>
29 - </div>
30 - <div v-if="rule.desc_type === 'url'" class="rule-box" @click="showUrl(rule)">
31 - {{ rule.desc_btn_name }}&nbsp;<van-icon name="link-o" />
32 - </div>
33 - </div>
34 - </template>
35 - </van-checkbox-group>
36 </template> 27 </template>
37 - </van-field> 28 + </nut-checkbox-group>
38 - </div> 29 + <div
39 - 30 + v-if="show_error"
40 - <van-overlay :show="show" :lock-scroll="false"> 31 + style="padding: 5px 20px; color: red; font-size: 12px;"
41 - <div class="rule-wrapper" @click.stop> 32 + >
42 - <div class="rule-block"> 33 + {{ error_msg }}
43 - <div style="height: 70vh; min-height: 70vh; overflow: scroll; white-space: pre-wrap; line-height: 1.5;" v-html="rule_content"></div> 34 + </div>
44 - <div class="close-btn"> 35 + <nut-overlay v-model:visible="show" :lock-scroll="true">
45 - <van-button type="primary" block @click="closeRule" 36 + <div class="rule-wrapper">
46 - >关&nbsp;&nbsp;闭</van-button 37 + <div class="rule-block">
47 - > 38 + <div style="height: 70vh; min-height: 70vh; overflow: scroll; white-space: pre-wrap; line-height: 1.5;font-size: 15px;" v-html="rule_content"></div>
39 + <div class="close-btn">
40 + <nut-button type="primary" block @click="closeRule">关&nbsp;&nbsp;闭</nut-button>
41 + </div>
42 + <div></div>
48 </div> 43 </div>
49 - <div></div>
50 </div> 44 </div>
51 - </div> 45 + </nut-overlay>
52 - </van-overlay> 46 + </div>
53 </template> 47 </template>
54 48
55 <script setup> 49 <script setup>
50 +import { ref, computed, watch, onMounted, reactive } from "vue";
56 import { styleColor } from "@/constant.js"; 51 import { styleColor } from "@/constant.js";
57 -import $ from "jquery"; 52 +import { $ } from '@tarojs/extend';
53 +import { Link } from '@nutui/icons-vue-taro';
58 54
59 const props = defineProps({ 55 const props = defineProps({
60 item: Object, 56 item: Object,
...@@ -70,8 +66,28 @@ const themeVars = { ...@@ -70,8 +66,28 @@ const themeVars = {
70 onMounted(() => { 66 onMounted(() => {
71 $(".rule-box").css("color", themeVars.radioColor); 67 $(".rule-box").css("color", themeVars.radioColor);
72 }); 68 });
69 +
70 +const emit = defineEmits(["active"]);
73 const show = ref(false); 71 const show = ref(false);
74 -const checked = ref([]); 72 +const checkbox_value = ref([]);
73 +const options = props.item.component_props.options;
74 +
75 +const onClick = (item) => {
76 + item.checked = !item.checked;
77 + // 校验输入项数据
78 + validMultiRule();
79 + // 发送自定义数据结构
80 + props.item.value = { key: props.item.key, value: checkbox_value.value, type: "multi_rule" };
81 + console.warn(props.item.value);
82 + emit("active", props.item.value);
83 +}
84 +
85 +onMounted(() => {
86 + // 发送自定义数据结构
87 + props.item.value = { key: props.item.key, value: checkbox_value.value, type: "multi_rule" };
88 + emit("active", props.item.value);
89 +});
90 +
75 const showRule = (rule) => { 91 const showRule = (rule) => {
76 show.value = true; 92 show.value = true;
77 rule.desc_text = rule.desc_text.replace(/\\n/g, "<br>") 93 rule.desc_text = rule.desc_text.replace(/\\n/g, "<br>")
...@@ -81,55 +97,66 @@ const closeRule = () => { ...@@ -81,55 +97,66 @@ const closeRule = () => {
81 show.value = false; 97 show.value = false;
82 rule_content.value = ""; 98 rule_content.value = "";
83 }; 99 };
84 -const showUrl = (rule) => { 100 +const h5 = computed(() => {
85 - location.href = rule.desc_url 101 + if (process.env.TARO_ENV === 'h5') {
102 + return true
103 + } else {
104 + return false;
105 + }
106 +})
107 +const showUrl = (rule) => { // 跳转设置链接
108 + if (process.env.TARO_ENV === 'h5') {
109 + location.href = rule.desc_url
110 + }
111 + // 小程序需要配置制定域名内网页,功能无法实现。
86 } 112 }
87 const rule_content = ref(""); 113 const rule_content = ref("");
88 const required = props.item.component_props.required; 114 const required = props.item.component_props.required;
89 const min_count = props.item.component_props.min_count; 115 const min_count = props.item.component_props.min_count;
90 const max_count = props.item.component_props.max_count; 116 const max_count = props.item.component_props.max_count;
91 -const validator = (val) => { 117 +
92 - if (required && !val.length) { 118 +const show_error = ref(false);
93 - return false; 119 +const error_msg = ref('');
94 - } else if (min_count && props.item.value.length < min_count) { 120 +// 校验模块
95 - return false; 121 +const validMultiRule= () => {
96 - } else if (max_count && props.item.value.length > max_count) { 122 + // 必填项
97 - return false; 123 + if (required && !checkbox_value.value.length) {
124 + show_error.value = true;
125 + error_msg.value = '选择项不能为空';
126 + } else if (min_count && checkbox_value.value.length < min_count) {
127 + show_error.value = true;
128 + error_msg.value = `最少选择 ${min_count} 项`;
129 + } else if (max_count && checkbox_value.value.length > max_count) {
130 + show_error.value = true;
131 + error_msg.value = `最多选择 ${max_count} 项`;
98 } else { 132 } else {
99 - return true; 133 + show_error.value = false;
100 - } 134 + error_msg.value = '';
101 -};
102 -// 错误提示文案
103 -const validatorMessage = (val, rule) => {
104 - if (required && !val.length) {
105 - return "选择项不能为空";
106 - } else if (min_count && props.item.value.length < min_count) {
107 - return `最少选择${min_count}项`;
108 - } else if (max_count && props.item.value.length > max_count) {
109 - return `最多选择${max_count}项`;
110 } 135 }
136 + return !show_error.value;
111 }; 137 };
112 -const rules = [{ validator, message: validatorMessage }]; 138 +
139 +defineExpose({ validMultiRule });
113 </script> 140 </script>
114 141
115 -<style lang="less" scoped> 142 +<style lang="less">
116 .multi-rule-field-page { 143 .multi-rule-field-page {
117 .label { 144 .label {
118 - padding: 1rem 1rem 0 1rem; 145 + padding: 30px 30px 0 30px;
119 - font-size: 0.9rem; 146 + font-size: 26px;
120 font-weight: bold; 147 font-weight: bold;
121 - span.required { 148 + text.required {
122 color: red; 149 color: red;
123 } 150 }
124 } 151 }
125 .rule-desc-text { 152 .rule-desc-text {
126 - margin: 0.35rem 0.5rem 0.5rem 1.75rem; 153 + margin: 0.35rem 0.5rem 0.5rem 60px;
127 - font-size: 0.8rem; 154 + font-size: 28px;
128 color: #808080; 155 color: #808080;
129 } 156 }
130 .rule-box { 157 .rule-box {
131 - font-size: 0.85rem; 158 + font-size: 28px;
132 - margin-left: 1.8rem; 159 + margin-left: 60px;
133 padding-bottom: 0.5rem; 160 padding-bottom: 0.5rem;
134 width: fit-content; 161 width: fit-content;
135 } 162 }
...@@ -158,8 +185,11 @@ const rules = [{ validator, message: validatorMessage }]; ...@@ -158,8 +185,11 @@ const rules = [{ validator, message: validatorMessage }];
158 .multi-rule-field-box { 185 .multi-rule-field-box {
159 border: 1px solid #eaeaea; 186 border: 1px solid #eaeaea;
160 border-radius: 0.25rem; 187 border-radius: 0.25rem;
161 - padding: 1rem 0.5rem 0 0.5rem; 188 + padding: 25px;
162 - // width: 100vw; 189 + margin: 25px;
163 - margin-bottom: 0.5rem; 190 +}
191 +
192 +.nut-checkbox__label {
193 + margin-left: 20px;
164 } 194 }
165 </style> 195 </style>
......
...@@ -23,7 +23,7 @@ import CheckboxField from '@/components/CheckboxField/index.vue' ...@@ -23,7 +23,7 @@ import CheckboxField from '@/components/CheckboxField/index.vue'
23 // import MarqueeField from '@/components/MarqueeField/index.vue' 23 // import MarqueeField from '@/components/MarqueeField/index.vue'
24 // import ContactField from '@/components/ContactField/index.vue' 24 // import ContactField from '@/components/ContactField/index.vue'
25 // import RuleField from '@/components/RuleField/index.vue' 25 // import RuleField from '@/components/RuleField/index.vue'
26 -// import MultiRuleField from '@/components/MultiRuleField/index.vue' 26 +import MultiRuleField from '@/components/MultiRuleField/index.vue'
27 // import ButtonField from '@/components/ButtonField/index.vue' 27 // import ButtonField from '@/components/ButtonField/index.vue'
28 // import NoteField from '@/components/NoteField/index.vue' 28 // import NoteField from '@/components/NoteField/index.vue'
29 // import NameField from '@/components/NameField/index.vue' 29 // import NameField from '@/components/NameField/index.vue'
...@@ -163,11 +163,11 @@ export function createComponentType(data) { ...@@ -163,11 +163,11 @@ export function createComponentType(data) {
163 // item.name = item.key 163 // item.name = item.key
164 // item.component = ButtonField 164 // item.component = ButtonField
165 // } 165 // }
166 - // if (item.component_props.tag === 'multi_rule') { 166 + if (item.component_props.tag === 'multi_rule') {
167 - // item.name = item.key 167 + item.name = item.key
168 - // item.value = [] 168 + item.value = []
169 - // item.component = MultiRuleField 169 + item.component = MultiRuleField
170 - // } 170 + }
171 // if (item.component_props.tag === 'note') { 171 // if (item.component_props.tag === 'note') {
172 // item.name = item.key 172 // item.name = item.key
173 // item.component = NoteField 173 // item.component = NoteField
......
1 <!-- 1 <!--
2 * @Date: 2023-03-24 09:19:27 2 * @Date: 2023-03-24 09:19:27
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2023-04-04 10:21:43 4 + * @LastEditTime: 2023-04-04 14:38:13
5 * @FilePath: /custom_form/src/pages/table/index.vue 5 * @FilePath: /custom_form/src/pages/table/index.vue
6 * @Description: 文件描述 6 * @Description: 文件描述
7 --> 7 -->
...@@ -130,6 +130,7 @@ const input = ref([]); ...@@ -130,6 +130,7 @@ const input = ref([]);
130 const textarea = ref([]); 130 const textarea = ref([]);
131 const radio = ref([]); 131 const radio = ref([]);
132 const checkbox = ref([]); 132 const checkbox = ref([]);
133 +const multi_rule = ref([]);
133 const area_picker = ref([]); 134 const area_picker = ref([]);
134 const image_uploader = ref([]); 135 const image_uploader = ref([]);
135 const file_uploader = ref([]); 136 const file_uploader = ref([]);
...@@ -150,6 +151,9 @@ const setRefMap = (el, item) => { ...@@ -150,6 +151,9 @@ const setRefMap = (el, item) => {
150 if (item.component_props.tag === "checkbox") { 151 if (item.component_props.tag === "checkbox") {
151 checkbox.value.push(el); 152 checkbox.value.push(el);
152 } 153 }
154 + if (item.component_props.tag === "multi_rule") {
155 + multi_rule.value.push(el);
156 + }
153 if (item.component_props.tag === "area_picker") { 157 if (item.component_props.tag === "area_picker") {
154 area_picker.value.push(el); 158 area_picker.value.push(el);
155 } 159 }
...@@ -393,6 +397,10 @@ const onActive = (item) => { ...@@ -393,6 +397,10 @@ const onActive = (item) => {
393 }); 397 });
394 postData.value = Object.assign(postData.value, { [item.key]: checkbox_value }); 398 postData.value = Object.assign(postData.value, { [item.key]: checkbox_value });
395 } 399 }
400 + if (item.type === "multi_rule") {
401 + const checkbox_value = deepClone(item.value)
402 + postData.value = Object.assign(postData.value, { [item.key]: checkbox_value });
403 + }
396 if (item.key === "area_picker") { 404 if (item.key === "area_picker") {
397 postData.value[item.filed_name] = item.value; 405 postData.value[item.filed_name] = item.value;
398 } 406 }
...@@ -469,6 +477,18 @@ const validOther = () => { ...@@ -469,6 +477,18 @@ const validOther = () => {
469 } 477 }
470 }); 478 });
471 } 479 }
480 + if (multi_rule.value) {
481 + // 多选规则控件
482 + multi_rule.value.forEach((item, index) => {
483 + if (!multi_rule.value[index].validMultiRule()) {
484 + valid = {
485 + status: multi_rule.value[index].validMultiRule(),
486 + key: "multi_rule",
487 + };
488 + return false;
489 + }
490 + });
491 + }
472 if (area_picker.value) { 492 if (area_picker.value) {
473 // 省市区地址 493 // 省市区地址
474 area_picker.value.forEach((item, index) => { 494 area_picker.value.forEach((item, index) => {
......