新增全部用户查看删除邮箱

This commit is contained in:
eoao
2025-09-21 19:20:00 +08:00
parent 457304eafb
commit 82bd308d56
21 changed files with 244 additions and 77 deletions

8
mail-vue/jsconfig.json Normal file
View File

@@ -0,0 +1,8 @@
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
},
"exclude": ["node_modules", "dist"]
}

View File

@@ -36,7 +36,7 @@
"terser": "^5.39.0", "terser": "^5.39.0",
"unplugin-auto-import": "^19.3.0", "unplugin-auto-import": "^19.3.0",
"unplugin-vue-components": "^28.7.0", "unplugin-vue-components": "^28.7.0",
"vite": "6.3.4", "vite": "7.1.5",
"vite-plugin-pwa": "^1.0.3" "vite-plugin-pwa": "^1.0.3"
} }
} }

View File

@@ -62,7 +62,7 @@ importers:
devDependencies: devDependencies:
'@vitejs/plugin-vue': '@vitejs/plugin-vue':
specifier: ^5.2.1 specifier: ^5.2.1
version: 5.2.4(vite@6.3.4(less@4.4.1)(sass@1.91.0)(terser@5.43.1))(vue@3.5.20) version: 5.2.4(vite@7.1.5(less@4.4.1)(sass@1.91.0)(terser@5.43.1))(vue@3.5.20)
less: less:
specifier: ^4.2.2 specifier: ^4.2.2
version: 4.4.1 version: 4.4.1
@@ -79,11 +79,11 @@ importers:
specifier: ^28.7.0 specifier: ^28.7.0
version: 28.8.0(@babel/parser@7.28.3)(vue@3.5.20) version: 28.8.0(@babel/parser@7.28.3)(vue@3.5.20)
vite: vite:
specifier: 6.3.4 specifier: 7.1.5
version: 6.3.4(less@4.4.1)(sass@1.91.0)(terser@5.43.1) version: 7.1.5(less@4.4.1)(sass@1.91.0)(terser@5.43.1)
vite-plugin-pwa: vite-plugin-pwa:
specifier: ^1.0.3 specifier: ^1.0.3
version: 1.0.3(vite@6.3.4(less@4.4.1)(sass@1.91.0)(terser@5.43.1))(workbox-build@7.3.0)(workbox-window@7.3.0) version: 1.0.3(vite@7.1.5(less@4.4.1)(sass@1.91.0)(terser@5.43.1))(workbox-build@7.3.0)(workbox-window@7.3.0)
packages: packages:
@@ -2217,6 +2217,10 @@ packages:
resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
engines: {node: '>=12.0.0'} engines: {node: '>=12.0.0'}
tinyglobby@0.2.15:
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
engines: {node: '>=12.0.0'}
to-regex-range@5.0.1: to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'} engines: {node: '>=8.0'}
@@ -2343,19 +2347,19 @@ packages:
'@vite-pwa/assets-generator': '@vite-pwa/assets-generator':
optional: true optional: true
vite@6.3.4: vite@7.1.5:
resolution: {integrity: sha512-BiReIiMS2fyFqbqNT/Qqt4CVITDU9M9vE+DKcVAsB+ZV0wvTKd+3hMbkpxz1b+NmEDMegpVbisKiAZOnvO92Sw==} resolution: {integrity: sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
'@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 '@types/node': ^20.19.0 || >=22.12.0
jiti: '>=1.21.0' jiti: '>=1.21.0'
less: '*' less: ^4.0.0
lightningcss: ^1.21.0 lightningcss: ^1.21.0
sass: '*' sass: ^1.70.0
sass-embedded: '*' sass-embedded: ^1.70.0
stylus: '*' stylus: '>=0.54.8'
sugarss: '*' sugarss: ^5.0.0
terser: ^5.16.0 terser: ^5.16.0
tsx: ^4.8.1 tsx: ^4.8.1
yaml: ^2.4.2 yaml: ^2.4.2
@@ -3501,9 +3505,9 @@ snapshots:
'@types/web-bluetooth@0.0.21': {} '@types/web-bluetooth@0.0.21': {}
'@vitejs/plugin-vue@5.2.4(vite@6.3.4(less@4.4.1)(sass@1.91.0)(terser@5.43.1))(vue@3.5.20)': '@vitejs/plugin-vue@5.2.4(vite@7.1.5(less@4.4.1)(sass@1.91.0)(terser@5.43.1))(vue@3.5.20)':
dependencies: dependencies:
vite: 6.3.4(less@4.4.1)(sass@1.91.0)(terser@5.43.1) vite: 7.1.5(less@4.4.1)(sass@1.91.0)(terser@5.43.1)
vue: 3.5.20 vue: 3.5.20
'@vue/compiler-core@3.5.20': '@vue/compiler-core@3.5.20':
@@ -4821,6 +4825,11 @@ snapshots:
fdir: 6.5.0(picomatch@4.0.3) fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3 picomatch: 4.0.3
tinyglobby@0.2.15:
dependencies:
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
to-regex-range@5.0.1: to-regex-range@5.0.1:
dependencies: dependencies:
is-number: 7.0.0 is-number: 7.0.0
@@ -4962,25 +4971,25 @@ snapshots:
dependencies: dependencies:
inherits: 2.0.3 inherits: 2.0.3
vite-plugin-pwa@1.0.3(vite@6.3.4(less@4.4.1)(sass@1.91.0)(terser@5.43.1))(workbox-build@7.3.0)(workbox-window@7.3.0): vite-plugin-pwa@1.0.3(vite@7.1.5(less@4.4.1)(sass@1.91.0)(terser@5.43.1))(workbox-build@7.3.0)(workbox-window@7.3.0):
dependencies: dependencies:
debug: 4.4.1 debug: 4.4.1
pretty-bytes: 6.1.1 pretty-bytes: 6.1.1
tinyglobby: 0.2.14 tinyglobby: 0.2.14
vite: 6.3.4(less@4.4.1)(sass@1.91.0)(terser@5.43.1) vite: 7.1.5(less@4.4.1)(sass@1.91.0)(terser@5.43.1)
workbox-build: 7.3.0 workbox-build: 7.3.0
workbox-window: 7.3.0 workbox-window: 7.3.0
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
vite@6.3.4(less@4.4.1)(sass@1.91.0)(terser@5.43.1): vite@7.1.5(less@4.4.1)(sass@1.91.0)(terser@5.43.1):
dependencies: dependencies:
esbuild: 0.25.9 esbuild: 0.25.9
fdir: 6.5.0(picomatch@4.0.3) fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3 picomatch: 4.0.3
postcss: 8.5.6 postcss: 8.5.6
rollup: 4.50.0 rollup: 4.50.0
tinyglobby: 0.2.14 tinyglobby: 0.2.15
optionalDependencies: optionalDependencies:
fsevents: 2.3.3 fsevents: 2.3.3
less: 4.4.1 less: 4.4.1

View File

@@ -66,7 +66,9 @@ http.interceptors.response.use((res) => {
}) })
reject(data) reject(data)
} }
resolve(data.data) setTimeout(() => {
resolve(data.data)
},0)
}) })
}, },
(error) => { (error) => {

View File

@@ -1,5 +1,5 @@
const en = { const en = {
inbox: 'Inbox', '收件箱': 'Inbox',
drafts: 'Drafts', drafts: 'Drafts',
sent: 'Sent', sent: 'Sent',
starred: 'Starred', starred: 'Starred',
@@ -14,6 +14,8 @@ const en = {
noMessagesFound: 'No messages found', noMessagesFound: 'No messages found',
addAccount: 'Add Account', addAccount: 'Add Account',
emailAccount: 'Email', emailAccount: 'Email',
account: 'Account',
userAccount: 'User Accounts',
deleteUser: 'Delete Account', deleteUser: 'Delete Account',
deleteUserBtn: 'Delete', deleteUserBtn: 'Delete',
changePassword: 'Change Password', changePassword: 'Change Password',

View File

@@ -1,5 +1,5 @@
const zh = { const zh = {
inbox: '收件箱', '收件箱': '收件箱',
drafts: '草稿箱', drafts: '草稿箱',
sent: '已发送', sent: '已发送',
starred: '星标邮件', starred: '星标邮件',
@@ -14,6 +14,8 @@ const zh = {
noMessagesFound: '没有任何邮件', noMessagesFound: '没有任何邮件',
addAccount: '添加邮箱', addAccount: '添加邮箱',
emailAccount: '邮箱', emailAccount: '邮箱',
account: '邮箱',
userAccount: '用户邮箱',
deleteUser: '删除账户', deleteUser: '删除账户',
deleteUserBtn: '删除账户', deleteUserBtn: '删除账户',
changePassword: '修改密码', changePassword: '修改密码',

View File

@@ -9,7 +9,7 @@
<el-menu-item @click="router.push({name: 'email'})" index="email" <el-menu-item @click="router.push({name: 'email'})" index="email"
:class="route.meta.name === 'email' ? 'choose-item' : ''"> :class="route.meta.name === 'email' ? 'choose-item' : ''">
<Icon icon="hugeicons:mailbox-01" width="20" height="20" /> <Icon icon="hugeicons:mailbox-01" width="20" height="20" />
<span class="menu-name" style="margin-left: 21px">{{$t('inbox')}}</span> <span class="menu-name" style="margin-left: 21px">{{$t('收件箱')}}</span>
</el-menu-item> </el-menu-item>
<el-menu-item @click="router.push({name: 'send'})" index="send" v-perm="'email:send'" <el-menu-item @click="router.push({name: 'send'})" index="send" v-perm="'email:send'"
:class="route.meta.name === 'send' ? 'choose-item' : ''"> :class="route.meta.name === 'send' ? 'choose-item' : ''">

View File

@@ -10,17 +10,6 @@
</div> </div>
</div> </div>
<div class="toolbar"> <div class="toolbar">
<el-dropdown>
<div class="translate icon-item">
<Icon icon="carbon:ibm-watson-language-translator"/>
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="changeLang('zh')">简体中文</el-dropdown-item>
<el-dropdown-item @click="changeLang('en')">English</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<div v-if="uiStore.dark" class="sun-icon icon-item" @click="openDark($event)"> <div v-if="uiStore.dark" class="sun-icon icon-item" @click="openDark($event)">
<Icon icon="mingcute:sun-fill"/> <Icon icon="mingcute:sun-fill"/>
</div> </div>
@@ -449,11 +438,6 @@ function formatName(email) {
font-size: 24px; font-size: 24px;
} }
.translate {
padding-top: 2px;
font-size: 21px;
}
.avatar { .avatar {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@@ -32,4 +32,12 @@ export function userRestSendCount(userId) {
export function userRestore(userId,type) { export function userRestore(userId,type) {
return http.put('/user/restore', {userId,type}) return http.put('/user/restore', {userId,type})
} }
export function userAllAccount(userId, num, size) {
return http.get('/user/allAccount', {params:{userId,num,size}})
}
export function userDeleteAccount(accountId) {
return http.delete('/user/deleteAccount', {params:{accountId}})
}

View File

@@ -16,7 +16,7 @@ const routes = [
name: 'email', name: 'email',
component: () => import('@/views/email/index.vue'), component: () => import('@/views/email/index.vue'),
meta: { meta: {
title: 'inbox', title: '收件箱',
name: 'email', name: 'email',
menu: true menu: true
} }

View File

@@ -11,8 +11,5 @@ export const useSettingStore = defineStore('setting', {
}), }),
actions: { actions: {
}, }
persist: {
pick: ['lang'],
},
}) })

View File

@@ -143,11 +143,14 @@
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item @click="openSetPwd(props.row)">{{ $t('chgPwd') }}</el-dropdown-item> <el-dropdown-item @click="openSetPwd(props.row)">{{ $t('chgPwd') }}</el-dropdown-item>
<el-dropdown-item @click="openSetType(props.row)">{{ $t('perm') }}</el-dropdown-item> <el-dropdown-item @click="openSetType(props.row)">{{ $t('perm') }}</el-dropdown-item>
<el-dropdown-item v-if="props.row.isDel !== 1" @click="setStatus(props.row)"> <template v-if="props.row.type !== 0">
{{ setStatusName(props.row) }} <el-dropdown-item v-if="props.row.isDel !== 1" @click="setStatus(props.row)">
</el-dropdown-item> {{ setStatusName(props.row) }}
<el-dropdown-item v-else @click="restore(props.row)">{{ $t('restore') }}</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item @click="delUser(props.row)">{{ $t('delete') }}</el-dropdown-item> <el-dropdown-item v-else @click="restore(props.row)">{{ $t('restore') }}</el-dropdown-item>
</template>
<el-dropdown-item @click="openAccountList(props.row.userId)">{{ $t('account') }}</el-dropdown-item>
<el-dropdown-item @click="delUser(props.row)" v-if="props.row.type !== 0">{{ $t('delete') }}</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>
@@ -237,6 +240,44 @@
</el-button> </el-button>
</div> </div>
</el-dialog> </el-dialog>
<el-dialog class="account-dialog" v-model="accountShow" :title="t('userAccount')" @closed="resetAccountList" >
<el-table :data="accountList" style="height: 480px" v-loading="accountLoading" element-loading-background="transparent" :empty-text="accountLoading ? '' : null">
<el-table-column property="email" :label="t('emailAccount')" >
<template #default="props">
<div class="email-row">{{ props.row.email }}</div>
</template>
</el-table-column>
<el-table-column property="address" :label="t('tabStatus')" :width="locale === 'en' ? 75 : 65" >
<template #default="props">
<el-tag type="primary" disable-transitions v-if="props.row.isDel === 0">{{$t('active')}}</el-tag>
<el-tag type="info" disable-transitions v-if="props.row.isDel === 1">{{$t('deleted')}}</el-tag>
</template>
</el-table-column>
<el-table-column :label="t('action')" :width="locale === 'en' ? 75 : 65" >
<template #default="props">
<el-dropdown trigger="click">
<el-button type="primary" size="small">{{t('action')}}</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="deleteAccount(props.row)">{{ $t('delete') }}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
</el-table-column>
</el-table>
<div class="account-pagination">
<el-pagination
:disabled="accountLoading"
background
layout="prev, pager, next"
:pager-count="3"
:total="accountParams.total"
@current-change="accountCurChange"
/>
</div>
</el-dialog>
</div> </div>
</template> </template>
@@ -249,7 +290,10 @@ import {
userSetStatus, userSetStatus,
userSetType, userSetType,
userAdd, userAdd,
userRestSendCount, userRestore userRestSendCount,
userRestore,
userDeleteAccount,
userAllAccount
} from '@/request/user.js' } from '@/request/user.js'
import {roleSelectUse} from "@/request/role.js"; import {roleSelectUse} from "@/request/role.js";
import {Icon} from "@iconify/vue"; import {Icon} from "@iconify/vue";
@@ -289,6 +333,7 @@ const users = ref([])
const total = ref(0) const total = ref(0)
const first = ref(true) const first = ref(true)
const scrollbarRef = ref(null) const scrollbarRef = ref(null)
const accountLoading = ref(false)
const domainList = settingStore.domainList const domainList = settingStore.domainList
@@ -314,6 +359,7 @@ const userForm = reactive({
}) })
const showAdd = ref(false) const showAdd = ref(false)
const accountShow = ref(false)
const addLoading = ref(false); const addLoading = ref(false);
const setTypeShow = ref(false) const setTypeShow = ref(false)
const setPwdShow = ref(false) const setPwdShow = ref(false)
@@ -323,6 +369,13 @@ const tableLoading = ref(true)
const roleList = reactive([]) const roleList = reactive([])
const mySelect = ref({}) const mySelect = ref({})
const key = ref(0) const key = ref(0)
const accountList = reactive([])
const accountParams = reactive({
size: 10,
num: 0,
total: 0,
userId: 0,
})
roleSelectUse().then(list => { roleSelectUse().then(list => {
roleList.length = 0 roleList.length = 0
@@ -331,11 +384,11 @@ roleSelectUse().then(list => {
const paramsStar = localStorage.getItem('user-params') const paramsStar = localStorage.getItem('user-params')
if (paramsStar) { if (paramsStar) {
const locaParams = JSON.parse(paramsStar) const localParams = JSON.parse(paramsStar)
params.num = locaParams.num params.num = localParams.num
params.size = locaParams.size params.size = localParams.size
params.timeSort = locaParams.timeSort params.timeSort = localParams.timeSort
params.status = locaParams.status params.status = localParams.status
} }
watch(() => params, () => { watch(() => params, () => {
@@ -363,6 +416,50 @@ const filterItem = reactive({
receive: ['normal', 'del'] receive: ['normal', 'del']
}) })
function deleteAccount(account) {
ElMessageBox.confirm(t('delConfirm', {msg: account.email}), {
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning'
}).then(() => {
userDeleteAccount(account.accountId).then(() => {
getAccountList()
ElMessage({
message: t('删除成功'),
type: "success",
plain: true
})
})
});
}
function accountCurChange(e) {
accountParams.num = e
getAccountList()
}
function resetAccountList() {
accountList.length = 0
accountParams.num = 0
accountParams.size = 10
accountParams.total = 0
}
function openAccountList(userId) {
accountParams.userId = userId
getAccountList(true)
accountShow.value = true
}
function getAccountList(loading = false) {
accountLoading.value = loading
userAllAccount(accountParams.userId,accountParams.num, accountParams.size).then(({list,total}) => {
accountList.length = 0
accountList.push(...list)
accountParams.total = total
accountLoading.value = false
})
}
function tableFilter(e) { function tableFilter(e) {
if (e.send) filterItem.send = e.send if (e.send) filterItem.send = e.send
@@ -820,6 +917,15 @@ function adjustWidth() {
} }
} }
:deep(.account-dialog) {
width: 500px !important;
@media (max-width: 540px) {
width: calc(100% - 40px) !important;
margin-right: 20px !important;
margin-left: 20px !important;
}
}
.header-actions { .header-actions {
padding: 9px 15px; padding: 9px 15px;
display: flex; display: flex;
@@ -889,6 +995,12 @@ function adjustWidth() {
} }
} }
.account-pagination {
display: flex;
justify-content: end;
width: 100%;
}
.pagination { .pagination {
margin-top: 15px; margin-top: 15px;
margin-bottom: 20px; margin-bottom: 20px;
@@ -982,15 +1094,6 @@ function adjustWidth() {
background: var(--el-bg-color); background: var(--el-bg-color);
} }
:deep(.el-dialog) {
width: 400px !important;
@media (max-width: 440px) {
width: calc(100% - 40px) !important;
margin-right: 20px !important;
margin-left: 20px !important;
}
}
:deep(.cell) { :deep(.cell) {
white-space: normal; white-space: normal;
overflow: visible; overflow: visible;
@@ -1020,4 +1123,4 @@ function adjustWidth() {
:deep(.el-message-box__container) { :deep(.el-message-box__container) {
align-items: start; align-items: start;
} }
</style> </style>

File diff suppressed because one or more lines are too long

View File

@@ -2,6 +2,7 @@ import app from '../hono/hono';
import userService from '../service/user-service'; import userService from '../service/user-service';
import result from '../model/result'; import result from '../model/result';
import userContext from '../security/user-context'; import userContext from '../security/user-context';
import accountService from '../service/account-service';
app.delete('/user/delete', async (c) => { app.delete('/user/delete', async (c) => {
await userService.physicsDelete(c, c.req.query()); await userService.physicsDelete(c, c.req.query());
@@ -42,3 +43,15 @@ app.put('/user/restore', async (c) => {
await userService.restore(c, await c.req.json()); await userService.restore(c, await c.req.json());
return c.json(result.ok()); return c.json(result.ok());
}); });
app.get('/user/allAccount', async (c) => {
const data = await accountService.allAccount(c, c.req.query());
return c.json(result.ok(data));
});
app.delete('/user/deleteAccount', async (c) => {
await accountService.physicsDelete(c, c.req.query());
return c.json(result.ok());
});

View File

@@ -43,6 +43,8 @@ const requirePerms = [
'/user/list', '/user/list',
'/user/resetSendCount', '/user/resetSendCount',
'/user/add', '/user/add',
'/user/deleteAccount',
'/user/allAccount',
'/regKey/add', '/regKey/add',
'/regKey/list', '/regKey/list',
'/regKey/delete', '/regKey/delete',
@@ -61,13 +63,13 @@ const premKey = {
'role:set': ['/role/set','/role/setDefault'], 'role:set': ['/role/set','/role/setDefault'],
'role:query': ['/role/list', '/role/tree'], 'role:query': ['/role/list', '/role/tree'],
'role:delete': ['/role/delete'], 'role:delete': ['/role/delete'],
'user:query': ['/user/list'], 'user:query': ['/user/list','/user/allAccount'],
'user:add': ['/user/add'], 'user:add': ['/user/add'],
'user:reset-send': ['/user/resetSendCount'], 'user:reset-send': ['/user/resetSendCount'],
'user:set-pwd': ['/user/setPwd'], 'user:set-pwd': ['/user/setPwd'],
'user:set-status': ['/user/setStatus'], 'user:set-status': ['/user/setStatus'],
'user:set-type': ['/user/setType'], 'user:set-type': ['/user/setType'],
'user:delete': ['/user/delete'], 'user:delete': ['/user/delete','/user/deleteAccount'],
'all-email:query': ['/allEmail/list'], 'all-email:query': ['/allEmail/list'],
'all-email:delete': ['/allEmail/delete','/allEmail/batchDelete'], 'all-email:delete': ['/allEmail/delete','/allEmail/batchDelete'],
'setting:query': ['/setting/query'], 'setting:query': ['/setting/query'],

View File

@@ -5,7 +5,7 @@ import userService from './user-service';
import emailService from './email-service'; import emailService from './email-service';
import orm from '../entity/orm'; import orm from '../entity/orm';
import account from '../entity/account'; import account from '../entity/account';
import { and, asc, eq, gt, inArray, count, sql } from 'drizzle-orm'; import { and, asc, eq, gt, inArray, count, sql, ne } from 'drizzle-orm';
import { isDel, settingConst } from '../const/entity-const'; import { isDel, settingConst } from '../const/entity-const';
import settingService from './setting-service'; import settingService from './setting-service';
import turnstileService from './turnstile-service'; import turnstileService from './turnstile-service';
@@ -195,7 +195,37 @@ const accountService = {
throw new BizError(t('usernameLengthLimit')); throw new BizError(t('usernameLengthLimit'));
} }
await orm(c).update(account).set({name}).where(and(eq(account.userId, userId),eq(account.accountId, accountId))).run(); await orm(c).update(account).set({name}).where(and(eq(account.userId, userId),eq(account.accountId, accountId))).run();
},
async allAccount(c, params) {
let { userId, num, size } = params
userId = Number(userId)
num = Number(num)
size = Number(size)
if (size > 30) {
size = 30;
}
num = (num - 1) * size;
const userRow = await userService.selectByIdIncludeDel(c, userId);
const list = await orm(c).select().from(account).where(and(eq(account.userId, userId),ne(account.email,userRow.email))).limit(size).offset(num);
const { total } = await orm(c).select({ total: count() }).from(account).where(eq(account.userId, userId)).get();
return { list, total }
},
async physicsDelete(c, params) {
const { accountId } = params
await emailService.physicsDeleteByAccountId(c, accountId)
await orm(c).delete(account).where(eq(account.accountId, accountId)).run();
} }
}; };
export default accountService; export default accountService;

View File

@@ -191,6 +191,11 @@ const attService = {
await r2Service.delete(c, batch); await r2Service.delete(c, batch);
} }
},
async removeByAccountId(c, accountId) {
console.log(accountId)
await this.removeAttByField(c, "account_id", [accountId])
} }
}; };

View File

@@ -655,6 +655,11 @@ const emailService = {
await attService.removeByEmailIds(c, emailIds); await attService.removeByEmailIds(c, emailIds);
await orm(c).delete(email).where(conditions.length > 1 ? and(...conditions) : conditions[0]).run(); await orm(c).delete(email).where(conditions.length > 1 ? and(...conditions) : conditions[0]).run();
},
async physicsDeleteByAccountId(c, accountId) {
await attService.removeByAccountId(c, accountId);
await orm(c).delete(email).where(eq(email.accountId, accountId)).run();
} }
}; };

View File

@@ -74,6 +74,10 @@ const userService = {
return orm(c).select().from(user).where(sql`${user.email} COLLATE NOCASE = ${email}`).get(); return orm(c).select().from(user).where(sql`${user.email} COLLATE NOCASE = ${email}`).get();
}, },
selectByIdIncludeDel(c, userId) {
return orm(c).select().from(user).where(eq(user.userId, userId)).get();
},
selectById(c, userId) { selectById(c, userId) {
return orm(c).select().from(user).where( return orm(c).select().from(user).where(
and( and(

6
package-lock.json generated
View File

@@ -1,6 +0,0 @@
{
"name": "cloud-mail",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}