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
f7789154
Commit
f7789154
authored
Oct 10, 2025
by
Sweet Zhang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
联系人管理页面不能滑动处理
parent
0fee6a3f
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
223 additions
and
177 deletions
+223
-177
index.html
+1
-1
public/favicon.gif
+0
-0
public/favicon.ico
+0
-0
src/components/CommonModal.vue
+2
-39
src/views/ComposeEmail.vue
+1
-11
src/views/ContactManagement.vue
+42
-102
src/views/ImportDialog.vue
+2
-2
src/views/SenderManagement.vue
+3
-3
src/views/VariableManagement.vue
+172
-19
No files found.
index.html
View file @
f7789154
...
...
@@ -2,7 +2,7 @@
<html
lang=
""
>
<head>
<meta
charset=
"UTF-8"
/>
<link
rel=
"icon"
href=
"/favicon.
ico
"
/>
<link
rel=
"icon"
href=
"/favicon.
gif
"
/>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1.0"
/>
<title>
银盾邮件系统
</title>
</head>
...
...
public/favicon.gif
0 → 100644
View file @
f7789154
1.35 KB
public/favicon.ico
deleted
100644 → 0
View file @
0fee6a3f
File deleted
src/components/CommonModal.vue
View file @
f7789154
...
...
@@ -20,13 +20,13 @@
<!-- 弹窗内容 -->
<div
class=
"modal-content"
>
<!-- 图标区域 -->
<div
<
!-- <
div
v-if="type && showIcon"
class="icon-container mr-4 flex-shrink-0"
:class="iconContainerClass"
>
<component :is="getIconComponent" class="w-6 h-6" />
</div>
</div>
-->
<!-- 内容区域 -->
<div
class=
"content-container flex-1"
>
...
...
@@ -260,43 +260,6 @@ const getButtonType = computed(() => {
}
})
// 获取图标组件
const
getIconComponent
=
computed
<
Component
>
(()
=>
{
switch
(
props
.
type
)
{
case
'success'
:
return
Check
case
'warning'
:
return
Warning
case
'error'
:
return
CircleClose
case
'info'
:
return
InfoFilled
case
'confirm'
:
return
QuestionFilled
default
:
return
InfoFilled
}
})
// 图标容器样式
const
iconContainerClass
=
computed
(()
=>
{
const
base
=
'rounded-full p-2'
switch
(
props
.
type
)
{
case
'success'
:
return
`
${
base
}
bg-green-100 text-green-600`
case
'warning'
:
return
`
${
base
}
bg-yellow-100 text-yellow-600`
case
'error'
:
return
`
${
base
}
bg-red-100 text-red-600`
case
'info'
:
return
`
${
base
}
bg-blue-100 text-blue-600`
case
'confirm'
:
return
`
${
base
}
bg-gray-100 text-gray-600`
default
:
return
`
${
base
}
bg-gray-100 text-gray-600`
}
})
// 处理关闭事件 - 传递triggerKey
const
handleClose
=
()
=>
{
dialogVisible
.
value
=
false
...
...
src/views/ComposeEmail.vue
View file @
f7789154
...
...
@@ -228,7 +228,7 @@
@
close=
"showVariableSelector = false"
/>
<!-- 发送邮件弹窗 -->
<el-dialog
v-model=
"dialogVisible"
title=
"提示"
width=
"500"
:before-close=
"handleClose"
>
<el-dialog
v-model=
"dialogVisible"
title=
"提示"
width=
"500"
>
<span>
邮件发送任务已提交,请前往邮件记录中查看发送状态
</span>
<template
#
footer
>
<div
class=
"dialog-footer"
>
...
...
@@ -267,16 +267,6 @@ import {
}
from
'../api/api'
const
dialogVisible
=
ref
(
false
)
const
handleClose
=
(
done
:
()
=>
void
)
=>
{
ElMessageBox
.
confirm
(
'邮件发送任务已提交,请前往邮件记录中查看发送状态'
)
.
then
(()
=>
{
done
()
})
.
catch
(()
=>
{
// catch error
})
}
// 远程搜索方法
const
remoteSearch
=
async
(
query
:
string
,
type
:
string
)
=>
{
console
.
log
(
query
,
type
)
...
...
src/views/ContactManagement.vue
View file @
f7789154
...
...
@@ -83,111 +83,49 @@
<!-- 联系人列表 -->
<div
class=
"bg-white rounded-lg shadow-sm overflow-hidden"
>
<div
class=
"overflow-x-auto"
>
<table
class=
"w-full"
>
<thead>
<tr
class=
"bg-gray-50 border-b border-gray-200"
>
<th
class=
"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
姓名
</th>
<th
class=
"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
称谓
</th>
<th
class=
"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
公司
</th>
<th
class=
"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
收件人邮箱
</th>
<th
class=
"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
抄送人邮箱
</th>
<th
class=
"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
其他信息
</th>
<th
class=
"px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider"
>
操作
</th>
</tr>
</thead>
<tbody
class=
"divide-y divide-gray-200"
>
<tr
v-for=
"contact in filteredContacts"
:key=
"contact.contactBizId"
class=
"hover:bg-gray-50 transition-colors"
>
<td
class=
"px-6 py-4 whitespace-nowrap"
>
<div
class=
"flex items-center"
>
<div
class=
"w-8 h-8 rounded-full bg-blue-100 flex items-center justify-center text-blue-600 mr-3"
>
<span
class=
"text-sm font-medium"
>
{{
contact
.
name
?.
charAt
(
0
)
||
'-'
}}
</span>
</div>
<div>
<div
class=
"text-sm font-medium text-gray-900"
>
{{
contact
.
name
||
'-'
}}
</div>
</div>
</div>
</td>
<td
class=
"px-6 py-4 whitespace-nowrap"
>
<div
class=
"text-sm text-gray-500"
>
{{
contact
.
appellation
||
'-'
}}
</div>
</td>
<td
class=
"px-6 py-4 whitespace-nowrap"
>
<div
class=
"text-sm text-gray-500"
>
{{
contact
.
companyName
||
'-'
}}
</div>
</td>
<td
class=
"px-6 py-4 whitespace-nowrap"
>
<div
class=
"text-sm text-gray-500"
>
{{
contact
.
email
||
'-'
}}
</div>
</td>
<td
class=
"px-6 py-4"
>
<div
class=
"flex flex-wrap gap-1"
>
<span
v-for=
"(email, index) in contact.ccEmailList || []"
:key=
"index"
class=
"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800"
>
{{
email
}}
</span>
<span
v-if=
"contact.ccEmailList?.length === 0"
class=
"text-sm text-gray-500"
>
-
</span
>
</div>
</td>
<td
class=
"px-6 py-4"
>
<div
class=
"text-sm text-gray-500 line-clamp-2"
>
{{
contact
.
other
||
'-'
}}
<el-table
:data=
"filteredContacts"
max-height=
"500"
style=
"width: 100%"
table-layout=
"auto"
>
<el-table-column
label=
"姓名"
>
<template
#
default=
"scope"
>
<div
style=
"display: flex; align-items: center"
>
<div
class=
"w-8 h-8 rounded-full bg-blue-100 flex items-center justify-center text-blue-600 mr-3"
>
<span
class=
"text-sm font-medium"
>
{{
scope
.
row
.
name
?.
charAt
(
0
)
||
'-'
}}
</span>
</div>
</td>
<td
class=
"px-6 py-4 whitespace-nowrap text-right text-sm font-medium"
>
<button
@
click=
"editContactModal(contact)"
class=
"text-blue-600 hover:text-blue-900 mr-4"
title=
"编辑"
<span
style=
"margin-left: 10px"
>
{{
scope
.
row
.
name
}}
</span>
</div>
</
template
>
</el-table-column>
<el-table-column
prop=
"title"
label=
"称谓"
/>
<el-table-column
prop=
"companyName"
label=
"公司"
/>
<el-table-column
prop=
"email"
label=
"收件人邮箱"
/>
<el-table-column
label=
"抄送人邮箱"
>
<
template
#
default=
"scope"
>
<div
class=
"flex flex-wrap gap-1"
>
<span
v-for=
"(email, index) in scope.row.ccEmailList || []"
:key=
"index"
class=
"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800"
>
<i
class=
"fas fa-edit"
></i>
</button>
<button
@
click=
"deleteContactModal(contact)"
class=
"text-red-600 hover:text-red-900"
title=
"删除"
{{
email
}}
</span>
<span
v-if=
"scope.row.ccEmailList?.length === 0"
class=
"text-sm text-gray-500"
>
-
</span
>
<i
class=
"fas fa-trash"
></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</
template
>
</el-table-column>
<el-table-column
prop=
"other"
label=
"其他信息"
/>
<el-table-column
label=
"操作"
>
<
template
#
default=
"scope"
>
<el-button
size=
"small"
@
click=
"editContactModal(scope.row)"
>
编辑
</el-button>
<el-button
size=
"small"
type=
"danger"
@
click=
"deleteContactModal(scope.row)"
>
删除
</el-button>
</
template
>
</el-table-column>
</el-table>
</div>
<!-- 分页组件 -->
<Pagination
...
...
@@ -404,6 +342,8 @@ const handleImportSuccess = (file: File) => {
title
:
'成功'
,
message
:
'联系人导入成功'
,
})
// 刷新联系人列表
fetchContacts
()
}
const
handleImportCancel
=
(
triggerKey
:
string
)
=>
{
...
...
src/views/ImportDialog.vue
View file @
f7789154
...
...
@@ -84,10 +84,10 @@ const handleDocumentUploadSuccess = (results: UploadResult[]) => {
const
handleDocumentUploadError
=
(
error
:
string
)
=>
{
emit
(
'error'
,
error
,
props
.
triggerKey
)
}
const
emit
=
defineEmits
([
'success'
,
'error'
,
'c
lose
'
,
'confirm'
])
const
emit
=
defineEmits
([
'success'
,
'error'
,
'c
ancel
'
,
'confirm'
])
const
handleCancel
=
()
=>
{
emit
(
'c
lose
'
,
props
.
triggerKey
)
emit
(
'c
ancel
'
,
props
.
triggerKey
)
}
const
handleConfirm
=
()
=>
{
emit
(
'confirm'
,
result
.
value
,
props
.
triggerKey
)
...
...
src/views/SenderManagement.vue
View file @
f7789154
...
...
@@ -370,12 +370,12 @@ const saveSender = () => {
if
(
res
.
code
===
200
)
{
getSenders
()
openModal
({
title
:
'
更新确认
'
,
message
:
'发件人更新成功'
,
title
:
'
提示
'
,
message
:
'发件人
信息
更新成功'
,
})
}
else
{
openModal
({
title
:
'
更新失败
'
,
title
:
'
提示
'
,
message
:
res
.
msg
||
'更新失败'
,
})
}
...
...
src/views/VariableManagement.vue
View file @
f7789154
...
...
@@ -167,10 +167,7 @@
{{
variablePrefix
}}{{
variable
.
variableNameEn
}}{{
variableNextfix
}}
</td>
<td
class=
"px-6 py-4"
>
{{
variable
.
description
||
'-'
}}
</td>
<td
class=
"px-6 py-4 whitespace-nowrap text-right text-sm font-medium"
v-if=
"variable.isGeneral !== 1"
>
<td
class=
"px-6 py-4 whitespace-nowrap text-right text-sm font-medium"
>
<button
@
click=
"editVariable(variable)"
class=
"text-blue-600 hover:text-blue-900 mr-3"
...
...
@@ -204,14 +201,88 @@
/>
</div>
<EditVariableGroup
ref=
"editVariableGroupRef"
:visible=
"showTemplateModal"
:editing-template-id=
"editingTemplateId"
:template-form=
"templateForm"
@
confirm=
"editVariableTemplate"
@
closeTemplateModal=
"closeTemplateModal"
/>
<!-- 变量模板弹窗 -->
<div
v-if=
"showTemplateModal"
class=
"fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4"
>
<div
class=
"bg-white rounded-lg shadow-xl w-full max-w-2xl max-h-[80vh] flex flex-col"
>
<div
class=
"p-4 border-b border-gray-200 flex justify-between items-center"
>
<h3
class=
"text-lg font-semibold"
>
{{
editingTemplateId
?
'编辑变量模板'
:
'创建变量模板'
}}
</h3>
<button
@
click=
"closeTemplateModal"
>
<i
class=
"fas fa-times text-gray-500"
></i>
</button>
</div>
<div
class=
"p-4 flex-1 overflow-y-auto"
>
<div
class=
"mb-4"
>
<label
class=
"block text-gray-700 mb-1 text-sm"
>
模板名称 *
</label>
<input
v-model=
"templateForm.groupName"
type=
"text"
class=
"w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
/>
</div>
<div
class=
"mb-4"
>
<label
class=
"block text-gray-700 mb-1 text-sm"
>
模板描述
</label>
<textarea
v-model=
"templateForm.description"
class=
"w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
rows=
"2"
></textarea>
</div>
<div
class=
"mb-4"
>
<label
class=
"block text-gray-700 mb-1 text-sm"
>
选择变量
</label>
<div
class=
"space-y-2 max-h-[300px] overflow-y-auto p-2 border border-gray-200 rounded-md"
>
<div
v-for=
"variable in variables"
:key=
"variable.id"
class=
"flex items-center p-2 hover:bg-blue-50 rounded"
>
<input
type=
"checkbox"
:id=
"'template-var-' + variable.variableBizId"
:checked=
"templateForm.variableBizIdList?.includes(variable.variableBizId || '')"
class=
"mr-3"
@
change=
"toggleTemplateVariable(variable.variableBizId || '')"
/>
<label
for=
"'template-var-' + variable.variableBizId"
>
<div
class=
"text-sm text-gray-500"
>
{{
variable
.
variableNameCn
}}
</div>
<div
class=
"font-medium font-mono text-sm"
>
{{
variablePrefix
}}{{
variable
.
variableNameEn
}}{{
variableNextfix
}}
</div>
</label>
</div>
</div>
<div
v-if=
"variables.length === 0"
class=
"p-4 text-center text-gray-500 text-sm"
>
<p>
暂无可用变量,请先添加变量
</p>
</div>
</div>
</div>
<div
class=
"p-4 border-t border-gray-200 flex justify-end gap-3"
>
<button
@
click=
"closeTemplateModal"
class=
"px-6 py-2 border border-gray-300 rounded-md hover:bg-gray-50 transition-colors"
>
取消
</button>
<button
@
click=
"saveVariableTemplate"
class=
"px-6 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-700 transition-colors"
:disabled=
"
!templateForm.groupName ||
!templateForm.variableBizIdList ||
templateForm.variableBizIdList.length === 0
"
>
{{
editingTemplateId
?
'更新模板'
:
'创建模板'
}}
</button>
</div>
</div>
</div>
</div>
<CommonModal
v-model:visible=
"modalVisible"
...
...
@@ -231,14 +302,14 @@ import type { Variable, VariableTemplate } from '../types'
import
{
variableApi
,
variableGroupApi
}
from
'@/api/api'
import
{
ElMessage
}
from
'element-plus'
import
EditVariableGroup
from
'@/views/EditVariableGroup.vue'
// 引入分页组件
import
Pagination
from
'@/components/Pagination.vue'
// 初始数据
const
total
=
ref
(
0
)
const
currentPage
=
ref
(
1
)
const
pageSize
=
ref
(
10
0
)
const
pageSize
=
ref
(
10
)
// 处理分页变化
const
handlePageChange
=
(
page
:
number
,
size
:
number
)
=>
{
...
...
@@ -492,7 +563,7 @@ const fetchVariableTemplates = () => {
// 方法 - 模板管理
const
showCreateTemplateModal
=
(
isNew
:
boolean
)
=>
{
showTemplateModal
.
value
=
true
console
.
log
(
'==='
)
if
(
isNew
)
{
editingTemplateId
.
value
=
''
templateForm
.
value
=
{
...
...
@@ -505,13 +576,10 @@ const showCreateTemplateModal = (isNew: boolean) => {
// 方法 - 编辑变量模版
const
editVariableTemplate
=
(
template
:
VariableTemplate
)
=>
{
editingTemplateId
.
value
=
template
.
variableGroupBizId
||
''
showTemplateModal
.
value
=
false
// 收到更新通知,重新查询变量模版列表
fetchVariableTemplates
()
showTemplateModal
.
value
=
true
}
const
closeTemplateModal
=
()
=>
{
console
.
log
(
'----'
)
showTemplateModal
.
value
=
false
editingTemplateId
.
value
=
''
templateForm
.
value
=
{
...
...
@@ -521,6 +589,86 @@ const closeTemplateModal = () => {
}
}
const
toggleTemplateVariable
=
(
variableId
:
string
)
=>
{
if
(
!
templateForm
.
value
.
variableBizIdList
)
{
templateForm
.
value
.
variableBizIdList
=
[]
}
const
index
=
templateForm
.
value
.
variableBizIdList
.
indexOf
(
variableId
)
if
(
index
>
-
1
)
{
templateForm
.
value
.
variableBizIdList
.
splice
(
index
,
1
)
}
else
{
templateForm
.
value
.
variableBizIdList
.
push
(
variableId
)
}
}
const
saveVariableTemplate
=
()
=>
{
if
(
!
templateForm
.
value
.
groupName
||
!
templateForm
.
value
.
variableBizIdList
||
templateForm
.
value
.
variableBizIdList
.
length
===
0
)
return
if
(
editingTemplateId
.
value
)
{
console
.
log
(
'更新变量模版'
,
templateForm
.
value
)
// 更新现有模板
variableGroupApi
.
editEmailVariableGroup
({
variableGroupBizId
:
editingTemplateId
.
value
,
groupName
:
templateForm
.
value
.
groupName
||
''
,
description
:
templateForm
.
value
.
description
||
''
,
variableBizIdList
:
templateForm
.
value
.
variableBizIdList
||
[],
})
.
then
(()
=>
{
// 刷新变量模版列表
fetchVariableTemplates
()
})
.
catch
((
error
)
=>
{
console
.
error
(
'更新变量模版失败:'
,
error
)
if
(
error
.
response
?.
data
?.
message
)
{
openModal
({
title
:
'错误'
,
message
:
error
.
response
.
data
.
message
,
})
}
else
{
openModal
({
title
:
'错误'
,
message
:
'更新变量模版失败'
,
})
}
})
}
else
{
// 调用变量组保存接口
variableGroupApi
.
addEmailVariableGroup
({
groupName
:
templateForm
.
value
.
groupName
||
''
,
description
:
templateForm
.
value
.
description
||
''
,
variableBizIdList
:
templateForm
.
value
.
variableBizIdList
||
[],
})
.
then
(()
=>
{
// 刷新变量模版列表
fetchVariableTemplates
()
})
.
catch
((
error
)
=>
{
console
.
error
(
'创建变量模版失败:'
,
error
)
if
(
error
.
response
?.
data
?.
message
)
{
openModal
({
title
:
'错误'
,
message
:
error
.
response
.
data
.
message
,
})
}
else
{
openModal
({
title
:
'错误'
,
message
:
'创建变量模版失败'
,
})
}
})
}
closeTemplateModal
()
}
const
deleteVariableTemplate
=
(
id
:
string
,
type
?:
string
)
=>
{
editingTemplateId
.
value
=
id
if
(
type
===
'confirmDelete'
)
{
...
...
@@ -554,6 +702,11 @@ const deleteVariableTemplate = (id: string, type?: string) => {
}
}
const
getVariableKeyById
=
(
id
:
string
)
=>
{
const
variable
=
variables
.
value
.
find
((
v
)
=>
v
.
variableBizId
===
id
)
return
variable
?.
variableNameEn
||
''
}
const
generateExcelTemplate
=
(
template
:
VariableTemplate
)
=>
{
variableGroupApi
.
exportEmailVariableGroup
(
template
.
variableGroupBizId
||
''
)
...
...
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