Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
有来技术
vue3-element-admin
提交
100ab2e0
V
vue3-element-admin
项目概览
有来技术
/
vue3-element-admin
通知
3
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vue3-element-admin
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
100ab2e0
编写于
1月 13, 2023
作者:
H
haoxr
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
refactor: 自动导入修改和项目重构优化
上级
c6d57558
变更
36
展开全部
隐藏空白更改
内联
并排
Showing
36 changed file
with
882 addition
and
387 deletion
+882
-387
src/api/user/index.ts
src/api/user/index.ts
+1
-1
src/components/Breadcrumb/index.vue
src/components/Breadcrumb/index.vue
+3
-3
src/components/IconSelect/index.vue
src/components/IconSelect/index.vue
+67
-75
src/components/Pagination/index.vue
src/components/Pagination/index.vue
+7
-9
src/components/Screenfull/index.vue
src/components/Screenfull/index.vue
+1
-1
src/components/SizeSelect/index.vue
src/components/SizeSelect/index.vue
+1
-1
src/components/SvgIcon/index.vue
src/components/SvgIcon/index.vue
+6
-5
src/components/ThemePicker/index.vue
src/components/ThemePicker/index.vue
+1
-4
src/components/Upload/MultiUpload.vue
src/components/Upload/MultiUpload.vue
+7
-9
src/directive/utils/index.ts
src/directive/utils/index.ts
+8
-8
src/layout/components/Navbar.vue
src/layout/components/Navbar.vue
+22
-22
src/layout/components/Sidebar/Link.vue
src/layout/components/Sidebar/Link.vue
+1
-1
src/layout/components/Sidebar/MixNav.vue
src/layout/components/Sidebar/MixNav.vue
+1
-1
src/layout/components/Sidebar/SidebarItem.vue
src/layout/components/Sidebar/SidebarItem.vue
+5
-5
src/layout/components/TagsView/ScrollPane.vue
src/layout/components/TagsView/ScrollPane.vue
+1
-8
src/layout/components/TagsView/index.vue
src/layout/components/TagsView/index.vue
+79
-86
src/layout/index.vue
src/layout/index.vue
+1
-1
src/main.ts
src/main.ts
+2
-8
src/store/modules/permission.ts
src/store/modules/permission.ts
+1
-3
src/styles/element-plus.scss
src/styles/element-plus.scss
+0
-28
src/styles/index.scss
src/styles/index.scss
+2
-2
src/styles/mixin.scss
src/styles/mixin.scss
+0
-14
src/types/auto-imports.d.ts
src/types/auto-imports.d.ts
+526
-0
src/types/components.d.ts
src/types/components.d.ts
+80
-0
src/types/env.d.ts
src/types/env.d.ts
+0
-0
src/types/global.d.ts
src/types/global.d.ts
+0
-0
src/utils/i18n.ts
src/utils/i18n.ts
+1
-1
src/views/dashboard/index.vue
src/views/dashboard/index.vue
+4
-4
src/views/login/index.vue
src/views/login/index.vue
+3
-3
src/views/system/dict/components/DictItem.vue
src/views/system/dict/components/DictItem.vue
+1
-1
src/views/system/dict/index.vue
src/views/system/dict/index.vue
+2
-2
src/views/system/menu/index.vue
src/views/system/menu/index.vue
+6
-26
src/views/system/role/index.vue
src/views/system/role/index.vue
+0
-1
src/views/system/user/index.vue
src/views/system/user/index.vue
+40
-43
tsconfig.json
tsconfig.json
+2
-2
types/components.d.ts
types/components.d.ts
+0
-9
未找到文件。
src/api/user/index.ts
浏览文件 @
100ab2e0
...
...
@@ -111,7 +111,7 @@ export function deleteUsers(ids: string) {
*
* @returns
*/
export
function
downloadTemplate
()
{
export
function
downloadTemplate
Api
()
{
return
request
({
url
:
'
/api/v1/users/template
'
,
method
:
'
get
'
,
...
...
src/components/Breadcrumb/index.vue
浏览文件 @
100ab2e0
...
...
@@ -10,10 +10,10 @@
item.redirect === 'noredirect' || index === breadcrumbs.length - 1
"
class=
"text-[#97a8be]"
>
{{
generateTitle
(
item
.
meta
.
title
)
}}
</span
>
{{
translateRouteTitleI18n
(
item
.
meta
.
title
)
}}
</span
>
<a
v-else
@
click.prevent=
"handleLink(item)"
>
{{
generateTitle
(
item
.
meta
.
title
)
}}
{{
translateRouteTitleI18n
(
item
.
meta
.
title
)
}}
</a>
</el-breadcrumb-item>
</transition-group>
...
...
@@ -25,7 +25,7 @@ import { onBeforeMount, ref, watch } from 'vue';
import
{
useRoute
,
RouteLocationMatched
}
from
'
vue-router
'
;
import
{
compile
}
from
'
path-to-regexp
'
;
import
router
from
'
@/router
'
;
import
{
generateTitle
}
from
'
@/utils/i18n
'
;
import
{
translateRouteTitleI18n
}
from
'
@/utils/i18n
'
;
const
currentRoute
=
useRoute
();
const
pathCompile
=
(
path
:
string
)
=>
{
...
...
src/components/IconSelect/index.vue
浏览文件 @
100ab2e0
<
template
>
<div
class=
"icon-select"
>
<el-input
v-model=
"iconName"
clearable
placeholder=
"请输入图标名称"
@
clear=
"filterIcons"
@
input=
"filterIcons"
>
<template
#suffix
><i
class=
"el-icon-search el-input__icon"
/></
template
>
</el-input>
<div
class=
"icon-select__list"
>
<div
v-for=
"(item, index) in iconList"
:key=
"index"
@
click=
"selectedIcon(item)"
>
<svg-icon
color=
"#999"
:icon-class=
"item"
style=
"height: 30px; width: 16px; margin-right: 5px"
/>
<span>
{{ item }}
</span>
</div>
</div>
</div>
</template>
<
script
setup
lang=
"ts"
>
import
{
ref
}
from
'
vue
'
;
import
SvgIcon
from
'
@/components/SvgIcon/index.vue
'
;
const
props
=
defineProps
({
modelValue
:
{
type
:
String
,
require
:
false
}
});
const
icons
=
[]
as
string
[];
const
modules
=
import
.
meta
.
glob
(
'
../../assets/icons/*.svg
'
);
for
(
const
path
in
modules
)
{
const
p
=
path
.
split
(
'
assets/icons/
'
)[
1
].
split
(
'
.svg
'
)[
0
];
icons
.
push
(
p
);
}
const
iconList
=
ref
(
icons
);
const
emit
=
defineEmits
([
'
update:modelValue
'
]);
const
visible
=
ref
(
false
);
const
inputValue
=
toRef
(
props
,
'
modelValue
'
);
const
iconList
=
ref
<
string
[]
>
([]);
const
iconNam
e
=
ref
(
''
);
const
filterValu
e
=
ref
(
''
);
const
emit
=
defineEmits
([
'
selected
'
]
);
const
icon
=
ref
(
'
perm
'
);
function
filterIcons
()
{
iconList
.
value
=
icons
;
if
(
iconName
.
value
)
{
iconList
.
value
=
icons
.
filter
(
item
=>
item
.
indexOf
(
iconName
.
value
)
!==
-
1
);
function
loadIcons
()
{
const
modules
=
import
.
meta
.
glob
(
'
../../assets/icons/*.svg
'
);
for
(
const
path
in
modules
)
{
const
icon
=
path
.
split
(
'
assets/icons/
'
)[
1
].
split
(
'
.svg
'
)[
0
];
iconList
.
value
.
push
(
icon
);
}
}
function
selectedIcon
(
name
:
string
)
{
emit
(
'
selected
'
,
name
);
document
.
body
.
click
();
}
function
reset
()
{
iconName
.
value
=
''
;
iconList
.
value
=
icons
;
}
defineExpose
({
reset
onMounted
(()
=>
{
loadIcons
();
});
</
script
>
<
style
lang=
"scss"
scoped
>
.icon-select
{
width
:
100%
;
padding
:
10px
;
<
template
>
<div
class=
"w-[400px] relative"
>
<el-input
v-model=
"inputValue"
readonly
>
<template
#prepend
>
<svg-icon
:iconName=
"icon"
></svg-icon>
</
template
>
</el-input>
<el-popover
shadow=
"none"
:visible=
"visible"
placement=
"bottom-end"
trigger=
"click"
>
<
template
#reference
>
<div
@
click=
"visible = !visible"
class=
"cursor-pointer text-[#999] absolute right-[10px] top-0"
>
<i-ep-caret-top
v-show=
"visible"
></i-ep-caret-top>
<i-ep-caret-bottom
v-show=
"!visible"
></i-ep-caret-bottom>
</div>
</
template
>
&
__list
{
height
:
200px
;
overflow-y
:
scroll
;
<!-- 下拉选择弹窗 -->
<el-input
class=
"p-2"
v-model=
"filterValue"
placeholder=
"搜索图标"
clearable
/>
<el-divider
border-style=
"dashed"
/>
div
{
height
:
30px
;
line-height
:
30px
;
margin-bottom
:
-5px
;
cursor
:
pointer
;
width
:
33%
;
float
:
left
;
}
<el-scrollbar
height=
"300px"
>
<ul
class=
"icon-list"
>
<li
class=
"icon-item"
v-for=
"(item, index) in iconList"
:key=
"index"
>
<svg-icon
color=
"#999"
:icon-name=
"item"
/>
<span>
{{ item }}
</span>
</li>
</ul>
</el-scrollbar>
</el-popover>
</div>
</template>
span
{
display
:
inline-block
;
vertical-align
:
-0
.15em
;
fill
:
currentColor
;
overflow
:
hidden
;
<
style
scoped
lang=
"scss"
>
.icon-list
{
.icon-item
{
&
:hover
{
border-color
:
var
(
--
el-color-primary
);
color
:
var
(
--
el-color-primary
);
transition
:
all
0
.4s
;
transform
:
scaleX
(
1
.05
);
}
}
}
...
...
src/components/Pagination/index.vue
浏览文件 @
100ab2e0
<
template
>
<div
:class=
"
{ hidden: hidden }" class="pagination-container
">
<div
:class=
"
'pagination ' +
{ hidden: hidden }
">
<el-pagination
:background=
"background"
v-model:current-page=
"currentPage"
...
...
@@ -89,13 +89,11 @@ function handleCurrentChange(val: number) {
}
</
script
>
<
style
scoped
>
.pagination-container
{
background
:
#fff
;
padding
:
32px
16px
;
}
.pagination-container.hidden
{
display
:
none
;
<
style
lang=
"scss"
scoped
>
.pagination
{
padding
:
12px
;
&
.hidden
{
display
:
none
;
}
}
</
style
>
src/components/Screenfull/index.vue
浏览文件 @
100ab2e0
<
template
>
<div
class=
"cursor-pointer w-[40px] h-[50px] leading-[50px] text-center"
>
<svg-icon
:icon-
class
=
"isFullscreen ? 'exit-fullscreen' : 'fullscreen'"
:icon-
name
=
"isFullscreen ? 'exit-fullscreen' : 'fullscreen'"
@
click=
"toggle"
/>
</div>
...
...
src/components/SizeSelect/index.vue
浏览文件 @
100ab2e0
...
...
@@ -22,7 +22,7 @@ function handleSizeChange(size: string) {
<
template
>
<el-dropdown
trigger=
"click"
@
command=
"handleSizeChange"
>
<div
class=
"cursor-pointerw-[40px] h-[50px] leading-[50px] text-center"
>
<svg-icon
icon-
class
=
"size"
/>
<svg-icon
icon-
name
=
"size"
/>
</div>
<template
#dropdown
>
<el-dropdown-menu>
...
...
src/components/SvgIcon/index.vue
浏览文件 @
100ab2e0
...
...
@@ -9,14 +9,12 @@
</
template
>
<
script
setup
lang=
"ts"
>
import
{
computed
}
from
'
vue
'
;
const
props
=
defineProps
({
prefix
:
{
type
:
String
,
default
:
'
icon
'
},
icon
Class
:
{
icon
Name
:
{
type
:
String
,
required
:
false
},
...
...
@@ -29,12 +27,15 @@ const props = defineProps({
}
});
const
symbolId
=
computed
(()
=>
`#
${
props
.
prefix
}
-
${
props
.
icon
Class
}
`
);
const
symbolId
=
computed
(()
=>
`#
${
props
.
prefix
}
-
${
props
.
icon
Name
}
`
);
</
script
>
<
style
scoped
>
.svg-icon
{
width
:
1em
;
height
:
1em
;
vertical-align
:
-0.15em
;
/* 因icon大小被设置为和字体大小一致,而span等标签的下边缘会和字体的基线对齐,故需设置一个往下的偏移比例,来纠正视觉上的未对齐效果 */
fill
:
currentColor
;
/* 定义元素的颜色,currentColor是一个变量,这个变量的值就表示当前元素的color值,如果当前元素未设置color值,则从父元素继承 */
overflow
:
hidden
;
fill
:
currentColor
;
}
</
style
>
src/components/ThemePicker/index.vue
浏览文件 @
100ab2e0
...
...
@@ -15,10 +15,7 @@
/>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
useSettingsStore
}
from
'
@/store/modules/settings
'
;
const
settingsStore
=
useSettingsStore
();
</
script
>
<
script
setup
lang=
"ts"
></
script
>
<
style
>
.theme-message
,
...
...
src/components/Upload/MultiUpload.vue
浏览文件 @
100ab2e0
...
...
@@ -11,20 +11,18 @@
:before-upload=
"handleBeforeUpload"
:http-request=
"handleUpload"
:on-remove=
"handleRemove"
:on-preview=
"
handlePreview
"
:on-preview=
"
previewImg
"
:limit=
"props.limit"
>
<
el-icon><Plus
/></el-icon
>
<
i-ep-plus
/
>
</el-upload>
<el-dialog
v-model=
"dialogVisible"
>
<img
w-full
:src=
"
dialogImage
Url"
alt=
"Preview Image"
/>
<img
w-full
:src=
"
previewImg
Url"
alt=
"Preview Image"
/>
</el-dialog>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
ref
,
watch
}
from
'
vue
'
;
import
{
Plus
}
from
'
@element-plus/icons-vue
'
;
import
{
ElMessage
,
ElUpload
,
...
...
@@ -55,7 +53,7 @@ const props = defineProps({
}
});
const
dialogImage
Url
=
ref
(
''
);
const
previewImg
Url
=
ref
(
''
);
const
dialogVisible
=
ref
(
false
);
const
fileList
=
ref
([]
as
UploadUserFile
[]);
...
...
@@ -134,10 +132,10 @@ function handleBeforeUpload(file: UploadRawFile) {
}
/**
*
图片预览
*
预览图片
*/
const
handlePreview
:
UploadProps
[
'
onPreview
'
]
=
uploadFile
=>
{
dialogImage
Url
.
value
=
uploadFile
.
url
!
;
const
previewImg
:
UploadProps
[
'
onPreview
'
]
=
uploadFile
=>
{
previewImg
Url
.
value
=
uploadFile
.
url
!
;
dialogVisible
.
value
=
true
;
};
</
script
>
src/directive/utils/index.ts
浏览文件 @
100ab2e0
import
{
Directive
,
DirectiveBinding
}
from
'
vue
'
;
import
{
Directive
}
from
'
vue
'
;
/**
* 按钮防抖
*/
export
const
deBounce
:
Directive
=
{
mounted
(
el
:
HTMLElement
)
{
export
const
deBounce
:
Directive
=
{
mounted
(
el
:
HTMLElement
)
{
el
.
addEventListener
(
'
click
'
,
e
=>
{
el
.
classList
.
add
(
'
is-disabled
'
)
el
.
classList
.
add
(
'
is-disabled
'
)
;
setTimeout
(()
=>
{
el
.
classList
.
remove
(
'
is-disabled
'
)
},
2000
)
})
el
.
classList
.
remove
(
'
is-disabled
'
)
;
},
2000
)
;
})
;
}
}
}
;
src/layout/components/Navbar.vue
浏览文件 @
100ab2e0
<
script
setup
lang=
"ts"
>
import
{
computed
}
from
'
vue
'
;
import
{
storeToRefs
}
from
'
pinia
'
;
import
{
useRoute
,
useRouter
}
from
'
vue-router
'
;
import
{
ElMessageBox
}
from
'
element-plus
'
;
import
Hamburger
from
'
@/components/Hamburger/index.vue
'
;
import
Breadcrumb
from
'
@/components/Breadcrumb/index.vue
'
;
import
Screenfull
from
'
@/components/Screenfull/index.vue
'
;
import
SizeSelect
from
'
@/components/SizeSelect/index.vue
'
;
import
LangSelect
from
'
@/components/LangSelect/index.vue
'
;
import
MixNav
from
'
./Sidebar/MixNav.vue
'
;
import
{
CaretBottom
}
from
'
@element-plus/icons-vue
'
;
import
{
useAppStore
}
from
'
@/store/modules/app
'
;
import
{
useTagsViewStore
}
from
'
@/store/modules/tagsView
'
;
import
{
useUserStore
}
from
'
@/store/modules/user
'
;
...
...
@@ -24,12 +14,14 @@ const settingsStore = useSettingsStore();
const
route
=
useRoute
();
const
router
=
useRouter
();
const
device
=
computed
(()
=>
appStore
.
device
);
const
{
device
}
=
storeToRefs
(
appStore
);
// 设备类型:desktop-宽屏设备 || mobile-窄屏设备
const
{
layout
}
=
storeToRefs
(
settingsStore
);
// 布局模式:left-左侧模式||top-顶部模式||mix-混合模式
function
toggleSideBar
()
{
appStore
.
toggleSidebar
(
true
);
}
// 注销
function
logout
()
{
ElMessageBox
.
confirm
(
'
确定注销并退出系统吗?
'
,
'
提示
'
,
{
confirmButtonText
:
'
确定
'
,
...
...
@@ -52,7 +44,7 @@ function logout() {
<div
class=
"navbar"
>
<div
class=
"flex justify-start"
v-if=
"device === 'mobile' ||
settingsStore.
layout === 'left'"
v-if=
"device === 'mobile' || layout === 'left'"
>
<hamburger
:is-active=
"appStore.sidebar.opened"
...
...
@@ -62,13 +54,24 @@ function logout() {
<breadcrumb
/>
</div>
<mix-nav
v-if=
"device !== 'mobile' &&
settingsStore.
layout === 'mix'"
/>
<mix-nav
v-if=
"device !== 'mobile' && layout === 'mix'"
/>
<!-- 宽屏或左侧模式显示 -->
<div
v-if=
"device === '
mobile' || settingsStore.
layout === 'left'"
v-if=
"device === '
desktop' ||
layout === 'left'"
class=
"flex justify-start"
>
<!-- 左侧窄屏不显示 -->
<div
v-if=
"device !== 'mobile'"
class=
"flex justify-center items-center"
>
<i-ep-add-location
/>
<i-ep-aim
/>
<div
i-ep-check
/>
<el-button>
<template
#icon
><i-ep-circle-check-filled
/></
template
>
Hello world
</el-button>
<!--全屏 -->
<screenfull
id=
"screenfull"
/>
...
...
@@ -80,14 +83,14 @@ function logout() {
<!--语言选择-->
<lang-select
/>
</div>
<!-- 头像 -->
<el-dropdown
trigger=
"click"
>
<div
class=
"flex justify-center items-center pr-[20px]"
>
<img
:src=
"userStore.avatar + '?imageView2/1/w/80/h/80'"
class=
"w-[40px] h-[40px] rounded-lg"
/>
<
CaretB
ottom
class=
"w-3 h-3"
/>
<
i-ep-caret-b
ottom
class=
"w-3 h-3"
/>
</div>
<
template
#dropdown
>
...
...
@@ -115,15 +118,12 @@ function logout() {
</template>
<
style
lang=
"scss"
scoped
>
.el-dropdown
{
font-size
:
18px
;
}
.navbar
{
background-color
:
#fff
;
height
:
50px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
box-shadow
:
0
0
px
2px
rgba
(
0
,
0
,
0
,
0
.2
)
;
box-shadow
:
0
0
1px
#0003
;
}
</
style
>
src/layout/components/Sidebar/Link.vue
浏览文件 @
100ab2e0
...
...
@@ -3,7 +3,7 @@ import { computed } from 'vue';
import
{
isExternal
}
from
'
@/utils/validate
'
;
import
{
useRouter
}
from
'
vue-router
'
;
import
{
DeviceType
,
useAppStore
}
from
'
@/store/modules/app
'
;
import
{
useAppStore
}
from
'
@/store/modules/app
'
;
const
appStore
=
useAppStore
();
const
sidebar
=
computed
(()
=>
appStore
.
sidebar
);
...
...
src/layout/components/Sidebar/MixNav.vue
浏览文件 @
100ab2e0
<
script
setup
lang=
"ts"
>
import
{
computed
,
onMounted
}
from
'
vue
'
;
import
{
RouterLink
,
useRoute
,
useRouter
,
RouteRecordRaw
}
from
'
vue-router
'
;
import
{
RouterLink
,
useRoute
,
useRouter
}
from
'
vue-router
'
;
import
{
ElDropdown
,
ElDropdownItem
,
...
...
src/layout/components/Sidebar/SidebarItem.vue
浏览文件 @
100ab2e0
...
...
@@ -4,7 +4,7 @@ import path from 'path-browserify';
import
{
isExternal
}
from
'
@/utils/validate
'
;
import
AppLink
from
'
./Link.vue
'
;
import
{
generateTitle
}
from
'
@/utils/i18n
'
;
import
{
translateRouteTitleI18n
}
from
'
@/utils/i18n
'
;
import
SvgIcon
from
'
@/components/SvgIcon/index.vue
'
;
const
props
=
defineProps
({
...
...
@@ -78,10 +78,10 @@ function resolvePath(routePath: string) {
>
<svg-icon
v-if=
"onlyOneChild.meta && onlyOneChild.meta.icon"
:icon-
class
=
"onlyOneChild.meta.icon"
:icon-
name
=
"onlyOneChild.meta.icon"
/>
<template
#title
>
{{
generateTitle
(
onlyOneChild
.
meta
.
title
)
}}
{{
translateRouteTitleI18n
(
onlyOneChild
.
meta
.
title
)
}}
</
template
>
</el-menu-item>
</app-link>
...
...
@@ -92,10 +92,10 @@ function resolvePath(routePath: string) {
<
template
#title
>
<svg-icon
v-if=
"item.meta && item.meta.icon"
:icon-
class
=
"item.meta.icon"
:icon-
name
=
"item.meta.icon"
/>
<span
v-if=
"item.meta && item.meta.title"
>
{{
generateTitle
(
item
.
meta
.
title
)
translateRouteTitleI18n
(
item
.
meta
.
title
)
}}
</span>
</
template
>
...
...
src/layout/components/TagsView/ScrollPane.vue
浏览文件 @
100ab2e0
<
script
setup
lang=
"ts"
>
import
{
ref
,
computed
,
onMounted
,
onBeforeUnmount
,
getCurrentInstance
}
from
'
vue
'
;
import
{
useTagsViewStore
,
TagView
}
from
'
@/store/modules/tagsView
'
;
const
tagAndTagSpacing
=
ref
(
4
);
...
...
@@ -102,8 +95,8 @@ defineExpose({
<
template
>
<el-scrollbar
ref=
"scrollContainer"
:vertical=
"false"
class=
"scroll-container"
:vertical=
"false"
@
wheel.prevent=
"handleScroll"
>
<slot
/>
...
...
src/layout/components/TagsView/index.vue
浏览文件 @
100ab2e0
...
...
@@ -7,26 +7,27 @@ import {
onMounted
,
ComponentInternalInstance
}
from
'
vue
'
;
import
{
storeToRefs
}
from
'
pinia
'
;
import
path
from
'
path-browserify
'
;
import
{
useRoute
,
useRouter
}
from
'
vue-router
'
;
import
ScrollPane
from
'
./ScrollPane.vue
'
;
import
SvgIcon
from
'
@/components/SvgIcon/index.vue
'
;
import
{
generateTitle
}
from
'
@/utils/i18n
'
;
import
{
translateRouteTitleI18n
}
from
'
@/utils/i18n
'
;
import
{
usePermissionStore
}
from
'
@/store/modules/permission
'
;
import
{
useTagsViewStore
,
TagView
}
from
'
@/store/modules/tagsView
'
;
const
permissionStore
=
usePermissionStore
();
const
tagsViewStore
=
useTagsViewStore
();
import
ScrollPane
from
'
./ScrollPane.vue
'
;
const
{
proxy
}
=
getCurrentInstance
()
as
ComponentInternalInstance
;
const
router
=
useRouter
();
const
route
=
useRoute
();
const
visible
=
ref
(
false
);
const
permissionStore
=
usePermissionStore
();
const
tagsViewStore
=
useTagsViewStore
();
const
{
visitedViews
}
=
storeToRefs
(
tagsViewStore
);
const
selectedTag
=
ref
({});
const
scrollPaneRef
=
ref
();
const
left
=
ref
(
0
);
...
...
@@ -45,11 +46,12 @@ watch(
}
);
watch
(
visible
,
value
=>
{
const
tagMenuVisible
=
ref
(
false
);
// 标签操作菜单显示状态
watch
(
tagMenuVisible
,
value
=>
{
if
(
value
)
{
document
.
body
.
addEventListener
(
'
click
'
,
closeMenu
);
document
.
body
.
addEventListener
(
'
click
'
,
close
Tag
Menu
);
}
else
{
document
.
body
.
removeEventListener
(
'
click
'
,
closeMenu
);
document
.
body
.
removeEventListener
(
'
click
'
,
close
Tag
Menu
);
}
});
...
...
@@ -78,11 +80,11 @@ function filterAffixTags(routes: any[], basePath = '/') {
}
function
initTags
()
{
const
tags
=
filterAffixTags
(
permissionStore
.
routes
);
const
tags
:
TagView
[]
=
filterAffixTags
(
permissionStore
.
routes
);
affixTags
.
value
=
tags
;
for
(
const
tag
of
tags
)
{
// Must have tag name
if
(
(
tag
as
TagView
)
.
name
)
{
if
(
tag
.
name
)
{
tagsViewStore
.
addVisitedView
(
tag
);
}
}
...
...
@@ -205,7 +207,7 @@ function closeAllTags(view: TagView) {
});
}
function
openMenu
(
tag
:
TagView
,
e
:
MouseEvent
)
{
function
open
Tag
Menu
(
tag
:
TagView
,
e
:
MouseEvent
)
{
const
menuMinWidth
=
105
;
const
offsetLeft
=
proxy
?.
$el
.
getBoundingClientRect
().
left
;
// container margin left
const
offsetWidth
=
proxy
?.
$el
.
offsetWidth
;
// container width
...
...
@@ -219,16 +221,16 @@ function openMenu(tag: TagView, e: MouseEvent) {
}
top
.
value
=
e
.
clientY
;
v
isible
.
value
=
true
;
tagMenuV
isible
.
value
=
true
;
selectedTag
.
value
=
tag
;
}
function
closeMenu
()
{
v
isible
.
value
=
false
;
function
close
Tag
Menu
()
{
tagMenuV
isible
.
value
=
false
;
}
function
handleScroll
()
{
closeMenu
();
close
Tag
Menu
();
}
onMounted
(()
=>
{
...
...
@@ -237,71 +239,71 @@ onMounted(() => {
</
script
>
<
template
>
<div
class=
"h-[34px] w-full border-b-[1px] border-gray-200 shadow-lg shadow-[rgba(0, 21, 41, 0.08)]"
<scroll-pane
class=
"tags-container"
ref=
"scrollPaneRef"
@
scroll=
"handleScroll"
>
<scroll-pane
ref=
"scrollPaneRef"
class=
"tags-container"
@
scroll=
"handleScroll"
<router-link
:class=
"'tags-item ' + (isActive(tag) ? 'active' : '')"
v-for=
"tag in visitedViews"
:key=
"tag.path"
:data-path=
"tag.path"
:to=
"
{ path: tag.path, query: tag.query }"
@click.middle="!isAffix(tag) ? closeSelectedTag(tag) : ''"
@contextmenu.prevent="openTagMenu(tag, $event)"
>
<router-link
v-for=
"tag in tagsViewStore.visitedViews"
:key=
"tag.path"
:data-path=
"tag.path"
:class=
"isActive(tag) ? 'active' : ''"
:to=
"
{ path: tag.path, query: tag.query }"
class="tags-item"
@click.middle="!isAffix(tag) ? closeSelectedTag(tag) : ''"
@contextmenu.prevent="openMenu(tag, $event)"
{{
translateRouteTitleI18n
(
tag
.
meta
?.
title
)
}}
<span
v-if=
"!isAffix(tag)"
class=
"rounded-[60%] hover:bg-gray-300"
@
click.prevent.stop=
"closeSelectedTag(tag)"
>
{{
generateTitle
(
tag
.
meta
?.
title
)
}}
<span
v-if=
"!isAffix(tag)"
class=
"tags-item-remove"
@
click.prevent.stop=
"closeSelectedTag(tag)"
>
<svg-icon
icon-class=
"close"
/>
</span>
</router-link>
</scroll-pane>
<ul
v-show=
"visible"
:style=
"
{ left: left + 'px', top: top + 'px' }"
class="tags-item-menu"
>
<li
@
click=
"refreshSelectedTag(selectedTag)"
>
<svg-icon
icon-class=
"refresh"
/>
刷新
</li>
<li
v-if=
"!isAffix(selectedTag)"
@
click=
"closeSelectedTag(selectedTag)"
>
<svg-icon
icon-class=
"close"
/>
关闭
</li>
<li
@
click=
"closeOtherTags"
>
<svg-icon
icon-class=
"close_other"
/>
关闭其它
</li>
<li
v-if=
"!isFirstView()"
@
click=
"closeLeftTags"
>
<svg-icon
icon-class=
"close_left"
/>
关闭左侧
</li>
<li
v-if=
"!isLastView()"
@
click=
"closeRightTags"
>
<svg-icon
icon-class=
"close_right"
/>
关闭右侧
</li>
<li
@
click=
"closeAllTags(selectedTag)"
>
<svg-icon
icon-class=
"close_all"
/>
关闭所有
</li>
</ul>
</div>
<i-ep-close
class=
"text-[10px]"
/>
</span>
</router-link>
</scroll-pane>
<!-- tag标签操作菜单 -->
<ul
v-show=
"tagMenuVisible"
class=
"tag-menu"
:style=
"
{ left: left + 'px', top: top + 'px' }"
>
<li
@
click=
"refreshSelectedTag(selectedTag)"
>
<svg-icon
icon-name=
"refresh"
/>
刷新
</li>
<li
v-if=
"!isAffix(selectedTag)"
@
click=
"closeSelectedTag(selectedTag)"
>
<svg-icon
icon-name=
"close"
/>
关闭
</li>
<li
@
click=
"closeOtherTags"
>
<svg-icon
icon-name=
"close_other"
/>
关闭其它
</li>
<li
v-if=
"!isFirstView()"
@
click=
"closeLeftTags"
>
<svg-icon
icon-name=
"close_left"
/>
关闭左侧
</li>
<li
v-if=
"!isLastView()"
@
click=
"closeRightTags"
>
<svg-icon
icon-name=
"close_right"
/>
关闭右侧
</li>
<li
@
click=
"closeAllTags(selectedTag)"
>
<svg-icon
icon-name=
"close_all"
/>
关闭所有
</li>
</ul>
</
template
>
<
style
lang=
"scss"
scoped
>
.tags-container
{
height
:
34px
;
width
:
100%
;
border
:
1px
solid
#eee
;
box-shadow
:
0px
1px
1px
#eee
;
.tags-item
{
display
:
inline-block
;
cursor
:
pointer
;
...
...
@@ -324,7 +326,7 @@ onMounted(() => {
&
.active
{
background-color
:
var
(
--
el-color-primary
);
color
:
var
(
--
el-color-primary-light-9
)
;
color
:
#fff
;
border-color
:
var
(
--
el-color-primary
);
&
::before
{
content
:
''
;
...
...
@@ -333,22 +335,13 @@ onMounted(() => {
width
:
8px
;
height
:
8px
;
border-radius
:
50%
;
position
:
relative
;
margin-right
:
5px
;
}
}
&
-remove
{
border-radius
:
50%
;
&
:hover
{
color
:
#fff
;
background-color
:
#ccc
;
}
}
}
}
.tag
s-item
-menu
{
.tag-menu
{
background
:
#fff
;
z-index
:
99
;
position
:
absolute
;
...
...
src/layout/index.vue
浏览文件 @
100ab2e0
...
...
@@ -5,7 +5,7 @@ import { AppMain, Navbar, Settings, TagsView } from './components/index';
import
Sidebar
from
'
./components/Sidebar/index.vue
'
;
import
RightPanel
from
'
@/components/RightPanel/index.vue
'
;
import
{
DeviceType
,
useAppStore
}
from
'
@/store/modules/app
'
;
import
{
useAppStore
}
from
'
@/store/modules/app
'
;
import
{
useSettingsStore
}
from
'
@/store/modules/settings
'
;
const
{
width
}
=
useWindowSize
();
...
...
src/main.ts
浏览文件 @
100ab2e0
...
...
@@ -5,10 +5,9 @@ import { setupStore } from '@/store';
import
ElementPlus
from
'
element-plus
'
;
import
Pagination
from
'
@/components/Pagination/index.vue
'
;
import
'
@/permission
'
;
//
引入svg注册脚本
//
本地SVG图标
import
'
virtual:svg-icons-register
'
;
// 国际化
...
...
@@ -31,9 +30,4 @@ app.config.globalProperties.$getDictionaries = getDictionaries;
// 全局挂载
setupStore
(
app
);
app
.
component
(
'
Pagination
'
,
Pagination
)
.
use
(
router
)
.
use
(
ElementPlus
)
.
use
(
i18n
)
.
mount
(
'
#app
'
);
app
.
use
(
router
).
use
(
ElementPlus
).
use
(
i18n
).
mount
(
'
#app
'
);
src/store/modules/permission.ts
浏览文件 @
100ab2e0
...
...
@@ -3,13 +3,13 @@ import { defineStore } from 'pinia';
import
{
constantRoutes
}
from
'
@/router
'
;
import
{
store
}
from
'
@/store
'
;
import
{
listRoutes
}
from
'
@/api/menu
'
;
import
{
ref
}
from
'
vue
'
;
const
modules
=
import
.
meta
.
glob
(
'
../../views/**/**.vue
'
);
export
const
Layout
=
()
=>
import
(
'
@/layout/index.vue
'
);
const
hasPermission
=
(
roles
:
string
[],
route
:
RouteRecordRaw
)
=>
{
if
(
route
.
meta
&&
route
.
meta
.
roles
)
{
// 默认超级管理员角色拥有所有权限,忽略校验
if
(
roles
.
includes
(
'
ROOT
'
))
{
return
true
;
}
...
...
@@ -51,11 +51,9 @@ const filterAsyncRoutes = (routes: RouteRecordRaw[], roles: string[]) => {
export
const
usePermissionStore
=
defineStore
(
'
permission
'
,
()
=>
{
// state
const
routes
=
ref
<
RouteRecordRaw
[]
>
([]);
const
addRoutes
=
ref
<
RouteRecordRaw
[]
>
([]);
// actions
function
setRoutes
(
newRoutes
:
RouteRecordRaw
[])
{
addRoutes
.
value
=
newRoutes
;
routes
.
value
=
constantRoutes
.
concat
(
newRoutes
);
}
...
...
src/styles/element-plus.scss
浏览文件 @
100ab2e0
...
...
@@ -10,41 +10,13 @@
font-weight
:
400
!
important
;
}
.el-upload
{
input
[
type
=
'file'
]
{
display
:
none
!
important
;
}
}
.el-upload__input
{
display
:
none
;
}
// dropdown
.el-dropdown-menu
{
a
{
display
:
block
;
}
}
// to fix el-date-picker css style
.el-range-separator
{
box-sizing
:
content-box
;
}
// 选中行背景色值
.el-table__body
tr
.current-row
td
{
background-color
:
#e1f3d8
b5
!
important
;
}
// card 的header统一高度
.el-card__header
{
height
:
60px
!
important
;
}
// 表格表头和表体未对齐
.el-table__header
col
[
name
=
'gutter'
]
{
display
:
table-cell
!
important
;
}
src/styles/index.scss
浏览文件 @
100ab2e0
...
...
@@ -16,8 +16,8 @@ html,body,#app{
padding
:
18px
0
0
10px
;
margin-bottom
:
10px
;
border-radius
:
5px
;
border
:
1px
solid
#
ddd
;
box-shadow
:
6px
2px
6px
#CCC
;
border
:
1px
solid
#
eee
;
box-shadow
:
1px
1px
1px
#eee
;
}
svg
{
...
...
src/styles/mixin.scss
浏览文件 @
100ab2e0
...
...
@@ -6,20 +6,6 @@
}
}
@mixin
scrollBar
{
&
::-webkit-scrollbar-track-piece
{
background
:
#d3dce6
;
}
&
::-webkit-scrollbar
{
width
:
6px
;
}
&
::-webkit-scrollbar-thumb
{
background
:
#99a9bf
;
border-radius
:
20px
;
}
}
@mixin
relative
{
position
:
relative
;
...
...
src/types/auto-imports.d.ts
0 → 100644
浏览文件 @
100ab2e0
此差异已折叠。
点击以展开。
src/types/components.d.ts
0 → 100644
浏览文件 @
100ab2e0
// generated by unplugin-vue-components
// We suggest you to commit this file into source control
// Read more: https://github.com/vuejs/core/pull/3399
import
'
@vue/runtime-core
'
export
{}
declare
module
'
@vue/runtime-core
'
{
export
interface
GlobalComponents
{
Breadcrumb
:
typeof
import
(
'
./../components/Breadcrumb/index.vue
'
)[
'
default
'
]
ElAlert
:
typeof
import
(
'
element-plus/es
'
)[
'
ElAlert
'
]
ElBadge
:
typeof
import
(
'
element-plus/es
'
)[
'
ElBadge
'
]
ElBreadcrumb
:
typeof
import
(
'
element-plus/es
'
)[
'
ElBreadcrumb
'
]
ElBreadcrumbItem
:
typeof
import
(
'
element-plus/es
'
)[
'
ElBreadcrumbItem
'
]
ElButton
:
typeof
import
(
'
element-plus/es
'
)[
'
ElButton
'
]
ElCard
:
typeof
import
(
'
element-plus/es
'
)[
'
ElCard
'
]
ElCol
:
typeof
import
(
'
element-plus/es
'
)[
'
ElCol
'
]
ElDialog
:
typeof
import
(
'
element-plus/es
'
)[
'
ElDialog
'
]
ElDivider
:
typeof
import
(
'
element-plus/es
'
)[
'
ElDivider
'
]
ElDropdown
:
typeof
import
(
'
element-plus/es
'
)[
'
ElDropdown
'
]
ElDropdownItem
:
typeof
import
(
'
element-plus/es
'
)[
'
ElDropdownItem
'
]
ElDropdownMenu
:
typeof
import
(
'
element-plus/es
'
)[
'
ElDropdownMenu
'
]
ElForm
:
typeof
import
(
'
element-plus/es
'
)[
'
ElForm
'
]
ElFormItem
:
typeof
import
(
'
element-plus/es
'
)[
'
ElFormItem
'
]
ElIcon
:
typeof
import
(
'
element-plus/es
'
)[
'
ElIcon
'
]
ElImage
:
typeof
import
(
'
element-plus/es
'
)[
'
ElImage
'
]
ElInput
:
typeof
import
(
'
element-plus/es
'
)[
'
ElInput
'
]
ElInputNumber
:
typeof
import
(
'
element-plus/es
'
)[
'
ElInputNumber
'
]
ElLink
:
typeof
import
(
'
element-plus/es
'
)[
'
ElLink
'
]
ElMenu
:
typeof
import
(
'
element-plus/es
'
)[
'
ElMenu
'
]
ElMenuItem
:
typeof
import
(
'
element-plus/es
'
)[
'
ElMenuItem
'
]
ElOption
:
typeof
import
(
'
element-plus/es
'
)[
'
ElOption
'
]
ElPagination
:
typeof
import
(
'
element-plus/es
'
)[
'
ElPagination
'
]
ElPopover
:
typeof
import
(
'
element-plus/es
'
)[
'
ElPopover
'
]
ElRadio
:
typeof
import
(
'
element-plus/es
'
)[
'
ElRadio
'
]
ElRadioGroup
:
typeof
import
(
'
element-plus/es
'
)[
'
ElRadioGroup
'
]
ElRow
:
typeof
import
(
'
element-plus/es
'
)[
'
ElRow
'
]
ElScrollbar
:
typeof
import
(
'
element-plus/es
'
)[
'
ElScrollbar
'
]
ElSelect
:
typeof
import
(
'
element-plus/es
'
)[
'
ElSelect
'
]
ElSubMenu
:
typeof
import
(
'
element-plus/es
'
)[
'
ElSubMenu
'
]
ElSwitch
:
typeof
import
(
'
element-plus/es
'
)[
'
ElSwitch
'
]
ElTable
:
typeof
import
(
'
element-plus/es
'
)[
'
ElTable
'
]
ElTableColumn
:
typeof
import
(
'
element-plus/es
'
)[
'
ElTableColumn
'
]
ElTabPane
:
typeof
import
(
'
element-plus/es
'
)[
'
ElTabPane
'
]
ElTabs
:
typeof
import
(
'
element-plus/es
'
)[
'
ElTabs
'
]
ElTag
:
typeof
import
(
'
element-plus/es
'
)[
'
ElTag
'
]
ElTooltip
:
typeof
import
(
'
element-plus/es
'
)[
'
ElTooltip
'
]
ElTree
:
typeof
import
(
'
element-plus/es
'
)[
'
ElTree
'
]
ElTreeSelect
:
typeof
import
(
'
element-plus/es
'
)[
'
ElTreeSelect
'
]
ElUpload
:
typeof
import
(
'
element-plus/es
'
)[
'
ElUpload
'
]
GithubCorner
:
typeof
import
(
'
./../components/GithubCorner/index.vue
'
)[
'
default
'
]
Hamburger
:
typeof
import
(
'
./../components/Hamburger/index.vue
'
)[
'
default
'
]
IconSelect
:
typeof
import
(
'
./../components/IconSelect/index.vue
'
)[
'
default
'
]
IEpAddLocation
:
typeof
import
(
'
~icons/ep/add-location
'
)[
'
default
'
]
IEpAim
:
typeof
import
(
'
~icons/ep/aim
'
)[
'
default
'
]
IEpCaretBottom
:
typeof
import
(
'
~icons/ep/caret-bottom
'
)[
'
default
'
]
IEpCaretTop
:
typeof
import
(
'
~icons/ep/caret-top
'
)[
'
default
'
]
IEpCircleCheckFilled
:
typeof
import
(
'
~icons/ep/circle-check-filled
'
)[
'
default
'
]
IEpClose
:
typeof
import
(
'
~icons/ep/close
'
)[
'
default
'
]
IEpDownload
:
typeof
import
(
'
~icons/ep/download
'
)[
'
default
'
]
IEpEdit
:
typeof
import
(
'
~icons/ep/edit
'
)[
'
default
'
]
IEpIcon
:
typeof
import
(
'
~icons/ep/icon
'
)[
'
default
'
]
IEpTop
:
typeof
import
(
'
~icons/ep/top
'
)[
'
default
'
]
LangSelect
:
typeof
import
(
'
./../components/LangSelect/index.vue
'
)[
'
default
'
]
MultiUpload
:
typeof
import
(
'
./../components/Upload/MultiUpload.vue
'
)[
'
default
'
]
Pagination
:
typeof
import
(
'
./../components/Pagination/index.vue
'
)[
'
default
'
]
RightPanel
:
typeof
import
(
'
./../components/RightPanel/index.vue
'
)[
'
default
'
]
RouterLink
:
typeof
import
(
'
vue-router
'
)[
'
RouterLink
'
]
RouterView
:
typeof
import
(
'
vue-router
'
)[
'
RouterView
'
]
Screenfull
:
typeof
import
(
'
./../components/Screenfull/index.vue
'
)[
'
default
'
]
SingleUpload
:
typeof
import
(
'
./../components/Upload/SingleUpload.vue
'
)[
'
default
'
]
SizeSelect
:
typeof
import
(
'
./../components/SizeSelect/index.vue
'
)[
'
default
'
]
SvgIcon
:
typeof
import
(
'
./../components/SvgIcon/index.vue
'
)[
'
default
'
]
ThemePicker
:
typeof
import
(
'
./../components/ThemePicker/index.vue
'
)[
'
default
'
]
WangEditor
:
typeof
import
(
'
./../components/WangEditor/index.vue
'
)[
'
default
'
]
}
export
interface
ComponentCustomProperties
{
vLoading
:
typeof
import
(
'
element-plus/es
'
)[
'
ElLoadingDirective
'
]
}
}
types/env.d.ts
→
src/
types/env.d.ts
浏览文件 @
100ab2e0
文件已移动
types/global.d.ts
→
src/
types/global.d.ts
浏览文件 @
100ab2e0
文件已移动
src/utils/i18n.ts
浏览文件 @
100ab2e0
// translate router.meta.title, be used in breadcrumb sidebar tagsview
import
i18n
from
'
@/lang/index
'
;
export
function
generateTitle
(
title
:
any
)
{
export
function
translateRouteTitleI18n
(
title
:
any
)
{
// 判断是否存在国际化配置,如果没有原生返回
const
hasKey
=
i18n
.
global
.
te
(
'
route.
'
+
title
);
if
(
hasKey
)
{
...
...
src/views/dashboard/index.vue
浏览文件 @
100ab2e0
...
...
@@ -23,7 +23,7 @@ import Team from './components/Team/index.vue';
<el-col
:xs=
"24"
:sm=
"12"
:lg=
"6"
class=
"card-panel__col"
>
<div
class=
"card-panel"
>
<div
class=
"card-panel-icon-wrapper icon-user"
>
<svg-icon
icon-
class
=
"uv"
size=
"4em"
/>
<svg-icon
icon-
name
=
"uv"
size=
"4em"
/>
</div>
<div
class=
"card-panel-description"
>
<div
class=
"card-panel-text"
>
访问数
</div>
...
...
@@ -35,7 +35,7 @@ import Team from './components/Team/index.vue';
<el-col
:xs=
"24"
:sm=
"12"
:lg=
"6"
class=
"card-panel__col"
>
<div
class=
"card-panel"
>
<div
class=
"card-panel-icon-wrapper icon-message"
>
<svg-icon
icon-
class
=
"message"
size=
"4em"
/>
<svg-icon
icon-
name
=
"message"
size=
"4em"
/>
</div>
<div
class=
"card-panel-description"
>
<div
class=
"card-panel-text"
>
消息数
</div>
...
...
@@ -47,7 +47,7 @@ import Team from './components/Team/index.vue';
<el-col
:xs=
"24"
:sm=
"12"
:lg=
"6"
class=
"card-panel__col"
>
<div
class=
"card-panel"
>
<div
class=
"card-panel-icon-wrapper icon-money"
>
<svg-icon
icon-
class
=
"money"
size=
"4em"
/>
<svg-icon
icon-
name
=
"money"
size=
"4em"
/>
</div>
<div
class=
"card-panel-description"
>
<div
class=
"card-panel-text"
>
收入金额
</div>
...
...
@@ -58,7 +58,7 @@ import Team from './components/Team/index.vue';
<el-col
:xs=
"24"
:sm=
"12"
:lg=
"6"
class=
"card-panel__col"
>
<div
class=
"card-panel"
>
<div
class=
"card-panel-icon-wrapper icon-shopping"
>
<svg-icon
icon-
class
=
"shopping"
size=
"4em"
/>
<svg-icon
icon-
name
=
"shopping"
size=
"4em"
/>
</div>
<div
class=
"card-panel-description"
>
<div
class=
"card-panel-text"
>
订单数
</div>
...
...
src/views/login/index.vue
浏览文件 @
100ab2e0
...
...
@@ -15,7 +15,7 @@
<el-form-item
prop=
"username"
>
<span
class=
"svg-container"
>
<svg-icon
icon-
class
=
"user"
/>
<svg-icon
icon-
name
=
"user"
/>
</span>
<el-input
ref=
"username"
...
...
@@ -35,7 +35,7 @@
>
<el-form-item
prop=
"password"
>
<span
class=
"svg-container"
>
<svg-icon
icon-
class
=
"password"
/>
<svg-icon
icon-
name
=
"password"
/>
</span>
<el-input
ref=
"passwordRef"
...
...
@@ -52,7 +52,7 @@
/>
<span
class=
"show-pwd"
@
click=
"showPwd"
>
<svg-icon
:icon-
class
=
"passwordType === 'password' ? 'eye' : 'eye-open'"
:icon-
name
=
"passwordType === 'password' ? 'eye' : 'eye-open'"
/>
</span>
</el-form-item>
...
...
src/views/system/dict/components/DictItem.vue
浏览文件 @
100ab2e0
...
...
@@ -15,7 +15,7 @@ import {
updateDictItem
,
deleteDictItems
}
from
'
@/api/dict
'
;
import
{
Search
,
Plus
,
Edit
,
Refresh
,
Delete
}
from
'
@element-plus/icons-vue
'
;
import
{
Search
,
Plus
,
Refresh
,
Delete
}
from
'
@element-plus/icons-vue
'
;
import
{
DictItem
,
DictItemForm
,
DictItemQuery
}
from
'
@/api/dict/types
'
;
const
props
=
defineProps
({
...
...
src/views/system/dict/index.vue
浏览文件 @
100ab2e0
...
...
@@ -29,7 +29,7 @@ const handleDictTypeClick = (row: any) => {
<el-col
:span=
"10"
:xs=
"24"
>
<el-card
class=
"box-card"
>
<template
#header
>
<svg-icon
icon-
class
=
"dict"
/>
<svg-icon
icon-
name
=
"dict"
/>
字典类型
</
template
>
<dict-type
@
dictClick=
"handleDictTypeClick"
/>
...
...
@@ -39,7 +39,7 @@ const handleDictTypeClick = (row: any) => {
<el-col
:span=
"14"
:xs=
"24"
>
<el-card
class=
"box-card"
>
<
template
#header
>
<svg-icon
icon-
class
=
"dict_item"
/>
<svg-icon
icon-
name
=
"dict_item"
/>
<span
style=
"margin: 0 5px"
>
字典数据项
</span>
<el-tag
type=
"success"
v-if=
"typeCode"
size=
"small"
>
{{
typeName
...
...
src/views/system/menu/index.vue
浏览文件 @
100ab2e0
...
...
@@ -40,7 +40,7 @@
<el-table-column
label=
"菜单名称"
>
<
template
#default=
"scope"
>
<svg-icon
:icon-
class
=
"
:icon-
name
=
"
scope.row.type === 'BUTTON' ? 'button' : scope.row.icon
"
/>
...
...
@@ -121,6 +121,7 @@
</el-table-column>
</el-table>
</el-card>
<!-- dialog -->
<el-dialog
:title=
"dialog.title"
...
...
@@ -214,27 +215,8 @@
prop=
"icon"
v-if=
"formData.type !== 'BUTTON'"
>
<el-popover
ref=
"popoverRef"
placement=
"bottom-start"
:width=
"570"
trigger=
"click"
>
<
template
#reference
>
<el-input
v-model=
"formData.icon"
placeholder=
"点击选择图标"
readonly
@
click=
"iconSelectVisible = true"
>
<template
#prefix
>
<svg-icon
:icon-class=
"formData.icon"
/>
</
template
>
</el-input>
</template>
<icon-select
@
selected=
"selected"
/>
</el-popover>
<!-- 图标选择器 -->
<icon-select
v-model=
"formData.icon"
/>
</el-form-item>
<el-form-item
label=
"跳转路由"
v-if=
"formData.type == 'CATEGORY'"
>
...
...
@@ -271,8 +253,8 @@
<
script
setup
lang=
"ts"
>
import
{
reactive
,
ref
,
onMounted
,
toRefs
}
from
'
vue
'
;
import
{
Search
,
Plus
,
Edit
,
Refresh
,
Delete
}
from
'
@element-plus/icons-vue
'
;
import
{
ElForm
,
ElMessage
,
ElMessageBox
,
ElPopover
}
from
'
element-plus
'
;
import
{
Search
,
Plus
,
Refresh
}
from
'
@element-plus/icons-vue
'
;
import
{
ElForm
,
ElMessage
,
ElMessageBox
}
from
'
element-plus
'
;
import
{
MenuQuery
,
MenuForm
,
Menu
}
from
'
@/api/menu/types
'
;
// API 依赖
...
...
@@ -291,7 +273,6 @@ import IconSelect from '@/components/IconSelect/index.vue';
const
emit
=
defineEmits
([
'
menuClick
'
]);
const
queryFormRef
=
ref
(
ElForm
);
const
dataFormRef
=
ref
(
ElForm
);
const
popoverRef
=
ref
(
ElPopover
);
const
state
=
reactive
({
loading
:
true
,
...
...
@@ -339,7 +320,6 @@ const {
formData
,
rules
,
menuOptions
,
iconSelectVisible
,
cacheData
}
=
toRefs
(
state
);
...
...
src/views/system/role/index.vue
浏览文件 @
100ab2e0
...
...
@@ -292,7 +292,6 @@ onMounted(() => {
>
资源分配
</el-button>
<el-button
type=
"primary"
link
...
...
src/views/system/user/index.vue
浏览文件 @
100ab2e0
...
...
@@ -23,7 +23,7 @@ import {
updateUser
,
updateUserStatus
,
updateUserPassword
,
downloadTemplate
,
downloadTemplate
Api
,
exportUser
,
importUser
}
from
'
@/api/user
'
;
...
...
@@ -353,8 +353,8 @@ function getGenderOptions() {
/**
* 下载导入模板
*/
function
handleD
ownloadTemplate
()
{
downloadTemplate
().
then
((
response
:
any
)
=>
{
function
d
ownloadTemplate
()
{
downloadTemplate
Api
().
then
((
response
:
any
)
=>
{
const
blob
=
new
Blob
([
response
.
data
],
{
type
:
'
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8
'
});
...
...
@@ -520,46 +520,43 @@ onMounted(() => {
<el-card
shadow=
"never"
>
<template
#header
>
<el-form-item
style=
"float: left"
>
<el-button
type=
"success"
:icon=
"Plus"
@
click=
"handleAdd"
v-hasPerm=
"['sys:user:add']"
>
新增
</el-button
>
<el-button
type=
"danger"
:icon=
"Delete"
:disabled=
"ids.length === 0"
@
click=
"handleDelete"
v-hasPerm=
"['sys:user:delete']"
>
删除
</el-button
>
</el-form-item>
<el-form-item
style=
"float: right"
>
<el-dropdown
split-button
style=
"margin-left: 12px"
>
导入
<template
#dropdown
>
<el-dropdown-menu>
<el-dropdown-item
:icon=
"Download"
@
click=
"handleDownloadTemplate"
>
下载模板
</el-dropdown-item
>
<el-dropdown-item
:icon=
"Top"
@
click=
"showImportDialog"
>
导入数据
</el-dropdown-item
>
</el-dropdown-menu>
</
template
>
</el-dropdown>
<el-button
:icon=
"Download"
style=
"margin-left: 12px"
@
click=
"handleExport"
>
导出
</el-button
>
</el-form-item>
<div
class=
"flex justify-between"
>
<div>
<el-button
type=
"success"
:icon=
"Plus"
@
click=
"handleAdd"
v-hasPerm=
"['sys:user:add']"
>
新增
</el-button
>
<el-button
type=
"danger"
:icon=
"Delete"
:disabled=
"ids.length === 0"
@
click=
"handleDelete"
v-hasPerm=
"['sys:user:delete']"
>
删除
</el-button
>
</div>
<div>
<el-dropdown
split-button
>
导入
<template
#dropdown
>
<el-dropdown-menu>
<el-dropdown-item
@
click=
"downloadTemplate"
>
<i-ep-download
/>
下载模板
</el-dropdown-item
>
<el-dropdown-item
@
click=
"showImportDialog"
>
<i-ep-top
/>
导入数据
</el-dropdown-item
>
</el-dropdown-menu>
</
template
>
</el-dropdown>
<el-button
class=
"ml-3"
@
click=
"handleExport"
><
template
#icon
><i-ep-download
/></
template
>
导出
</el-button
>
</div>
</div>
</template>
<el-table
...
...
tsconfig.json
浏览文件 @
100ab2e0
...
...
@@ -21,9 +21,9 @@
"types"
:
[
"element-plus/global"
],
"typeRoots"
:
[
"./node_modules/@types/"
,
"
.
/types"
"
src
/types"
]
/*
指定多个文件夹,这些文件夹的作用类似于
'./node_modules/@types'.
*/
},
"include"
:
[
"src/**/*.ts"
,
"src/**/*.vue"
,
"types/**/*.d.ts"
],
"include"
:
[
"src/**/*.ts"
,
"src/**/*.vue"
,
"
src/
types/**/*.d.ts"
],
"exclude"
:
[
"node_modules"
,
"dist"
,
"**/*.js"
]
}
types/components.d.ts
已删除
100644 → 0
浏览文件 @
c6d57558
// 全局组件类型声明
import
Pagination
from
'
@/components/Pagination/index.vue
'
;
declare
module
'
@vue/runtime-core
'
{
export
interface
GlobalComponents
{
Pagination
:
typeof
Pagination
;
}
}
export
{};
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录