Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
V
vue3-quasar-ts-study01
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
hucy
vue3-quasar-ts-study01
Commits
4b56b9ee
Commit
4b56b9ee
authored
Jan 18, 2023
by
hucy
☘
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix:表单样式修改
parent
589b9c5c
Changes
21
Show whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
711 additions
and
662 deletions
+711
-662
dialog-layout-props.ts
src/common/types/dialog-layout-props.ts
+7
-0
index.ts
src/common/types/index.ts
+2
-0
index.ts
src/common/utils/index.ts
+1
-0
MyForm.vue
src/components/MyForm.vue
+41
-10
DialogLayout.vue
src/components/dialog-layout/DialogLayout.vue
+129
-0
index.ts
src/components/index.ts
+3
-0
config.ts
src/layouts/config.ts
+16
-16
tree.svg
src/layouts/menuListIcons/tree.svg
+1
-0
IndexPage.vue
src/modules/form-test/IndexPage.vue
+6
-1
config.ts
src/modules/form-test/config.ts
+5
-25
FormDialog.vue
src/modules/form-test/element/FormDialog.vue
+71
-67
route.ts
src/modules/form-test/route.ts
+1
-1
IndexPage.vue
src/modules/page2/IndexPage.vue
+1
-1
config.ts
src/modules/page2/config.ts
+3
-5
IndexPage.vue
src/modules/tree/IndexPage.vue
+151
-118
IndexPage3.vue
src/modules/tree/IndexPage3.vue
+0
-97
nested.vue
src/modules/tree/element/nested.vue
+264
-0
nested.vue
src/modules/tree/infra/nested.vue
+0
-188
nested3.vue
src/modules/tree/infra/nested3.vue
+0
-124
route.ts
src/modules/tree/route.ts
+1
-1
routes.ts
src/router/routes.ts
+8
-8
No files found.
src/common/types/dialog-layout-props.ts
0 → 100644
View file @
4b56b9ee
interface
DialogLayoutProps
{
width
?:
number
;
height
?:
number
;
[
proppName
:
string
]:
any
;
}
export
type
{
DialogLayoutProps
};
src/common/types/index.ts
View file @
4b56b9ee
export
interface
AnyType
{
export
interface
AnyType
{
[
proppName
:
string
]:
any
;
[
proppName
:
string
]:
any
;
}
}
export
*
from
'./dialog-layout-props'
;
src/common/utils/index.ts
View file @
4b56b9ee
...
@@ -23,4 +23,5 @@ export {
...
@@ -23,4 +23,5 @@ export {
replace
,
replace
,
repeat
,
repeat
,
uniqueId
,
uniqueId
,
omit
,
}
from
'lodash-es'
;
}
from
'lodash-es'
;
src/components/MyForm.vue
View file @
4b56b9ee
...
@@ -20,6 +20,9 @@
...
@@ -20,6 +20,9 @@
{{
item
.
label
}}
{{
item
.
label
}}
</div>
</div>
<q-input
<q-input
:class=
"
{
'form-label-padding-bottom': isEmpty(item.bind?.rules),
}"
:type="item.isPwd ? 'password' : 'text'"
:type="item.isPwd ? 'password' : 'text'"
v-model="formValue[item.fild]"
v-model="formValue[item.fild]"
v-bind="item.bind"
v-bind="item.bind"
...
@@ -56,6 +59,9 @@
...
@@ -56,6 +59,9 @@
{{
item
.
label
}}
{{
item
.
label
}}
</div>
</div>
<date-time-pick
<date-time-pick
:class=
"
{
'form-label-padding-bottom': isEmpty(item.bind?.rules),
}"
:dense="
:dense="
item.bind.dense === undefined ? props.dense : item.bind.dense
item.bind.dense === undefined ? props.dense : item.bind.dense
"
"
...
@@ -86,6 +92,9 @@
...
@@ -86,6 +92,9 @@
{{
item
.
label
}}
{{
item
.
label
}}
</div>
</div>
<time-pick
<time-pick
:class=
"
{
'form-label-padding-bottom': isEmpty(item.bind?.rules),
}"
format24h
format24h
v-model="formValue[item.fild]"
v-model="formValue[item.fild]"
:config="item.bind"
:config="item.bind"
...
@@ -114,6 +123,9 @@
...
@@ -114,6 +123,9 @@
{{
item
.
label
}}
{{
item
.
label
}}
</div>
</div>
<date-multiple
<date-multiple
:class=
"
{
'form-label-padding-bottom': isEmpty(item.bind?.rules),
}"
v-model="formValue[item.fild]"
v-model="formValue[item.fild]"
:config="item.bind"
:config="item.bind"
:dense="
:dense="
...
@@ -141,6 +153,9 @@
...
@@ -141,6 +153,9 @@
{{
item
.
label
}}
{{
item
.
label
}}
</div>
</div>
<date-range
<date-range
:class=
"
{
'form-label-padding-bottom': isEmpty(item.bind?.rules),
}"
v-model="formValue[item.fild]"
v-model="formValue[item.fild]"
:config="item.bind"
:config="item.bind"
:dense="
:dense="
...
@@ -168,6 +183,9 @@
...
@@ -168,6 +183,9 @@
{{
item
.
label
}}
{{
item
.
label
}}
</div>
</div>
<color-pick
<color-pick
:class=
"
{
'form-label-padding-bottom': isEmpty(item.bind?.rules),
}"
v-model="formValue[item.fild]"
v-model="formValue[item.fild]"
:config="item.bind"
:config="item.bind"
:dense="
:dense="
...
@@ -194,7 +212,11 @@
...
@@ -194,7 +212,11 @@
>
>
{{
item
.
label
}}
{{
item
.
label
}}
</div>
</div>
<q-input
<q-input
:class=
"
{
'form-label-padding-bottom': isEmpty(item.bind?.rules),
}"
v-if="item.type !== 'select'"
v-if="item.type !== 'select'"
:type="item.type"
:type="item.type"
v-model="formValue[item.fild]"
v-model="formValue[item.fild]"
...
@@ -215,6 +237,9 @@
...
@@ -215,6 +237,9 @@
/>
/>
<q-select
<q-select
class=
"my-select"
class=
"my-select"
:class=
"
{
'form-label-padding-bottom': isEmpty(item.bind?.rules),
}"
v-if="item.type === 'select'"
v-if="item.type === 'select'"
v-bind="item.bind"
v-bind="item.bind"
v-model="formValue[item.fild]"
v-model="formValue[item.fild]"
...
@@ -245,7 +270,7 @@ import TimePick from './TimePick.vue';
...
@@ -245,7 +270,7 @@ import TimePick from './TimePick.vue';
import
DateMultiple
from
'./DateMultiple.vue'
;
import
DateMultiple
from
'./DateMultiple.vue'
;
import
DateRange
from
'./DateRange.vue'
;
import
DateRange
from
'./DateRange.vue'
;
import
ColorPick
from
'./ColorPick.vue'
;
import
ColorPick
from
'./ColorPick.vue'
;
import
{
cloneDeep
,
isObjEqual
}
from
'src/common/utils'
;
import
{
cloneDeep
,
isObjEqual
,
isEmpty
}
from
'src/common/utils'
;
interface
Props
{
interface
Props
{
config
:
any
;
config
:
any
;
...
@@ -334,6 +359,9 @@ function reset() {
...
@@ -334,6 +359,9 @@ function reset() {
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
>
.item
{
.item
{
padding
:
$padding-sm
;
padding
:
$padding-sm
;
padding-bottom
:
0
;
padding-top
:
0
;
// border: 1px solid red;
}
}
.item-content
{
.item-content
{
height
:
100%
;
height
:
100%
;
...
@@ -350,14 +378,17 @@ function reset() {
...
@@ -350,14 +378,17 @@ function reset() {
margin-bottom
:
2px
;
margin-bottom
:
2px
;
display
:
inline-block
;
display
:
inline-block
;
}
}
.form-label-padding-bottom
{
:deep
(
.my-select
padding-bottom
:
20px
;
>
:nth-child
(
1
)
>
:nth-child
(
1
)
>
:nth-child
(
1
)
>
:nth-child
(
1
)
>
span
)
{
white-space
:
nowrap
;
overflow
:
hidden
;
}
}
// :deep(.my-select
// > :nth-child(1)
// > :nth-child(1)
// > :nth-child(1)
// > :nth-child(1)
// > span) {
// white-space: nowrap;
// overflow: hidden;
// }
</
style
>
</
style
>
src/components/dialog-layout/DialogLayout.vue
0 → 100644
View file @
4b56b9ee
<
script
setup
lang=
"ts"
>
import
{
reactive
,
computed
}
from
'vue'
;
interface
IDetailProps
{
title
?:
any
;
width
?:
number
;
maxWidth
?:
number
;
minWidth
?:
number
;
height
?:
number
;
maxHeight
?:
number
;
minHeight
?:
number
;
}
const
props
=
withDefaults
(
defineProps
<
IDetailProps
>
(),
{
title
:
''
,
width
:
1000
,
maxWidth
:
1000
,
minWidth
:
500
,
height
:
600
,
maxHeight
:
900
,
minHeight
:
500
,
});
const
emit
=
defineEmits
<
{
(
e
:
'onOk'
):
void
;
(
e
:
'onCancel'
):
void
;
}
>
();
const
myCardStyle
=
computed
(()
=>
{
return
{
width
:
props
.
width
+
'px'
,
maxWidth
:
props
.
maxWidth
+
'px'
,
minWidth
:
props
.
minWidth
+
'px'
,
height
:
props
.
height
+
'px'
,
maxHeight
:
props
.
maxHeight
+
'px'
,
minHeight
:
props
.
minHeight
+
'px'
,
};
});
const
thumbStyle
=
reactive
({
right
:
'4px'
,
borderRadius
:
'5px'
,
backgroundColor
:
'#64b3f4'
,
width
:
'5px'
,
opacity
:
'1'
,
});
const
barStyle
=
reactive
({
right
:
'2px'
,
borderRadius
:
'9px'
,
backgroundColor
:
'#027be3'
,
width
:
'9px'
,
opacity
:
'0.2'
,
});
function
onCancel
()
{
emit
(
'onCancel'
);
}
function
onSave
()
{
emit
(
'onOk'
);
}
</
script
>
<
template
>
<q-card
class=
"my-card"
:style=
"myCardStyle"
>
<div
class=
"card-content"
>
<div
class=
"title"
>
{{
title
}}
</div>
<div
class=
"content"
>
<q-scroll-area
style=
"height: 100%; max-width: 100%"
:thumb-style=
"thumbStyle"
:bar-style=
"barStyle"
>
<slot></slot>
</q-scroll-area>
</div>
<div
class=
"bottom-action"
>
<q-btn
flat
style=
"color: #64b3f4"
label=
"取消"
@
click=
"onCancel"
/>
<q-btn
unelevated
style=
"background: #64b3f4; color: white"
label=
"确定"
@
click=
"onSave()"
/>
</div>
</div>
</q-card>
</
template
>
<
style
lang=
"scss"
scoped
>
.my-card
{
padding
:
20px
;
background-image
:
linear-gradient
(
60deg
,
#c2e59c
0%
,
#64b3f4
100%
);
box-sizing
:
border-box
;
display
:
flex
;
}
.card-content
{
width
:
100%
;
background-color
:
#fff
;
display
:
flex
;
flex-direction
:
column
;
overflow
:
hidden
;
.title
{
height
:
40px
;
padding
:
8px
;
font-size
:
16px
;
font-weight
:
bolder
;
color
:
#c2e59c
;
display
:
flex
;
align-items
:
center
;
}
.content
{
flex
:
1
;
padding
:
8px
;
position
:
relative
;
}
.bottom-action
{
padding
:
8px
;
display
:
flex
;
flex-direction
:
row
;
column-gap
:
4px
;
justify-content
:
flex-end
;
align-items
:
center
;
}
}
</
style
>
src/components/index.ts
View file @
4b56b9ee
...
@@ -15,6 +15,7 @@ import AgGridNoRowsComponent from './ag-grid/NoRowsOverlayComponent.vue';
...
@@ -15,6 +15,7 @@ import AgGridNoRowsComponent from './ag-grid/NoRowsOverlayComponent.vue';
import
AgGridLoadingOverlayComponent
from
'./ag-grid/LoadingOverlayComponent.vue'
;
import
AgGridLoadingOverlayComponent
from
'./ag-grid/LoadingOverlayComponent.vue'
;
import
AgGridDateComponent
from
'./ag-grid/DateComponent.vue'
;
import
AgGridDateComponent
from
'./ag-grid/DateComponent.vue'
;
import
DialogTip
from
'./dialog-tip/DialogTip.vue'
;
import
DialogTip
from
'./dialog-tip/DialogTip.vue'
;
import
DialogLayout
from
'./dialog-layout/DialogLayout.vue'
;
export
{
export
{
DateTimePick
as
ComDateTimePick
,
DateTimePick
as
ComDateTimePick
,
...
@@ -33,6 +34,7 @@ export {
...
@@ -33,6 +34,7 @@ export {
AgGridLoadingOverlayComponent
as
ComAgGridLoadingOverlayComponent
,
AgGridLoadingOverlayComponent
as
ComAgGridLoadingOverlayComponent
,
AgGridDateComponent
as
ComAgGridDateComponent
,
AgGridDateComponent
as
ComAgGridDateComponent
,
DialogTip
as
ComDialogTip
,
DialogTip
as
ComDialogTip
,
DialogLayout
as
ComDialogLayout
,
};
};
export
default
{
export
default
{
...
@@ -52,4 +54,5 @@ export default {
...
@@ -52,4 +54,5 @@ export default {
AgGridLoadingOverlayComponent
,
AgGridLoadingOverlayComponent
,
AgGridDateComponent
,
AgGridDateComponent
,
DialogTip
,
DialogTip
,
DialogLayout
,
};
};
src/layouts/config.ts
View file @
4b56b9ee
...
@@ -7,45 +7,45 @@ export const MenuList = [
...
@@ -7,45 +7,45 @@ export const MenuList = [
active
:
false
,
active
:
false
,
},
},
{
{
title
:
'
一
'
,
title
:
'
图表
'
,
caption
:
'
日历
'
,
caption
:
'
chart虚拟滚动
'
,
icon
:
require
(
'./menuListIcons/page1.svg'
),
icon
:
require
(
'./menuListIcons/page1.svg'
),
link
:
'/page1'
,
link
:
'/page1'
,
active
:
false
,
active
:
false
,
},
},
{
{
title
:
'
四
'
,
title
:
'
canvas
'
,
caption
:
'canvas小车动画'
,
caption
:
'canvas小车动画'
,
icon
:
require
(
'./menuListIcons/page4.svg'
),
icon
:
require
(
'./menuListIcons/page4.svg'
),
link
:
'/page4'
,
link
:
'/page4'
,
active
:
false
,
active
:
false
,
},
},
{
{
title
:
'
八
'
,
title
:
'
动画
'
,
caption
:
'
动画
'
,
caption
:
''
,
icon
:
require
(
'./menuListIcons/page8.svg'
),
icon
:
require
(
'./menuListIcons/page8.svg'
),
link
:
'/page8'
,
link
:
'/page8'
,
active
:
false
,
active
:
false
,
},
},
{
{
title
:
'
九
'
,
title
:
'
表格
'
,
caption
:
'动画2&表格'
,
caption
:
'动画2&表格'
,
icon
:
require
(
'./menuListIcons/page9.svg'
),
icon
:
require
(
'./menuListIcons/page9.svg'
),
link
:
'/page9'
,
link
:
'/page9'
,
active
:
false
,
active
:
false
,
},
},
{
{
title
:
'
十
'
,
title
:
'
设计
'
,
caption
:
'
设计
'
,
caption
:
'
一言
'
,
icon
:
require
(
'./menuListIcons/page10.svg'
),
icon
:
require
(
'./menuListIcons/page10.svg'
),
link
:
'/page10'
,
link
:
'/page10'
,
active
:
false
,
active
:
false
,
},
},
{
{
title
:
'
t
ree'
,
title
:
'
T
ree'
,
caption
:
'树'
,
caption
:
'树'
,
icon
:
require
(
'./menuListIcons/
page10
.svg'
),
icon
:
require
(
'./menuListIcons/
tree
.svg'
),
link
:
'/tree'
,
link
:
'/tree'
,
active
:
false
,
active
:
false
,
},
},
...
@@ -56,8 +56,8 @@ export const MenuList = [
...
@@ -56,8 +56,8 @@ export const MenuList = [
active
:
false
,
active
:
false
,
children
:
[
children
:
[
{
{
title
:
'
贰
'
,
title
:
'
表单
'
,
caption
:
'
表单
'
,
caption
:
''
,
icon
:
require
(
'./menuListIcons/page2.svg'
),
icon
:
require
(
'./menuListIcons/page2.svg'
),
link
:
'/page2'
,
link
:
'/page2'
,
active
:
false
,
active
:
false
,
...
@@ -85,14 +85,14 @@ export const MenuList = [
...
@@ -85,14 +85,14 @@ export const MenuList = [
active
:
false
,
active
:
false
,
},
},
{
{
title
:
'
五
'
,
title
:
'
防抖节流
'
,
caption
:
'表格&防抖节流'
,
caption
:
'表格&防抖节流'
,
icon
:
require
(
'./menuListIcons/page5.svg'
),
icon
:
require
(
'./menuListIcons/page5.svg'
),
link
:
'/page5'
,
link
:
'/page5'
,
active
:
false
,
active
:
false
,
},
},
{
{
title
:
'
六
'
,
title
:
'
JS
'
,
caption
:
'一些js练习'
,
caption
:
'一些js练习'
,
icon
:
require
(
'./menuListIcons/page6.png'
),
icon
:
require
(
'./menuListIcons/page6.png'
),
link
:
'/js-page6'
,
link
:
'/js-page6'
,
...
@@ -107,8 +107,8 @@ export const MenuList = [
...
@@ -107,8 +107,8 @@ export const MenuList = [
active
:
false
,
active
:
false
,
children
:
[
children
:
[
{
{
title
:
'
七
'
,
title
:
'
疫情防控
'
,
caption
:
'
疫情防控
'
,
caption
:
''
,
icon
:
require
(
'./menuListIcons/page7.svg'
),
icon
:
require
(
'./menuListIcons/page7.svg'
),
link
:
'/page7'
,
link
:
'/page7'
,
active
:
false
,
active
:
false
,
...
...
src/layouts/menuListIcons/tree.svg
0 → 100644
View file @
4b56b9ee
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg
t=
"1674021701598"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
p-id=
"1097"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
width=
"200"
height=
"200"
><path
d=
"M165.8 224.4l333.3 217.5M487.3 450.6L154 233.1l23.6-17.3L511 433.2zM874.7 224.4L541.4 441.9M553.2 450.6l333.4-217.5-23.7-17.3-333.4 217.4z"
fill=
"#65C8D0"
p-id=
"1098"
></path><path
d=
"M485.8 412.2h64.3v545.2h-64.3z"
fill=
"#65C8D0"
p-id=
"1099"
></path><path
d=
"M312.3 159.7a43.1 35.6 0 1 0 86.2 0 43.1 35.6 0 1 0-86.2 0Z"
fill=
"#65C8D0"
p-id=
"1100"
></path><path
d=
"M467.9 297.6a43.1 35.6 0 1 0 86.2 0 43.1 35.6 0 1 0-86.2 0Z"
fill=
"#65C8D0"
p-id=
"1101"
></path><path
d=
"M648.4 207.6a43.1 35.6 0 1 0 86.2 0 43.1 35.6 0 1 0-86.2 0Z"
fill=
"#65C8D0"
p-id=
"1102"
></path><path
d=
"M495.3 124.1a43.1 35.6 0 1 0 86.2 0 43.1 35.6 0 1 0-86.2 0Z"
fill=
"#65C8D0"
p-id=
"1103"
></path></svg>
\ No newline at end of file
src/modules/form-test/IndexPage.vue
View file @
4b56b9ee
...
@@ -43,11 +43,16 @@ function getData() {
...
@@ -43,11 +43,16 @@ function getData() {
function
clickAdd
()
{
function
clickAdd
()
{
formDialogRef
.
value
.
openDialog
();
formDialogRef
.
value
.
openDialog
();
}
}
function
viewData
()
{
console
.
log
(
'查看'
,
state
.
rowData
);
}
</
script
>
</
script
>
<
template
>
<
template
>
<div
class=
"box"
>
<div
class=
"box"
>
<div
class=
"actions"
>
<div
class=
"actions"
>
<q-btn
color=
"primary"
label=
"添加"
@
click=
"clickAdd"
/>
<q-btn
unelevated
color=
"primary"
label=
"添加"
@
click=
"clickAdd"
/>
<q-btn
unelevated
color=
"primary"
label=
"查看"
@
click=
"viewData"
/>
</div>
</div>
<div
class=
"ag-table"
>
<div
class=
"ag-table"
>
<ag-grid-vue
<ag-grid-vue
...
...
src/modules/form-test/config.ts
View file @
4b56b9ee
...
@@ -21,7 +21,6 @@ export const form_config = [
...
@@ -21,7 +21,6 @@ export const form_config = [
bind
:
{
bind
:
{
filled
:
true
,
filled
:
true
,
lazyRules
:
true
,
lazyRules
:
true
,
hideBottomSpace
:
true
,
rules
:
[(
val
:
any
)
=>
!
isEmpty
(
val
)
||
'必填'
],
rules
:
[(
val
:
any
)
=>
!
isEmpty
(
val
)
||
'必填'
],
},
},
},
},
...
@@ -34,7 +33,6 @@ export const form_config = [
...
@@ -34,7 +33,6 @@ export const form_config = [
bind
:
{
bind
:
{
filled
:
true
,
filled
:
true
,
lazyRules
:
true
,
lazyRules
:
true
,
hideBottomSpace
:
true
,
rules
:
[(
val
:
any
)
=>
!
isEmpty
(
val
)
||
'必填'
],
rules
:
[(
val
:
any
)
=>
!
isEmpty
(
val
)
||
'必填'
],
},
},
},
},
...
@@ -47,7 +45,6 @@ export const form_config = [
...
@@ -47,7 +45,6 @@ export const form_config = [
bind
:
{
bind
:
{
filled
:
true
,
filled
:
true
,
lazyRules
:
true
,
lazyRules
:
true
,
hideBottomSpace
:
true
,
rules
:
[
rules
:
[
(
val
:
any
)
=>
!
isEmpty
(
val
)
||
'必填'
,
(
val
:
any
)
=>
!
isEmpty
(
val
)
||
'必填'
,
(
val
:
any
)
=>
(
val
>
0
&&
val
<
100
)
||
'请输入真实年龄'
,
(
val
:
any
)
=>
(
val
>
0
&&
val
<
100
)
||
'请输入真实年龄'
,
...
@@ -55,29 +52,8 @@ export const form_config = [
...
@@ -55,29 +52,8 @@ export const form_config = [
},
},
},
},
{
{
fild
:
'sex'
,
solt
:
'sex'
,
label
:
'性别'
,
col
:
'col-4'
,
col
:
'col-4'
,
type
:
'select'
,
required
:
true
,
bind
:
{
filled
:
true
,
lazyRules
:
true
,
hideBottomSpace
:
true
,
rules
:
[(
val
:
any
)
=>
!
isEmpty
(
val
)
||
'必填'
],
emitValue
:
true
,
mapOptions
:
true
,
options
:
[
{
label
:
'男'
,
value
:
1
,
},
{
label
:
'女'
,
value
:
0
,
},
],
},
},
},
{
{
fild
:
'dateRange'
,
fild
:
'dateRange'
,
...
@@ -122,6 +98,10 @@ export const form_config = [
...
@@ -122,6 +98,10 @@ export const form_config = [
label
:
'Facebook'
,
label
:
'Facebook'
,
value
:
'Facebook'
,
value
:
'Facebook'
,
},
},
{
label
:
'AAA'
,
value
:
'aaa'
,
},
],
],
},
},
},
},
...
...
src/modules/form-test/element/FormDialog.vue
View file @
4b56b9ee
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
ref
,
reactive
,
onMounted
}
from
'vue'
;
import
{
ref
,
reactive
,
onMounted
}
from
'vue'
;
import
{
useMessage
}
from
'src/common/hooks'
;
import
Com
from
'src/components'
;
import
Com
from
'src/components'
;
import
{
isEmpty
}
from
'src/common/utils'
;
import
{
form_config
}
from
'../config'
;
import
{
form_config
}
from
'../config'
;
import
type
{
DialogLayoutProps
}
from
'src/common/types'
;
defineExpose
({
defineExpose
({
openDialog
,
openDialog
,
closeDialog
,
closeDialog
,
});
});
const
{
warn
}
=
useMessage
();
const
formRef
=
ref
<
any
>
(
null
);
const
formRef
=
ref
<
any
>
(
null
);
const
show
=
ref
(
false
);
const
show
=
ref
(
false
);
...
@@ -19,6 +24,21 @@ const state = reactive({
...
@@ -19,6 +24,21 @@ const state = reactive({
formData
:
{}
as
any
,
formData
:
{}
as
any
,
});
});
const
pagestate
=
reactive
<
DialogLayoutProps
>
({
title
:
'添加'
,
});
const
sexOpt
=
reactive
([
{
label
:
'男'
,
value
:
1
,
},
{
label
:
'女'
,
value
:
0
,
},
]);
onMounted
(()
=>
{
onMounted
(()
=>
{
initFormConfig
();
initFormConfig
();
});
});
...
@@ -40,89 +60,73 @@ function closeDialog() {
...
@@ -40,89 +60,73 @@ function closeDialog() {
initDialog
();
initDialog
();
}
}
function
onCancel
()
{
closeDialog
();
}
function
onSave
()
{
function
onSave
()
{
const
{
formData
}
=
state
;
formRef
.
value
.
validate
().
then
((
suc
:
any
)
=>
{
formRef
.
value
.
validate
().
then
((
suc
:
any
)
=>
{
if
(
!
suc
)
return
;
if
(
!
suc
)
return
;
console
.
log
(
'formData >>>>'
,
state
.
formData
);
if
(
isEmpty
(
formData
.
sex
))
return
warn
(
'性别必填'
);
console
.
log
(
'formData >>>>'
,
formData
);
closeDialog
();
closeDialog
();
});
});
}
}
function
onCancel
()
{
closeDialog
();
}
</
script
>
</
script
>
<
template
>
<
template
>
<q-dialog
v-model=
"show"
persistent
>
<q-dialog
v-model=
"show"
persistent
>
<q-card
class=
"my-card"
>
<Com
.
DialogLayout
v-bind=
"pagestate"
@
onOk=
"onSave"
@
onCancel=
"onCancel"
>
<div
class=
"card-content"
>
<div
class=
"title"
>
添加
</div>
<div
class=
"content"
>
<Com
.
MyForm
<Com
.
MyForm
ref=
"formRef"
ref=
"formRef"
dense
dense
:readonly=
"state.readonly"
:readonly=
"state.readonly"
:config=
"state.formConfig"
:config=
"state.formConfig"
v-model=
"state.formData"
v-model=
"state.formData"
></Com
.MyForm
>
>
</div>
<template
#
sex
>
<div
class=
"bottom-action"
>
<div
class=
"item-content"
>
<q-btn
flat
style=
"color: #64b3f4"
label=
"取消"
@
click=
"onCancel"
/>
<div
class=
"label-title text-required"
>
性别
</div>
<q-btn
<div
class=
"label-content"
>
unelevated
<q-option-group
style=
"background: #64b3f4; color: white"
v-model=
"state.formData.sex"
label=
"确定"
:options=
"sexOpt"
@
click=
"onSave()"
color=
"primary"
inline
:disable=
"state.readonly"
/>
/>
</div>
</div>
</div>
</div>
</q-card>
</
template
>
</Com
.MyForm
>
</Com
.DialogLayout
>
</q-dialog>
</q-dialog>
</template>
</template>
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
>
.my-card
{
.item-content
{
width
:
1000px
;
height
:
40px
;
max-width
:
1000px
;
min-height
:
500px
;
padding
:
20px
;
background-image
:
linear-gradient
(
60deg
,
#c2e59c
0%
,
#64b3f4
100%
);
box-sizing
:
border-box
;
display
:
flex
;
}
.card-content
{
width
:
100%
;
width
:
100%
;
background-color
:
#fff
;
display
:
flex
;
display
:
flex
;
flex-direction
:
column
;
flex-direction
:
column
;
flex-wrap
:
nowrap
;
.title
{
}
height
:
40px
;
.label-title
{
padding
:
8px
;
height
:
22px
;
font-size
:
16px
;
font-size
:
14px
;
font-weight
:
bolder
;
line-height
:
22px
;
color
:
#c2e59c
;
color
:
rgba
(
0
,
0
,
0
,
0
.871
);
display
:
flex
;
margin-bottom
:
2px
;
align-items
:
center
;
display
:
inline-block
;
// background-color: #ee9ca7;
}
}
.label-content
{
.content
{
flex
:
1
;
flex
:
1
;
padding
:
8px
;
}
.bottom-action
{
// background-color: #209cff;
padding
:
8px
;
display
:
flex
;
display
:
flex
;
flex-direction
:
row
;
flex-direction
:
row
;
column-gap
:
4px
;
justify-content
:
flex-end
;
align-items
:
center
;
align-items
:
center
;
}
background-color
:
rgba
(
0
,
0
,
0
,
0
.05
);
border-radius
:
4px
4px
0
0
;
}
}
</
style
>
</
style
>
src/modules/form-test/route.ts
View file @
4b56b9ee
...
@@ -4,7 +4,7 @@ export default [
...
@@ -4,7 +4,7 @@ export default [
name
:
'FORM_TEST'
,
name
:
'FORM_TEST'
,
component
:
()
=>
import
(
'./IndexPage.vue'
),
component
:
()
=>
import
(
'./IndexPage.vue'
),
meta
:
{
meta
:
{
title
:
'
表单&表格
'
,
title
:
'
信息
'
,
permission
:
[
'*'
],
permission
:
[
'*'
],
keepalive
:
true
,
keepalive
:
true
,
},
},
...
...
src/modules/page2/IndexPage.vue
View file @
4b56b9ee
...
@@ -265,7 +265,7 @@ function onResetForm() {
...
@@ -265,7 +265,7 @@ function onResetForm() {
border
:
1px
solid
$border-color
;
border
:
1px
solid
$border-color
;
}
}
.item-content
{
.item-content
{
height
:
100%
;
height
:
calc
(
100%
-
20px
)
;
width
:
100%
;
width
:
100%
;
display
:
flex
;
display
:
flex
;
flex-direction
:
column
;
flex-direction
:
column
;
...
...
src/modules/page2/config.ts
View file @
4b56b9ee
...
@@ -9,7 +9,6 @@ export const form = [
...
@@ -9,7 +9,6 @@ export const form = [
readonly
:
true
,
readonly
:
true
,
filled
:
true
,
filled
:
true
,
lazyRules
:
true
,
lazyRules
:
true
,
hideBottomSpace
:
true
,
rules
:
[(
val
:
any
)
=>
(
val
&&
val
.
length
>
0
)
||
'必填'
],
rules
:
[(
val
:
any
)
=>
(
val
&&
val
.
length
>
0
)
||
'必填'
],
},
},
},
},
...
@@ -19,11 +18,11 @@ export const form = [
...
@@ -19,11 +18,11 @@ export const form = [
col
:
'col-6'
,
col
:
'col-6'
,
type
:
'password'
,
type
:
'password'
,
isPwd
:
true
,
isPwd
:
true
,
required
:
true
,
bind
:
{
bind
:
{
filled
:
true
,
filled
:
true
,
// lazyRules: true,
lazyRules
:
true
,
// hideBottomSpace: true,
rules
:
[(
val
:
any
)
=>
(
val
&&
val
.
length
>
0
)
||
'必填'
],
// rules: [(val: any) => (val && val.length > 0) || '必填'],
},
},
},
},
{
{
...
@@ -59,7 +58,6 @@ export const form = [
...
@@ -59,7 +58,6 @@ export const form = [
},
},
],
],
// lazyRules: true,
// lazyRules: true,
// hideBottomSpace: true,
// rules: [(val: any) => (val && val.length > 0) || '必填'],
// rules: [(val: any) => (val && val.length > 0) || '必填'],
clearable
:
true
,
clearable
:
true
,
},
},
...
...
src/modules/tree/IndexPage.vue
View file @
4b56b9ee
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
reactive
,
onMounted
}
from
'vue'
;
import
{
reactive
,
onMounted
}
from
'vue'
;
import
{
cloneDeep
,
isEmpty
}
from
'src/common/utils'
;
import
{
useQuasar
}
from
'quasar'
;
import
nestedDraggable
from
'./infra/nested.vue'
;
import
{
cloneDeep
,
isEmpty
,
omit
}
from
'src/common/utils'
;
import
nestedDraggable
from
'./element/nested.vue'
;
import
{
ComDialogTip
}
from
'src/components'
;
const
$q
=
useQuasar
();
const
SpcGroupItem
=
{
show
:
true
,
title
:
null
,
children
:
[],
};
const
data
=
[
const
data
=
[
{
{
name
:
'task 1'
,
title
:
'1'
,
show
:
true
,
children
:
[
tasks
:
[
{
{
name
:
'task 2'
,
title
:
'1-1'
,
show
:
true
,
children
:
[],
tasks
:
[],
},
],
key
:
'1'
,
},
},
{
{
name
:
'task 3
'
,
title
:
'1-2
'
,
show
:
true
,
children
:
[]
,
tasks
:
[
},
{
{
name
:
'task 4'
,
title
:
'1-3'
,
show
:
true
,
children
:
[],
tasks
:
[],
},
},
],
],
key
:
'2'
,
},
},
{
{
name
:
'task 5'
,
title
:
'2'
,
show
:
true
,
children
:
[],
tasks
:
[],
key
:
'3'
,
},
},
];
];
const
state
=
reactive
({
const
state
=
reactive
({
list
:
[]
as
any
[],
originalData
:
[]
as
any
[],
originalData
:
[]
as
any
[],
list
:
[]
as
any
[],
itemKey
:
'key'
,
childrenKey
:
'children'
,
labelKey
:
'title'
,
dataStacks
:
[]
as
any
,
});
});
onMounted
(()
=>
{
onMounted
(()
=>
{
state
.
originalData
=
cloneDeep
(
data
);
initData
(
data
);
handleData
(
data
);
state
.
list
=
data
;
});
});
function
handleData
(
data
:
any
,
key
=
'tasks'
,
before
=
0
)
{
function
initData
(
data
:
any
)
{
state
.
originalData
=
data
;
const
_data
=
cloneDeep
(
data
);
handleData
(
_data
);
state
.
list
=
_data
;
pushDataToStacks
();
// console.log('state.list', state.list);
}
function
pushDataToStacks
()
{
state
.
dataStacks
.
push
({
data
:
cloneDeep
(
state
.
list
),
});
}
function
handleData
(
data
:
any
,
key
=
state
.
childrenKey
,
before
=
0
)
{
let
index
=
0
;
let
index
=
0
;
data
.
map
((
item
:
any
)
=>
{
data
.
map
((
item
:
any
)
=>
{
let
indexstr
;
let
indexstr
;
if
(
before
)
{
if
(
before
)
{
indexstr
=
before
+
'-'
+
String
(
index
);
indexstr
=
String
(
before
)
+
'-'
+
String
(
index
);
}
else
{
}
else
{
indexstr
=
String
(
index
);
indexstr
=
String
(
index
);
}
}
if
(
isEmpty
(
item
.
show
))
{
item
.
show
=
true
;
}
item
[
'test_index'
]
=
indexstr
;
item
[
'test_index'
]
=
indexstr
;
item
[
state
.
itemKey
]
=
indexstr
;
if
(
data
.
length
-
1
===
index
)
{
item
.
lastChild
=
true
;
}
else
{
item
.
lastChild
=
false
;
}
index
++
;
index
++
;
if
(
!
isEmpty
(
item
[
key
]))
{
if
(
!
isEmpty
(
item
[
key
]))
{
...
@@ -69,61 +94,93 @@ function handleData(data: any, key = 'tasks', before = 0) {
...
@@ -69,61 +94,93 @@ function handleData(data: any, key = 'tasks', before = 0) {
});
});
}
}
function
viewData
()
{
function
handelDel
(
listdata
:
any
[])
{
console
.
log
(
'查看 >>>>'
,
state
.
list
);
const
chiledKey
=
state
.
childrenKey
;
let
newArr
=
[]
as
any
[];
listdata
.
map
((
item
)
=>
{
if
(
!
isEmpty
(
item
[
chiledKey
]))
{
item
[
chiledKey
]
=
handelDel
(
item
[
chiledKey
]);
}
if
(
!
item
[
'test_delete'
])
{
newArr
.
push
(
item
);
}
});
return
newArr
;
}
}
function
onReset
()
{
function
getTarget
(
list
:
any
,
index
:
number
)
{
const
data
=
cloneDeep
(
state
.
originalData
);
const
target
=
list
[
index
];
handleData
(
data
);
const
parent
=
list
;
state
.
list
=
data
;
return
{
target
,
parent
};
}
function
delTestKey
(
listdata
:
any
[])
{
const
chiledKey
=
state
.
childrenKey
;
let
seq
=
1
;
return
listdata
.
map
((
item
:
any
)
=>
{
if
(
!
isEmpty
(
item
[
chiledKey
]))
{
item
[
chiledKey
]
=
delTestKey
(
item
[
chiledKey
]);
}
const
newObj
=
omit
(
item
,
[
'key'
,
'test_index'
,
'show'
,
'lastChild'
]);
newObj
.
seq
=
seq
;
seq
++
;
return
newObj
;
});
}
}
// 查看
function
viewData
()
{
const
data
=
cloneDeep
(
state
.
list
);
const
resdata
=
delTestKey
(
data
);
console
.
log
(
'最后处理格式'
,
resdata
);
}
// 重置
function
onReset
()
{
state
.
dataStacks
=
[];
initData
(
cloneDeep
(
state
.
originalData
));
}
// 拖拽结束
// 拖拽结束
function
dragEnd
()
{
function
dragEnd
()
{
handleData
(
state
.
list
);
handleData
(
state
.
list
);
console
.
log
(
'拖拽结束2'
,
state
.
list
);
pushDataToStacks
(
);
}
}
// 添加
function
onAdd
()
{
function
onAdd
()
{
let
obj
:
any
=
{
let
obj
=
{
...
SpcGroupItem
}
as
any
;
name
:
null
,
obj
[
state
.
itemKey
]
=
Date
.
now
();
tasks
:
[],
key
:
Date
.
now
(),
};
state
.
list
.
push
(
obj
);
state
.
list
.
push
(
obj
);
handleData
(
state
.
list
);
handleData
(
state
.
list
);
pushDataToStacks
();
}
}
// 删除
// 删除
function
delItem
(
data
:
any
)
{
function
delItem
(
data
:
any
)
{
console
.
log
(
'删除'
,
data
);
let
msg
=
''
;
if
(
!
isEmpty
(
data
.
children
))
{
msg
=
'确定删除 '
+
<
string
>
data
.
title
+
'及其所有子项?'
;
}
else
{
msg
=
'确定删除 '
+
<
string
>
data
.
title
+
'?'
;
}
$q
.
dialog
({
component
:
ComDialogTip
,
componentProps
:
{
persistent
:
true
,
text
:
msg
,
color
:
'negative'
,
},
}).
onOk
(()
=>
{
data
[
'test_delete'
]
=
true
;
data
[
'test_delete'
]
=
true
;
let
res
=
handelDel
(
state
.
list
);
let
res
=
handelDel
(
state
.
list
);
handleData
(
res
);
handleData
(
res
);
state
.
list
=
res
;
state
.
list
=
res
;
}
pushDataToStacks
();
function
handelDel
(
listdata
:
any
[])
{
const
chiledKey
=
'tasks'
;
let
newArr
=
[]
as
any
[];
listdata
.
map
((
item
)
=>
{
if
(
!
isEmpty
(
item
[
chiledKey
]))
{
item
[
chiledKey
]
=
handelDel
(
item
[
chiledKey
]);
}
if
(
!
item
[
'test_delete'
])
{
newArr
.
push
(
item
);
}
});
});
return
newArr
;
}
}
// 同级添加
// 同级添加
function
addItem
(
data
:
any
)
{
function
addItem
(
data
:
any
)
{
console
.
log
(
'同级添加'
,
data
);
const
key
=
state
.
childrenKey
;
const
key
=
'tasks'
;
const
indexList
=
data
[
'test_index'
].
split
(
'-'
);
const
indexList
=
data
[
'test_index'
].
split
(
'-'
);
let
re
:
any
;
let
re
:
any
;
...
@@ -136,21 +193,16 @@ function addItem(data: any) {
...
@@ -136,21 +193,16 @@ function addItem(data: any) {
}
}
}
}
let
obj
:
any
=
{
let
obj
=
{
...
SpcGroupItem
}
as
any
;
name
:
null
,
obj
[
state
.
itemKey
]
=
Date
.
now
();
show
:
true
,
key
:
Date
.
now
(),
};
obj
[
key
]
=
[];
re
.
parent
.
push
(
obj
);
re
.
parent
.
push
(
obj
);
handleData
(
state
.
list
);
handleData
(
state
.
list
);
pushDataToStacks
();
}
}
// 子级添加
// 子级添加
function
addNest
(
data
:
any
)
{
function
addNest
(
data
:
any
)
{
const
key
=
'tasks'
;
const
key
=
state
.
childrenKey
;
console
.
log
(
'子级添加'
,
data
);
const
indexList
=
data
[
'test_index'
].
split
(
'-'
);
const
indexList
=
data
[
'test_index'
].
split
(
'-'
);
let
re
:
any
;
let
re
:
any
;
...
@@ -163,53 +215,41 @@ function addNest(data: any) {
...
@@ -163,53 +215,41 @@ function addNest(data: any) {
}
}
}
}
let
obj
:
any
=
{
let
obj
=
{
...
SpcGroupItem
}
as
any
;
name
:
null
,
obj
[
state
.
itemKey
]
=
Date
.
now
();
show
:
true
,
key
:
Date
.
now
(),
};
obj
[
key
]
=
[];
re
.
target
[
key
].
push
(
obj
);
re
.
target
[
key
].
push
(
obj
);
handleData
(
state
.
list
);
handleData
(
state
.
list
);
pushDataToStacks
();
}
}
// 撤销
function
getTarget
(
list
:
any
,
index
:
number
)
{
function
onUndo
()
{
const
target
=
list
[
index
];
const
lastindex
=
state
.
dataStacks
.
length
-
2
;
const
parent
=
list
;
const
lastdata
=
state
.
dataStacks
[
lastindex
];
return
{
target
,
parent
};
state
.
list
=
cloneDeep
(
lastdata
.
data
);
}
state
.
dataStacks
.
splice
(
lastindex
+
1
,
1
);
function
getParamData
()
{
//
let
data
=
cloneDeep
(
state
.
list
);
let
res
=
delTestKey
(
data
);
console
.
log
(
'原来的格式'
,
res
);
}
function
delTestKey
(
listdata
:
any
[],
delKey
=
'test_index'
)
{
const
chiledKey
=
'tasks'
;
return
listdata
.
map
((
item
:
any
)
=>
{
if
(
!
isEmpty
(
item
[
chiledKey
]))
{
item
[
chiledKey
]
=
delTestKey
(
item
[
chiledKey
],
delKey
);
}
delete
item
[
delKey
];
return
item
;
});
}
}
</
script
>
</
script
>
<
template
>
<
template
>
<div
class=
"box"
>
<div
class=
"box"
>
<div
class=
"actions"
>
<div
class=
"actions"
>
<q-btn
color=
"primary"
label=
"查看"
@
click=
"viewData"
/>
<q-btn
unelevated
color=
"primary"
label=
"查看"
@
click=
"viewData"
/>
<q-btn
color=
"primary"
label=
"原来的格式"
@
click=
"getParamData"
/>
<q-btn
unelevated
color=
"primary"
label=
"重置"
@
click=
"onReset"
/>
<q-btn
color=
"primary"
label=
"重置"
@
click=
"onReset"
/>
<q-btn
unelevated
color=
"primary"
label=
"添加"
@
click=
"onAdd"
/>
<q-btn
color=
"primary"
label=
"添加"
@
click=
"onAdd"
/>
<q-btn
unelevated
color=
"primary"
label=
"撤销"
@
click=
"onUndo"
:disable=
"state.dataStacks.length
<
2
"
/>
</div>
</div>
<div
class=
"tree-box"
>
<div
class=
"tree-box"
>
<nested-draggable
<nested-draggable
:tasks=
"state.list"
:tasks=
"state.list"
:item-key=
"state.itemKey"
:children-key=
"state.childrenKey"
:label-key=
"state.labelKey"
@
onEnd=
"dragEnd"
@
onEnd=
"dragEnd"
@
addItem=
"addItem"
@
addItem=
"addItem"
@
addNest=
"addNest"
@
addNest=
"addNest"
...
@@ -221,7 +261,7 @@ function delTestKey(listdata: any[], delKey = 'test_index') {
...
@@ -221,7 +261,7 @@ function delTestKey(listdata: any[], delKey = 'test_index') {
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
>
.actions
{
.actions
{
padding
:
1
0px
;
padding
:
20px
10px
10px
2
0px
;
display
:
flex
;
display
:
flex
;
flex-direction
:
row
;
flex-direction
:
row
;
justify-content
:
flex-start
;
justify-content
:
flex-start
;
...
@@ -229,13 +269,6 @@ function delTestKey(listdata: any[], delKey = 'test_index') {
...
@@ -229,13 +269,6 @@ function delTestKey(listdata: any[], delKey = 'test_index') {
column-gap
:
10px
;
column-gap
:
10px
;
}
}
.tree-box
{
.tree-box
{
// width: 600px;
transform
:
translateX
(
-20px
);
height
:
500px
;
box-sizing
:
border-box
;
// border: 1px solid brown;
overflow
:
auto
;
>
:nth-child
(
1
)
{
// padding-right: 10px;
}
}
}
</
style
>
</
style
>
src/modules/tree/IndexPage3.vue
deleted
100644 → 0
View file @
589b9c5c
<
template
>
<div
class=
"row"
>
<div
class=
"col-1"
>
<button
class=
"btn btn-secondary button"
@
click=
"add"
>
Add
</button>
</div>
<div
class=
"col-7"
>
<h3>
Draggable
{{
draggingInfo
}}
</h3>
<draggable
tag=
"ul"
:list=
"list"
class=
"list-group"
handle=
".handle"
item-key=
"name"
>
<template
#
item=
"
{ element, index }">
<li
class=
"list-group-item"
>
<i
class=
"fa fa-align-justify handle"
></i>
<span
class=
"text"
>
{{
element
.
name
}}
</span>
<input
type=
"text"
class=
"form-control"
v-model=
"element.text"
/>
<i
class=
"fa fa-times close"
@
click=
"removeAt(index)"
></i>
</li>
</
template
>
</draggable>
</div>
<rawDisplayer
class=
"col-3"
:value=
"list"
title=
"List"
/>
</div>
</template>
<
script
>
let
id
=
3
;
import
draggable
from
'vuedraggable'
;
export
default
{
// eslint-disable-next-line vue/multi-word-component-names
name
:
'handle'
,
display
:
'Handle'
,
instruction
:
'Drag using the handle icon'
,
order
:
5
,
components
:
{
draggable
,
},
data
()
{
return
{
list
:
[
{
name
:
'John'
,
text
:
''
,
id
:
0
},
{
name
:
'Joao'
,
text
:
''
,
id
:
1
},
{
name
:
'Jean'
,
text
:
''
,
id
:
2
},
],
dragging
:
false
,
};
},
computed
:
{
draggingInfo
()
{
return
this
.
dragging
?
'under drag'
:
''
;
},
},
methods
:
{
removeAt
(
idx
)
{
this
.
list
.
splice
(
idx
,
1
);
},
add
:
function
()
{
id
++
;
this
.
list
.
push
({
name
:
'Juan '
+
id
,
id
,
text
:
''
});
},
},
};
</
script
>
<
style
scoped
>
.button
{
margin-top
:
35px
;
}
.handle
{
float
:
left
;
padding-top
:
8px
;
padding-bottom
:
8px
;
}
.close
{
float
:
right
;
padding-top
:
8px
;
padding-bottom
:
8px
;
}
input
{
display
:
inline-block
;
width
:
50%
;
}
.text
{
margin
:
20px
;
}
</
style
>
src/modules/tree/element/nested.vue
0 → 100644
View file @
4b56b9ee
<
template
>
<draggable
class=
"drag-area"
tag=
"div"
:scroll=
"true"
:list=
"tasks"
:group=
"
{ name: 'g1' }"
:item-key="itemKey"
:onEnd="onEnd"
:animation="150"
>
<template
#
item=
"
{ element }">
<div
:class=
"[
'drag-area-item',
`dragareaitem-$
{element.test_index}`,
{ 'has-left-line': hasLeftLine(element.test_index) },
]"
>
<span
class=
"has-left-vertical-line"
:class=
"
{ 'has-left-vertical-line-last': element.lastChild }"
>
</span>
<div
class=
"drag-area-item-conten"
:style=
"
{
paddingLeft: isEmpty(element[childrenKey]) ? '6px' : '0px',
}"
>
<div
class=
"drag-area-item-conten-left"
>
<q-icon
v-if=
"!isEmpty(element[childrenKey])"
@
click=
"element.show = !element.show"
color=
"grey"
name=
"bi-caret-down-fill"
class=
"handle"
:style=
"
{
transform: element.show ? 'rotate(0deg)' : 'rotate(-90deg)',
}"
/>
<input
type=
"text"
class=
"item-conten-input"
v-model=
"element[labelKey]"
/>
</div>
<div
class=
"actions"
>
<q-btn
color=
"grey"
dense
flat
icon=
"bi-hdd-stack-fill"
@
click=
"addItem(element)"
>
<q-tooltip>
同级添加
</q-tooltip>
</q-btn>
<q-btn
color=
"grey"
dense
flat
icon=
"bi-hdd-network-fill"
@
click=
"addNest(element)"
>
<q-tooltip>
子级添加
</q-tooltip>
</q-btn>
<q-btn
color=
"grey"
dense
flat
icon=
"bi-trash"
@
click=
"delItem(element)"
>
<q-tooltip>
删除
</q-tooltip>
</q-btn>
</div>
</div>
<q-slide-transition>
<nested-draggable
v-show=
"element.show"
:tasks=
"element[childrenKey]"
:item-key=
"itemKey"
:children-key=
"childrenKey"
:label-key=
"labelKey"
@
onEnd=
"onEnd"
@
addItem=
"addItem"
@
addNest=
"addNest"
@
delItem=
"delItem"
/>
</q-slide-transition>
</div>
</
template
>
</draggable>
</template>
<
script
>
import
{
computed
}
from
'vue'
;
import
{
isEmpty
}
from
'src/common/utils'
;
import
draggable
from
'vuedraggable'
;
export
default
{
name
:
'nested-draggable'
,
props
:
{
tasks
:
{
required
:
true
,
type
:
Array
,
},
itemKey
:
{
required
:
true
,
type
:
String
,
},
childrenKey
:
{
required
:
true
,
type
:
String
,
},
labelKey
:
{
required
:
true
,
type
:
String
,
},
},
components
:
{
draggable
,
},
setup
(
props
,
ctx
)
{
const
addItem
=
(
data
)
=>
{
ctx
.
emit
(
'addItem'
,
data
);
};
const
addNest
=
(
data
)
=>
{
ctx
.
emit
(
'addNest'
,
data
);
};
const
delItem
=
(
data
)
=>
{
ctx
.
emit
(
'delItem'
,
data
);
};
//
const
onEnd
=
(
data
)
=>
{
ctx
.
emit
(
'onEnd'
,
data
);
};
const
hasLeftLine
=
computed
(()
=>
(
str
)
=>
{
let
falg
;
const
leng
=
str
.
split
(
'-'
);
if
(
leng
.
length
>
1
)
{
falg
=
true
;
}
else
{
falg
=
false
;
}
return
falg
;
});
return
{
isEmpty
,
addItem
,
addNest
,
delItem
,
onEnd
,
hasLeftLine
,
};
},
};
</
script
>
<
style
scoped
lang=
"scss"
>
.drag-area
{
// min-width: 600px;
// min-height: 20px;
overflow
:
auto
;
/* outline: 1px dashed; */
// border: 1px solid red;
padding-left
:
40px
;
&
>
:nth-child
(
1
)
{
margin-top
:
10px
;
}
.drag-area-item
{
position
:
relative
;
// min-width: 600px;
// outline: 1px solid rgba(0, 0, 0, 0.125);
margin-bottom
:
10px
;
// background-color: pink;
.drag-area-item-conten
{
height
:
40px
;
box-sizing
:
border-box
;
background-color
:
rgba
(
0
,
0
,
0
,
0
.075
);
// background-color: pink;
display
:
flex
;
flex-direction
:
row
;
flex-wrap
:
nowrap
;
justify-content
:
space-between
;
.drag-area-item-conten-left
{
// border: 1px solid purple;
// background-color: purple;
display
:
flex
;
flex-direction
:
row
;
align-items
:
center
;
}
.item-conten-input
{
// display: inline-block;
// background-color: #fff;
// display: flex;
// min-width: 180px;
// align-items: center;
outline-style
:
none
;
border
:
1px
solid
rgba
(
0
,
0
,
0
,
0
.075
);
border-radius
:
3px
;
height
:
32px
;
padding
:
0
8px
;
&
:focus
{
// width: fit-content;
border-color
:
$primary
;
outline
:
0
;
-webkit-box-shadow
:
inset
0
1px
1px
rgba
(
0
,
0
,
0
,
0
.075
)
,
0
0
8px
$primary-1
;
box-shadow
:
inset
0
1px
1px
rgba
(
0
,
0
,
0
,
0
.075
)
,
0
0
8px
$primary-1
;
}
}
.actions
{
padding
:
10px
;
display
:
flex
;
flex-direction
:
row
;
justify-content
:
flex-start
;
align-items
:
center
;
column-gap
:
10px
;
}
}
}
.has-left-line
{
&
:
:
before
{
content
:
''
;
position
:
absolute
;
top
:
18px
;
left
:
-40px
;
box-sizing
:
border-box
;
width
:
36px
;
border-top
:
1px
solid
rgba
(
0
,
0
,
0
,
0
.125
);
}
}
.has-left-vertical-line
{
display
:
inline-block
;
position
:
absolute
;
box-sizing
:
border-box
;
// width: 50px;
height
:
calc
(
100%
+
10px
);
left
:
-40px
;
top
:
-10px
;
border-left
:
1px
solid
rgba
(
0
,
0
,
0
,
0
.125
);
}
.has-left-vertical-line-last
{
// border-color: green;
height
:
30px
;
}
.handle
{
float
:
left
;
padding
:
4px
8px
;
font-size
:
16px
;
cursor
:
pointer
;
// border: 1px solid red;
transition
:
transform
0
.3s
;
}
}
</
style
>
src/modules/tree/infra/nested.vue
deleted
100644 → 0
View file @
589b9c5c
<
template
>
<draggable
class=
"drag-area"
tag=
"div"
:list=
"tasks"
:group=
"
{ name: 'g1' }"
handle=".handle-icon"
item-key="key"
:onEnd="onEnd"
:animation="150"
>
<template
#
item=
"
{ element }">
<div
class=
"item"
>
<div>
<div
:class=
"['toggle-box',
{ 'toggle-box-btn': !element.show }]">
<div
class=
"toggle-left-content"
>
<q-icon
name=
"fa-solid fa-bars"
class=
"handle-icon"
/>
<input
type=
"text"
class=
"input-control"
v-model=
"element.name"
/>
</div>
<div
class=
"toggle-right-content"
>
<q-btn
flat
dense
label=
"同级添加"
@
click=
"addItem(element)"
/>
<q-btn
flat
dense
label=
"子级添加"
@
click=
"addNest(element)"
/>
<q-btn
flat
dense
label=
"删除"
style=
"margin-right: 20px"
@
click=
"delItem(element)"
/>
<q-icon
v-if=
"!isEmpty(element.tasks)"
name=
"bi-chevron-down"
:class=
"[
'expansion-icon',
{ 'expansion-icon-hide': !element.show },
]"
@click="element.show = !element.show"
/>
</div>
</div>
<q-slide-transition>
<div
v-show=
"element.show"
class=
"content"
>
<div
:class=
"[
'placeholder',
{ 'placeholder-last': isEmpty(element.tasks) },
]"
>
</div>
<nested-draggable
v-show=
"element.show"
:tasks=
"element.tasks"
@
onEnd=
"onEnd"
@
addItem=
"addItem"
@
addNest=
"addNest"
@
delItem=
"delItem"
/>
</div>
</q-slide-transition>
</div>
</div>
</
template
>
</draggable>
</template>
<
script
>
// import { ref } from 'vue';
import
{
isEmpty
}
from
'src/common/utils'
;
import
draggable
from
'vuedraggable'
;
export
default
{
name
:
'nested-draggable'
,
props
:
{
tasks
:
{
required
:
true
,
type
:
Array
,
},
},
components
:
{
draggable
,
},
setup
(
props
,
ctx
)
{
const
addItem
=
(
data
)
=>
{
ctx
.
emit
(
'addItem'
,
data
);
};
const
addNest
=
(
data
)
=>
{
ctx
.
emit
(
'addNest'
,
data
);
};
const
delItem
=
(
data
)
=>
{
ctx
.
emit
(
'delItem'
,
data
);
};
// 拖拽结束
const
onEnd
=
(
data
)
=>
{
ctx
.
emit
(
'onEnd'
,
data
);
};
return
{
isEmpty
,
addItem
,
addNest
,
delItem
,
onEnd
,
};
},
};
</
script
>
<
style
scoped
lang=
"scss"
>
.drag-area
{
// border: 1px solid red;
}
.item
{
// outline: 1px solid rgba(0, 0, 0, 0.035);
// background-color: pink;
background-color
:
rgba
(
0
,
0
,
0
,
0
.035
);
margin
:
10px
0
;
padding-left
:
10px
;
margin-left
:
20px
;
margin-top
:
10px
;
transition
:
height
0
.3s
;
}
.toggle-box
{
display
:
flex
;
flex-direction
:
row
;
justify-content
:
space-between
;
align-items
:
center
;
padding-top
:
8px
;
// padding-bottom: 6px;
padding-right
:
10px
;
}
.toggle-box-btn
{
padding-bottom
:
6px
;
}
.toggle-left-content
{
display
:
flex
;
flex-direction
:
row
;
justify-content
:
space-between
;
align-items
:
center
;
column-gap
:
10px
;
}
.toggle-right-content
{
display
:
grid
;
grid-template-columns
:
70px
70px
60px
30px
;
align-items
:
center
;
}
.handle-icon
{
font-size
:
18px
;
box-sizing
:
border-box
;
display
:
inline-block
;
// border: 1px solid red;
cursor
:
grab
;
}
.expansion-icon
{
font-size
:
16px
;
cursor
:
pointer
;
transform
:
rotate
(
180deg
);
transition
:
transform
0
.3s
;
}
.expansion-icon-hide
{
transform
:
rotate
(
0
);
transition
:
transform
0
.3s
;
}
.content
{
// height: 46px;
// background-color: pink;
}
.placeholder
{
height
:
20px
;
// background-color: pink;
}
.placeholder-last
{
height
:
6px
;
// background-color: pink;
}
.input-control
{
outline-style
:
none
;
border
:
1px
solid
rgba
(
0
,
0
,
0
,
0
.035
);
border-radius
:
3px
;
height
:
32px
;
padding
:
0
6px
;
&
:focus
{
border-color
:
$primary
;
outline
:
0
;
-webkit-box-shadow
:
inset
0
1px
1px
rgba
(
0
,
0
,
0
,
0
.075
)
,
0
0
8px
$primary-1
;
box-shadow
:
inset
0
1px
1px
rgba
(
0
,
0
,
0
,
0
.075
)
,
0
0
8px
$primary-1
;
}
}
</
style
>
src/modules/tree/infra/nested3.vue
deleted
100644 → 0
View file @
589b9c5c
<
template
>
<draggable
class=
"drag-area"
tag=
"div"
:list=
"tasks"
handle=
".handle"
:group=
"
{ name: 'g1' }"
item-key="key"
:onEnd="onEnd"
:animation="150"
>
<template
#
item=
"
{ element }">
<div
class=
"drag-area-item"
>
<div
class=
"drag-area-item-conten"
>
<!--
<div
class=
"text"
>
{{
element
.
name
}}
</div>
-->
<div>
<i
class=
"fa fa-align-justify handle"
></i>
<input
type=
"text"
class=
"form-control"
v-model=
"element.name"
/>
</div>
<div
class=
"actions"
>
<q-btn
color=
"primary"
icon=
"bi-list"
@
click=
"addItem(element)"
/>
<q-btn
color=
"primary"
icon=
"bi-list-nested"
@
click=
"addNest(element)"
/>
<q-btn
color=
"primary"
label=
"删除"
@
click=
"delItem(element)"
/>
</div>
</div>
<nested-draggable
:tasks=
"element.tasks"
@
onEnd=
"onEnd"
@
addItem=
"addItem"
@
addNest=
"addNest"
@
delItem=
"delItem"
/>
</div>
</
template
>
</draggable>
</template>
<
script
>
import
{
isEmpty
}
from
'src/common/utils'
;
import
draggable
from
'vuedraggable'
;
export
default
{
name
:
'nested-draggable'
,
props
:
{
tasks
:
{
required
:
true
,
type
:
Array
,
},
},
components
:
{
draggable
,
},
setup
(
props
,
ctx
)
{
const
addItem
=
(
data
)
=>
{
ctx
.
emit
(
'addItem'
,
data
);
};
const
addNest
=
(
data
)
=>
{
ctx
.
emit
(
'addNest'
,
data
);
};
const
delItem
=
(
data
)
=>
{
ctx
.
emit
(
'delItem'
,
data
);
};
// 拖拽结束
const
onEnd
=
(
data
)
=>
{
ctx
.
emit
(
'onEnd'
,
data
);
};
return
{
isEmpty
,
addItem
,
addNest
,
delItem
,
onEnd
,
};
},
};
</
script
>
<
style
scoped
lang=
"scss"
>
.drag-area
{
min-width
:
450px
;
// min-height: 20px;
overflow
:
auto
;
/* outline: 1px dashed; */
border
:
1px
solid
red
;
padding-left
:
40px
;
&
>
:nth-child
(
1
)
{
margin-top
:
10px
;
}
.drag-area-item
{
min-width
:
450px
;
outline
:
1px
solid
#1ee3cf
;
margin-bottom
:
10px
;
.drag-area-item-conten
{
height
:
40px
;
box-sizing
:
border-box
;
background-color
:
#f9bcdd
;
display
:
flex
;
flex-direction
:
row
;
flex-wrap
:
nowrap
;
justify-content
:
space-between
;
.actions
{
padding
:
10px
;
display
:
flex
;
flex-direction
:
row
;
justify-content
:
flex-start
;
align-items
:
center
;
column-gap
:
10px
;
}
}
}
.handle
{
float
:
left
;
padding
:
8px
;
}
}
</
style
>
src/modules/tree/route.ts
View file @
4b56b9ee
...
@@ -4,7 +4,7 @@ export default [
...
@@ -4,7 +4,7 @@ export default [
name
:
'TREE'
,
name
:
'TREE'
,
component
:
()
=>
import
(
'./IndexPage.vue'
),
component
:
()
=>
import
(
'./IndexPage.vue'
),
meta
:
{
meta
:
{
title
:
'
树
'
,
title
:
'
Tree
'
,
permission
:
[
'*'
],
permission
:
[
'*'
],
keepalive
:
true
,
keepalive
:
true
,
},
},
...
...
src/router/routes.ts
View file @
4b56b9ee
...
@@ -30,7 +30,7 @@ const routes: RouteRecordRaw[] = [
...
@@ -30,7 +30,7 @@ const routes: RouteRecordRaw[] = [
name
:
'PAGE1'
,
name
:
'PAGE1'
,
component
:
()
=>
import
(
'../modules/page1/IndexPage.vue'
),
component
:
()
=>
import
(
'../modules/page1/IndexPage.vue'
),
meta
:
{
meta
:
{
title
:
'
页面1
'
,
title
:
'
图表
'
,
permission
:
[
'*'
],
permission
:
[
'*'
],
keepalive
:
true
,
keepalive
:
true
,
},
},
...
@@ -40,7 +40,7 @@ const routes: RouteRecordRaw[] = [
...
@@ -40,7 +40,7 @@ const routes: RouteRecordRaw[] = [
name
:
'PAGE2'
,
name
:
'PAGE2'
,
component
:
()
=>
import
(
'../modules/page2/IndexPage.vue'
),
component
:
()
=>
import
(
'../modules/page2/IndexPage.vue'
),
meta
:
{
meta
:
{
title
:
'
页面2
'
,
title
:
'
表单
'
,
permission
:
[
'*'
],
permission
:
[
'*'
],
keepalive
:
true
,
keepalive
:
true
,
},
},
...
@@ -50,7 +50,7 @@ const routes: RouteRecordRaw[] = [
...
@@ -50,7 +50,7 @@ const routes: RouteRecordRaw[] = [
name
:
'PAGE4'
,
name
:
'PAGE4'
,
component
:
()
=>
import
(
'../modules/page4/IndexPage.vue'
),
component
:
()
=>
import
(
'../modules/page4/IndexPage.vue'
),
meta
:
{
meta
:
{
title
:
'
页面4
'
,
title
:
'
canvas
'
,
permission
:
[
'*'
],
permission
:
[
'*'
],
keepalive
:
true
,
keepalive
:
true
,
},
},
...
@@ -60,7 +60,7 @@ const routes: RouteRecordRaw[] = [
...
@@ -60,7 +60,7 @@ const routes: RouteRecordRaw[] = [
name
:
'PAGE5'
,
name
:
'PAGE5'
,
component
:
()
=>
import
(
'../modules/page5/IndexPage.vue'
),
component
:
()
=>
import
(
'../modules/page5/IndexPage.vue'
),
meta
:
{
meta
:
{
title
:
'
页面5
'
,
title
:
'
防抖节流
'
,
permission
:
[
'*'
],
permission
:
[
'*'
],
keepalive
:
true
,
keepalive
:
true
,
},
},
...
@@ -70,7 +70,7 @@ const routes: RouteRecordRaw[] = [
...
@@ -70,7 +70,7 @@ const routes: RouteRecordRaw[] = [
name
:
'PAGE7'
,
name
:
'PAGE7'
,
component
:
()
=>
import
(
'../modules/page7/IndexPage.vue'
),
component
:
()
=>
import
(
'../modules/page7/IndexPage.vue'
),
meta
:
{
meta
:
{
title
:
'
页面7
'
,
title
:
'
疫情防控
'
,
permission
:
[
'*'
],
permission
:
[
'*'
],
keepalive
:
true
,
keepalive
:
true
,
},
},
...
@@ -90,7 +90,7 @@ const routes: RouteRecordRaw[] = [
...
@@ -90,7 +90,7 @@ const routes: RouteRecordRaw[] = [
name
:
'PAGE9'
,
name
:
'PAGE9'
,
component
:
()
=>
import
(
'../modules/page9/IndexPage.vue'
),
component
:
()
=>
import
(
'../modules/page9/IndexPage.vue'
),
meta
:
{
meta
:
{
title
:
'
动画2&
表格'
,
title
:
'表格'
,
permission
:
[
'*'
],
permission
:
[
'*'
],
keepalive
:
true
,
keepalive
:
true
,
},
},
...
@@ -110,7 +110,7 @@ const routes: RouteRecordRaw[] = [
...
@@ -110,7 +110,7 @@ const routes: RouteRecordRaw[] = [
name
:
'JS_PAGE3'
,
name
:
'JS_PAGE3'
,
component
:
()
=>
import
(
'../modules/page3/IndexPage.vue'
),
component
:
()
=>
import
(
'../modules/page3/IndexPage.vue'
),
meta
:
{
meta
:
{
title
:
'
页面3
'
,
title
:
'
链表
'
,
permission
:
[
'*'
],
permission
:
[
'*'
],
keepalive
:
true
,
keepalive
:
true
,
},
},
...
@@ -120,7 +120,7 @@ const routes: RouteRecordRaw[] = [
...
@@ -120,7 +120,7 @@ const routes: RouteRecordRaw[] = [
name
:
'JS_PAGE6'
,
name
:
'JS_PAGE6'
,
component
:
()
=>
import
(
'../modules/page6/IndexPage.vue'
),
component
:
()
=>
import
(
'../modules/page6/IndexPage.vue'
),
meta
:
{
meta
:
{
title
:
'
一些js练习
'
,
title
:
'
JS
'
,
permission
:
[
'*'
],
permission
:
[
'*'
],
keepalive
:
true
,
keepalive
:
true
,
},
},
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment