Toggle navigation
Toggle navigation
This project
Loading...
Sign in
Hooke
/
data-table
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
2024-05-29 14:29:03 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
0f6307e52ad58874a0f56b73057445fd870bcd6d
0f6307e5
1 parent
12a31211
新增树形选择组件
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
376 additions
and
2 deletions
components.d.ts
package.json
src/components/TreeField/index.vue
src/hooks/useComponentType.js
src/views/index.vue
yarn.lock
components.d.ts
View file @
0f6307e
...
...
@@ -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'
]
...
...
package.json
View file @
0f6307e
...
...
@@ -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"
,
...
...
src/components/TreeField/index.vue
0 → 100644
View file @
0f6307e
<!--
* @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"> *</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" /> 点击搜索
</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>
src/hooks/useComponentType.js
View file @
0f6307e
...
...
@@ -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
;
}
})
}
...
...
src/views/index.vue
View file @
0f6307e
<!--
* @Date: 2022-07-18 10:22:22
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-05-2
8 10:39:05
* @LastEditTime: 2024-05-2
9 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 : "请输入",
...
...
yarn.lock
View file @
0f6307e
This diff could not be displayed because it is too large.
Please
register
or
login
to post a comment