474 lines
13 KiB
Vue
474 lines
13 KiB
Vue
<template>
|
||
<div class="email-record-container" style="padding-bottom: calc(50px + env(safe-area-inset-bottom, 0px));">
|
||
<!-- 顶部导航栏 -->
|
||
<van-nav-bar title="邮件记录" fixed placeholder>
|
||
<template #right>
|
||
<van-button
|
||
size="small"
|
||
type="primary"
|
||
:loading="syncing"
|
||
@click="handleSync"
|
||
>
|
||
立即同步
|
||
</van-button>
|
||
</template>
|
||
</van-nav-bar>
|
||
|
||
<!-- 下拉刷新区域 -->
|
||
<van-pull-refresh v-model="refreshing" @refresh="onRefresh" class="refresh-wrapper">
|
||
<!-- 加载提示 -->
|
||
<van-loading v-if="loading && !(emailList && emailList.length)" vertical style="padding: 50px 0">
|
||
加载中...
|
||
</van-loading>
|
||
|
||
<!-- 邮件列表 -->
|
||
<van-list
|
||
v-model:loading="loading"
|
||
:finished="finished"
|
||
finished-text="没有更多了"
|
||
@load="onLoad"
|
||
>
|
||
<van-cell-group v-if="emailList && emailList.length" inset style="margin-top: 10px">
|
||
<van-swipe-cell
|
||
v-for="email in emailList"
|
||
:key="email.id"
|
||
>
|
||
<van-cell
|
||
:title="email.subject"
|
||
:label="`来自: ${email.from}`"
|
||
is-link
|
||
@click="viewDetail(email)"
|
||
>
|
||
<template #value>
|
||
<div class="email-info">
|
||
<div class="email-date">{{ formatDate(email.receivedDate) }}</div>
|
||
<div class="bill-count" v-if="email.transactionCount > 0">
|
||
<span style="font-size: 12px;">已解析{{ email.transactionCount }}条账单</span>
|
||
</div>
|
||
|
||
</div>
|
||
</template>
|
||
</van-cell>
|
||
<template #right>
|
||
<van-button
|
||
square
|
||
type="danger"
|
||
text="删除"
|
||
class="delete-button"
|
||
@click="handleDelete(email)"
|
||
/>
|
||
</template>
|
||
</van-swipe-cell>
|
||
</van-cell-group>
|
||
|
||
<van-empty
|
||
v-if="!loading && !(emailList && emailList.length)"
|
||
description="暂无邮件记录"
|
||
/>
|
||
</van-list>
|
||
</van-pull-refresh>
|
||
|
||
<!-- 详情弹出层 -->
|
||
<van-popup
|
||
v-model:show="detailVisible"
|
||
position="bottom"
|
||
:style="{ height: '80%' }"
|
||
round
|
||
closeable
|
||
>
|
||
<div class="email-detail" v-if="currentEmail">
|
||
<div class="detail-header" style="margin-top: 10px; margin-left: 10px;">
|
||
<h3>{{ currentEmail.Subject || currentEmail.subject || '(无主题)' }}</h3>
|
||
</div>
|
||
<van-cell-group inset>
|
||
<van-cell title="发件人" :value="currentEmail.From || currentEmail.from || '未知'" />
|
||
<van-cell title="接收时间" :value="formatDate(currentEmail.ReceivedDate || currentEmail.receivedDate)" />
|
||
<van-cell title="记录时间" :value="formatDate(currentEmail.CreateTime || currentEmail.createTime)" />
|
||
<van-cell
|
||
title="已解析账单数"
|
||
:value="`${currentEmail.TransactionCount || currentEmail.transactionCount || 0}条`"
|
||
is-link
|
||
@click="viewTransactions"
|
||
v-if="(currentEmail.TransactionCount || currentEmail.transactionCount || 0) > 0"
|
||
/>
|
||
</van-cell-group>
|
||
<div class="email-content">
|
||
<h4 style="margin-left: 10px;">邮件内容</h4>
|
||
<div
|
||
v-if="currentEmail.htmlBody"
|
||
v-html="currentEmail.htmlBody"
|
||
class="content-body html-content"
|
||
></div>
|
||
<div
|
||
v-else-if="currentEmail.body"
|
||
class="content-body"
|
||
>
|
||
{{ currentEmail.body }}
|
||
</div>
|
||
<div v-else class="content-body empty-content">
|
||
暂无邮件内容
|
||
<div style="font-size: 12px; margin-top: 8px; color: #999;">
|
||
Debug: {{ Object.keys(currentEmail).join(', ') }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="margin: 16px;">
|
||
<van-button
|
||
round
|
||
block
|
||
type="primary"
|
||
:loading="refreshingAnalysis"
|
||
@click="handleRefreshAnalysis"
|
||
>
|
||
重新分析
|
||
</van-button>
|
||
</div>
|
||
|
||
|
||
</div>
|
||
</van-popup>
|
||
|
||
<!-- 账单列表弹出层 -->
|
||
<van-popup
|
||
v-model:show="transactionListVisible"
|
||
position="bottom"
|
||
:style="{ height: '70%' }"
|
||
round
|
||
closeable
|
||
>
|
||
<div class="transaction-list-popup">
|
||
<div class="list-header">
|
||
<h3 style="margin: 16px;">关联账单列表</h3>
|
||
</div>
|
||
<TransactionList
|
||
:transactions="transactionList"
|
||
:loading="false"
|
||
:finished="true"
|
||
:show-delete="false"
|
||
@click="handleTransactionClick"
|
||
/>
|
||
</div>
|
||
</van-popup>
|
||
|
||
<!-- 账单详情编辑弹出层 -->
|
||
<TransactionDetail
|
||
:show="transactionDetailVisible"
|
||
:transaction="currentTransaction"
|
||
@update:show="transactionDetailVisible = $event"
|
||
@save="handleTransactionSave"
|
||
/>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, onMounted } from 'vue'
|
||
import { showToast, showConfirmDialog } from 'vant'
|
||
import { getEmailList, getEmailDetail, deleteEmail, refreshTransactionRecords, syncEmails, getEmailTransactions } from '@/api/emailRecord'
|
||
import { getTransactionDetail } from '@/api/transactionRecord'
|
||
import TransactionList from '@/components/TransactionList.vue'
|
||
import TransactionDetail from '@/components/TransactionDetail.vue'
|
||
|
||
const emailList = ref([])
|
||
const loading = ref(false)
|
||
const refreshing = ref(false)
|
||
const finished = ref(false)
|
||
const lastId = ref(null) // 游标分页:记录最后一条记录的ID
|
||
const lastTime = ref(null) // 游标分页:记录最后一条记录的时间
|
||
const total = ref(0)
|
||
const detailVisible = ref(false)
|
||
const currentEmail = ref(null)
|
||
const refreshingAnalysis = ref(false)
|
||
const syncing = ref(false)
|
||
const transactionListVisible = ref(false)
|
||
const transactionList = ref([])
|
||
const transactionDetailVisible = ref(false)
|
||
const currentTransaction = ref(null)
|
||
|
||
// 加载数据
|
||
const loadData = async (isRefresh = false) => {
|
||
if (loading.value) return // 防止重复加载
|
||
|
||
if (isRefresh) {
|
||
lastId.value = null
|
||
lastTime.value = null
|
||
emailList.value = []
|
||
finished.value = false
|
||
}
|
||
|
||
loading.value = true
|
||
try {
|
||
const params = {}
|
||
if (lastTime.value && lastId.value) {
|
||
params.lastReceivedDate = lastTime.value
|
||
params.lastId = lastId.value
|
||
}
|
||
|
||
const response = await getEmailList(params)
|
||
|
||
if (response.success) {
|
||
const newList = response.data || []
|
||
total.value = response.total || 0
|
||
const newLastId = response.lastId || 0
|
||
const newLastTime = response.lastTime
|
||
|
||
if (isRefresh) {
|
||
emailList.value = newList
|
||
} else {
|
||
emailList.value = [...(emailList.value || []), ...newList]
|
||
}
|
||
|
||
// 更新游标
|
||
if (newLastId > 0 && newLastTime) {
|
||
lastId.value = newLastId
|
||
lastTime.value = newLastTime
|
||
}
|
||
|
||
// 判断是否还有更多数据(返回数据少于20条或为空,说明没有更多了)
|
||
if (newList.length === 0 || newList.length < 20) {
|
||
finished.value = true
|
||
} else {
|
||
finished.value = false
|
||
}
|
||
} else {
|
||
showToast(response.message || '加载数据失败')
|
||
finished.value = true
|
||
}
|
||
} catch (error) {
|
||
console.error('加载数据出错:', error)
|
||
showToast('加载数据出错: ' + (error.message || '未知错误'))
|
||
finished.value = true
|
||
} finally {
|
||
loading.value = false
|
||
refreshing.value = false
|
||
}
|
||
}
|
||
|
||
// 下拉刷新
|
||
const onRefresh = () => {
|
||
loadData(true)
|
||
}
|
||
|
||
// 加载更多
|
||
const onLoad = () => {
|
||
if (!finished.value && !loading.value) {
|
||
loadData()
|
||
}
|
||
}
|
||
|
||
// 查看详情
|
||
const viewDetail = async (email) => {
|
||
try {
|
||
const response = await getEmailDetail(email.id)
|
||
console.log('详情 API 返回:', response)
|
||
if (response.success) {
|
||
currentEmail.value = response.data
|
||
console.log('currentEmail:', currentEmail.value)
|
||
detailVisible.value = true
|
||
} else {
|
||
showToast(response.message || '获取详情失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('获取详情出错:', error)
|
||
showToast('获取详情失败')
|
||
}
|
||
}
|
||
|
||
// 删除
|
||
const handleDelete = async (email) => {
|
||
try {
|
||
await showConfirmDialog({
|
||
title: '提示',
|
||
message: '确定要删除这封邮件吗?',
|
||
})
|
||
|
||
const response = await deleteEmail(email.id)
|
||
if (response.success) {
|
||
showToast('删除成功')
|
||
loadData(true)
|
||
} else {
|
||
showToast(response.message || '删除失败')
|
||
}
|
||
} catch (error) {
|
||
if (error !== 'cancel') {
|
||
console.error('删除出错:', error)
|
||
showToast('删除失败')
|
||
}
|
||
}
|
||
}
|
||
|
||
// 重新分析
|
||
const handleRefreshAnalysis = async () => {
|
||
if (!currentEmail.value) return
|
||
|
||
try {
|
||
await showConfirmDialog({
|
||
title: '提示',
|
||
message: '确定要重新分析该邮件并刷新交易记录吗?',
|
||
})
|
||
|
||
refreshingAnalysis.value = true
|
||
const response = await refreshTransactionRecords(currentEmail.value.id || currentEmail.value.Id)
|
||
|
||
if (response.success) {
|
||
showToast('重新分析成功')
|
||
detailVisible.value = false
|
||
} else {
|
||
showToast(response.message || '重新分析失败')
|
||
}
|
||
} catch (error) {
|
||
if (error !== 'cancel') {
|
||
console.error('重新分析出错:', error)
|
||
showToast('重新分析失败: ' + (error.message || '未知错误'))
|
||
}
|
||
} finally {
|
||
refreshingAnalysis.value = false
|
||
}
|
||
}
|
||
|
||
// 立即同步
|
||
const handleSync = async () => {
|
||
try {
|
||
syncing.value = true
|
||
const response = await syncEmails()
|
||
|
||
if (response.success) {
|
||
showToast(response.message || '同步成功')
|
||
// 同步成功后刷新列表
|
||
loadData(true)
|
||
} else {
|
||
showToast(response.message || '同步失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('同步出错:', error)
|
||
showToast('同步失败: ' + (error.message || '未知错误'))
|
||
} finally {
|
||
syncing.value = false
|
||
}
|
||
}
|
||
|
||
// 查看关联的账单列表
|
||
const viewTransactions = async () => {
|
||
if (!currentEmail.value) return
|
||
|
||
try {
|
||
const emailId = currentEmail.value.id || currentEmail.value.Id
|
||
const response = await getEmailTransactions(emailId)
|
||
|
||
if (response.success) {
|
||
transactionList.value = response.data || []
|
||
transactionListVisible.value = true
|
||
} else {
|
||
showToast(response.message || '获取账单列表失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('获取账单列表出错:', error)
|
||
showToast('获取账单列表失败')
|
||
}
|
||
}
|
||
|
||
// 处理点击账单
|
||
const handleTransactionClick = async (transaction) => {
|
||
try {
|
||
const response = await getTransactionDetail(transaction.id)
|
||
if (response.success) {
|
||
currentTransaction.value = response.data
|
||
transactionDetailVisible.value = true
|
||
} else {
|
||
showToast(response.message || '获取账单详情失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('获取账单详情出错:', error)
|
||
showToast('获取账单详情失败')
|
||
}
|
||
}
|
||
|
||
// 账单保存后刷新列表
|
||
const handleTransactionSave = async () => {
|
||
// 刷新账单列表
|
||
if (currentEmail.value) {
|
||
const emailId = currentEmail.value.id || currentEmail.value.Id
|
||
const response = await getEmailTransactions(emailId)
|
||
if (response.success) {
|
||
transactionList.value = response.data || []
|
||
}
|
||
}
|
||
}
|
||
|
||
// 格式化日期
|
||
const formatDate = (dateString) => {
|
||
if (!dateString) return ''
|
||
const date = new Date(dateString)
|
||
return date.toLocaleString('zh-CN', {
|
||
year: 'numeric',
|
||
month: '2-digit',
|
||
day: '2-digit',
|
||
hour: '2-digit',
|
||
minute: '2-digit',
|
||
second: '2-digit'
|
||
})
|
||
}
|
||
|
||
onMounted(() => {
|
||
loadData(true)
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
@import '@/styles/common.css';
|
||
|
||
.email-info {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-end;
|
||
gap: 4px;
|
||
}
|
||
|
||
.bill-count {
|
||
margin-bottom: 2px;
|
||
}
|
||
|
||
.email-date {
|
||
font-size: 12px;
|
||
color: #969799;
|
||
padding-right: 10px;
|
||
}
|
||
|
||
.transaction-list-popup {
|
||
height: 100%;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.email-content {
|
||
margin-top: 16px;
|
||
}
|
||
|
||
.email-content h4 {
|
||
margin: 0 0 12px 0;
|
||
font-size: 16px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.content-body {
|
||
padding: 12px;
|
||
border-radius: 8px;
|
||
white-space: pre-wrap;
|
||
word-break: break-word;
|
||
font-size: 14px;
|
||
line-height: 1.6;
|
||
max-height: 300px;
|
||
overflow-y: auto;
|
||
margin: 0 20px;
|
||
}
|
||
|
||
@media (prefers-color-scheme: dark) {
|
||
.content-body {
|
||
background-color: #2c2c2c;
|
||
border: 1px solid #3a3a3a;
|
||
}
|
||
}
|
||
|
||
.delete-button {
|
||
height: 100%;
|
||
}
|
||
</style> |