修复星标不能查看,附件等多个bug,优化样式
This commit is contained in:
@@ -25,7 +25,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ref="scroll" class="scroll">
|
<div ref="scroll" class="scroll">
|
||||||
<el-scrollbar ref="scrollbarRef" @scroll="handleScroll" >
|
<el-scrollbar ref="scrollbarRef" @scroll="handleScroll">
|
||||||
<div class="scroll-box" :infinite-scroll-immediate="false" v-infinite-scroll="loadData"
|
<div class="scroll-box" :infinite-scroll-immediate="false" v-infinite-scroll="loadData"
|
||||||
infinite-scroll-distance="600">
|
infinite-scroll-distance="600">
|
||||||
<div v-for="item in emailList" :key="item.emailId">
|
<div v-for="item in emailList" :key="item.emailId">
|
||||||
@@ -274,18 +274,26 @@ function htmlToText(email) {
|
|||||||
tempDiv.innerHTML = email.content;
|
tempDiv.innerHTML = email.content;
|
||||||
const scriptsAndStyles = tempDiv.querySelectorAll('script, style, title');
|
const scriptsAndStyles = tempDiv.querySelectorAll('script, style, title');
|
||||||
scriptsAndStyles.forEach(el => el.remove());
|
scriptsAndStyles.forEach(el => el.remove());
|
||||||
const text = tempDiv.textContent || tempDiv.innerText || '';
|
let text = tempDiv.textContent || tempDiv.innerText || '';
|
||||||
return text.replace(/\s+/g, ' ').trim();
|
text = text.replace(/\s+/g, ' ').trim();
|
||||||
|
return cleanSpace(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (email.text) {
|
if (email.text) {
|
||||||
return email.text
|
return cleanSpace(email.text)
|
||||||
} else {
|
} else {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cleanSpace(text) {
|
||||||
|
return text
|
||||||
|
.replace(/[\u200B-\u200F\uFEFF]/g, '') // 移除零宽空格、ZWNJ、ZWJ、LRM、RLM、BOM
|
||||||
|
.replace(/\s+/g, ' ') // 多空白合并成一个空格
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function starChange(email) {
|
function starChange(email) {
|
||||||
|
|
||||||
|
|||||||
@@ -32,8 +32,17 @@ function loadFontInShadow() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateContent() {
|
function updateContent() {
|
||||||
if (!shadowRoot) return
|
if (!shadowRoot) return;
|
||||||
|
|
||||||
|
// 1. 提取 <body> 的 style 属性(如果存在)
|
||||||
|
const bodyStyleRegex = /<body[^>]*style="([^"]*)"[^>]*>/i;
|
||||||
|
const bodyStyleMatch = props.html.match(bodyStyleRegex);
|
||||||
|
const bodyStyle = bodyStyleMatch ? bodyStyleMatch[1] : '';
|
||||||
|
|
||||||
|
// 2. 移除 <body> 标签(保留内容)
|
||||||
|
const cleanedHtml = props.html.replace(/<\/?body[^>]*>/gi, '');
|
||||||
|
|
||||||
|
// 3. 将 body 的 style 应用到 .shadow-content
|
||||||
shadowRoot.innerHTML = `
|
shadowRoot.innerHTML = `
|
||||||
<style>
|
<style>
|
||||||
:host {
|
:host {
|
||||||
@@ -53,6 +62,7 @@ function updateContent() {
|
|||||||
width: fit-content;
|
width: fit-content;
|
||||||
height: fit-content;
|
height: fit-content;
|
||||||
min-width: 100%;
|
min-width: 100%;
|
||||||
|
${bodyStyle ? bodyStyle : ''} /* 注入 body 的 style */
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
@@ -72,12 +82,11 @@ function updateContent() {
|
|||||||
a {
|
a {
|
||||||
color: #409EFF !important;
|
color: #409EFF !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<div class="shadow-content">
|
<div class="shadow-content">
|
||||||
${props.html}
|
${cleanedHtml}
|
||||||
</div>
|
</div>
|
||||||
`
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function autoScale() {
|
function autoScale() {
|
||||||
@@ -109,6 +118,7 @@ onMounted(() => {
|
|||||||
shadowRoot = container.value.attachShadow({ mode: 'open' })
|
shadowRoot = container.value.attachShadow({ mode: 'open' })
|
||||||
updateContent()
|
updateContent()
|
||||||
autoScale()
|
autoScale()
|
||||||
|
console.log(props.html)
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(() => props.html, () => {
|
watch(() => props.html, () => {
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ const handleResize = () => {
|
|||||||
|
|
||||||
.main-box-show {
|
.main-box-show {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 250px 1fr;
|
grid-template-columns: 260px 1fr;
|
||||||
height: calc(100% - 60px);
|
height: calc(100% - 60px);
|
||||||
@media (max-width: 1200px) {
|
@media (max-width: 1200px) {
|
||||||
grid-template-columns: 250px 1fr;
|
grid-template-columns: 250px 1fr;
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
<div class="form-wrapper">
|
<div class="form-wrapper">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<span class="form-title">{{settingStore.settings.title}}</span>
|
<span class="form-title">{{settingStore.settings.title}}</span>
|
||||||
<span class="form-desc" v-if="show === 'login'">请输入你的账号信息以开始使用邮箱系统</span>
|
<span class="form-desc" v-if="show === 'login'">请输入账号信息以开始使用邮箱系统</span>
|
||||||
<span class="form-desc" v-else>请输入你的账号密码以开始注册邮箱系统</span>
|
<span class="form-desc" v-else>请输入账号密码以开始注册邮箱系统</span>
|
||||||
<div v-if="show === 'login'">
|
<div v-if="show === 'login'">
|
||||||
<el-input class="email-input" v-model="form.email" type="text" placeholder="邮箱" autocomplete="off">
|
<el-input class="email-input" v-model="form.email" type="text" placeholder="邮箱" autocomplete="off">
|
||||||
<template #append>
|
<template #append>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<template #default="props">
|
<template #default="props">
|
||||||
<div class="role-name">
|
<div class="role-name">
|
||||||
<span >{{props.row.name}}</span>
|
<span >{{props.row.name}}</span>
|
||||||
<span v-if="props.row.isDefault"><el-tag class="def-tag" type="success">默认</el-tag></span>
|
<span v-if="props.row.isDefault"><el-tag class="def-tag" >默认</el-tag></span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|||||||
@@ -71,7 +71,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<span class="details-item-title">发件次数:</span>
|
<span class="details-item-title">发件次数:</span>
|
||||||
<span>{{ formatSendCount(props.row) }}</span>
|
<span>{{ formatSendCount(props.row) }}</span>
|
||||||
<el-tag style="margin-left: 10px" v-if="props.row.sendAction.hasPerm" type="success">
|
<el-tag style="margin-left: 10px" v-if="props.row.sendAction.hasPerm" >
|
||||||
{{ formatSendType(props.row) }}
|
{{ formatSendType(props.row) }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
<el-button size="small" style="margin-left: 10px"
|
<el-button size="small" style="margin-left: 10px"
|
||||||
@@ -174,10 +174,11 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog class="dialog" v-model="setTypeShow" title="设置权限" @closed="resetUserForm">
|
<el-dialog class="dialog" v-model="setTypeShow" title="设置权限" @closed="resetUserForm">
|
||||||
<div class="dialog-box">
|
<div class="dialog-box">
|
||||||
<el-select v-model="userForm.type" placeholder="Select">
|
<el-input disabled model-value="超级管理员" v-if="userForm.type === 0" />
|
||||||
|
<el-select v-else v-model="userForm.type" placeholder="Select" >
|
||||||
<el-option v-for="item in roleList" :label="item.name" :value="item.roleId" :key="item.roleId"/>
|
<el-option v-for="item in roleList" :label="item.name" :value="item.roleId" :key="item.roleId"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-button class="btn" :loading="settingLoading" type="primary" @click="setType"
|
<el-button :disabled="userForm.type === 0" class="btn" :loading="settingLoading" type="primary" @click="setType"
|
||||||
>保存
|
>保存
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4
mail-worker/dist/index.html
vendored
4
mail-worker/dist/index.html
vendored
@@ -6,8 +6,8 @@
|
|||||||
<title></title>
|
<title></title>
|
||||||
<link rel="icon" href="/assets/favicon-C5dAZutX.svg" type="image/svg+xml">
|
<link rel="icon" href="/assets/favicon-C5dAZutX.svg" type="image/svg+xml">
|
||||||
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
|
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
|
||||||
<script type="module" crossorigin src="/assets/index-CT6Gv1uc.js"></script>
|
<script type="module" crossorigin src="/assets/index-DWsyDqKg.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-3kOBVh6Q.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-DeM-iAnI.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="loading-first">
|
<div id="loading-first">
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import settingService from '../service/setting-service';
|
|||||||
import attService from '../service/att-service';
|
import attService from '../service/att-service';
|
||||||
import constant from '../const/constant';
|
import constant from '../const/constant';
|
||||||
import fileUtils from '../utils/file-utils';
|
import fileUtils from '../utils/file-utils';
|
||||||
import { emailConst, isDel } from '../const/entity-const';
|
import {attConst, emailConst, isDel} from '../const/entity-const';
|
||||||
|
|
||||||
export async function email(message, env, ctx) {
|
export async function email(message, env, ctx) {
|
||||||
|
|
||||||
@@ -60,6 +60,7 @@ export async function email(message, env, ctx) {
|
|||||||
attachment.emailId = emailRow.emailId;
|
attachment.emailId = emailRow.emailId;
|
||||||
attachment.userId = emailRow.userId;
|
attachment.userId = emailRow.userId;
|
||||||
attachment.accountId = emailRow.accountId;
|
attachment.accountId = emailRow.accountId;
|
||||||
|
attachment.type = attachment.contentId ? attConst.type.EMBED : attConst.type.ATT
|
||||||
})
|
})
|
||||||
|
|
||||||
if (attachments.length > 0) {
|
if (attachments.length > 0) {
|
||||||
|
|||||||
@@ -46,11 +46,9 @@ const accountService = {
|
|||||||
const userRow = await userService.selectById(c, userId);
|
const userRow = await userService.selectById(c, userId);
|
||||||
const roleRow = await roleService.selectById(c, userRow.type);
|
const roleRow = await roleService.selectById(c, userRow.type);
|
||||||
|
|
||||||
if (roleRow.accountCount) {
|
if (roleRow.accountCount && userRow.email !== c.env.admin) {
|
||||||
|
|
||||||
const userAccountCount = await accountService.countUserAccount(c, userId)
|
const userAccountCount = await accountService.countUserAccount(c, userId)
|
||||||
if(userAccountCount >= roleRow.accountCount) throw new BizError(`添加邮箱数量限制${roleRow.accountCount}个`, 403);
|
if(userAccountCount >= roleRow.accountCount) throw new BizError(`添加邮箱数量限制${roleRow.accountCount}个`, 403);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await settingService.isAddEmailVerify(c)) {
|
if (await settingService.isAddEmailVerify(c)) {
|
||||||
|
|||||||
@@ -154,7 +154,12 @@ const attService = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
selectByEmailIds(c, emailIds) {
|
selectByEmailIds(c, emailIds) {
|
||||||
return orm(c).select().from(att).where(and(inArray(att.emailId,emailIds),eq(att.type, attConst.type.ATT))).all();
|
return orm(c).select().from(att).where(
|
||||||
|
and(
|
||||||
|
inArray(att.emailId,emailIds),
|
||||||
|
eq(att.type, attConst.type.ATT),
|
||||||
|
isNull(att.contentId)))
|
||||||
|
.all();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ import BizError from '../error/biz-error';
|
|||||||
import { and, desc, eq, lt, sql, inArray } from 'drizzle-orm';
|
import { and, desc, eq, lt, sql, inArray } from 'drizzle-orm';
|
||||||
import email from '../entity/email';
|
import email from '../entity/email';
|
||||||
import { isDel } from '../const/entity-const';
|
import { isDel } from '../const/entity-const';
|
||||||
import { att } from '../entity/att';
|
import attService from "./att-service";
|
||||||
import userService from './user-service';
|
|
||||||
|
|
||||||
const starService = {
|
const starService = {
|
||||||
|
|
||||||
@@ -64,6 +63,16 @@ const starService = {
|
|||||||
.orderBy(desc(star.emailId))
|
.orderBy(desc(star.emailId))
|
||||||
.limit(size)
|
.limit(size)
|
||||||
.all();
|
.all();
|
||||||
|
|
||||||
|
const emailIds = list.map(item => item.emailId);
|
||||||
|
|
||||||
|
const attsList = await attService.selectByEmailIds(c, emailIds);
|
||||||
|
|
||||||
|
list.forEach(emailRow => {
|
||||||
|
const atts = attsList.filter(attsRow => attsRow.emailId === emailRow.emailId);
|
||||||
|
emailRow.attList = atts;
|
||||||
|
});
|
||||||
|
|
||||||
return { list };
|
return { list };
|
||||||
},
|
},
|
||||||
async removeByEmailIds(c, emailIds) {
|
async removeByEmailIds(c, emailIds) {
|
||||||
|
|||||||
Reference in New Issue
Block a user