feat: admin page add account mail count && sendbox default all && send access suppory filter (#172)

This commit is contained in:
Dream Hunter
2024-04-28 14:02:33 +08:00
committed by GitHub
parent 4fd7f776f6
commit 90e80fee53
6 changed files with 159 additions and 29 deletions

View File

@@ -1,5 +1,20 @@
# CHANGE LOG
## v0.3.0
Breaking Changes:
DB changes:
`address` 表的前缀将从代码中迁移到 db 中,请将下面 sql 中的 `tmp` 替换为你的前缀,然后执行。
```sql
update
address
set
name = 'tmp' || name;
```
## v0.2.10
- `ENABLE_USER_DELETE_EMAIL` 是否允许用户删除账户和邮件

View File

@@ -1,4 +0,0 @@
update
address
set
name = 'tmp' || name;

View File

@@ -1,10 +1,11 @@
<script setup>
import { ref, h, onMounted, watch } from 'vue';
import { NBadge } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import { useGlobalState } from '../../store'
import { api } from '../../api'
import { NMenu } from 'naive-ui';
import { NButton, NMenu } from 'naive-ui';
import { MenuFilled } from '@vicons/material'
const {
@@ -19,6 +20,9 @@ const { t } = useI18n({
en: {
name: 'Name',
created_at: 'Created At',
update_at: 'Update At',
mail_count: 'Mail Count',
send_count: 'Send Count',
showPass: 'Show Passwrod',
password: 'Password',
passwordTip: 'Please copy the password and you can use it to login to your email account.',
@@ -35,6 +39,9 @@ const { t } = useI18n({
zh: {
name: '名称',
created_at: '创建时间',
update_at: '更新时间',
mail_count: '邮件数量',
send_count: '发送数量',
showPass: '显示密码',
password: '密码',
passwordTip: '请复制密码,你可以使用它登录你的邮箱。',
@@ -116,6 +123,62 @@ const columns = [
title: t('created_at'),
key: "created_at"
},
{
title: t('updated_at'),
key: "updated_at"
},
{
title: t('mail_count'),
key: "mail_count",
render(row) {
return h(NButton,
{
text: true,
onClick: () => {
if (row.mail_count > 0) {
adminMailTabAddress.value = row.name;
adminTab.value = "mails";
}
}
},
{
icon: () => h(NBadge, {
value: row.mail_count,
'show-zero': true,
max: 99,
type: "success"
}),
default: () => row.mail_count > 0 ? t('viewMails') : ""
}
)
}
},
{
title: t('send_count'),
key: "send_count",
render(row) {
return h(NButton,
{
text: true,
onClick: () => {
if (row.send_count > 0) {
adminSendBoxTabAddress.value = row.name;
adminTab.value = "sendBox";
}
}
},
{
icon: () => h(NBadge, {
value: row.send_count,
'show-zero': true,
max: 99,
type: "success"
}),
default: () => row.send_count > 0 ? t('viewSendBox') : ""
}
)
}
},
{
title: t('actions'),
key: 'actions',
@@ -132,8 +195,7 @@ const columns = [
{
label: () => h(NButton,
{
bordered: false,
ghost: true,
text: true,
onClick: () => showPassword(row.id)
},
{ default: () => t('showPass') }
@@ -142,8 +204,7 @@ const columns = [
{
label: () => h(NButton,
{
bordered: false,
ghost: true,
text: true,
onClick: () => {
adminMailTabAddress.value = row.name;
adminTab.value = "mails";
@@ -155,8 +216,7 @@ const columns = [
{
label: () => h(NButton,
{
bordered: false,
ghost: true,
text: true,
onClick: () => {
adminSendBoxTabAddress.value = row.name;
adminTab.value = "sendBox";
@@ -168,8 +228,7 @@ const columns = [
{
label: () => h(NButton,
{
bordered: false,
ghost: true,
text: true,
onClick: () => {
curDeleteAddressId.value = row.id;
showDelteAccount.value = true;

View File

@@ -44,15 +44,12 @@ const curRow = ref({})
const showModal = ref(false)
const fetchData = async () => {
if (!adminSendBoxTabAddress.value) {
return
}
try {
const { results, count: addressCount } = await api.fetch(
`/admin/sendbox`
+ `?address=${adminSendBoxTabAddress.value}`
+ `&limit=${pageSize.value}`
+ `?limit=${pageSize.value}`
+ `&offset=${(page.value - 1) * pageSize.value}`
+ (adminSendBoxTabAddress.value ? `&address=${adminSendBoxTabAddress.value}` : '')
);
data.value = results.map((item) => {
try {

View File

@@ -22,7 +22,7 @@ const { t } = useI18n({
itemCount: 'itemCount',
modalTip: 'Please input the sender balance',
balance: 'Balance',
refresh: 'Refresh',
query: 'Query',
ok: 'OK'
},
zh: {
@@ -36,7 +36,7 @@ const { t } = useI18n({
itemCount: '总数',
modalTip: '请输入发件额度',
balance: '余额',
refresh: '刷新',
query: '查询',
ok: '确定'
}
}
@@ -51,6 +51,7 @@ const showModal = ref(false)
const senderBalance = ref(0)
const senderEnabled = ref(false)
const addressQuery = ref('')
const updateData = async () => {
try {
@@ -77,6 +78,7 @@ const fetchData = async () => {
`/admin/address_sender`
+ `?limit=${pageSize.value}`
+ `&offset=${(page.value - 1) * pageSize.value}`
+ (addressQuery.value ? `&address=${addressQuery.value}` : '')
);
data.value = results;
if (addressCount > 0) {
@@ -166,17 +168,18 @@ onMounted(async () => {
</n-button>
</template>
</n-modal>
<n-input-group>
<n-input v-model:value="addressQuery" />
<n-button @click="fetchData" type="primary" ghost>
{{ t('query') }}
</n-button>
</n-input-group>
<div style="display: inline-block;">
<n-pagination v-model:page="page" v-model:page-size="pageSize" :item-count="count" :page-sizes="[20, 50, 100]"
show-size-picker>
<template #prefix="{ itemCount }">
{{ t('itemCount') }}: {{ itemCount }}
</template>
<template #suffix>
<n-button @click="fetchData" type="primary" size="small" ghost>
{{ t('refresh') }}
</n-button>
</template>
</n-pagination>
</div>
<n-data-table :columns="columns" :data="data" :bordered="false" />

View File

@@ -15,7 +15,12 @@ api.get('/admin/address', async (c) => {
}
if (query) {
const { results } = await c.env.DB.prepare(
`SELECT * FROM address where name like ? order by id desc limit ? offset ? `
`SELECT a.*,`
+ ` (SELECT COUNT(*) FROM raw_mails WHERE address = a.name) AS mail_count,`
+ ` (SELECT COUNT(*) FROM sendbox WHERE address = a.name) AS send_count`
+ ` FROM address a`
+ ` where name like ?`
+ ` order by id desc limit ? offset ?`
).bind(`%${query}%`, limit, offset).all();
let count = 0;
if (offset == 0) {
@@ -30,7 +35,11 @@ api.get('/admin/address', async (c) => {
})
}
const { results } = await c.env.DB.prepare(
`SELECT * FROM address order by id desc limit ? offset ? `
`SELECT a.*,`
+ ` (SELECT COUNT(*) FROM raw_mails WHERE address = a.name) AS mail_count,`
+ ` (SELECT COUNT(*) FROM sendbox WHERE address = a.name) AS send_count`
+ ` FROM address a`
+ ` order by id desc limit ? offset ?`
).bind(limit, offset).all();
let count = 0;
if (offset == 0) {
@@ -136,13 +145,29 @@ api.get('/admin/mails_unknow', async (c) => {
});
api.get('/admin/address_sender', async (c) => {
const { limit, offset } = c.req.query();
const { address, limit, offset } = c.req.query();
if (!limit || limit < 0 || limit > 100) {
return c.text("Invalid limit", 400)
}
if (!offset || offset < 0) {
return c.text("Invalid offset", 400)
}
if (address) {
const { results } = await c.env.DB.prepare(
`SELECT * FROM address_sender where address = ? order by id desc limit ? offset ?`
).bind(address, limit, offset).all();
let count = 0;
if (offset == 0) {
const { count: addressCount } = await c.env.DB.prepare(
`SELECT count(*) as count FROM address_sender where address = ?`
).bind(address).first();
count = addressCount;
}
return c.json({
results: results,
count: count
})
}
const { results } = await c.env.DB.prepare(
`SELECT * FROM address_sender order by id desc limit ? offset ? `
).bind(limit, offset).all();
@@ -182,7 +207,42 @@ api.post('/admin/address_sender', async (c) => {
api.get('/admin/sendbox', async (c) => {
const { address, limit, offset } = c.req.query();
return getSendbox(c, address, limit, offset);
if (!limit || limit < 0 || limit > 100) {
return c.text("Invalid limit", 400)
}
if (!offset || offset < 0) {
return c.text("Invalid offset", 400)
}
if (!address) {
const { results } = await c.env.DB.prepare(
`SELECT * FROM sendbox order by id desc limit ? offset ?`
).bind(limit, offset).all();
let count = 0;
if (offset == 0) {
const { count: mailCount } = await c.env.DB.prepare(
`SELECT count(*) as count FROM sendbox`
).first();
count = mailCount;
}
return c.json({
results: results,
count: count
})
}
const { results } = await c.env.DB.prepare(
`SELECT * FROM sendbox where address = ? order by id desc limit ? offset ?`
).bind(address, limit, offset).all();
let count = 0;
if (offset == 0) {
const { count: mailCount } = await c.env.DB.prepare(
`SELECT count(*) as count FROM sendbox where address = ?`
).bind(address).first();
count = mailCount;
}
return c.json({
results: results,
count: count
})
})
api.get('/admin/statistics', async (c) => {