Explorar el Código

级联选择表单组件

wulanhaote
zhao hace 2 años
padre
commit
f0bcc592ed
Se han modificado 6 ficheros con 280 adiciones y 8 borrados
  1. +3
    -1
      src/components/form/FieldCalender.vue
  2. +255
    -0
      src/components/form/FieldCascader.vue
  3. +4
    -1
      src/components/form/FieldCheckbox.vue
  4. +4
    -2
      src/components/form/FieldDatePicker.vue
  5. +7
    -2
      src/components/form/FieldRadio.vue
  6. +7
    -2
      src/components/form/FieldSelect.vue

+ 3
- 1
src/components/form/FieldCalender.vue Ver fichero

@@ -1,3 +1,4 @@
<!-- 日历表单组件 zhao -->
<template>
<!-- !!!注: 不支持逝去的日子, 以`FieldDatePicker`代替 !!! -->
<div>
@@ -36,7 +37,8 @@ import { formatDate } from "element-ui/src/utils/date-util.js"
export default {
name: "FieldCalender",
props: [
'name', 'readonly', 'value', 'label', 'placeholder', 'required', 'rules', 'formatter', 'labelWidth'
'name', 'readonly', 'value', 'label', 'placeholder', 'required', 'rules', 'labelWidth',
'formatter', // value的格式化 String|Function|undefined 字符串为格式字符串, 函数则必须有返回 undefined则不转换
],
watch: {
value: function (newVal, oldVal) {


+ 255
- 0
src/components/form/FieldCascader.vue Ver fichero

@@ -0,0 +1,255 @@
<!-- 级联树选择器表单组件 zhao -->
<template>
<div>
<van-field
:readonly="true"
:clickable="!readonly"
:name="name"
:value="visibleValue"
:label="label"
:placeholder="placeholder"
@click="openPopup"
input-align="right"
right-icon="arrow-down"
:rules="rules"
:required="required"
:label-width="labelWidth || 'auto'"
>
</van-field>
<van-popup v-model="popupVisible" position="bottom">
<van-cascader
ref="picker"
:title="label"
v-model="internalValue"
:placeholder="placeholder || '请选择'"
:options="internalOptions"
:readonly="readonly"
:loading="loading"
:field-names="{
text: textName || 'text',
value: valueName || 'value',
children: childrenName || 'children',
}"
@finish="onConfirm"
@close="onCancel"
@change="onChanged"
/>
</van-popup>
</div>
</template>

<script>
import request from "@/utils/request";

export default {
name: "fieldCascader",
props: [
'name', 'readonly', 'value', 'label', 'placeholder', 'required', 'rules', 'labelWidth',
'options', // 树结构数组/普通数组
'textName', // 名称键名 String 默认text
'valueName', // 值键名 String 默认value
'remoteUrl', // 远程列表加载地址 String
'onRemoteResponse', // 远程获取到结果的处理回调 String|Function 如果是函数需返回数组, 如果是字符串支持.分割
'childrenName', // 子级数组键名 String 默认children
'parentName', // 父的值键名 String 如果不为空 则自动转数组为树树结构数组 String
'showTextAndValue', // 是否显示值和键 Bool|String 字符串为分隔符, true为空字符串
'showHasChildren', // 是否显示存在子级的标识 Bool|String 字符串为标识符, true为` >`
],
watch: {
value: function (newVal, oldVal) {
if(newVal != this.internalValue)
{
this.internalValue = newVal;
this.syncIndex();
}
},
options: function (newVal, oldVal) {
this.internalOptions = this.makeTree(JSON.parse(JSON.stringify(newVal)));
this.handleTree(this.internalOptions);
this.syncIndex();
},
remoteUrl: function (newVal, oldVal) {
this.requestRemote();
},
onRemoteResponse: function (newVal, oldVal) {
this.parseRemote();
}
},
created() {
if(this.options && Array.isArray(this.options) && this.options.length > 0)
{
this.internalOptions = this.makeTree(JSON.parse(JSON.stringify(this.options)));
this.handleTree(this.internalOptions);
this.syncIndex();
}
else if(this.remoteUrl)
this.requestRemote();
},
data() {
return {
popupVisible: false,
internalValue: this.value,
visibleValue: '',
defaultIndex: 0,
internalOptions: [],
loading: false,
remoteResponse: null,
};
},
methods: {
openPopup() {
if(!this.readonly)
{
this.popupVisible = true;
this.$nextTick(() => {
//this.$refs.picker.setIndexes([this.defaultIndex]);
})
}
},
closePopup() {
this.popupVisible = false;
},
onChanged({ value, selectedOptions, tabIndex }) {
this.$emit('change', { value, selectedOptions, });
},
onConfirm({ value, selectedOptions, tabIndex }) {
this.syncValue(value, selectedOptions[selectedOptions.length - 1]);
this.$emit('input', this.internalValue);
this.$emit('confirm', this.internalValue);
this.closePopup();
},
onCancel() {
this.closePopup();
this.$emit('cancel');
},
getValue(data) {
return typeof(data) === 'object' && this.valueName ? data[this.valueName] : data;
},
getLabel(data) {
return typeof(data) === 'object' && this.textName ? data[this.textName] : data;
},
syncValue(value, data) {
this.internalValue = value;
this.visibleValue = this.getLabel(data);
},
requestRemote() {
if(!this.remoteUrl)
return;
this.loading = true;
this.internalOptions = [];
let promise = typeof(this.remoteUrl) === 'function' ? this.remoteUrl() : (this.remoteUrl instanceof Promise ? this.remoteUrl : request(this.remoteUrl));
promise.then((resp) => {
this.remoteResponse = resp;
this.parseRemote();
}).catch((e) => {
console.error(e);
}).finally(() => {
this.loading = false;
})
},
parseRemote() {
if(!this.remoteResponse)
return;
let type = typeof(this.onRemoteResponse);
if(type === 'function')
this.internalOptions = this.makeTree(this.onRemoteResponse(this.remoteResponse));
else if(type === 'string')
{
let arr = this.onRemoteResponse.split('.');
let ptr = this.remoteResponse;
for(let i in arr)
{
ptr = this.remoteResponse[arr[i]];
}
this.internalOptions = this.makeTree(ptr);
}
else
this.internalOptions = this.makeTree(this.remoteResponse);
this.handleTree(this.internalOptions);
this.syncIndex();
},
makeTree(list) {
let parentName = this.parentName;
let valueName = this.valueName || 'value';
let childrenName = this.childrenName || 'children';
function isnull(p) {
return p === null || p === undefined || p === '';
}
function makeTree_r(l, p) {
const isRoot = isnull(p);
let res = [];
for(let v of l)
{
const parentValue = v[parentName];
const value = v[valueName];
if((isRoot && isnull(parentValue)) || (!isRoot && parentValue == p))
{
let arr = makeTree_r(l, value);
if(arr && arr.length > 0)
v[childrenName] = arr;
else
delete v[childrenName];
res.push(v);
}
}
return res;
}
if(this.parentName)
return makeTree_r(list);
else
return list;
},
handleTree(tree) {
if(!this.showTextAndValue && !this.showHasChildren)
return;
let split = this.showTextAndValue === false || this.showTextAndValue === undefined || this.showTextAndValue === null ? false : (typeof(this.showTextAndValue) === 'boolean' ? "" : this.showTextAndValue);
let hasChildren = this.showHasChildren === false || this.showHasChildren === undefined || this.showHasChildren === null ? false : (typeof(this.showHasChildren) === 'boolean' ? " >" : this.showHasChildren);
let textName = this.textName || 'text';
let valueName = this.valueName || 'value';
let childrenName = this.childrenName || 'children';
function handleTree_r(l) {
for(let v of l)
{
if(split !== false)
v[textName] = v[valueName] + split + v[textName];
if(v[childrenName] && Array.isArray(v[childrenName]) && v[childrenName].length > 0)
{
if(hasChildren !== false)
v[textName] = v[textName] + hasChildren;
handleTree_r(v[childrenName]);
}
}
}
handleTree_r(tree);
},
findTree(tree, value) {
let valueName = this.valueName || 'value';
let childrenName = this.childrenName || 'children';
function findTree_r(l) {
for(let v of l)
{
if(value == v[valueName])
return v;
if(v[childrenName] && Array.isArray(v[childrenName]) && v[childrenName].length > 0)
{
let res = findTree_r(v[childrenName]);
if(res !== undefined)
return res;
}
}
return;
}
return findTree_r(tree);
},
syncIndex() {
let item = this.findTree(this.internalOptions, this.internalValue);
if(item)
this.visibleValue = item[this.textName || 'text'];
}
},
}
</script>

<style scoped>

</style>

+ 4
- 1
src/components/form/FieldCheckbox.vue Ver fichero

@@ -1,3 +1,4 @@
<!-- 状态单选框表单组件 zhao -->
<template>
<div>
<van-field
@@ -27,7 +28,9 @@ export default {
name: "fieldCheckbox",
props: [
'name', 'readonly', 'value', 'label', 'placeholder', 'required', 'rules',
'trueLabel', 'falseLabel', 'labelWidth'
'labelWidth',
'trueLabel', // 选中的值
'falseLabel', // 未选中的值
],
watch: {
value: function (newVal, oldVal) {


+ 4
- 2
src/components/form/FieldDatePicker.vue Ver fichero

@@ -1,3 +1,4 @@
<!-- 日期选择表单组件 zhao -->
<template>
<div>
<van-field
@@ -40,8 +41,9 @@ import { formatDate } from "element-ui/src/utils/date-util.js"
export default {
name: "fieldDatePicker",
props: [
'name', 'readonly', 'value', 'label', 'placeholder', 'required', 'rules', 'formatter', 'labelWidth',
'type', // datetime date time year-month month-day datehour
'name', 'readonly', 'value', 'label', 'placeholder', 'required', 'rules', 'labelWidth',
'type', // 类型, 仅支持 datetime date time year-month month-day datehour
'formatter', // value的格式化 String|Function|undefined 字符串为格式字符串, 函数则必须有返回 undefined则不转换
],
watch: {
value: function (newVal, oldVal) {


+ 7
- 2
src/components/form/FieldRadio.vue Ver fichero

@@ -1,3 +1,4 @@
<!-- 单选框组表单组件 zhao -->
<template>
<div>
<van-field
@@ -24,8 +25,12 @@ import request from "@/utils/request";
export default {
name: "fieldRadio",
props: [
'name', 'readonly', 'value', 'label', 'placeholder', 'required', 'rules', 'columns',
'valueKey', 'dataKey', 'remoteUrl', 'onRemoteResponse', 'labelWidth'
'name', 'readonly', 'value', 'label', 'placeholder', 'required', 'rules', 'labelWidth',
'columns', // 列表数据 Array
'valueKey', // 名称键名 String
'dataKey', // 值键名 String
'remoteUrl', // 远程列表加载地址 String
'onRemoteResponse', // 远程获取到结果的处理回调 String|Function 如果是函数需返回数组, 如果是字符串支持.分割
],
watch: {
value: function (newVal, oldVal) {


+ 7
- 2
src/components/form/FieldSelect.vue Ver fichero

@@ -1,3 +1,4 @@
<!-- 下拉列表表单组件 zhao -->
<template>
<div>
<van-field
@@ -38,8 +39,12 @@ import request from "@/utils/request";
export default {
name: "fieldSelect",
props: [
'name', 'readonly', 'value', 'label', 'placeholder', 'required', 'rules', 'columns',
'valueKey', 'dataKey', 'remoteUrl', 'onRemoteResponse', 'labelWidth'
'name', 'readonly', 'value', 'label', 'placeholder', 'required', 'rules', 'labelWidth',
'columns', // 列表数据 Array
'valueKey', // 名称键名 String
'dataKey', // 值键名 String
'remoteUrl', // 远程列表加载地址 String
'onRemoteResponse', // 远程获取到结果的处理回调 String|Function 如果是函数需返回数组, 如果是字符串支持.分割
],
watch: {
value: function (newVal, oldVal) {


Cargando…
Cancelar
Guardar