问题修复
This commit is contained in:
parent
2ba2738107
commit
16069f0ae0
@ -0,0 +1,96 @@
|
||||
<script setup lang="ts">
|
||||
import { ElButton, ElTable, ElTableColumn, ElPopconfirm, ElMessage, ElTag } from 'element-plus'
|
||||
import { postUsersInitPasswordSendEmailApi } from '@/api/vadmin/auth/user'
|
||||
import { ref, PropType } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
selections: {
|
||||
type: Object as PropType<Recordable[]>
|
||||
}
|
||||
})
|
||||
|
||||
const tableData = ref(JSON.parse(JSON.stringify(props.selections)))
|
||||
const loading = ref(false)
|
||||
|
||||
const handleDelete = (index: number) => {
|
||||
tableData.value.splice(index, 1)
|
||||
}
|
||||
|
||||
const initPassword = async () => {
|
||||
loading.value = true
|
||||
const ids = tableData.value
|
||||
.filter((item) => item.reset_password_status !== true)
|
||||
.map((item) => item.id)
|
||||
if (ids.length <= 0) {
|
||||
return ElMessage.warning('已全部重置完成,无需重复操作')
|
||||
}
|
||||
const res = await postUsersInitPasswordSendEmailApi(ids).finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
if (res) {
|
||||
tableData.value = res.data
|
||||
ElMessage.success('重置成功')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="flex justify-between">
|
||||
<span>已选用户列表</span>
|
||||
<ElButton
|
||||
type="primary"
|
||||
:disabled="tableData?.length === 0"
|
||||
:loading="loading"
|
||||
@click="initPassword"
|
||||
>确认重置并发送邮件通知</ElButton
|
||||
>
|
||||
</div>
|
||||
<ElTable
|
||||
:data="tableData"
|
||||
:stripe="true"
|
||||
:border="true"
|
||||
style="width: 100%"
|
||||
class="mt-10px"
|
||||
max-height="500px"
|
||||
>
|
||||
<ElTableColumn prop="id" label="用户编号" width="100" align="center" />
|
||||
<ElTableColumn prop="name" label="姓名" width="120" align="center" />
|
||||
<ElTableColumn prop="email" label="邮箱" width="200" align="center" />
|
||||
<ElTableColumn prop="reset_password_status" label="重置状态" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<ElTag v-if="scope.row.reset_password_status === true" type="success" effect="dark">
|
||||
重置成功
|
||||
</ElTag>
|
||||
<ElTag v-else-if="scope.row.reset_password_status === false" type="danger" effect="dark">
|
||||
重置失败
|
||||
</ElTag>
|
||||
<ElTag v-else type="warning" effect="dark"> 待重置 </ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn prop="send_sms_status" label="发送状态" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<ElTag v-if="scope.row.send_sms_status === true" type="success" effect="dark">
|
||||
发送成功
|
||||
</ElTag>
|
||||
<ElTag v-else-if="scope.row.send_sms_status === false" type="danger" effect="dark">
|
||||
发送失败
|
||||
</ElTag>
|
||||
<ElTag v-else type="warning" effect="dark"> 待发送 </ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn prop="send_sms_msg" label="描述" align="center" />
|
||||
<ElTableColumn fixed="right" label="操作" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<ElPopconfirm title="确认移除吗?" @confirm="handleDelete(scope.$index)">
|
||||
<template #reference>
|
||||
<ElButton v-if="scope.row.send_sms_status !== true" link type="primary" size="small"
|
||||
>移除</ElButton
|
||||
>
|
||||
</template>
|
||||
</ElPopconfirm>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</ElTable>
|
||||
</div>
|
||||
</template>
|
@ -0,0 +1,96 @@
|
||||
<script setup lang="ts">
|
||||
import { ElButton, ElTable, ElTableColumn, ElPopconfirm, ElMessage, ElTag } from 'element-plus'
|
||||
import { postUsersInitPasswordSendSMSApi } from '@/api/vadmin/auth/user'
|
||||
import { ref, PropType } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
selections: {
|
||||
type: Object as PropType<Recordable[]>
|
||||
}
|
||||
})
|
||||
|
||||
const tableData = ref(JSON.parse(JSON.stringify(props.selections)))
|
||||
const loading = ref(false)
|
||||
|
||||
const handleDelete = (index: number) => {
|
||||
tableData.value.splice(index, 1)
|
||||
}
|
||||
|
||||
const initPassword = async () => {
|
||||
loading.value = true
|
||||
const ids = tableData.value
|
||||
.filter((item) => item.reset_password_status !== true)
|
||||
.map((item) => item.id)
|
||||
if (ids.length <= 0) {
|
||||
return ElMessage.warning('已全部重置完成,无需重复操作')
|
||||
}
|
||||
const res = await postUsersInitPasswordSendSMSApi(ids).finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
if (res) {
|
||||
tableData.value = res.data
|
||||
ElMessage.success('重置成功')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="flex justify-between">
|
||||
<span>已选用户列表</span>
|
||||
<ElButton
|
||||
type="primary"
|
||||
:disabled="tableData?.length === 0"
|
||||
:loading="loading"
|
||||
@click="initPassword"
|
||||
>确认重置并发送短信通知</ElButton
|
||||
>
|
||||
</div>
|
||||
<ElTable
|
||||
:data="tableData"
|
||||
:stripe="true"
|
||||
:border="true"
|
||||
style="width: 100%"
|
||||
class="mt-10px"
|
||||
max-height="500px"
|
||||
>
|
||||
<ElTableColumn prop="id" label="用户编号" width="100" align="center" />
|
||||
<ElTableColumn prop="name" label="姓名" width="120" align="center" />
|
||||
<ElTableColumn prop="telephone" label="手机号" width="120" align="center" />
|
||||
<ElTableColumn prop="reset_password_status" label="重置状态" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<ElTag v-if="scope.row.reset_password_status === true" type="success" effect="dark">
|
||||
重置成功
|
||||
</ElTag>
|
||||
<ElTag v-else-if="scope.row.reset_password_status === false" type="danger" effect="dark">
|
||||
重置失败
|
||||
</ElTag>
|
||||
<ElTag v-else type="warning" effect="dark"> 待重置 </ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn prop="send_sms_status" label="发送状态" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<ElTag v-if="scope.row.send_sms_status === true" type="success" effect="dark">
|
||||
发送成功
|
||||
</ElTag>
|
||||
<ElTag v-else-if="scope.row.send_sms_status === false" type="danger" effect="dark">
|
||||
发送失败
|
||||
</ElTag>
|
||||
<ElTag v-else type="warning" effect="dark"> 待发送 </ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn prop="send_sms_msg" label="描述" align="center" />
|
||||
<ElTableColumn fixed="right" label="操作" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<ElPopconfirm title="确认移除吗?" @confirm="handleDelete(scope.$index)">
|
||||
<template #reference>
|
||||
<ElButton v-if="scope.row.send_sms_status !== true" link type="primary" size="small"
|
||||
>移除</ElButton
|
||||
>
|
||||
</template>
|
||||
</ElPopconfirm>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</ElTable>
|
||||
</div>
|
||||
</template>
|
@ -0,0 +1,64 @@
|
||||
import { FormSchema } from '@/types/form'
|
||||
import { reactive } from 'vue'
|
||||
|
||||
export const schema = reactive<FormSchema[]>([
|
||||
{
|
||||
field: 'email_access',
|
||||
label: '邮箱账号',
|
||||
colProps: {
|
||||
span: 24
|
||||
},
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
style: {
|
||||
width: '500px'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'email_password',
|
||||
label: '邮箱密码',
|
||||
colProps: {
|
||||
span: 24
|
||||
},
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
style: {
|
||||
width: '500px'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'email_server',
|
||||
label: '邮箱服务器',
|
||||
colProps: {
|
||||
span: 24
|
||||
},
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
style: {
|
||||
width: '500px'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'email_port',
|
||||
label: '服务器端口',
|
||||
colProps: {
|
||||
span: 24
|
||||
},
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
style: {
|
||||
width: '500px'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'active',
|
||||
label: '',
|
||||
colProps: {
|
||||
span: 24
|
||||
}
|
||||
}
|
||||
])
|
64
kinit-admin/src/views/vadmin/system/settings/email.vue
Normal file
64
kinit-admin/src/views/vadmin/system/settings/email.vue
Normal file
@ -0,0 +1,64 @@
|
||||
<script setup lang="ts">
|
||||
import { Form } from '@/components/Form'
|
||||
import { useForm } from '@/hooks/web/useForm'
|
||||
import { schema } from './components/email.data'
|
||||
import { ElButton } from 'element-plus'
|
||||
import { getSystemSettingsApi, putSystemSettingsApi } from '@/api/vadmin/system/settings'
|
||||
import { ref, unref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
|
||||
const props = defineProps({
|
||||
tabId: propTypes.number
|
||||
})
|
||||
|
||||
const { register, methods, elFormRef } = useForm({
|
||||
schema: schema
|
||||
})
|
||||
|
||||
const { setValues } = methods
|
||||
|
||||
let formData = ref({} as Recordable)
|
||||
|
||||
const getData = async () => {
|
||||
const res = await getSystemSettingsApi({ tab_id: props.tabId })
|
||||
if (res) {
|
||||
setValues(res.data)
|
||||
formData.value = res.data
|
||||
}
|
||||
}
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const save = async () => {
|
||||
const formRef = unref(elFormRef)
|
||||
await formRef?.validate(async (isValid) => {
|
||||
if (isValid) {
|
||||
loading.value = true
|
||||
let data = await methods.getFormData()
|
||||
if (!data) {
|
||||
loading.value = false
|
||||
return ElMessage.error('未获取到数据')
|
||||
}
|
||||
const res = await putSystemSettingsApi(data)
|
||||
if (res) {
|
||||
getData()
|
||||
return ElMessage.success('更新成功')
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
getData()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Form @register="register">
|
||||
<template #active>
|
||||
<ElButton type="primary" @click="save">立即提交</ElButton>
|
||||
</template>
|
||||
</Form>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less"></style>
|
@ -96,7 +96,7 @@ def migrate(env: Environment = Environment.pro):
|
||||
:params name: 数据库环境
|
||||
"""
|
||||
print("开始更新数据库表")
|
||||
InitializeData().migrate_model(env)
|
||||
InitializeData.migrate_model(env)
|
||||
|
||||
|
||||
@shell_app.command()
|
||||
|
40
kinit-api/utils/count.py
Normal file
40
kinit-api/utils/count.py
Normal file
@ -0,0 +1,40 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @version : 1.0
|
||||
# @Creaet Time : 2022/11/3 17:23
|
||||
# @File : count.py
|
||||
# @IDE : PyCharm
|
||||
# @desc : 计数
|
||||
|
||||
|
||||
from aioredis.client import Redis
|
||||
|
||||
|
||||
class Count:
|
||||
"""
|
||||
计数
|
||||
"""
|
||||
|
||||
def __init__(self, rd: Redis, key):
|
||||
self.rd = rd
|
||||
self.key = key
|
||||
|
||||
async def add(self, ex: int = None) -> int:
|
||||
await self.rd.set(self.key, await self.get_count() + 1, ex=ex)
|
||||
return await self.get_count()
|
||||
|
||||
async def subtract(self, ex: int = None) -> int:
|
||||
await self.rd.set(self.key, await self.get_count() - 1, ex=ex)
|
||||
return await self.get_count()
|
||||
|
||||
async def get_count(self) -> int:
|
||||
number = await self.rd.get(self.key)
|
||||
if number:
|
||||
return int(number)
|
||||
return 0
|
||||
|
||||
async def reset(self) -> None:
|
||||
await self.rd.set(self.key, 0)
|
||||
|
||||
async def delete(self) -> None:
|
||||
await self.rd.delete(self.key)
|
91
kinit-api/utils/send_email.py
Normal file
91
kinit-api/utils/send_email.py
Normal file
@ -0,0 +1,91 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @version : 1.0
|
||||
# @Creaet Time : 2023/3/27 9:48
|
||||
# @File : send_email.py
|
||||
# @IDE : PyCharm
|
||||
# @desc : 发送邮件封装类
|
||||
|
||||
|
||||
import smtplib
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.application import MIMEApplication
|
||||
from typing import List
|
||||
from aioredis import Redis
|
||||
|
||||
from core.exception import CustomException
|
||||
from utils.cache import Cache
|
||||
|
||||
|
||||
class EmailSender:
|
||||
|
||||
def __init__(self, rd: Redis):
|
||||
self.email = None
|
||||
self.password = None
|
||||
self.smtp_server = None
|
||||
self.smtp_port = None
|
||||
self.server = None
|
||||
self.rd = rd
|
||||
|
||||
async def __get_settings(self, retry: int = 3):
|
||||
"""
|
||||
获取配置信息
|
||||
"""
|
||||
web_email = await Cache(self.rd).get_tab_name("web_email", retry)
|
||||
self.email = web_email.get("email_access")
|
||||
self.password = web_email.get("email_password")
|
||||
self.smtp_server = web_email.get("email_server")
|
||||
self.smtp_port = int(web_email.get("email_port"))
|
||||
|
||||
self.server = smtplib.SMTP(self.smtp_server, self.smtp_port)
|
||||
self.server.starttls()
|
||||
try:
|
||||
self.server.login(self.email, self.password)
|
||||
except smtplib.SMTPAuthenticationError:
|
||||
raise CustomException("邮箱服务器认证失败!")
|
||||
|
||||
async def send_email(self, to_emails: List[str], subject: str, body: str, attachments: List[str] = None):
|
||||
"""
|
||||
发送邮件
|
||||
:param to_emails: 收件人,一个或多个
|
||||
:param subject: 主题
|
||||
:param body: 内容
|
||||
:param attachments: 附件
|
||||
"""
|
||||
await self.__get_settings()
|
||||
|
||||
message = MIMEMultipart()
|
||||
message['From'] = self.email
|
||||
message['To'] = ', '.join(to_emails)
|
||||
message['Subject'] = subject
|
||||
body = MIMEText(body)
|
||||
message.attach(body)
|
||||
if attachments:
|
||||
for attachment in attachments:
|
||||
with open(attachment, 'rb') as f:
|
||||
file_data = f.read()
|
||||
filename = attachment.split('/')[-1]
|
||||
attachment = MIMEApplication(file_data, Name=filename)
|
||||
attachment['Content-Disposition'] = f'attachment; filename="{filename}"'
|
||||
message.attach(attachment)
|
||||
try:
|
||||
result = self.server.sendmail(self.email, to_emails, message.as_string())
|
||||
self.server.quit()
|
||||
print("邮件发送结果", result)
|
||||
if result:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
except smtplib.SMTPException as e:
|
||||
self.server.quit()
|
||||
print('邮件发送失败!错误信息:', e)
|
||||
return False
|
||||
|
||||
|
||||
# if __name__ == '__main__':
|
||||
# sender = EmailSender()
|
||||
# to_emails = ['ktianc2001@163.com', '2445667550@qq.com']
|
||||
# subject = 'Test email'
|
||||
# body = 'This is a test email'
|
||||
# sender.send_email(to_emails, subject, body)
|
Loading…
x
Reference in New Issue
Block a user