hookehuyr

新增树形选择组件

......@@ -7,11 +7,13 @@ export {}
declare module '@vue/runtime-core' {
export interface GlobalComponents {
_index: typeof import('./src/components/TreeField/_index.vue')['default']
AppointmentField: typeof import('./src/components/AppointmentField/index.vue')['default']
AreaPickerField: typeof import('./src/components/AreaPickerField/index.vue')['default']
ButtonField: typeof import('./src/components/ButtonField/index.vue')['default']
CalendarField: typeof import('./src/components/CalendarField/index.vue')['default']
CheckboxField: typeof import('./src/components/CheckboxField/index.vue')['default']
Children: typeof import('./src/components/TreeField/children.vue')['default']
ContactField: typeof import('./src/components/ContactField/index.vue')['default']
CustomField: typeof import('./src/components/CustomField/index.vue')['default']
DatePickerField: typeof import('./src/components/DatePickerField/index.vue')['default']
......@@ -43,6 +45,9 @@ declare module '@vue/runtime-core' {
TextareaField: typeof import('./src/components/TextareaField/index.vue')['default']
TextField: typeof import('./src/components/TextField/index.vue')['default']
TimePickerField: typeof import('./src/components/TimePickerField/index.vue')['default']
Tree: typeof import('./src/components/TreeField/tree.vue')['default']
TreeField: typeof import('./src/components/TreeField/index.vue')['default']
TreeSelect: typeof import('./src/components/TreeField/treeSelect.vue')['default']
VanArea: typeof import('vant/es')['Area']
VanButton: typeof import('vant/es')['Button']
VanCalendar: typeof import('vant/es')['Calendar']
......@@ -69,8 +74,11 @@ declare module '@vue/runtime-core' {
VanRadioGroup: typeof import('vant/es')['RadioGroup']
VanRate: typeof import('vant/es')['Rate']
VanRow: typeof import('vant/es')['Row']
VanSearch: typeof import('vant/es')['Search']
VanSwipe: typeof import('vant/es')['Swipe']
VanSwipeItem: typeof import('vant/es')['SwipeItem']
VanTab: typeof import('vant/es')['Tab']
VanTabs: typeof import('vant/es')['Tabs']
VanTimePicker: typeof import('vant/es')['TimePicker']
VanUploader: typeof import('vant/es')['Uploader']
VideoField: typeof import('./src/components/VideoField/index.vue')['default']
......
......@@ -39,6 +39,7 @@
"@vant/touch-emulator": "^1.4.0",
"@vitejs/plugin-legacy": "^1.8.2",
"@vueuse/core": "^8.5.0",
"@wsfe/vue-tree": "^3.2.0",
"animate.css": "^4.1.1",
"browser-md5-file": "^1.1.1",
"dayjs": "^1.11.3",
......@@ -55,7 +56,7 @@
"sha1": "^1.1.1",
"typescript": "^4.7.3",
"uuid": "^8.3.2",
"vant": "^4.1.1",
"vant": "^4.9.0",
"vconsole": "^3.14.6",
"vite-plugin-dynamic-import": "^0.9.6",
"vite-plugin-mp": "^1.6.1",
......
<!--
* @Date: 2022-08-29 14:31:20
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-05-29 14:19:52
* @FilePath: /data-table/src/components/TreeField/index.vue
* @Description: 树形组件
-->
<template>
<div v-if="HideShow" class="name-field-page">
<div :class="[isGroup ? 'group-label' : 'label']">
<span v-if="item.component_props.required">&nbsp;*</span>
{{ item.component_props.label }}
</div>
<van-popup
v-model:show="showBottom"
position="bottom"
:style="{ height: '80vh' }"
>
<div v-if="!is_search" class="search-box" @click="onSearchFocus">
<van-icon name="search" size="1.1rem" />&nbsp;点击搜索
</div>
<van-field ref="searchInputRef" v-else v-model="search_value" label="" placeholder="可通过名称,手机号或邮箱查询" :border="false" @blur="onSearchBlur" @focus="onSearchFocus">
<template #button>
<van-button size="small" type="primary" @click="onCloseSearch">关闭</van-button>
</template>
</van-field>
<div>
{{ value }}
</div>
<div v-if="!is_search" class="tab-tree-container">
<van-tabs :color="styleColor.baseColor" v-model:active="tabActive" @click-tab="onClickTab" style="margin-bottom: 1rem;">
<van-tab title="组织结构"></van-tab>
<van-tab title="角色"></van-tab>
<van-tab title="成员"></van-tab>
</van-tabs>
<div v-if="tabActive === 0" style="padding: 0 0 1rem 1rem;">
<Vtree
ref="orgTreeRef"
v-model="select_org_value"
checkable
titleField="name"
keyField="id"
:expandOnFilter="false"
:showCheckedButton="false"
:showFooter="false"
:cascade="false"
:defaultExpandAll="false"
@search="searchMethod"
@checked-change="checkedChangeMethod"
>
<span slot="empty">暂无数据</span>
</Vtree>
</div>
<div v-if="tabActive === 1" style="padding: 0 0 1rem 1rem;">
<van-checkbox-group
v-model="role_checked"
>
<van-checkbox v-for="(role, index) in roleList" :key="index" :name="role.id" shape="square" icon-size="13px" :checked-color="styleColor.baseColor" style="margin-bottom: 0.5rem;">{{ role.name }}</van-checkbox>
</van-checkbox-group>
</div>
<div v-if="tabActive === 2" style="padding: 0 0 0 1rem;">
<van-row gutter="">
<van-col span="10" style="border-right: 1px solid #eee; height: 70vh; max-height: 60vh; overflow: scroll;">
<Vtree
ref="memberTreeRef"
v-model="select_member_value"
selectable
titleField="name"
keyField="id"
:expandOnFilter="false"
:showCheckedButton="false"
@update:modelValue="() => {}"
>
<span slot="empty">暂无数据</span>
</Vtree>
</van-col>
<van-col span="14">
<!-- {{ select_member_value }} -->
<van-checkbox-group
v-model="member_checked"
style="padding: 0 0 1rem 1rem;"
>
<van-checkbox v-for="(member, index) in memberList" :key="index" :name="member.id" shape="square" icon-size="13px" :checked-color="styleColor.baseColor" style="margin-bottom: 0.5rem;">{{ member.name }}</van-checkbox>
</van-checkbox-group>
</van-col>
</van-row>
</div>
</div>
<div v-else class="search-container">
<div>
<p>部门</p>
<div>1</div>
</div>
<div>
<p>角色</p>
<div>2</div>
</div>
<div>
<p>成员</p>
<div>3</div>
</div>
</div>
</van-popup>
</div>
</template>
<script setup>
import { styleColor } from "@/constant.js";
// 大家可以根据需要是否引入VTreeNode, VTreeSearch, VTreeDrop
import Vtree, { VTreeNode, VTreeSearch, VTreeDrop } from '@wsfe/vue-tree'
import '@wsfe/vue-tree/style.css';
const props = defineProps({
item: Object,
});
// 隐藏显示
const HideShow = computed(() => {
return !props.item.component_props.disabled
});
// 集合组标识
const isGroup = computed(() => {
return props.item.component_props.is_field_group
});
const showBottom = ref(true);
const search_value = ref('');
const onSearch = (val) => {
console.log(val);
};
const onCancel = () => {
search_value.value = '';
};
const tabActive = ref(2);
const select_org_value = ref();
const orgTreeRef = ref();
const role_checked = ref([]);
const roleList = ref([{
id: 'a',
name: '法务组长',
}, {
id: 'b',
name: '接待组长',
}, {
id: 'c',
name: '场地管理',
}]);
const select_member_value = ref();
const memberTreeRef = ref();
const member_checked = ref([]);
const memberList = ref([{
id: 'a',
name: '法务组长',
}, {
id: 'b',
name: '接待组长',
}, {
id: 'c',
name: '场地管理',
}]);
const onClickTab = ({ title }) => { // tab点击事件
if (title === '组织结构') {
nextTick(() => {
orgListReset();
});
}
if (title === '角色') {
nextTick(() => {
roleListReset();
});
}
if (title === '成员') {
nextTick(() => {
memberListReset();
});
}
};
const testData = [{
id: 1,
name: '西园寺',
children: [{
name: '保安',
id: 2,
children: [{
name: '1号',
id: 3
}]
}, {
name: '餐饮',
id: 4,
children: [{
name: '5号',
id: 5
}]
}, {
name: '保安',
id: 21,
children: [{
name: '1号',
id: 31
}]
}, {
name: '餐饮',
id: 41,
children: [{
name: '5号',
id: 51
}]
}, {
name: '保安',
id: 22,
children: [{
name: '1号',
id: 32
}]
}, {
name: '餐饮',
id: 42,
children: [{
name: '5号',
id: 52
}]
}]
}]
onMounted(() => {
props.item.value = props.item.component_props.default;
// TODO:获取数据
memberTreeRef.value.setData(testData);
// 默认展开第一个
memberTreeRef.value.setExpand(1, true)
});
const searchMethod = (value) => {
console.log(value)
}
const checkedChangeMethod = (value) => {
console.log(value)
// console.log(orgTreeRef.value.getCheckedNodes())
}
const is_search = ref(false); // 默认不显示搜索框
const onSearchBlur = () => { // 搜索框失去焦点
}
const onSearchFocus = () => { // 搜索框获取焦点
is_search.value = true;
nextTick(() => {
searchInputRef.value.focus()
})
}
const onCloseSearch = () => {
is_search.value = false;
}
const searchInputRef = ref(null);
const orgListReset = () => { // 组织重置列表
orgTreeRef.value.setData(testData);
orgTreeRef.value.setExpand(1, true)
}
const roleListReset = () => {
}
const memberListReset = () => {
memberTreeRef.value.setData(testData);
memberTreeRef.value.setExpand(1, true)
}
</script>
<style lang="less" scoped>
.name-field-page {
.label {
padding: 1rem 1rem 0 1rem;
font-size: 0.9rem;
font-weight: bold;
span {
color: red;
}
}
.group-label {
padding: 0.75rem 0 0.75rem 1rem;
font-size: 0.9rem;
font-weight: bold;
background-color: #f9f9f9;
color: #666;
border-top: 1px solid #eee;
border-bottom: 1px solid #eee;
span {
color: red;
}
}
}
:deep(.van-field__body) {
border: 1px solid #eaeaea;
border-radius: 0.25rem;
padding: 0.25rem 0.5rem;
}
.search-box {
display: flex;
align-items: center;
justify-content: center;
background-color: #eee;
margin: 1rem;
border-radius: 3px;
padding: 0.6rem;
font-size: 0.9rem;
}
:deep(.ctree-tree-node__checkbox_checked) {
border-color: #C2915F;
background-color: #C2915F;
}
:deep(.ctree-tree-node__title_selected) {
background-color: #f8e2cb;
}
</style>
......@@ -32,6 +32,7 @@ import GenderField from '@/components/GenderField/index.vue';
import AppointmentField from '@/components/AppointmentField/index.vue';
import CustomField from '@/components/CustomField/index.vue';
import GroupField from '@/components/GroupField/index.vue';
import TreeField from '@/components/TreeField/index.vue';
/**
* 生成自定义组件类型
......@@ -63,6 +64,7 @@ import GroupField from '@/components/GroupField/index.vue';
* @type gender 性别控件 GenderField
* @type appointment 预约控件 AppointmentField
* @type group 组集合输入控件 GroupField
* @type tree 树形选择控件 TreeField
*/
export function createComponentType(data) {
// 判断类型和使用组件
......@@ -195,5 +197,9 @@ export function createComponentType(data) {
item.name = item.key;
item.component = GroupField;
}
if (item.component_props.tag === 'tree') {
item.name = item.key;
item.component = TreeField;
}
})
}
......
<!--
* @Date: 2022-07-18 10:22:22
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-05-28 10:39:05
* @LastEditTime: 2024-05-29 14:28:37
* @FilePath: /data-table/src/views/index.vue
* @Description: 首页
-->
......@@ -249,6 +249,23 @@ onMounted(async () => {
// field_name : "field_4",
// index : 41,
// interaction_type : "h5edit",
// label : "树形选择器",
// name : "name_41",
// placeholder : "请输入",
// readonly : false,
// required : false,
// tag : "tree",
// unique : false,
// });
// page_form.unshift({
// data_type : "text",
// default : "",
// disabled : false,
// field_id : 1414832,
// field_name : "field_4",
// index : 41,
// interaction_type : "h5edit",
// label : "物品详情",
// name : "name_41",
// placeholder : "请输入",
......
This diff could not be displayed because it is too large.