Toggle navigation
Toggle navigation
This project
Loading...
Sign in
Hooke
/
custom_form
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Graphs
Network
Create a new issue
Commits
Issue Boards
Authored by
hookehuyr
2023-04-03 17:16:39 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
ec1a24528a5168e27918b568a2a4f9b443aac46d
ec1a2452
1 parent
f0b69cc0
✨ feat(单选框): 调整组件样式和功能
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
115 additions
and
64 deletions
components.d.ts
src/components/RadioField/index.vue
src/hooks/useComponentType.js
src/pages/table/index.vue
components.d.ts
View file @
ec1a245
...
...
@@ -29,10 +29,14 @@ declare module '@vue/runtime-core' {
NutButton
:
typeof
import
(
'@nutui/nutui-taro'
)[
'Button'
]
NutConfigProvider
:
typeof
import
(
'@nutui/nutui-taro'
)[
'ConfigProvider'
]
NutDialog
:
typeof
import
(
'@nutui/nutui-taro'
)[
'Dialog'
]
NutField
:
typeof
import
(
'@nutui/nutui-taro'
)[
'Field'
]
NutForm
:
typeof
import
(
'@nutui/nutui-taro'
)[
'Form'
]
NutFormItem
:
typeof
import
(
'@nutui/nutui-taro'
)[
'FormItem'
]
NutInput
:
typeof
import
(
'@nutui/nutui-taro'
)[
'Input'
]
NutNoticebar
:
typeof
import
(
'@nutui/nutui-taro'
)[
'Noticebar'
]
NutOverlay
:
typeof
import
(
'@nutui/nutui-taro'
)[
'Overlay'
]
NutRadio
:
typeof
import
(
'@nutui/nutui-taro'
)[
'Radio'
]
NutRadioGroup
:
typeof
import
(
'@nutui/nutui-taro'
)[
'RadioGroup'
]
NutSwiper
:
typeof
import
(
'@nutui/nutui-taro'
)[
'Swiper'
]
NutSwiperItem
:
typeof
import
(
'@nutui/nutui-taro'
)[
'SwiperItem'
]
NutTextarea
:
typeof
import
(
'@nutui/nutui-taro'
)[
'Textarea'
]
...
...
src/components/RadioField/index.vue
View file @
ec1a245
<!--
* @Date: 2022-08-30 11:34:19
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2023-0
2-22 11:02:05
* @FilePath: /
data-table
/src/components/RadioField/index.vue
* @LastEditTime: 2023-0
4-03 17:13:20
* @FilePath: /
custom_form
/src/components/RadioField/index.vue
* @Description: 单项选择控件
-->
<template>
<div v-if="HideShow" class="radio-field-page">
<div class="label">
<
span v-if="item.component_props.required"> *</span
>
<
text v-if="item.component_props.required"> *</text
>
{{ item.component_props.label }}
</div>
<div v-if="item.component_props.note" class="note" v-html="item.component_props.note" />
<van-field :rules="item.rules">
<template #input>
<van-radio-group @change="onChange(item)" v-model="radio_value" :direction="item.component_props.direction"
<nut-radio-group @change="onChange(item)" v-model="radio_value" :direction="item.component_props.direction"
style="width: 100%">
<div v-for="x in item.component_props.options" :key="x.value" class="radio-wrapper">
<van-radio :name="x.value" icon-size="1rem" :checked-color="themeVars.radioColor"
style="margin-bottom: 0.25rem">{{ x.title }}</van-radio>
<nut-radio :label="x.value" icon-size="16" style="margin-bottom: 0.25rem">{{ x.title }}</nut-radio>
<div v-if="x.desc_text" class="van-multi-ellipsis--l3 rule-desc-text">{{ x.desc_text }}</div>
<div v-if="x.desc_type === 'text'" class="rule-box" @click="showRule(x)">
{{ x.desc_btn_name }} >>
</div>
<div v-if="x.desc_type === 'url'
" class="rule-box" @click="showUrl(x)">
{{ x.desc_btn_name }} <van-icon name="link-o
" />
<div v-if="x.desc_type === 'url' && h5
" class="rule-box" @click="showUrl(x)">
{{ x.desc_btn_name }} <Link size="12
" />
</div>
<van-field v-if="radio_value === x.value && x.is_input" @blur="onBlur(x)" v-model="x.affix" label=" " label-width="5px"
:placeholder="x.input_placeholder" :rules="x.input_required ? rules : ''" :required="x.input_required"
class="affix-input" />
<nut-input v-if="radio_value === x.value && x.is_input" @blur="onBlur(x)" v-model="x.affix" label=" " label-width="5px"
:placeholder="x.input_placeholder" :required="x.input_required" :border="false" class="affix-input" />
<div
v-if="x.show_error"
style="padding: 5px 20px; color: red; font-size: 12px;"
>
{{ x.error_msg }}
</div>
</van-radio-group>
</template>
</van-field>
</div>
<van-overlay :show="show" :lock-scroll="fals
e">
<div class="rule-wrapper" @click.stop
>
</nut-radio-group>
<nut-overlay v-model:visible="show" :lock-scroll="tru
e">
<div class="rule-wrapper"
>
<div class="rule-block">
<div style="height: 70vh; min-height: 70vh; overflow: scroll; white-space: pre-wrap; line-height: 1.5;" v-html="rule_content"></div>
<div class="close-btn">
<van
-button type="primary" block @click="closeRule"
>关 闭</van
-button
<nut
-button type="primary" block @click="closeRule"
>关 闭</nut
-button
>
</div>
<div></div>
</div>
</div>
</van-overlay>
</nut-overlay>
</div>
</template>
<script setup>
import { ref, computed, watch, onMounted, reactive } from "vue";
import { styleColor } from "@/constant.js";
import $ from "jquery";
import { $ } from '@tarojs/extend';
import { Link } from '@nutui/icons-vue-taro';
const props = defineProps({
item: Object,
...
...
@@ -67,23 +68,6 @@ const HideShow = computed(() => {
return !props.item.component_props.disabled
})
// TODO: 等待数据结构更新,看看怎么判断必填
// 校验函数返回 true 表示校验通过,false 表示不通过
const validator = (val) => {
if (!val) {
return false;
} else {
return true;
}
};
// 错误提示文案
const validatorMessage = (val, rule) => {
if (!val) {
return "补充信息不能为空";
}
};
const rules = [{ validator, message: validatorMessage }];
const emit = defineEmits(["active"]);
const radio_value = ref(props.item.component_props.default);
const affix_value = ref('');
...
...
@@ -101,16 +85,24 @@ const onBlur = (item) => {
props.item.value = { key: props.item.key, value: radio_value.value, affix: affix_value.value, type: "radio" };
emit("active", props.item.value);
}
const options = props.item.component_props.options;
const clearAffix = () => {
const options = props.item.component_props.options;
// 为选中项目的补充清空
options.forEach(element => {
if (element.value !== radio_value.value) {
element.affix = ''
}
element.show_error = false;
element.error_msg = '';
});
}
onMounted(() => {
// 新增错误提示标识
options.forEach(element => {
element.show_error = false;
element.error_msg = '';
});
//
radio_value.value = props.item.component_props.default ? props.item.component_props.default : '';
// 发送自定义数据结构
props.item.value = { key: props.item.key, value: radio_value.value, affix: affix_value.value, type: "radio" };
...
...
@@ -130,26 +122,56 @@ const closeRule = () => {
show.value = false;
rule_content.value = "";
};
const showUrl = (rule) => {
const h5 = computed(() => {
if (process.env.TARO_ENV === 'h5') {
return true
} else {
return false;
}
})
const showUrl = (rule) => { // 跳转设置链接
if (process.env.TARO_ENV === 'h5') {
location.href = rule.desc_url
}
// 小程序需要配置制定域名内网页,功能无法实现。
}
const rule_content = ref("");
const show_error = ref(false);
// 校验模块
const validRadio = () => {
// 必填项
props.item.component_props.options.some(item => {
if (radio_value.value === item.value && item.is_input && item.input_required && !item.affix) {
show_error.value = true;
item.show_error = true;
item.error_msg = '补充信息不能为空';
return true;
} else {
show_error.value = false;
item.show_error = false;
item.error_msg = '';
}
});
return !show_error.value;
};
defineExpose({ validRadio });
</script>
<style lang="less"
scoped
>
<style lang="less">
.radio-field-page {
.label {
padding:
1rem 1rem 0 1rem
;
font-size:
0.9rem
;
padding:
30px 30px 0 30px
;
font-size:
26px
;
font-weight: bold;
span {
text {
color: red;
}
}
.note {
font-size:
0.9rem
;
font-size:
30px
;
margin-left: 1rem;
color: gray;
padding-bottom: 0.5rem;
...
...
@@ -159,8 +181,9 @@ const rule_content = ref("");
.radio-wrapper {
border: 1px solid #eaeaea;
border-radius: 0.25rem;
padding: 0.25rem 0.5rem;
margin-bottom: 0.25rem;
padding: 25px;
margin: 25px;
margin-top: 0;
}
.affix-input {
border: 1px solid #eaeaea;
...
...
@@ -170,13 +193,13 @@ const rule_content = ref("");
margin-bottom: 0.25rem;
}
.rule-desc-text {
margin: 0.35rem 0.5rem 0.5rem
1.75rem
;
font-size:
0.8rem
;
margin: 0.35rem 0.5rem 0.5rem
60px
;
font-size:
28px
;
color: #808080;
}
.rule-box {
font-size:
0.85rem
;
margin-left:
1.8rem
;
font-size:
28px
;
margin-left:
60px
;
padding-bottom: 0.5rem;
width: fit-content;
}
...
...
@@ -184,18 +207,22 @@ const rule_content = ref("");
.rule-wrapper {
display: flex;
height: 100%;
align-items: center;
justify-content: center;
height: 100%;
}
.rule-block {
position: relative;
//
position: relative;
width: 80vw;
height: 80vh;
background-color: #fff;
overflow: scroll;
padding: 1rem;
display: flex;
border-radius: 8px;
align-items: center;
justify-content: center;
.close-btn {
position: absolute;
bottom: 1rem;
...
...
@@ -216,4 +243,8 @@ const rule_content = ref("");
// border-radius: 0.25rem;
// padding: 0.25rem 0.5rem;
}
.nut-radio__label {
margin-left: 25px;
}
</style>
...
...
src/hooks/useComponentType.js
View file @
ec1a245
import
_
from
'@/utils/lodash'
import
TextField
from
'@/components/TextField/index.vue'
import
TextareaField
from
'@/components/TextareaField/index.vue'
//
import RadioField from '@/components/RadioField/index.vue'
import
RadioField
from
'@/components/RadioField/index.vue'
// import CheckboxField from '@/components/CheckboxField/index.vue'
// import PickerField from '@/components/PickerField/index.vue'
// import AreaPickerField from '@/components/AreaPickerField/index.vue'
...
...
@@ -84,9 +84,9 @@ export function createComponentType(data) {
// item.name = item.key
// item.component = NumberField
// }
//
if (item.component_props.tag === 'radio') {
//
item.component = RadioField
//
}
if
(
item
.
component_props
.
tag
===
'radio'
)
{
item
.
component
=
RadioField
}
// if (item.component_props.tag === 'checkbox') {
// item.component = CheckboxField
// }
...
...
src/pages/table/index.vue
View file @
ec1a245
<!--
* @Date: 2023-03-24 09:19:27
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2023-04-03 1
3:32:11
* @LastEditTime: 2023-04-03 1
6:52:30
* @FilePath: /custom_form/src/pages/table/index.vue
* @Description: 文件描述
-->
...
...
@@ -128,6 +128,7 @@ const formatData = (data) => {
// 省市区选择,图片上传,文件上传,电子签名,评分组件
const input = ref([]);
const textarea = ref([]);
const radio = ref([]);
const area_picker = ref([]);
const image_uploader = ref([]);
const file_uploader = ref([]);
...
...
@@ -142,6 +143,9 @@ const setRefMap = (el, item) => {
if (item.component_props.tag === "textarea") {
textarea.value.push(el);
}
if (item.component_props.tag === "radio") {
radio.value.push(el);
}
if (item.component_props.tag === "area_picker") {
area_picker.value.push(el);
}
...
...
@@ -371,6 +375,9 @@ const onActive = (item) => {
if (item.key === "textarea") {
postData.value[item.filed_name] = item.value;
}
if (item.type === "radio") { // 单选控件
postData.value = Object.assign(postData.value, { [item.key]: item.affix ? item.affix : item.value });
}
if (item.key === "area_picker") {
postData.value[item.filed_name] = item.value;
}
...
...
@@ -389,9 +396,6 @@ const onActive = (item) => {
if (item.type === "picker") { // 下拉框控件
postData.value = _.assign(postData.value, { [item.key]: item.value });
}
if (item.type === "radio") { // 单选控件
postData.value = _.assign(postData.value, { [item.key]: item.affix ? item.affix : item.value });
}
if (item.type === "checkbox") { // 多选控件
const checkbox_value = _.cloneDeep(item.value)
checkbox_value.forEach((element, index) => {
...
...
@@ -437,6 +441,18 @@ const validOther = () => {
}
});
}
if (radio.value) {
// 单选框
radio.value.forEach((item, index) => {
if (!radio.value[index].validRadio()) {
valid = {
status: radio.value[index].validRadio(),
key: "radio",
};
return false;
}
});
}
if (area_picker.value) {
// 省市区地址
area_picker.value.forEach((item, index) => {
...
...
Please
register
or
login
to post a comment