mirror of
https://github.com/himool/HimoolERP.git
synced 2024-09-20 06:46:00 +08:00
feat: update
This commit is contained in:
parent
092e1895a0
commit
56a472adc5
3
Pipfile
3
Pipfile
|
@ -4,7 +4,7 @@ verify_ssl = true
|
|||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
django = "*"
|
||||
django = "==3.2.16"
|
||||
djangorestframework = "*"
|
||||
djangorestframework-simplejwt = "*"
|
||||
drf-spectacular = "*"
|
||||
|
@ -17,6 +17,7 @@ number-precision = "*"
|
|||
openpyxl = "*"
|
||||
uvicorn = "*"
|
||||
gunicorn = "*"
|
||||
tencentcloud-sdk-python = "*"
|
||||
|
||||
[dev-packages]
|
||||
autopep8 = "*"
|
||||
|
|
|
@ -11,6 +11,9 @@ class Team(Model):
|
|||
enable_auto_stock_in = BooleanField(default=False, verbose_name='启用自动入库')
|
||||
enable_auto_stock_out = BooleanField(default=False, verbose_name='启用自动出库')
|
||||
|
||||
register_phone = CharField(max_length=32, blank=True, null=True, verbose_name='注册手机号')
|
||||
register_city = CharField(max_length=32, blank=True, null=True, verbose_name='所在城市')
|
||||
|
||||
|
||||
class PermissionGroup(Model):
|
||||
"""权限分组"""
|
||||
|
@ -64,6 +67,14 @@ class User(Model):
|
|||
unique_together = [('username', 'team'), ('name', 'team')]
|
||||
|
||||
|
||||
class VerificationCode(Model):
|
||||
"""验证码"""
|
||||
|
||||
phone = CharField(max_length=32, verbose_name='手机号')
|
||||
code = CharField(max_length=6, verbose_name='验证码')
|
||||
create_time = DateTimeField(auto_now_add=True, verbose_name='创建时间')
|
||||
|
||||
|
||||
__all__ = [
|
||||
'Team', 'PermissionGroup', 'Permission', 'Role', 'User',
|
||||
'Team', 'PermissionGroup', 'Permission', 'Role', 'User', 'VerificationCode',
|
||||
]
|
||||
|
|
|
@ -33,8 +33,22 @@ class SetPasswordRequest(Serializer):
|
|||
new_password = CharField(label='新密码')
|
||||
|
||||
|
||||
class MakeCodeRequest(Serializer):
|
||||
phone = CharField(label='手机号')
|
||||
|
||||
|
||||
class RegisterRequest(Serializer):
|
||||
register_city = CharField(label='所在城市')
|
||||
phone = CharField(label='手机号')
|
||||
code = CharField(label='验证码')
|
||||
number = CharField(label='公司编号')
|
||||
username = CharField(label='用户名')
|
||||
password = CharField(label='密码')
|
||||
|
||||
|
||||
__all__ = [
|
||||
'GetTokenRequest', 'GetTokenResponse',
|
||||
'RefreshTokenRequest', 'RefreshTokenResponse',
|
||||
'UserInfoResponse', 'SetPasswordRequest',
|
||||
'MakeCodeRequest', 'RegisterRequest',
|
||||
]
|
||||
|
|
|
@ -11,6 +11,11 @@ from extensions.viewsets import *
|
|||
from apps.system.serializers import *
|
||||
from apps.system.schemas import *
|
||||
from apps.system.models import *
|
||||
from django.utils import timezone
|
||||
from datetime import timedelta
|
||||
import random
|
||||
from scripts.create_user import create_user
|
||||
from scripts.send_phone_code import send_phone_code
|
||||
|
||||
|
||||
class PermissionGroupViewSet(BaseViewSet, ListModelMixin):
|
||||
|
@ -187,6 +192,42 @@ class UserActionViewSet(FunctionViewSet):
|
|||
|
||||
return Response(status=status.HTTP_200_OK)
|
||||
|
||||
@extend_schema(request=MakeCodeRequest, responses={204: None})
|
||||
@action(detail=False, methods=['post'])
|
||||
def make_code(self, request, *args, **kwargs):
|
||||
"""生产验证码"""
|
||||
|
||||
serializer = MakeCodeRequest(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
validated_data = serializer.validated_data
|
||||
|
||||
code = str(random.randint(100000, 999999))
|
||||
VerificationCode.objects.create(phone=validated_data['phone'], code=code)
|
||||
send_phone_code(validated_data['phone'], code)
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
@extend_schema(request=RegisterRequest, responses={204: None})
|
||||
@action(detail=False, methods=['post'])
|
||||
def register(self, request, *args, **kwargs):
|
||||
"""注册"""
|
||||
|
||||
serializer = RegisterRequest(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
validated_data = serializer.validated_data
|
||||
|
||||
if Team.objects.filter(number=validated_data['number']).exists():
|
||||
raise ValidationError('公司编号已存在')
|
||||
|
||||
start_time = timezone.localtime() - timedelta(minutes=10)
|
||||
if not VerificationCode.objects.filter(
|
||||
phone=validated_data['phone'], code=validated_data['code'], create_time__gte=start_time).exists():
|
||||
raise ValidationError('验证码错误或超时')
|
||||
|
||||
expiry_time = timezone.localtime() + timedelta(days=3)
|
||||
create_user(validated_data['number'], validated_data['phone'], validated_data['register_city'],
|
||||
expiry_time, validated_data['username'], validated_data['password'])
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
|
||||
__all__ = [
|
||||
'PermissionGroupViewSet',
|
||||
|
|
|
@ -16,3 +16,12 @@ DATABASES = {
|
|||
'NAME': BASE_DIR / 'db.sqlite3',
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Tencent 短信接口
|
||||
SECRET_ID = ''
|
||||
SECRET_KEY = ''
|
||||
SMS_SDK_APP_ID = ''
|
||||
TEMPLATE_ID = ''
|
||||
SIGN_NAME = ''
|
||||
REGION = ''
|
||||
|
|
|
@ -24,6 +24,7 @@ python manage.py createsuperuser
|
|||
python manage.py runscript init_permission
|
||||
python manage.py runscript create_user
|
||||
python manage.py runscript create_test_data
|
||||
python manage.py runscript send_phone_code
|
||||
python manage.py runserver
|
||||
gunicorn project.asgi:application -c configs/gunicorn.py -k uvicorn.workers.UvicornWorker
|
||||
ps -aux | grep gunicorn | awk '{print $2}'| xargs kill -9
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"serve": "export NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
|
@ -12,6 +12,7 @@
|
|||
"ant-design-vue": "^1.6.5",
|
||||
"axios": "^0.20.0",
|
||||
"core-js": "^3.6.5",
|
||||
"element-china-area-data": "^6.1.0",
|
||||
"html2canvas": "^1.3.3",
|
||||
"js-cookie": "^2.2.1",
|
||||
"jsbarcode": "^3.11.5",
|
||||
|
|
|
@ -1,32 +1,41 @@
|
|||
import request from '@/utils/request';
|
||||
|
||||
import request from "@/utils/request";
|
||||
|
||||
// GetToken
|
||||
export function getToken(data) {
|
||||
return request({ url: `/user/get_token/`, method: 'post', data }, false)
|
||||
return request({ url: `/user/get_token/`, method: "post", data }, false);
|
||||
}
|
||||
|
||||
// RefreshToken
|
||||
export function refreshToken(data) {
|
||||
return request({ url: `/user/refresh_token/`, method: 'post', data })
|
||||
return request({ url: `/user/refresh_token/`, method: "post", data });
|
||||
}
|
||||
|
||||
// GetInfo
|
||||
export function getInfo(params) {
|
||||
return request({ url: `/user/info/`, method: 'get', params })
|
||||
return request({ url: `/user/info/`, method: "get", params });
|
||||
}
|
||||
|
||||
// SetPassword
|
||||
export function setPassword(data) {
|
||||
return request({ url: `/user/set_password/`, method: 'post', data })
|
||||
return request({ url: `/user/set_password/`, method: "post", data });
|
||||
}
|
||||
|
||||
// 常用功能
|
||||
export function getCommonFunctions(params) {
|
||||
return request({ url: `/user/common_functions/`, method: 'get', params })
|
||||
return request({ url: `/user/common_functions/`, method: "get", params });
|
||||
}
|
||||
|
||||
// 设置常用功能
|
||||
export function setCommonFunctions(data) {
|
||||
return request({ url: `/user/set_common_functions/`, method: 'post', data })
|
||||
}
|
||||
return request({ url: `/user/set_common_functions/`, method: "post", data });
|
||||
}
|
||||
|
||||
// MakeCode
|
||||
export function makeCode(data) {
|
||||
return request({ url: `/user/make_code/`, method: "post", data });
|
||||
}
|
||||
|
||||
// Register
|
||||
export function registerAccount(data) {
|
||||
return request({ url: `/user/register/`, method: "post", data });
|
||||
}
|
||||
|
|
|
@ -1,19 +1,25 @@
|
|||
export default {
|
||||
path: '/user',
|
||||
name: 'user',
|
||||
component: () => import('@/layouts/UserLayout'),
|
||||
path: "/user",
|
||||
name: "user",
|
||||
component: () => import("@/layouts/UserLayout"),
|
||||
children: [
|
||||
{
|
||||
path: 'login',
|
||||
name: 'login',
|
||||
meta: { title: '登录' },
|
||||
component: () => import('@/views/login/Login'),
|
||||
path: "login",
|
||||
name: "login",
|
||||
meta: { title: "登录" },
|
||||
component: () => import("@/views/login/Login"),
|
||||
},
|
||||
{
|
||||
path: 'set_password',
|
||||
name: 'setPassword',
|
||||
meta: { title: '设置密码' },
|
||||
component: () => import('@/views/setPassword/SetPassword'),
|
||||
path: "register",
|
||||
name: "register",
|
||||
meta: { title: "注册" },
|
||||
component: () => import("@/views/register/index"),
|
||||
},
|
||||
{
|
||||
path: "set_password",
|
||||
name: "setPassword",
|
||||
meta: { title: "设置密码" },
|
||||
component: () => import("@/views/setPassword/SetPassword"),
|
||||
},
|
||||
],
|
||||
}
|
||||
};
|
||||
|
|
|
@ -14,79 +14,75 @@
|
|||
</a-form-model>
|
||||
</div>
|
||||
|
||||
<a-row>
|
||||
<a-row :gutter="[4, 4]">
|
||||
<a-col :span="14" offset="5">
|
||||
<a-button type="primary" size="large" :loading="isLoading" style="width: 100%;" @click="login">登录</a-button>
|
||||
<a-button type="primary" size="large" :loading="isLoading" style="width: 100%" @click="login">登录</a-button>
|
||||
</a-col>
|
||||
<a-col :span="14" offset="5" style="text-align: right">
|
||||
<a @click="$router.push('/user/register')">注册账号</a>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<div style="text-align: center; width: 100%; margin-top: 24px;">
|
||||
<div style="text-align: center; width: 100%; margin-top: 24px">
|
||||
<div>试用,购买或问题咨询请扫描下方客户经理二维码</div>
|
||||
<div>
|
||||
试用,购买或问题咨询请扫描下方客户经理二维码
|
||||
</div>
|
||||
<div>
|
||||
<img :src="wechatCustomerService" width="100" style="margin-top: 8px;" />
|
||||
<img :src="wechatCustomerService" width="100" style="margin-top: 8px" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getToken } from '@/api/user';
|
||||
import Cookies from 'js-cookie';
|
||||
import { getToken } from "@/api/user";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
export default {
|
||||
name: 'Login',
|
||||
data() {
|
||||
return {
|
||||
wechatCustomerService: require('@/assets/wechat_customer_service.png'),
|
||||
isLoading: false,
|
||||
form: {
|
||||
number: '',
|
||||
username: '',
|
||||
password: '',
|
||||
},
|
||||
rules: {
|
||||
number: [
|
||||
{ required: true, message: '请输入公司编号', trigger: 'change' },
|
||||
],
|
||||
username: [
|
||||
{ required: true, message: '请输入用户名', trigger: 'change' },
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: '请输入密码', trigger: 'change' },
|
||||
],
|
||||
},
|
||||
export default {
|
||||
name: "Login",
|
||||
data() {
|
||||
return {
|
||||
wechatCustomerService: require("@/assets/wechat_customer_service.png"),
|
||||
isLoading: false,
|
||||
form: {
|
||||
number: "",
|
||||
username: "",
|
||||
password: "",
|
||||
},
|
||||
rules: {
|
||||
number: [{ required: true, message: "请输入公司编号", trigger: "change" }],
|
||||
username: [{ required: true, message: "请输入用户名", trigger: "change" }],
|
||||
password: [{ required: true, message: "请输入密码", trigger: "change" }],
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
initialize() {
|
||||
document.onkeypress = (e) => {
|
||||
let code = document.all ? event.keyCode : e.which;
|
||||
if (code == 13) {
|
||||
this.login();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
initialize() {
|
||||
document.onkeypress = (e) => {
|
||||
let code = document.all ? event.keyCode : e.which;
|
||||
if (code == 13) {
|
||||
this.login();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
login() {
|
||||
this.$refs.form.validate(valid => {
|
||||
if (valid) {
|
||||
this.isLoading = true;
|
||||
getToken(this.form).then(data => {
|
||||
Cookies.set('access', data.access);
|
||||
Cookies.set('refresh', data.refresh);
|
||||
this.$router.push('/home');
|
||||
}).finally(() => {
|
||||
login() {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.isLoading = true;
|
||||
getToken(this.form)
|
||||
.then((data) => {
|
||||
Cookies.set("access", data.access);
|
||||
Cookies.set("refresh", data.refresh);
|
||||
this.$router.push("/home");
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
||||
},
|
||||
created() {
|
||||
this.initialize();
|
||||
},
|
||||
}
|
||||
</script>
|
||||
},
|
||||
created() {
|
||||
this.initialize();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
114
frontend/src/views/register/index.vue
Normal file
114
frontend/src/views/register/index.vue
Normal file
|
@ -0,0 +1,114 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>
|
||||
<a-form-model ref="form" :model="form" :rules="rules" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
|
||||
<a-form-model-item prop="phone" label="手机号">
|
||||
<a-input size="large" v-model="form.phone" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item prop="code" label="验证码">
|
||||
<a-space>
|
||||
<a-input size="large" v-model="form.code" />
|
||||
<a-button type="primary" size="large" @click="sendCode">{{ countDown > 0 ? `${countDown} s` : "发送" }}</a-button>
|
||||
</a-space>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item prop="register_city" label="所在城市">
|
||||
<a-cascader size="large" v-model="form.cityCode" placeholder="" :options="provinceAndCityData" @change="changeCity" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item prop="number" label="公司编号">
|
||||
<a-input size="large" v-model="form.number" placeholder="公司英文名或拼音缩写" @pressEnter="register" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item prop="username" label="用户名">
|
||||
<a-input size="large" v-model="form.username" @pressEnter="register" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item prop="password" label="密码">
|
||||
<a-input-password size="large" v-model="form.password" @pressEnter="register" />
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</div>
|
||||
|
||||
<a-row :gutter="[4, 4]">
|
||||
<a-col :span="14" offset="5">
|
||||
<a-button type="primary" size="large" :loading="isLoading" style="width: 100%" @click="register"> 注册 </a-button>
|
||||
</a-col>
|
||||
<a-col :span="14" offset="5" style="text-align: right">
|
||||
<a @click="$router.push('/user/login')">返回登录</a>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { makeCode, registerAccount } from "@/api/user";
|
||||
import { provinceAndCityData } from "element-china-area-data";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
form: {
|
||||
cityCode: undefined,
|
||||
register_city: "",
|
||||
phone: "",
|
||||
code: "",
|
||||
number: "",
|
||||
username: "",
|
||||
password: "",
|
||||
},
|
||||
rules: {
|
||||
register_city: [{ required: true, message: "请选择城市", trigger: "change" }],
|
||||
phone: [{ required: true, message: "请输入手机号", trigger: "change" }],
|
||||
code: [{ required: true, message: "请输入验证码", trigger: "change" }],
|
||||
number: [{ required: true, message: "请输入公司", trigger: "change" }],
|
||||
username: [{ required: true, message: "请输入用户名", trigger: "change" }],
|
||||
password: [{ required: true, message: "请输入密码", trigger: "change" }],
|
||||
},
|
||||
countDown: -1,
|
||||
provinceAndCityData,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
changeCity(_, selectedOptions) {
|
||||
this.form.register_city = selectedOptions.map((item) => item.label).join(" ");
|
||||
},
|
||||
register() {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.isLoading = true;
|
||||
registerAccount(this.form)
|
||||
.then((data) => {
|
||||
this.$message.success("注册成功");
|
||||
this.$router.push("/user/login");
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
sendCode() {
|
||||
if (/^1[3-9]\d{9}$/.test(this.form.phone)) {
|
||||
makeCode({ phone: this.form.phone }).then(() => {
|
||||
this.$message.success("验证码发送成功");
|
||||
this.startCountDown();
|
||||
});
|
||||
} else {
|
||||
this.$message.warning("手机号错误");
|
||||
}
|
||||
},
|
||||
startCountDown() {
|
||||
if (this.countDown < 0) {
|
||||
this.countDown = 60;
|
||||
} else if (this.countDown == 0) {
|
||||
this.countDown = -1;
|
||||
return;
|
||||
} else {
|
||||
this.countDown--;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
this.startCountDown();
|
||||
}, 1000);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -1,32 +1,42 @@
|
|||
asgiref==3.4.1
|
||||
attrs==21.2.0
|
||||
autopep8==1.6.0
|
||||
click==8.0.3
|
||||
Django==3.2
|
||||
django-debug-toolbar==3.2.2
|
||||
django-extensions==3.1.5
|
||||
django-filter==21.1
|
||||
djangorestframework==3.12.4
|
||||
djangorestframework-simplejwt==5.0.0
|
||||
drf-spectacular==0.21.0
|
||||
asgiref==3.7.2
|
||||
attrs==23.1.0
|
||||
autopep8==2.0.4
|
||||
certifi==2023.7.22
|
||||
charset-normalizer==3.3.0
|
||||
click==8.1.7
|
||||
Django==3.2.16
|
||||
django-debug-toolbar==4.2.0
|
||||
django-extensions==3.2.3
|
||||
django-filter==23.3
|
||||
djangorestframework==3.14.0
|
||||
djangorestframework-simplejwt==5.3.0
|
||||
drf-spectacular==0.26.5
|
||||
et-xmlfile==1.1.0
|
||||
gunicorn==20.1.0
|
||||
h11==0.12.0
|
||||
gunicorn==21.2.0
|
||||
h11==0.14.0
|
||||
idna==3.4
|
||||
inflection==0.5.1
|
||||
jsonschema==4.2.1
|
||||
jsonschema==4.19.1
|
||||
jsonschema-specifications==2023.7.1
|
||||
number-precision==2021.1.30
|
||||
openpyxl==3.0.9
|
||||
openpyxl==3.1.2
|
||||
packaging==23.2
|
||||
pendulum==2.1.2
|
||||
Pillow==8.4.0
|
||||
pycodestyle==2.8.0
|
||||
PyJWT==2.3.0
|
||||
pyrsistent==0.18.0
|
||||
Pillow==10.0.1
|
||||
pycodestyle==2.11.0
|
||||
PyJWT==2.8.0
|
||||
python-dateutil==2.8.2
|
||||
pytz==2021.3
|
||||
pytz==2023.3.post1
|
||||
pytzdata==2020.1
|
||||
PyYAML==6.0
|
||||
PyYAML==6.0.1
|
||||
referencing==0.30.2
|
||||
requests==2.31.0
|
||||
rpds-py==0.10.4
|
||||
six==1.16.0
|
||||
sqlparse==0.4.2
|
||||
toml==0.10.2
|
||||
sqlparse==0.4.4
|
||||
tencentcloud-sdk-python==3.0.992
|
||||
tomli==2.0.1
|
||||
typing_extensions==4.8.0
|
||||
uritemplate==4.1.1
|
||||
uvicorn==0.16.0
|
||||
urllib3==2.0.6
|
||||
uvicorn==0.23.2
|
||||
|
|
|
@ -4,15 +4,22 @@ from apps.system.models import *
|
|||
import pendulum
|
||||
|
||||
|
||||
@transaction.atomic
|
||||
def create_user(team_number, register_phone, register_city, expiry_time, username, password):
|
||||
team = Team.objects.create(
|
||||
number=team_number,
|
||||
expiry_time=expiry_time,
|
||||
register_phone=register_phone,
|
||||
register_city=register_city)
|
||||
|
||||
User.objects.create(team=team, username=username, password=make_password(password), name=username, is_manager=True)
|
||||
|
||||
|
||||
def run(*args):
|
||||
number = input('编号: ')
|
||||
username = input('用户名: ')
|
||||
password = input('密码: ')
|
||||
name = input('名称: ')
|
||||
activation_days = input('激活天数: ')
|
||||
expiry_time = pendulum.now().add(days=float(activation_days))
|
||||
|
||||
with transaction.atomic():
|
||||
team = Team.objects.create(number=number, expiry_time=expiry_time)
|
||||
User.objects.create(team=team, username=username, password=make_password(password),
|
||||
name=name, is_manager=True)
|
||||
create_user(number, None, None, expiry_time, username, password)
|
||||
|
|
49
scripts/send_phone_code.py
Normal file
49
scripts/send_phone_code.py
Normal file
|
@ -0,0 +1,49 @@
|
|||
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
|
||||
from tencentcloud.common.profile.client_profile import ClientProfile
|
||||
from tencentcloud.common.profile.http_profile import HttpProfile
|
||||
from tencentcloud.sms.v20210111 import sms_client, models
|
||||
from extensions.exceptions import ServerError
|
||||
from tencentcloud.common import credential
|
||||
import json
|
||||
from configs.django import SECRET_ID, SECRET_KEY, SMS_SDK_APP_ID, TEMPLATE_ID, SIGN_NAME, REGION
|
||||
|
||||
|
||||
def send_phone_code(phone, code):
|
||||
"""发送验证码"""
|
||||
|
||||
try:
|
||||
# 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密
|
||||
# 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考,建议采用更安全的方式来使用密钥,请参见:https://cloud.tencent.com/document/product/1278/85305
|
||||
# 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
|
||||
cred = credential.Credential(SECRET_ID, SECRET_KEY)
|
||||
# 实例化一个http选项,可选的,没有特殊需求可以跳过
|
||||
httpProfile = HttpProfile()
|
||||
httpProfile.endpoint = 'sms.tencentcloudapi.com'
|
||||
|
||||
# 实例化一个client选项,可选的,没有特殊需求可以跳过
|
||||
clientProfile = ClientProfile()
|
||||
clientProfile.httpProfile = httpProfile
|
||||
# 实例化要请求产品的client对象,clientProfile是可选的
|
||||
client = sms_client.SmsClient(cred, REGION, clientProfile)
|
||||
|
||||
# 实例化一个请求对象,每个接口都会对应一个request对象
|
||||
req = models.SendSmsRequest()
|
||||
params = {
|
||||
'PhoneNumberSet': [f'+86{phone}'],
|
||||
'SmsSdkAppId': SMS_SDK_APP_ID,
|
||||
'SignName': SIGN_NAME,
|
||||
'TemplateId': TEMPLATE_ID,
|
||||
'TemplateParamSet': [code],
|
||||
}
|
||||
req.from_json_string(json.dumps(params))
|
||||
|
||||
# 返回的resp是一个SendSmsResponse的实例,与请求对象对应
|
||||
client.SendSms(req)
|
||||
except TencentCloudSDKException:
|
||||
raise ServerError('验证码发送错误')
|
||||
|
||||
|
||||
def run(*args):
|
||||
phone = input('手机号: ')
|
||||
code = input('验证码: ')
|
||||
send_phone_code(phone, code)
|
|
@ -103,6 +103,16 @@ DATABASES = {{
|
|||
'NAME': BASE_DIR / 'db.sqlite3',
|
||||
}}
|
||||
}}
|
||||
"""
|
||||
|
||||
file_content += f"""
|
||||
# Tencent 短信参数
|
||||
SECRET_ID = ''
|
||||
SECRET_KEY = ''
|
||||
SMS_SDK_APP_ID = ''
|
||||
TEMPLATE_ID = ''
|
||||
SIGN_NAME = ''
|
||||
REGION = ''
|
||||
"""
|
||||
with open(BASE_DIR / 'configs/django.py', 'w') as file:
|
||||
file.write(file_content)
|
||||
|
|
Loading…
Reference in a new issue