mirror of
https://github.com/dreamhunter2333/cloudflare_temp_email.git
synced 2026-05-07 05:42:50 +08:00
feat: admin page add account mail count && sendbox default all && send access suppory filter (#172)
This commit is contained in:
15
CHANGELOG.md
15
CHANGELOG.md
@@ -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` 是否允许用户删除账户和邮件
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
update
|
||||
address
|
||||
set
|
||||
name = 'tmp' || name;
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
Reference in New Issue
Block a user