Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
F
frontend-yd-email
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Sweet Zhang
frontend-yd-email
Commits
0fd0cb01
Commit
0fd0cb01
authored
Sep 29, 2025
by
Sweet Zhang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
分页对接,菜单可折叠
parent
79fddc42
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
221 additions
and
89 deletions
+221
-89
src/App.vue
+15
-9
src/utils/menuConfig.ts
+50
-0
src/views/ComposeEmail.vue
+11
-6
src/views/MobileSidebar.vue
+11
-25
src/views/Sidebar.vue
+96
-47
src/views/VariableManagement.vue
+38
-2
No files found.
src/App.vue
View file @
0fd0cb01
...
...
@@ -6,7 +6,12 @@
<!-- 主应用布局 -->
<div
v-else
class=
"flex flex-1 h-screen"
>
<!-- 侧边导航 -->
<Sidebar
:current-page=
"currentPage"
@
logout=
"handleLogout"
/>
<Sidebar
:current-page=
"currentPage"
:collapsed=
"sidebarCollapsed"
@
logout=
"handleLogout"
@
toggle-collapse=
"toggleSidebar"
/>
<!-- 移动端菜单按钮 -->
<button
...
...
@@ -25,7 +30,10 @@
/>
<!-- 主内容区域 -->
<div
class=
"flex-1 flex flex-col"
>
<div
class=
"flex-1 flex flex-col transition-all duration-300"
:class=
"sidebarCollapsed ? 'ml-16' : 'ml-64'"
>
<main
class=
"flex-1 overflow-y-auto bg-gray-50 p-4 md:p-6"
>
<header
class=
"mb-6"
>
<h2
class=
"text-2xl font-bold text-gray-800"
>
...
...
@@ -47,6 +55,7 @@ import { useRoute, useRouter } from 'vue-router'
import
LoginPage
from
'./views/LoginPage.vue'
import
Sidebar
from
'./views/Sidebar.vue'
import
MobileSidebar
from
'./views/MobileSidebar.vue'
import
{
pageTitles
}
from
'@/utils/menuConfig'
const
route
=
useRoute
()
const
router
=
useRouter
()
...
...
@@ -56,6 +65,7 @@ const isLoginPage = ref(true)
const
isAuthenticated
=
ref
(
false
)
const
currentPage
=
ref
(
'compose'
)
const
showMobileMenu
=
ref
(
false
)
const
sidebarCollapsed
=
ref
(
false
)
// 新增:侧边栏折叠状态
// 监听路由变化,更新当前页面状态
watch
(
...
...
@@ -67,13 +77,9 @@ watch(
},
)
// 页面标题映射(保持不变)
const
pageTitles
=
{
compose
:
'写邮件'
,
contacts
:
'联系人管理'
,
senders
:
'发件人管理'
,
variables
:
'变量管理'
,
emails
:
'邮件记录'
,
// 切换侧边栏折叠状态
const
toggleSidebar
=
()
=>
{
sidebarCollapsed
.
value
=
!
sidebarCollapsed
.
value
}
// 方法(移除页面切换相关方法)
...
...
src/utils/menuConfig.ts
0 → 100644
View file @
0fd0cb01
// 菜单项接口定义
export
interface
MenuItem
{
name
:
string
path
:
string
icon
:
string
title
:
string
}
// 菜单配置
export
const
menuConfig
:
MenuItem
[]
=
[
{
name
:
'compose'
,
path
:
'/compose'
,
icon
:
'fas fa-pen'
,
title
:
'写邮件'
,
},
{
name
:
'contacts'
,
path
:
'/contacts'
,
icon
:
'fas fa-address-book'
,
title
:
'联系人管理'
,
},
{
name
:
'senders'
,
path
:
'/senders'
,
icon
:
'fas fa-user-circle'
,
title
:
'发件人管理'
,
},
{
name
:
'variables'
,
path
:
'/variables'
,
icon
:
'fas fa-file-excel'
,
title
:
'变量管理'
,
},
{
name
:
'emails'
,
path
:
'/emails'
,
icon
:
'fas fa-history'
,
title
:
'邮件记录'
,
},
]
// 页面标题映射
export
const
pageTitles
:
Record
<
string
,
string
>
=
{
compose
:
'写邮件'
,
contacts
:
'联系人管理'
,
senders
:
'发件人管理'
,
variables
:
'变量管理'
,
emails
:
'邮件记录'
,
}
src/views/ComposeEmail.vue
View file @
0fd0cb01
...
...
@@ -196,7 +196,7 @@
:records=
"importRecords"
@
update-record=
"updateImportRecord"
@
delete-record=
"deleteImportRecord"
@
close=
"
((showImportRecordManager = false), getImportedContacts())
"
@
close=
"
showImportRecordManager = false
"
/>
<!-- 导入数据弹窗 -->
...
...
@@ -397,7 +397,7 @@ const updateImportRecord = (updatedRecord: ImportRecord) => {
type
:
'success'
,
})
// 更新成功之后,刷新导入记录列表
getImportedContacts
(
emailForm
.
value
.
sessionId
||
''
)
getImportedContacts
(
emailForm
.
value
.
sessionId
||
''
,
'update'
)
}
else
{
ElMessage
({
message
:
'导入记录更新失败'
,
...
...
@@ -468,7 +468,7 @@ const sendEmail = () => {
}
// 通过sessionId获取导入的联系人
const
getImportedContacts
=
(
sessionId
?:
string
)
=>
{
const
getImportedContacts
=
(
sessionId
?:
string
,
type
?:
string
)
=>
{
const
params
=
{
sessionId
:
sessionId
||
emailForm
.
value
.
sessionId
||
''
,
source
:
importSource
.
value
,
...
...
@@ -477,9 +477,14 @@ const getImportedContacts = (sessionId?: string) => {
if
(
res
.
code
===
200
)
{
console
.
log
(
'导入的联系人:'
,
res
.
data
)
importRecords
.
value
=
res
.
data
.
records
||
[]
// 更新页面展示的抄送人和收件人
// emailForm.value.receiveEmail = res.data?.receiveEmails || ''
// emailForm.value.ccEmails = res.data?.ccEmails || ''
// 从导入记录中提取收件人和抄送人
if
(
type
==
'update'
)
{
debugger
emailForm
.
value
.
receiveEmail
=
importRecords
.
value
.
map
((
item
)
=>
item
.
receiveEmail
)
.
join
(
','
)
emailForm
.
value
.
ccEmails
=
importRecords
.
value
.
map
((
item
)
=>
item
.
ccEmail
).
join
(
','
)
}
}
})
}
...
...
src/views/MobileSidebar.vue
View file @
0fd0cb01
...
...
@@ -9,34 +9,14 @@
</div>
<nav>
<ul>
<li
class=
"mb-2"
>
<li
v-for=
"menu in menuItems"
:key=
"menu.name"
class=
"mb-2"
>
<router-link
to=
"/compose
"
:to=
"menu.path
"
class=
"w-full text-left px-4 py-2 rounded hover:bg-blue-500 transition-colors flex items-center block"
:class=
"
{ 'bg-blue-500': currentPage ===
'compose'
}"
:class=
"
{ 'bg-blue-500': currentPage ===
menu.name
}"
@click="$emit('close-menu')"
>
<i
class=
"fas fa-pen mr-2"
></i>
写邮件
</router-link>
</li>
<li
class=
"mb-2"
>
<router-link
to=
"/variables"
class=
"w-full text-left px-4 py-2 rounded hover:bg-blue-500 transition-colors flex items-center block"
:class=
"
{ 'bg-blue-500': currentPage === 'variables' }"
@click="$emit('close-menu')"
>
<i
class=
"fas fa-file-excel mr-2"
></i>
变量管理
</router-link>
</li>
<li
class=
"mb-2"
>
<router-link
to=
"/emails"
class=
"w-full text-left px-4 py-2 rounded hover:bg-blue-500 transition-colors flex items-center block"
:class=
"
{ 'bg-blue-500': currentPage === 'emails' }"
@click="$emit('close-menu')"
>
<i
class=
"fas fa-history mr-2"
></i>
邮件记录
<i
:class=
"menu.icon"
class=
"mr-2"
></i>
{{
menu
.
title
}}
</router-link>
</li>
</ul>
...
...
@@ -53,16 +33,22 @@
</div>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
ref
,
watch
}
from
'vue'
import
{
ref
,
watch
,
computed
}
from
'vue'
import
{
useRouter
}
from
'vue-router'
import
{
menuConfig
}
from
'@/utils/menuConfig'
const
router
=
useRouter
()
const
currentPage
=
ref
(
router
.
currentRoute
.
value
.
name
as
string
)
// 使用统一的菜单配置
const
menuItems
=
computed
(()
=>
menuConfig
)
watch
(
()
=>
router
.
currentRoute
.
value
.
name
,
(
name
)
=>
{
if
(
name
)
{
currentPage
.
value
=
name
as
string
}
},
)
</
script
>
src/views/Sidebar.vue
View file @
0fd0cb01
<
template
>
<aside
class=
"bg-sky-700 text-white w-64 flex-shrink-0 hidden md:block transition-all duration-300 ease-in-out"
class=
"bg-sky-700 text-white flex-shrink-0 hidden md:block transition-all duration-300 ease-in-out fixed h-full z-40"
:class=
"collapsed ? 'w-16' : 'w-64'"
>
<div
class=
"p-4 border-b border-blue-500"
>
<h1
class=
"text-xl font-bold"
>
邮件系统
</h1>
<!-- 顶部区域 -->
<div
class=
"p-4 border-b border-blue-500 flex items-center justify-between"
>
<h1
class=
"text-xl font-bold transition-all duration-300"
:class=
"collapsed ? 'opacity-0 w-0' : 'opacity-100'"
>
邮件系统
</h1>
<button
@
click=
"$emit('toggle-collapse')"
class=
"p-1 rounded hover:bg-blue-500 transition-colors flex items-center justify-center"
:title=
"collapsed ? '展开菜单' : '折叠菜单'"
>
<i
class=
"fas"
:class=
"collapsed ? 'fa-chevron-right' : 'fa-chevron-left'"
></i>
</button>
</div>
<!-- 导航菜单 -->
<nav
class=
"p-4"
>
<ul>
<li
class=
"mb-2"
>
<router-link
to=
"/compose"
class=
"w-full text-left px-4 py-2 rounded hover:bg-blue-500 transition-colors flex items-center block"
:class=
"
{ 'bg-blue-500': currentPage === 'compose' }"
>
<i
class=
"fas fa-pen mr-2"
></i>
写邮件
</router-link>
</li>
<li
class=
"mb-2"
>
<router-link
to=
"/contacts"
class=
"w-full text-left px-4 py-2 rounded hover:bg-blue-500 transition-colors flex items-center block"
:class=
"
{ 'bg-blue-500': currentPage === 'contacts' }"
>
<i
class=
"fas fa-address-book mr-2"
></i>
联系人管理
</router-link>
</li>
<li
class=
"mb-2"
>
<li
v-for=
"menu in menuItems"
:key=
"menu.name"
class=
"mb-2"
>
<router-link
to=
"/senders"
class=
"w-full text-left px-4 py-2 rounded hover:bg-blue-500 transition-colors flex items-center block"
:class=
"
{ 'bg-blue-500': currentPage === 'senders' }"
:to=
"menu.path"
class=
"w-full text-left px-4 py-2 rounded hover:bg-blue-500 transition-colors flex items-center"
:class=
"
{
'bg-blue-500': currentPage === menu.name,
'justify-center': collapsed,
'justify-start': !collapsed,
}"
:title="collapsed ? menu.title : ''"
>
<i
class=
"fas fa-user-circle mr-2"
></i>
发件人管理
</router-link>
</li>
<li
class=
"mb-2"
>
<router-link
to=
"/variables"
class=
"w-full text-left px-4 py-2 rounded hover:bg-blue-500 transition-colors flex items-center block"
:class=
"
{ 'bg-blue-500': currentPage === 'variables' }"
<i
:class=
"[menu.icon, collapsed ? '' : 'mr-2']"
class=
"flex-shrink-0"
></i>
<span
class=
"transition-all duration-300"
:class=
"collapsed ? 'opacity-0 w-0 ml-0' : 'opacity-100 ml-2'"
>
<i
class=
"fas fa-file-excel mr-2"
></i>
变量管理
</router-link>
</li>
<li
class=
"mb-2"
>
<router-link
to=
"/emails"
class=
"w-full text-left px-4 py-2 rounded hover:bg-blue-500 transition-colors flex items-center block"
:class=
"
{ 'bg-blue-500': currentPage === 'emails' }"
>
<i
class=
"fas fa-history mr-2"
></i>
邮件记录
{{
menu
.
title
}}
</span>
</router-link>
</li>
</ul>
</nav>
<!-- 底部退出按钮 -->
<div
class=
"absolute bottom-4 left-0 right-0 px-4"
>
<button
@
click=
"$emit('logout')"
class=
"text-left px-4 py-2 rounded hover:bg-blue-500 transition-colors flex items-center text-sm"
class=
"w-full text-left px-4 py-2 rounded hover:bg-blue-500 transition-colors flex items-center justify-center text-sm"
:class=
"collapsed ? 'justify-center' : 'justify-start'"
:title=
"collapsed ? '退出登录' : ''"
>
<i
class=
"fas fa-sign-out-alt flex-shrink-0"
:class=
"collapsed ? '' : 'mr-2'"
></i>
<span
class=
"transition-all duration-300"
:class=
"collapsed ? 'opacity-0 w-0' : 'opacity-100'"
>
<i
class=
"fas fa-sign-out-alt mr-2"
></i>
退出登录
退出登录
</span>
</button>
</div>
</aside>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
defineProps
,
defineEmits
}
from
'vue'
import
{
defineProps
,
defineEmits
,
computed
}
from
'vue'
import
{
menuConfig
}
from
'@/utils/menuConfig'
const
props
=
defineProps
({
currentPage
:
{
type
:
String
,
required
:
true
,
},
collapsed
:
{
type
:
Boolean
,
default
:
false
,
},
})
const
emits
=
defineEmits
([
'logout'
])
const
emits
=
defineEmits
([
'logout'
,
'toggle-collapse'
])
// 使用统一的菜单配置
const
menuItems
=
computed
(()
=>
menuConfig
)
</
script
>
<
style
scoped
>
/* 确保折叠时图标居中 */
.router-link-active
{
@apply
bg-blue-500;
}
/* 优化折叠状态下的样式 */
aside
{
box-shadow
:
2px
0
10px
rgba
(
0
,
0
,
0
,
0.1
);
}
/* 防止文字在折叠时显示 */
span
{
white-space
:
nowrap
;
overflow
:
hidden
;
}
/* 增加菜单项的可点击区域 */
li
a
{
min-height
:
44px
;
/* 确保触摸友好的最小高度 */
cursor
:
pointer
;
}
/* 优化折叠状态下的交互体验 */
li
a
:hover
{
background-color
:
rgba
(
59
,
130
,
246
,
0.8
);
}
/* 确保图标和文字垂直对齐 */
li
a
{
align-items
:
center
;
}
/* 优化图标和文字的间距 */
i
{
width
:
1.25rem
;
/* 固定图标宽度 */
text-align
:
center
;
}
</
style
>
src/views/VariableManagement.vue
View file @
0fd0cb01
...
...
@@ -189,6 +189,16 @@
<i
class=
"fas fa-variable text-4xl mb-3 opacity-30"
></i>
<p>
暂无变量,请添加变量
</p>
</div>
<!-- 分页组件 -->
<Pagination
:total=
"total"
:current=
"currentPage"
:page-size=
"pageSize"
@
change=
"handlePageChange"
@
update:current=
"handleCurrentUpdate"
@
update:page-size=
"handlePageSizeUpdate"
/>
</div>
<!-- 变量模板弹窗 -->
...
...
@@ -292,6 +302,31 @@ import type { Variable, VariableTemplate } from '../types'
import
{
variableApi
,
variableGroupApi
}
from
'@/api/api'
import
{
ElMessage
}
from
'element-plus'
// 引入分页组件
import
Pagination
from
'@/components/Pagination.vue'
// 初始数据
const
total
=
ref
(
0
)
const
currentPage
=
ref
(
1
)
const
pageSize
=
ref
(
10
)
// 处理分页变化
const
handlePageChange
=
(
page
:
number
,
size
:
number
)
=>
{
console
.
log
(
'分页变化:'
,
page
,
size
)
fetchVariables
()
// 这里可以发起API请求获取新数据
}
const
handleCurrentUpdate
=
(
page
:
number
)
=>
{
currentPage
.
value
=
page
}
const
handlePageSizeUpdate
=
(
size
:
number
)
=>
{
pageSize
.
value
=
size
currentPage
.
value
=
1
// 重置到第一页
}
// 引入弹窗组件
import
CommonModal
from
'@/components/CommonModal.vue'
// 弹窗提示信息对象
...
...
@@ -474,13 +509,14 @@ const deleteVariable = (id: string, type?: string) => {
// 查询变量列表
const
fetchVariables
=
()
=>
{
const
params
=
{
pageNo
:
1
,
pageSize
:
10
,
pageNo
:
currentPage
.
value
,
pageSize
:
pageSize
.
value
,
}
variableApi
.
getEmailVariableList
(
params
)
.
then
((
res
)
=>
{
variables
.
value
=
res
.
data
.
records
||
[]
total
.
value
=
res
.
data
.
total
||
0
})
.
catch
((
error
)
=>
{
console
.
error
(
'查询变量列表失败:'
,
error
)
...
...
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