Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
jinli gu
RuoYi Vue
Commits
46444bd0
Commit
46444bd0
authored
Oct 08, 2019
by
RuoYi
Browse files
RuoYi-Vue 1.0
parent
5bc74554
Changes
400
Show whitespace changes
Inline
Side-by-side
ruoyi-ui/src/components/Pagination/index.vue
0 → 100644
View file @
46444bd0
<
template
>
<div
:class=
"
{'hidden':hidden}" class="pagination-container">
<el-pagination
:background=
"background"
:current-page.sync=
"currentPage"
:page-size.sync=
"pageSize"
:layout=
"layout"
:page-sizes=
"pageSizes"
:total=
"total"
v-bind=
"$attrs"
@
size-change=
"handleSizeChange"
@
current-change=
"handleCurrentChange"
/>
</div>
</
template
>
<
script
>
import
{
scrollTo
}
from
'
@/utils/scroll-to
'
export
default
{
name
:
'
Pagination
'
,
props
:
{
total
:
{
required
:
true
,
type
:
Number
},
page
:
{
type
:
Number
,
default
:
1
},
limit
:
{
type
:
Number
,
default
:
20
},
pageSizes
:
{
type
:
Array
,
default
()
{
return
[
10
,
20
,
30
,
50
]
}
},
layout
:
{
type
:
String
,
default
:
'
total, sizes, prev, pager, next, jumper
'
},
background
:
{
type
:
Boolean
,
default
:
true
},
autoScroll
:
{
type
:
Boolean
,
default
:
true
},
hidden
:
{
type
:
Boolean
,
default
:
false
}
},
computed
:
{
currentPage
:
{
get
()
{
return
this
.
page
},
set
(
val
)
{
this
.
$emit
(
'
update:page
'
,
val
)
}
},
pageSize
:
{
get
()
{
return
this
.
limit
},
set
(
val
)
{
this
.
$emit
(
'
update:limit
'
,
val
)
}
}
},
methods
:
{
handleSizeChange
(
val
)
{
this
.
$emit
(
'
pagination
'
,
{
page
:
this
.
currentPage
,
limit
:
val
})
if
(
this
.
autoScroll
)
{
scrollTo
(
0
,
800
)
}
},
handleCurrentChange
(
val
)
{
this
.
$emit
(
'
pagination
'
,
{
page
:
val
,
limit
:
this
.
pageSize
})
if
(
this
.
autoScroll
)
{
scrollTo
(
0
,
800
)
}
}
}
}
</
script
>
<
style
scoped
>
.pagination-container
{
background
:
#fff
;
padding
:
32px
16px
;
}
.pagination-container.hidden
{
display
:
none
;
}
</
style
>
ruoyi-ui/src/components/PanThumb/index.vue
0 → 100644
View file @
46444bd0
<
template
>
<div
:style=
"
{zIndex:zIndex,height:height,width:width}" class="pan-item">
<div
class=
"pan-info"
>
<div
class=
"pan-info-roles-container"
>
<slot
/>
</div>
</div>
<!-- eslint-disable-next-line -->
<div
:style=
"
{backgroundImage: `url(${image})`}" class="pan-thumb">
</div>
</div>
</
template
>
<
script
>
export
default
{
name
:
'
PanThumb
'
,
props
:
{
image
:
{
type
:
String
,
required
:
true
},
zIndex
:
{
type
:
Number
,
default
:
1
},
width
:
{
type
:
String
,
default
:
'
150px
'
},
height
:
{
type
:
String
,
default
:
'
150px
'
}
}
}
</
script
>
<
style
scoped
>
.pan-item
{
width
:
200px
;
height
:
200px
;
border-radius
:
50%
;
display
:
inline-block
;
position
:
relative
;
cursor
:
default
;
box-shadow
:
0
1px
3px
rgba
(
0
,
0
,
0
,
0.2
);
}
.pan-info-roles-container
{
padding
:
20px
;
text-align
:
center
;
}
.pan-thumb
{
width
:
100%
;
height
:
100%
;
background-position
:
center
center
;
background-size
:
cover
;
border-radius
:
50%
;
overflow
:
hidden
;
position
:
absolute
;
transform-origin
:
95%
40%
;
transition
:
all
0.3s
ease-in-out
;
}
/* .pan-thumb:after {
content: '';
width: 8px;
height: 8px;
position: absolute;
border-radius: 50%;
top: 40%;
left: 95%;
margin: -4px 0 0 -4px;
background: radial-gradient(ellipse at center, rgba(14, 14, 14, 1) 0%, rgba(125, 126, 125, 1) 100%);
box-shadow: 0 0 1px rgba(255, 255, 255, 0.9);
} */
.pan-info
{
position
:
absolute
;
width
:
inherit
;
height
:
inherit
;
border-radius
:
50%
;
overflow
:
hidden
;
box-shadow
:
inset
0
0
0
5px
rgba
(
0
,
0
,
0
,
0.05
);
}
.pan-info
h3
{
color
:
#fff
;
text-transform
:
uppercase
;
position
:
relative
;
letter-spacing
:
2px
;
font-size
:
18px
;
margin
:
0
60px
;
padding
:
22px
0
0
0
;
height
:
85px
;
font-family
:
'Open Sans'
,
Arial
,
sans-serif
;
text-shadow
:
0
0
1px
#fff
,
0
1px
2px
rgba
(
0
,
0
,
0
,
0.3
);
}
.pan-info
p
{
color
:
#fff
;
padding
:
10px
5px
;
font-style
:
italic
;
margin
:
0
30px
;
font-size
:
12px
;
border-top
:
1px
solid
rgba
(
255
,
255
,
255
,
0.5
);
}
.pan-info
p
a
{
display
:
block
;
color
:
#333
;
width
:
80px
;
height
:
80px
;
background
:
rgba
(
255
,
255
,
255
,
0.3
);
border-radius
:
50%
;
color
:
#fff
;
font-style
:
normal
;
font-weight
:
700
;
text-transform
:
uppercase
;
font-size
:
9px
;
letter-spacing
:
1px
;
padding-top
:
24px
;
margin
:
7px
auto
0
;
font-family
:
'Open Sans'
,
Arial
,
sans-serif
;
opacity
:
0
;
transition
:
transform
0.3s
ease-in-out
0.2s
,
opacity
0.3s
ease-in-out
0.2s
,
background
0.2s
linear
0s
;
transform
:
translateX
(
60px
)
rotate
(
90deg
);
}
.pan-info
p
a
:hover
{
background
:
rgba
(
255
,
255
,
255
,
0.5
);
}
.pan-item
:hover
.pan-thumb
{
transform
:
rotate
(
-110deg
);
}
.pan-item
:hover
.pan-info
p
a
{
opacity
:
1
;
transform
:
translateX
(
0px
)
rotate
(
0deg
);
}
</
style
>
ruoyi-ui/src/components/RightPanel/index.vue
0 → 100644
View file @
46444bd0
<
template
>
<div
ref=
"rightPanel"
:class=
"
{show:show}" class="rightPanel-container">
<div
class=
"rightPanel-background"
/>
<div
class=
"rightPanel"
>
<div
class=
"rightPanel-items"
>
<slot
/>
</div>
</div>
</div>
</
template
>
<
script
>
import
{
addClass
,
removeClass
}
from
'
@/utils
'
export
default
{
name
:
'
RightPanel
'
,
props
:
{
clickNotClose
:
{
default
:
false
,
type
:
Boolean
},
buttonTop
:
{
default
:
250
,
type
:
Number
}
},
computed
:
{
show
:
{
get
()
{
return
this
.
$store
.
state
.
settings
.
showSettings
},
set
(
val
)
{
this
.
$store
.
dispatch
(
'
settings/changeSetting
'
,
{
key
:
'
showSettings
'
,
value
:
val
})
}
},
theme
()
{
return
this
.
$store
.
state
.
settings
.
theme
},
},
watch
:
{
show
(
value
)
{
if
(
value
&&
!
this
.
clickNotClose
)
{
this
.
addEventClick
()
}
if
(
value
)
{
addClass
(
document
.
body
,
'
showRightPanel
'
)
}
else
{
removeClass
(
document
.
body
,
'
showRightPanel
'
)
}
}
},
mounted
()
{
this
.
insertToBody
()
this
.
addEventClick
()
},
beforeDestroy
()
{
const
elx
=
this
.
$refs
.
rightPanel
elx
.
remove
()
},
methods
:
{
addEventClick
()
{
window
.
addEventListener
(
'
click
'
,
this
.
closeSidebar
)
},
closeSidebar
(
evt
)
{
const
parent
=
evt
.
target
.
closest
(
'
.rightPanel
'
)
if
(
!
parent
)
{
this
.
show
=
false
window
.
removeEventListener
(
'
click
'
,
this
.
closeSidebar
)
}
},
insertToBody
()
{
const
elx
=
this
.
$refs
.
rightPanel
const
body
=
document
.
querySelector
(
'
body
'
)
body
.
insertBefore
(
elx
,
body
.
firstChild
)
}
}
}
</
script
>
<
style
>
.showRightPanel
{
overflow
:
hidden
;
position
:
relative
;
width
:
calc
(
100%
-
15px
);
}
</
style
>
<
style
lang=
"scss"
scoped
>
.rightPanel-background
{
position
:
fixed
;
top
:
0
;
left
:
0
;
opacity
:
0
;
transition
:
opacity
.3s
cubic-bezier
(
.7
,
.3
,
.1
,
1
);
background
:
rgba
(
0
,
0
,
0
,
.2
);
z-index
:
-1
;
}
.rightPanel
{
width
:
100%
;
max-width
:
260px
;
height
:
100vh
;
position
:
fixed
;
top
:
0
;
right
:
0
;
box-shadow
:
0px
0px
15px
0px
rgba
(
0
,
0
,
0
,
.05
);
transition
:
all
.25s
cubic-bezier
(
.7
,
.3
,
.1
,
1
);
transform
:
translate
(
100%
);
background
:
#fff
;
z-index
:
40000
;
}
.show
{
transition
:
all
.3s
cubic-bezier
(
.7
,
.3
,
.1
,
1
);
.rightPanel-background
{
z-index
:
20000
;
opacity
:
1
;
width
:
100%
;
height
:
100%
;
}
.rightPanel
{
transform
:
translate
(
0
);
}
}
.handle-button
{
width
:
48px
;
height
:
48px
;
position
:
absolute
;
left
:
-48px
;
text-align
:
center
;
font-size
:
24px
;
border-radius
:
6px
0
0
6px
!
important
;
z-index
:
0
;
pointer-events
:
auto
;
cursor
:
pointer
;
color
:
#fff
;
line-height
:
48px
;
i
{
font-size
:
24px
;
line-height
:
48px
;
}
}
</
style
>
ruoyi-ui/src/components/RuoYi/index.vue
0 → 100644
View file @
46444bd0
<
template
>
<div>
<svg-icon
icon-class=
"download"
@
click=
"handleDownload"
/>
</div>
</
template
>
<
script
>
export
default
{
name
:
'
RuoYi
'
,
data
()
{
return
{
url
:
'
https://gitee.com/y_project/RuoYi-Vue
'
}
},
methods
:
{
handleDownload
()
{
window
.
open
(
this
.
url
)
}
}
}
</
script
>
\ No newline at end of file
ruoyi-ui/src/components/Screenfull/index.vue
0 → 100644
View file @
46444bd0
<
template
>
<div>
<svg-icon
:icon-class=
"isFullscreen?'exit-fullscreen':'fullscreen'"
@
click=
"click"
/>
</div>
</
template
>
<
script
>
import
screenfull
from
'
screenfull
'
export
default
{
name
:
'
Screenfull
'
,
data
()
{
return
{
isFullscreen
:
false
}
},
mounted
()
{
this
.
init
()
},
beforeDestroy
()
{
this
.
destroy
()
},
methods
:
{
click
()
{
if
(
!
screenfull
.
enabled
)
{
this
.
$message
({
message
:
'
you browser can not work
'
,
type
:
'
warning
'
})
return
false
}
screenfull
.
toggle
()
},
change
()
{
this
.
isFullscreen
=
screenfull
.
isFullscreen
},
init
()
{
if
(
screenfull
.
enabled
)
{
screenfull
.
on
(
'
change
'
,
this
.
change
)
}
},
destroy
()
{
if
(
screenfull
.
enabled
)
{
screenfull
.
off
(
'
change
'
,
this
.
change
)
}
}
}
}
</
script
>
<
style
scoped
>
.screenfull-svg
{
display
:
inline-block
;
cursor
:
pointer
;
fill
:
#5a5e66
;
;
width
:
20px
;
height
:
20px
;
vertical-align
:
10px
;
}
</
style
>
ruoyi-ui/src/components/SizeSelect/index.vue
0 → 100644
View file @
46444bd0
<
template
>
<el-dropdown
trigger=
"click"
@
command=
"handleSetSize"
>
<div>
<svg-icon
class-name=
"size-icon"
icon-class=
"size"
/>
</div>
<el-dropdown-menu
slot=
"dropdown"
>
<el-dropdown-item
v-for=
"item of sizeOptions"
:key=
"item.value"
:disabled=
"size===item.value"
:command=
"item.value"
>
{{
item
.
label
}}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</
template
>
<
script
>
export
default
{
data
()
{
return
{
sizeOptions
:
[
{
label
:
'
Default
'
,
value
:
'
default
'
},
{
label
:
'
Medium
'
,
value
:
'
medium
'
},
{
label
:
'
Small
'
,
value
:
'
small
'
},
{
label
:
'
Mini
'
,
value
:
'
mini
'
}
]
}
},
computed
:
{
size
()
{
return
this
.
$store
.
getters
.
size
}
},
methods
:
{
handleSetSize
(
size
)
{
this
.
$ELEMENT
.
size
=
size
this
.
$store
.
dispatch
(
'
app/setSize
'
,
size
)
this
.
refreshView
()
this
.
$message
({
message
:
'
Switch Size Success
'
,
type
:
'
success
'
})
},
refreshView
()
{
// In order to make the cached page re-rendered
this
.
$store
.
dispatch
(
'
tagsView/delAllCachedViews
'
,
this
.
$route
)
const
{
fullPath
}
=
this
.
$route
this
.
$nextTick
(()
=>
{
this
.
$router
.
replace
({
path
:
'
/redirect
'
+
fullPath
})
})
}
}
}
</
script
>
ruoyi-ui/src/components/SvgIcon/index.vue
0 → 100644
View file @
46444bd0
<
template
>
<div
v-if=
"isExternal"
:style=
"styleExternalIcon"
class=
"svg-external-icon svg-icon"
v-on=
"$listeners"
/>
<svg
v-else
:class=
"svgClass"
aria-hidden=
"true"
v-on=
"$listeners"
>
<use
:xlink:href=
"iconName"
/>
</svg>
</
template
>
<
script
>
import
{
isExternal
}
from
'
@/utils/validate
'
export
default
{
name
:
'
SvgIcon
'
,
props
:
{
iconClass
:
{
type
:
String
,
required
:
true
},
className
:
{
type
:
String
,
default
:
''
}
},
computed
:
{
isExternal
()
{
return
isExternal
(
this
.
iconClass
)
},
iconName
()
{
return
`#icon-
${
this
.
iconClass
}
`
},
svgClass
()
{
if
(
this
.
className
)
{
return
'
svg-icon
'
+
this
.
className
}
else
{
return
'
svg-icon
'
}
},
styleExternalIcon
()
{
return
{
mask
:
`url(
${
this
.
iconClass
}
) no-repeat 50% 50%`
,
'
-webkit-mask
'
:
`url(
${
this
.
iconClass
}
) no-repeat 50% 50%`
}
}
}
}
</
script
>
<
style
scoped
>
.svg-icon
{
width
:
1em
;
height
:
1em
;
vertical-align
:
-0.15em
;
fill
:
currentColor
;
overflow
:
hidden
;
}
.svg-external-icon
{
background-color
:
currentColor
;
mask-size
:
cover
!important
;
display
:
inline-block
;
}
</
style
>
ruoyi-ui/src/components/ThemePicker/index.vue
0 → 100644
View file @
46444bd0
<
template
>
<el-color-picker
v-model=
"theme"
:predefine=
"['#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
class=
"theme-picker"
popper-class=
"theme-picker-dropdown"
/>
</
template
>
<
script
>
const
version
=
require
(
'
element-ui/package.json
'
).
version
// element-ui version from node_modules
const
ORIGINAL_THEME
=
'
#409EFF
'
// default color
export
default
{
data
()
{
return
{
chalk
:
''
,
// content of theme-chalk css
theme
:
''
}
},
computed
:
{
defaultTheme
()
{
return
this
.
$store
.
state
.
settings
.
theme
}
},
watch
:
{
defaultTheme
:
{
handler
:
function
(
val
,
oldVal
)
{
this
.
theme
=
val
},
immediate
:
true
},
async
theme
(
val
)
{
const
oldVal
=
this
.
chalk
?
this
.
theme
:
ORIGINAL_THEME
if
(
typeof
val
!==
'
string
'
)
return
const
themeCluster
=
this
.
getThemeCluster
(
val
.
replace
(
'
#
'
,
''
))
const
originalCluster
=
this
.
getThemeCluster
(
oldVal
.
replace
(
'
#
'
,
''
))
console
.
log
(
themeCluster
,
originalCluster
)
const
$message
=
this
.
$message
({
message
:
'
Compiling the theme
'
,
customClass
:
'
theme-message
'
,
type
:
'
success
'
,
duration
:
0
,
iconClass
:
'
el-icon-loading
'
})
const
getHandler
=
(
variable
,
id
)
=>
{
return
()
=>
{
const
originalCluster
=
this
.
getThemeCluster
(
ORIGINAL_THEME
.
replace
(
'
#
'
,
''
))
const
newStyle
=
this
.
updateStyle
(
this
[
variable
],
originalCluster
,
themeCluster
)
let
styleTag
=
document
.
getElementById
(
id
)
if
(
!
styleTag
)
{
styleTag
=
document
.
createElement
(
'
style
'
)
styleTag
.
setAttribute
(
'
id
'
,
id
)
document
.
head
.
appendChild
(
styleTag
)
}
styleTag
.
innerText
=
newStyle
}
}
if
(
!
this
.
chalk
)
{
const
url
=
`https://unpkg.com/element-ui@
${
version
}
/lib/theme-chalk/index.css`
await
this
.
getCSSString
(
url
,
'
chalk
'
)
}
const
chalkHandler
=
getHandler
(
'
chalk
'
,
'
chalk-style
'
)
chalkHandler
()
const
styles
=
[].
slice
.
call
(
document
.
querySelectorAll
(
'
style
'
))
.
filter
(
style
=>
{
const
text
=
style
.
innerText
return
new
RegExp
(
oldVal
,
'
i
'
).
test
(
text
)
&&
!
/Chalk Variables/
.
test
(
text
)
})
styles
.
forEach
(
style
=>
{
const
{
innerText
}
=
style
if
(
typeof
innerText
!==
'
string
'
)
return
style
.
innerText
=
this
.
updateStyle
(
innerText
,
originalCluster
,
themeCluster
)
})
this
.
$emit
(
'
change
'
,
val
)
$message
.
close
()
}
},
methods
:
{
updateStyle
(
style
,
oldCluster
,
newCluster
)
{
let
newStyle
=
style
oldCluster
.
forEach
((
color
,
index
)
=>
{
newStyle
=
newStyle
.
replace
(
new
RegExp
(
color
,
'
ig
'
),
newCluster
[
index
])
})
return
newStyle
},
getCSSString
(
url
,
variable
)
{
return
new
Promise
(
resolve
=>
{
const
xhr
=
new
XMLHttpRequest
()
xhr
.
onreadystatechange
=
()
=>
{
if
(
xhr
.
readyState
===
4
&&
xhr
.
status
===
200
)
{
this
[
variable
]
=
xhr
.
responseText
.
replace
(
/@font-face{
[^
}
]
+}/
,
''
)
resolve
()
}
}
xhr
.
open
(
'
GET
'
,
url
)
xhr
.
send
()
})
},
getThemeCluster
(
theme
)
{
const
tintColor
=
(
color
,
tint
)
=>
{
let
red
=
parseInt
(
color
.
slice
(
0
,
2
),
16
)
let
green
=
parseInt
(
color
.
slice
(
2
,
4
),
16
)
let
blue
=
parseInt
(
color
.
slice
(
4
,
6
),
16
)
if
(
tint
===
0
)
{
// when primary color is in its rgb space
return
[
red
,
green
,
blue
].
join
(
'
,
'
)
}
else
{
red
+=
Math
.
round
(
tint
*
(
255
-
red
))
green
+=
Math
.
round
(
tint
*
(
255
-
green
))
blue
+=
Math
.
round
(
tint
*
(
255
-
blue
))
red
=
red
.
toString
(
16
)
green
=
green
.
toString
(
16
)
blue
=
blue
.
toString
(
16
)
return
`#
${
red
}${
green
}${
blue
}
`
}
}
const
shadeColor
=
(
color
,
shade
)
=>
{
let
red
=
parseInt
(
color
.
slice
(
0
,
2
),
16
)
let
green
=
parseInt
(
color
.
slice
(
2
,
4
),
16
)
let
blue
=
parseInt
(
color
.
slice
(
4
,
6
),
16
)
red
=
Math
.
round
((
1
-
shade
)
*
red
)
green
=
Math
.
round
((
1
-
shade
)
*
green
)
blue
=
Math
.
round
((
1
-
shade
)
*
blue
)
red
=
red
.
toString
(
16
)
green
=
green
.
toString
(
16
)
blue
=
blue
.
toString
(
16
)
return
`#
${
red
}${
green
}${
blue
}
`
}
const
clusters
=
[
theme
]
for
(
let
i
=
0
;
i
<=
9
;
i
++
)
{
clusters
.
push
(
tintColor
(
theme
,
Number
((
i
/
10
).
toFixed
(
2
))))
}
clusters
.
push
(
shadeColor
(
theme
,
0.1
))
return
clusters
}
}
}
</
script
>
<
style
>
.theme-message
,
.theme-picker-dropdown
{
z-index
:
99999
!important
;
}
.theme-picker
.el-color-picker__trigger
{
height
:
26px
!important
;
width
:
26px
!important
;
padding
:
2px
;
}
.theme-picker-dropdown
.el-color-dropdown__link-btn
{
display
:
none
;
}
</
style
>
ruoyi-ui/src/directive/permission/hasPermi.js
0 → 100644
View file @
46444bd0
/**
* 操作权限处理
* Copyright (c) 2019 ruoyi
*/
import
store
from
'
@/store
'
export
default
{
inserted
(
el
,
binding
,
vnode
)
{
const
{
value
}
=
binding
const
all_permission
=
"
*:*:*
"
;
const
permissions
=
store
.
getters
&&
store
.
getters
.
permissions
if
(
value
&&
value
instanceof
Array
&&
value
.
length
>
0
)
{
const
permissionFlag
=
value
const
hasPermissions
=
permissions
.
some
(
permission
=>
{
return
all_permission
===
permission
||
permissionFlag
.
includes
(
permission
)
})
if
(
!
hasPermissions
)
{
el
.
parentNode
&&
el
.
parentNode
.
removeChild
(
el
)
}
}
else
{
throw
new
Error
(
`请设置操作权限标签值`
)
}
}
}
ruoyi-ui/src/directive/permission/hasRole.js
0 → 100644
View file @
46444bd0
/**
* 角色权限处理
* Copyright (c) 2019 ruoyi
*/
import
store
from
'
@/store
'
export
default
{
inserted
(
el
,
binding
,
vnode
)
{
const
{
value
}
=
binding
const
super_admin
=
"
admin
"
;
const
roles
=
store
.
getters
&&
store
.
getters
.
roles
if
(
value
&&
value
instanceof
Array
&&
value
.
length
>
0
)
{
const
roleFlag
=
value
const
hasRole
=
roles
.
some
(
role
=>
{
return
super_admin
===
role
||
roleFlag
.
includes
(
role
)
})
if
(
!
hasRole
)
{
el
.
parentNode
&&
el
.
parentNode
.
removeChild
(
el
)
}
}
else
{
throw
new
Error
(
`请设置角色权限标签值"`
)
}
}
}
ruoyi-ui/src/directive/permission/index.js
0 → 100644
View file @
46444bd0
import
hasRole
from
'
./hasRole
'
import
hasPermi
from
'
./hasPermi
'
const
install
=
function
(
Vue
)
{
Vue
.
directive
(
'
hasRole
'
,
hasRole
)
Vue
.
directive
(
'
hasPermi
'
,
hasPermi
)
}
if
(
window
.
Vue
)
{
window
[
'
hasRole
'
]
=
hasRole
window
[
'
hasPermi
'
]
=
hasPermi
Vue
.
use
(
install
);
// eslint-disable-line
}
export
default
install
ruoyi-ui/src/layout/components/AppMain.vue
0 → 100644
View file @
46444bd0
<
template
>
<section
class=
"app-main"
>
<transition
name=
"fade-transform"
mode=
"out-in"
>
<keep-alive
:include=
"cachedViews"
>
<router-view
:key=
"key"
/>
</keep-alive>
</transition>
</section>
</
template
>
<
script
>
export
default
{
name
:
'
AppMain
'
,
computed
:
{
cachedViews
()
{
return
this
.
$store
.
state
.
tagsView
.
cachedViews
},
key
()
{
return
this
.
$route
.
path
}
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
.app-main
{
/* 50= navbar 50 */
min-height
:
calc
(
100vh
-
50px
);
width
:
100%
;
position
:
relative
;
overflow
:
hidden
;
}
.fixed-header
+
.app-main
{
padding-top
:
50px
;
}
.hasTagsView
{
.app-main
{
/* 84 = navbar + tags-view = 50 + 34 */
min-height
:
calc
(
100vh
-
84px
);
}
.fixed-header
+
.app-main
{
padding-top
:
84px
;
}
}
</
style
>
<
style
lang=
"scss"
>
// fix css style bug in open el-dialog
.el-popup-parent--hidden
{
.fixed-header
{
padding-right
:
15px
;
}
}
</
style
>
ruoyi-ui/src/layout/components/Navbar.vue
0 → 100644
View file @
46444bd0
<
template
>
<div
class=
"navbar"
>
<hamburger
id=
"hamburger-container"
:is-active=
"sidebar.opened"
class=
"hamburger-container"
@
toggleClick=
"toggleSideBar"
/>
<breadcrumb
id=
"breadcrumb-container"
class=
"breadcrumb-container"
/>
<div
class=
"right-menu"
>
<template
v-if=
"device!=='mobile'"
>
<search
id=
"header-search"
class=
"right-menu-item"
/>
<el-tooltip
content=
"下载源码"
effect=
"dark"
placement=
"bottom"
>
<ruo-yi
id=
"ruoyi"
class=
"right-menu-item hover-effect"
/>
</el-tooltip>
<screenfull
id=
"screenfull"
class=
"right-menu-item hover-effect"
/>
<el-tooltip
content=
"布局大小"
effect=
"dark"
placement=
"bottom"
>
<size-select
id=
"size-select"
class=
"right-menu-item hover-effect"
/>
</el-tooltip>
</
template
>
<el-dropdown
class=
"avatar-container right-menu-item hover-effect"
trigger=
"click"
>
<div
class=
"avatar-wrapper"
>
<img
:src=
"avatar"
class=
"user-avatar"
>
<i
class=
"el-icon-caret-bottom"
/>
</div>
<el-dropdown-menu
slot=
"dropdown"
>
<router-link
to=
"/user/profile"
>
<el-dropdown-item>
个人中心
</el-dropdown-item>
</router-link>
<el-dropdown-item>
<span
@
click=
"setting = true"
>
布局设置
</span>
</el-dropdown-item>
<el-dropdown-item
divided
>
<span
@
click=
"logout"
>
退出登录
</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</template>
<
script
>
import
{
mapGetters
}
from
'
vuex
'
import
Breadcrumb
from
'
@/components/Breadcrumb
'
import
Hamburger
from
'
@/components/Hamburger
'
import
Screenfull
from
'
@/components/Screenfull
'
import
SizeSelect
from
'
@/components/SizeSelect
'
import
Search
from
'
@/components/HeaderSearch
'
import
RuoYi
from
'
@/components/RuoYi
'
export
default
{
components
:
{
Breadcrumb
,
Hamburger
,
Screenfull
,
SizeSelect
,
Search
,
RuoYi
},
computed
:
{
...
mapGetters
([
'
sidebar
'
,
'
avatar
'
,
'
device
'
]),
setting
:
{
get
()
{
return
this
.
$store
.
state
.
settings
.
showSettings
},
set
(
val
)
{
this
.
$store
.
dispatch
(
'
settings/changeSetting
'
,
{
key
:
'
showSettings
'
,
value
:
val
})
}
}
},
methods
:
{
toggleSideBar
()
{
this
.
$store
.
dispatch
(
'
app/toggleSideBar
'
)
},
async
logout
()
{
this
.
$confirm
(
'
确定注销并退出系统吗?
'
,
'
提示
'
,
{
confirmButtonText
:
'
确定
'
,
cancelButtonText
:
'
取消
'
,
type
:
'
warning
'
}).
then
(()
=>
{
this
.
$store
.
dispatch
(
'
LogOut
'
).
then
(()
=>
{
location
.
reload
()
})
})
}
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
.navbar
{
height
:
50px
;
overflow
:
hidden
;
position
:
relative
;
background
:
#fff
;
box-shadow
:
0
1px
4px
rgba
(
0
,
21
,
41
,.
08
);
.hamburger-container
{
line-height
:
46px
;
height
:
100%
;
float
:
left
;
cursor
:
pointer
;
transition
:
background
.3s
;
-webkit-tap-highlight-color
:transparent
;
&
:hover
{
background
:
rgba
(
0
,
0
,
0
,
.025
)
}
}
.breadcrumb-container
{
float
:
left
;
}
.errLog-container
{
display
:
inline-block
;
vertical-align
:
top
;
}
.right-menu
{
float
:
right
;
height
:
100%
;
line-height
:
50px
;
&
:focus
{
outline
:
none
;
}
.right-menu-item
{
display
:
inline-block
;
padding
:
0
8px
;
height
:
100%
;
font-size
:
18px
;
color
:
#5a5e66
;
vertical-align
:
text-bottom
;
&
.hover-effect
{
cursor
:
pointer
;
transition
:
background
.3s
;
&
:hover
{
background
:
rgba
(
0
,
0
,
0
,
.025
)
}
}
}
.avatar-container
{
margin-right
:
30px
;
.avatar-wrapper
{
margin-top
:
5px
;
position
:
relative
;
.user-avatar
{
cursor
:
pointer
;
width
:
40px
;
height
:
40px
;
border-radius
:
10px
;
}
.el-icon-caret-bottom
{
cursor
:
pointer
;
position
:
absolute
;
right
:
-20px
;
top
:
25px
;
font-size
:
12px
;
}
}
}
}
}
</
style
>
ruoyi-ui/src/layout/components/Settings/index.vue
0 → 100644
View file @
46444bd0
<
template
>
<div
class=
"drawer-container"
>
<div>
<h3
class=
"drawer-title"
>
系统布局配置
</h3>
<div
class=
"drawer-item"
>
<span>
主题颜色
</span>
<theme-picker
style=
"float: right;height: 26px;margin: -3px 8px 0 0;"
@
change=
"themeChange"
/>
</div>
<div
class=
"drawer-item"
>
<span>
开启 Tags-Views
</span>
<el-switch
v-model=
"tagsView"
class=
"drawer-switch"
/>
</div>
<div
class=
"drawer-item"
>
<span>
固定 Header
</span>
<el-switch
v-model=
"fixedHeader"
class=
"drawer-switch"
/>
</div>
<div
class=
"drawer-item"
>
<span>
显示 Logo
</span>
<el-switch
v-model=
"sidebarLogo"
class=
"drawer-switch"
/>
</div>
</div>
</div>
</
template
>
<
script
>
import
ThemePicker
from
'
@/components/ThemePicker
'
export
default
{
components
:
{
ThemePicker
},
data
()
{
return
{}
},
computed
:
{
fixedHeader
:
{
get
()
{
return
this
.
$store
.
state
.
settings
.
fixedHeader
},
set
(
val
)
{
this
.
$store
.
dispatch
(
'
settings/changeSetting
'
,
{
key
:
'
fixedHeader
'
,
value
:
val
})
}
},
tagsView
:
{
get
()
{
return
this
.
$store
.
state
.
settings
.
tagsView
},
set
(
val
)
{
this
.
$store
.
dispatch
(
'
settings/changeSetting
'
,
{
key
:
'
tagsView
'
,
value
:
val
})
}
},
sidebarLogo
:
{
get
()
{
return
this
.
$store
.
state
.
settings
.
sidebarLogo
},
set
(
val
)
{
this
.
$store
.
dispatch
(
'
settings/changeSetting
'
,
{
key
:
'
sidebarLogo
'
,
value
:
val
})
}
},
},
methods
:
{
themeChange
(
val
)
{
this
.
$store
.
dispatch
(
'
settings/changeSetting
'
,
{
key
:
'
theme
'
,
value
:
val
})
}
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
.drawer-container
{
padding
:
24px
;
font-size
:
14px
;
line-height
:
1
.5
;
word-wrap
:
break-word
;
.drawer-title
{
margin-bottom
:
12px
;
color
:
rgba
(
0
,
0
,
0
,
.85
);
font-size
:
14px
;
line-height
:
22px
;
}
.drawer-item
{
color
:
rgba
(
0
,
0
,
0
,
.65
);
font-size
:
14px
;
padding
:
12px
0
;
}
.drawer-switch
{
float
:
right
}
}
</
style
>
ruoyi-ui/src/layout/components/Sidebar/FixiOSBug.js
0 → 100644
View file @
46444bd0
export
default
{
computed
:
{
device
()
{
return
this
.
$store
.
state
.
app
.
device
}
},
mounted
()
{
// In order to fix the click on menu on the ios device will trigger the mouseleave bug
this
.
fixBugIniOS
()
},
methods
:
{
fixBugIniOS
()
{
const
$subMenu
=
this
.
$refs
.
subMenu
if
(
$subMenu
)
{
const
handleMouseleave
=
$subMenu
.
handleMouseleave
$subMenu
.
handleMouseleave
=
(
e
)
=>
{
if
(
this
.
device
===
'
mobile
'
)
{
return
}
handleMouseleave
(
e
)
}
}
}
}
}
ruoyi-ui/src/layout/components/Sidebar/Item.vue
0 → 100644
View file @
46444bd0
<
script
>
export
default
{
name
:
'
MenuItem
'
,
functional
:
true
,
props
:
{
icon
:
{
type
:
String
,
default
:
''
},
title
:
{
type
:
String
,
default
:
''
}
},
render
(
h
,
context
)
{
const
{
icon
,
title
}
=
context
.
props
const
vnodes
=
[]
if
(
icon
)
{
vnodes
.
push
(
<
svg
-
icon
icon
-
class
=
{
icon
}
/>
)
}
if
(
title
)
{
vnodes
.
push
(
<
span
slot
=
'
title
'
>
{(
title
)}
<
/span>
)
}
return
vnodes
}
}
</
script
>
ruoyi-ui/src/layout/components/Sidebar/Link.vue
0 → 100644
View file @
46444bd0
<
template
>
<!-- eslint-disable vue/require-component-is -->
<component
v-bind=
"linkProps(to)"
>
<slot
/>
</component>
</
template
>
<
script
>
import
{
isExternal
}
from
'
@/utils/validate
'
export
default
{
props
:
{
to
:
{
type
:
String
,
required
:
true
}
},
methods
:
{
linkProps
(
url
)
{
if
(
isExternal
(
url
))
{
return
{
is
:
'
a
'
,
href
:
url
,
target
:
'
_blank
'
,
rel
:
'
noopener
'
}
}
return
{
is
:
'
router-link
'
,
to
:
url
}
}
}
}
</
script
>
ruoyi-ui/src/layout/components/Sidebar/Logo.vue
0 → 100644
View file @
46444bd0
<
template
>
<div
class=
"sidebar-logo-container"
:class=
"
{'collapse':collapse}">
<transition
name=
"sidebarLogoFade"
>
<router-link
v-if=
"collapse"
key=
"collapse"
class=
"sidebar-logo-link"
to=
"/"
>
<img
v-if=
"logo"
:src=
"logo"
class=
"sidebar-logo"
>
<h1
v-else
class=
"sidebar-title"
>
{{
title
}}
</h1>
</router-link>
<router-link
v-else
key=
"expand"
class=
"sidebar-logo-link"
to=
"/"
>
<img
v-if=
"logo"
:src=
"logo"
class=
"sidebar-logo"
>
<h1
class=
"sidebar-title"
>
{{
title
}}
</h1>
</router-link>
</transition>
</div>
</
template
>
<
script
>
import
logoImg
from
'
@/assets/logo/logo.png
'
export
default
{
name
:
'
SidebarLogo
'
,
props
:
{
collapse
:
{
type
:
Boolean
,
required
:
true
}
},
data
()
{
return
{
title
:
'
若依管理系统
'
,
logo
:
logoImg
}
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
.sidebarLogoFade-enter-active
{
transition
:
opacity
1
.5s
;
}
.sidebarLogoFade-enter
,
.sidebarLogoFade-leave-to
{
opacity
:
0
;
}
.sidebar-logo-container
{
position
:
relative
;
width
:
100%
;
height
:
50px
;
line-height
:
50px
;
background
:
#2b2f3a
;
text-align
:
center
;
overflow
:
hidden
;
&
.sidebar-logo-link
{
height
:
100%
;
width
:
100%
;
&
.sidebar-logo
{
width
:
32px
;
height
:
32px
;
vertical-align
:
middle
;
margin-right
:
12px
;
}
&
.sidebar-title
{
display
:
inline-block
;
margin
:
0
;
color
:
#fff
;
font-weight
:
600
;
line-height
:
50px
;
font-size
:
14px
;
font-family
:
Avenir
,
Helvetica
Neue
,
Arial
,
Helvetica
,
sans-serif
;
vertical-align
:
middle
;
}
}
&
.collapse
{
.sidebar-logo
{
margin-right
:
0px
;
}
}
}
</
style
>
ruoyi-ui/src/layout/components/Sidebar/SidebarItem.vue
0 → 100644
View file @
46444bd0
<
template
>
<div
v-if=
"!item.hidden"
class=
"menu-wrapper"
>
<template
v-if=
"hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow"
>
<app-link
v-if=
"onlyOneChild.meta"
:to=
"resolvePath(onlyOneChild.path)"
>
<el-menu-item
:index=
"resolvePath(onlyOneChild.path)"
:class=
"
{'submenu-title-noDropdown':!isNest}">
<item
:icon=
"onlyOneChild.meta.icon||(item.meta&&item.meta.icon)"
:title=
"onlyOneChild.meta.title"
/>
</el-menu-item>
</app-link>
</
template
>
<el-submenu
v-else
ref=
"subMenu"
:index=
"resolvePath(item.path)"
popper-append-to-body
>
<
template
slot=
"title"
>
<item
v-if=
"item.meta"
:icon=
"item.meta && item.meta.icon"
:title=
"item.meta.title"
/>
</
template
>
<sidebar-item
v-for=
"child in item.children"
:key=
"child.path"
:is-nest=
"true"
:item=
"child"
:base-path=
"resolvePath(child.path)"
class=
"nest-menu"
/>
</el-submenu>
</div>
</template>
<
script
>
import
path
from
'
path
'
import
{
isExternal
}
from
'
@/utils/validate
'
import
Item
from
'
./Item
'
import
AppLink
from
'
./Link
'
import
FixiOSBug
from
'
./FixiOSBug
'
export
default
{
name
:
'
SidebarItem
'
,
components
:
{
Item
,
AppLink
},
mixins
:
[
FixiOSBug
],
props
:
{
// route object
item
:
{
type
:
Object
,
required
:
true
},
isNest
:
{
type
:
Boolean
,
default
:
false
},
basePath
:
{
type
:
String
,
default
:
''
}
},
data
()
{
this
.
onlyOneChild
=
null
return
{}
},
methods
:
{
hasOneShowingChild
(
children
=
[],
parent
)
{
const
showingChildren
=
children
.
filter
(
item
=>
{
if
(
item
.
hidden
)
{
return
false
}
else
{
// Temp set(will be used if only has one showing child)
this
.
onlyOneChild
=
item
return
true
}
})
// When there is only one child router, the child router is displayed by default
if
(
showingChildren
.
length
===
1
)
{
return
true
}
// Show parent if there are no child router to display
if
(
showingChildren
.
length
===
0
)
{
this
.
onlyOneChild
=
{
...
parent
,
path
:
''
,
noShowingChildren
:
true
}
return
true
}
return
false
},
resolvePath
(
routePath
)
{
if
(
isExternal
(
routePath
))
{
return
routePath
}
if
(
isExternal
(
this
.
basePath
))
{
return
this
.
basePath
}
return
path
.
resolve
(
this
.
basePath
,
routePath
)
}
}
}
</
script
>
ruoyi-ui/src/layout/components/Sidebar/index.vue
0 → 100644
View file @
46444bd0
<
template
>
<div
:class=
"
{'has-logo':showLogo}">
<logo
v-if=
"showLogo"
:collapse=
"isCollapse"
/>
<el-scrollbar
wrap-class=
"scrollbar-wrapper"
>
<el-menu
:default-active=
"activeMenu"
:collapse=
"isCollapse"
:background-color=
"variables.menuBg"
:text-color=
"variables.menuText"
:unique-opened=
"true"
:active-text-color=
"variables.menuActiveText"
:collapse-transition=
"false"
mode=
"vertical"
>
<sidebar-item
v-for=
"route in permission_routes"
:key=
"route.path"
:item=
"route"
:base-path=
"route.path"
/>
</el-menu>
</el-scrollbar>
</div>
</
template
>
<
script
>
import
{
mapGetters
}
from
'
vuex
'
import
Logo
from
'
./Logo
'
import
SidebarItem
from
'
./SidebarItem
'
import
variables
from
'
@/assets/styles/variables.scss
'
export
default
{
components
:
{
SidebarItem
,
Logo
},
computed
:
{
...
mapGetters
([
'
permission_routes
'
,
'
sidebar
'
]),
activeMenu
()
{
const
route
=
this
.
$route
const
{
meta
,
path
}
=
route
// if set path, the sidebar will highlight the path you set
if
(
meta
.
activeMenu
)
{
return
meta
.
activeMenu
}
return
path
},
showLogo
()
{
return
this
.
$store
.
state
.
settings
.
sidebarLogo
},
variables
()
{
return
variables
},
isCollapse
()
{
return
!
this
.
sidebar
.
opened
}
}
}
</
script
>
Prev
1
…
3
4
5
6
7
8
9
10
11
…
20
Next
Write
Preview
Supports
Markdown
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