hookehuyr

✨ feat(地址选择控件): 样式和功能调整

......@@ -26,11 +26,14 @@ declare module '@vue/runtime-core' {
NameField: typeof import('./src/components/NameField/index.vue')['default']
NoteField: typeof import('./src/components/NoteField/index.vue')['default']
NumberField: typeof import('./src/components/NumberField/index.vue')['default']
NutAddress: typeof import('@nutui/nutui-taro')['Address']
NutButton: typeof import('@nutui/nutui-taro')['Button']
NutCell: typeof import('@nutui/nutui-taro')['Cell']
NutCheckbox: typeof import('@nutui/nutui-taro')['Checkbox']
NutCheckboxGroup: typeof import('@nutui/nutui-taro')['CheckboxGroup']
NutConfigProvider: typeof import('@nutui/nutui-taro')['ConfigProvider']
NutDialog: typeof import('@nutui/nutui-taro')['Dialog']
NutDivider: typeof import('@nutui/nutui-taro')['Divider']
NutField: typeof import('@nutui/nutui-taro')['Field']
NutForm: typeof import('@nutui/nutui-taro')['Form']
NutFormItem: typeof import('@nutui/nutui-taro')['FormItem']
......
......@@ -55,6 +55,7 @@
"@tarojs/runtime": "3.6.2",
"@tarojs/shared": "3.6.2",
"@tarojs/taro": "3.6.2",
"@vant/area-data": "^1.4.1",
"axios-miniprogram": "^2.0.0-rc-2",
"dayjs": "^1.11.7",
"pinia": "2.0.10",
......
This diff could not be displayed because it is too large.
<!--
* @Date: 2022-08-30 14:32:11
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2023-02-14 14:37:45
* @FilePath: /data-table/src/components/AreaPickerField/index.vue
* @LastEditTime: 2023-04-07 13:36:31
* @FilePath: /custom_form/src/components/AreaPickerField/index.vue
* @Description: 省市区选择控件
-->
<template>
<div v-if="HideShow" class="area-picker-field">
<div class="label"><span v-if="item.component_props.required">&nbsp;*</span>{{ item.component_props.label }}</div>
<van-field
name="ignore"
v-model="fieldValue"
is-link
readonly
:required="item.component_props.required"
placeholder="请选择省市区"
:rules="item.rules"
@click="showPicker = true"
:border="show_address ? true : false"
/>
<van-field
v-if="show_address"
name="ignore"
v-model="address"
placeholder="请填写详细地址"
@blur="onBlur"
:rules="item.rules"
:border="false"
/>
<!-- <div
v-if="show_empty"
class="van-field__error-message"
style="padding: 0 1rem 1rem 1rem"
<div class="label">
<text v-if="item.component_props.required">&nbsp;*</text>
{{ item.component_props.label }}
</div>
<nut-cell title="请选择省市区" :desc="text" is-link @click="showAddress"></nut-cell>
<nut-textarea v-if="show_address" v-model="address_info" rows="2" :autosize="{ maxHeight: 100, minHeight: 50 }" placeholder="请填写详细地址" @blur="onBlur" :border="false" />
<nut-divider :style="{ color: '#ebedf0' }" />
<div
v-if="show_error"
style="padding-left: 20px; color: red; font-size: 12px;"
>
地址不能为空
</div> -->
<van-divider />
<van-popup v-model:show="showPicker" position="bottom">
<van-area
v-model="item.city_code"
title=""
:area-list="areaList"
@confirm="onConfirm"
@cancel="showPicker = false"
/>
</van-popup>
{{ error_msg }}
</div>
<nut-address v-model="address_value" v-model:visible="showPopup" :province="address.province" :city="address.city"
:country="address.country" :town="address.town" @change="onChange" @close="close"
custom-address-title="请选择所在地区"></nut-address>
</div>
</template>
<script setup>
import { areaList } from "@vant/area-data";
import { ref, computed, watch, onMounted, reactive } from "vue";
import { useCascaderAreaData } from "./index";
const props = defineProps({
item: Object,
});
const areaList = useCascaderAreaData()
// 隐藏显示
const HideShow = computed(() => {
return !props.item.component_props.disabled
})
const emit = defineEmits(["active"]);
const show_empty = ref(false);
const show_address = ref(!props.item.component_props.no_street)
const address_info = ref('')
const address = ref("");
const city_code = ref("");
const showPicker = ref(false);
let fieldValue = ref("");
const showPopup = ref(false);
const address = ref({
province: [],
city: [],
country: [],
town: []
})
const onConfirm = ({ selectedOptions }) => {
fieldValue.value = selectedOptions.map((option) => option.text).join(" ");
city_code.value = selectedOptions[2]?.value;
const customValue = (address_text, address_info, address_value) => {
let address = '';
if (address_text === '请选择地址') {
address = address_info
} else {
address = address_text + ' ' + address_info
}
// 发送自定义数据
props.item.value = {
key: "area_picker",
filed_name: props.item.key,
value: {
address: fieldValue.value + ' ' + address.value,
city_code: city_code.value
address,
city_code: JSON.stringify(address_value)
},
};
emit("active", props.item.value);
showPicker.value = false;
}
onMounted(() => {
// 初始化地址列表
address.value['province'] = areaList;
address.value['city'] = areaList[0]['children']
address.value['country'] = areaList[0]['children'][0]['children'];
customValue(text.value, address_info.value, address_value.value)
})
const text = ref('请选择地址')
const address_value = ref([])
const showAddress = () => {
showPopup.value = !showPopup.value;
};
const onChange = (cal) => {
if (cal.custom === 'province') { // 点击省列表时
const id = cal.value['id']; // 当前选中省的ID
const current_city = areaList.filter(item => item.id === id);
address.value['city'] = current_city[0]['children']; // 更新市列表
}
if (cal.custom === 'city') { // 点击市列表时
address.value['country'] = cal.value['children']; // 更新区列表
}
const name = address.value[cal.next]
if (name.length < 1) {
showPopup.value = false;
}
};
const close = val => {
const { province, city, country } = val.data;
text.value = `${province.name} ${city.name} ${country.name}`;
address_value.value = [province.id, city.id, country.id];
// 发送自定义数据
customValue(text.value, address_info.value, address_value.value)
};
const onBlur = () => {
props.item.value = {
key: "area_picker",
filed_name: props.item.key,
value: {
address: fieldValue.value + ' ' + address.value,
city_code: city_code.value
},
};
emit("active", props.item.value);
// 发送自定义数据
customValue(text.value, address_info.value, address_value.value)
}
// 错误提示
const show_error = ref(false);
const error_msg = ref('');
const required = props.item.component_props.required;
const show_street = !props.item.component_props.no_street; // 显示详细地址
// 校验模块
const validAreaPicker = () => {
// 必填项
if (props.item.component_props.required && !fieldValue.value) {
show_empty.value = true;
} else if (props.item.component_props.required && !address.value) {
show_empty.value = true;
if (required && show_street && (!address_value.value.length || !address_info.value)) {
show_error.value = true;
error_msg.value = '必填项不能为空'
} else if (required && !show_street && !address_value.value.length) {
show_error.value = true;
error_msg.value = '必填项不能为空'
} else {
show_empty.value = false;
show_error.value = false;
error_msg.value = ''
}
return !show_empty.value;
return !show_error.value;
};
defineExpose({ validAreaPicker });
defineExpose({ validAreaPicker, id: props.item.key });
</script>
<style lang="less" scoped>
<style lang="less">
.area-picker-field {
.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-wrapper {
font-size: 24px;
margin-left: 30px;
color: gray;
padding-bottom: 15px;
padding-top: 7px;
white-space: pre-wrap;
}
}
}
.nut-textarea {
padding: 10px 32px;
}
}
</style>
......
......@@ -4,7 +4,7 @@ import TextareaField from '@/components/TextareaField/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'
import AreaPickerField from '@/components/AreaPickerField/index.vue'
// import DatePickerField from '@/components/DatePickerField/index.vue'
// import TimePickerField from '@/components/TimePickerField/index.vue'
// import DateTimePickerField from '@/components/DateTimePickerField/index.vue'
......@@ -93,9 +93,9 @@ export function createComponentType(data) {
if (item.component_props.tag === 'select') {
item.component = PickerField
}
// if (item.component_props.tag === 'address') {
// item.component = AreaPickerField
// }
if (item.component_props.tag === 'address') {
item.component = AreaPickerField
}
// if (item.component_props.tag === 'date') {
// item.component = DatePickerField
// }
......
<!--
* @Date: 2023-03-24 09:19:27
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2023-04-06 17:14:16
* @LastEditTime: 2023-04-07 13:07:06
* @FilePath: /custom_form/src/pages/table/index.vue
* @Description: 文件描述
-->
......@@ -135,6 +135,7 @@ const picker = ref([]);
const number = ref([]);
const phone = ref([]);
const email = ref([]);
const address = ref([]);
const area_picker = ref([]);
const image_uploader = ref([]);
const file_uploader = ref([]);
......@@ -170,6 +171,9 @@ const setRefMap = (el, item) => {
if (item.component_props.tag === "email") {
email.value.push(el);
}
if (item.component_props.tag === "address") {
address.value.push(el);
}
if (item.component_props.tag === "area_picker") {
area_picker.value.push(el);
}
......@@ -438,6 +442,9 @@ const onActive = (item) => {
if (item.key === "email") {
postData.value[item.filed_name] = item.value;
}
if (item.key === "address") {
postData.value[item.filed_name] = item.value;
}
if (item.key === "image_uploader") {
postData.value[item.filed_name] = item.value;
}
......@@ -581,6 +588,19 @@ const validOther = () => {
}
});
}
if (address.value) {
// 地址选择器
address.value.forEach((item, index) => {
if (!address.value[index].validAreaPicker()) {
valid = {
status: address.value[index].validAreaPicker(),
key: "address",
id: address.value[index]?.id
};
return false;
}
});
}
if (area_picker.value) {
// 省市区地址
area_picker.value.forEach((item, index) => {
......
......@@ -2278,6 +2278,11 @@
"@typescript-eslint/types" "5.56.0"
eslint-visitor-keys "^3.3.0"
"@vant/area-data@^1.4.1":
version "1.4.1"
resolved "https://mirrors.cloud.tencent.com/npm/@vant/area-data/-/area-data-1.4.1.tgz#b4f1bce05dbb147dc08fd2ed9b2a0f63d3329b29"
integrity sha512-D8zI/rfxREhnIKGoYzsEJZ73fte4JARhFeFftLIH7ynu1sPrCBEgPkLEbwPyvw3VC4JdSIuzaK5uOhu+BcoPXw==
"@vue/babel-helper-vue-transform-on@^1.0.2":
version "1.0.2"
resolved "https://mirrors.cloud.tencent.com/npm/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.0.2.tgz#9b9c691cd06fc855221a2475c3cc831d774bc7dc"
......