更新
This commit is contained in:
parent
df40bebbfd
commit
5f8dc3c361
88
README.md
88
README.md
@ -10,19 +10,19 @@
|
|||||||
|
|
||||||
kinit 是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。
|
kinit 是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。
|
||||||
|
|
||||||
- 🧑🤝🧑前端采用 [vue-element-plus-admin](https://gitee.com/kailong110120130/vue-element-plus-admin) 、[Vue3](https://cn.vuejs.org/guide/introduction.html)、[Element Plus](https://element-plus.gitee.io/zh-CN/guide/design.html),[TypeScript](https://www.tslang.cn/),等主流技术开发。
|
- 🧑🤝🧑前端采用 [vue-element-plus-admin](https://gitee.com/kailong110120130/vue-element-plus-admin) 、[Vue3](https://cn.vuejs.org/guide/introduction.html)、[Element Plus](https://element-plus.gitee.io/zh-CN/guide/design.html)、[TypeScript](https://www.tslang.cn/),等主流技术开发。
|
||||||
- 👭后端采用 Python 语言高性能 [FastAPI](https://fastapi.tiangolo.com/zh/) 框架以及强大的 Mysql 数据库。
|
- 👭后端采用 Python 语言高性能 [FastAPI](https://fastapi.tiangolo.com/zh/) 框架以及强大的 Mysql 数据库。
|
||||||
- 👫权限认证使用[使用(哈希)密码和 JWT Bearer 令牌的 OAuth2](https://fastapi.tiangolo.com/zh/tutorial/security/oauth2-jwt/),支持多终端认证系统。
|
- 👫权限认证使用[(哈希)密码和 JWT Bearer 令牌的 OAuth2](https://fastapi.tiangolo.com/zh/tutorial/security/oauth2-jwt/),支持多终端认证系统。
|
||||||
- 👬支持加载动态权限菜单,多方式轻松权限控制。
|
- 👬支持加载动态权限菜单,多方式轻松权限控制。
|
||||||
- 💏特别鸣谢:[django-vue-admin](https://gitee.com/liqianglog/django-vue-admin) 、 [vue-element-plus-admin](https://gitee.com/kailong110120130/vue-element-plus-admin)。
|
- 💏特别鸣谢:[django-vue-admin](https://gitee.com/liqianglog/django-vue-admin) 、 [vue-element-plus-admin](https://gitee.com/kailong110120130/vue-element-plus-admin)。
|
||||||
- 开箱即用的中后台解决方案,可以用来作为项目的启动模版,也可用于学习参考。并且时刻关注着最新技术动向,尽可能的第一时间更新。
|
- 开箱即用的中后台解决方案,可以用来作为项目的启动模版,也可用于学习参考。并且时刻关注着最新技术动向,尽可能的第一时间更新。
|
||||||
|
|
||||||
## 在线体验
|
## 在线体验
|
||||||
|
|
||||||
👩👧👦演示地址:[http://demo.django-vue-admin.com](https://gitee.com/link?target=http%3A%2F%2Fdemo.django-vue-admin.com)
|
👩👧👦演示地址:正在部署中。。。。。
|
||||||
|
|
||||||
- 账号:superadmin
|
- 账号:admin
|
||||||
- 密码:admin123456
|
- 密码:123456
|
||||||
|
|
||||||
## 源码地址
|
## 源码地址
|
||||||
|
|
||||||
@ -33,13 +33,27 @@ github地址:https://gitee.com/ktianc/kinit👩👦👦
|
|||||||
## 内置功能
|
## 内置功能
|
||||||
|
|
||||||
- [x] 👨⚕️菜单管理:配置系统菜单,操作权限,按钮权限标识、后端接口权限等。
|
- [x] 👨⚕️菜单管理:配置系统菜单,操作权限,按钮权限标识、后端接口权限等。
|
||||||
|
|
||||||
- [x] 👩⚕️角色管理:角色菜单权限分配。
|
- [x] 👩⚕️角色管理:角色菜单权限分配。
|
||||||
|
|
||||||
- [x] 👨🎓用户管理:用户是系统操作者,该功能主要完成系统用户配置。
|
- [x] 👨🎓用户管理:用户是系统操作者,该功能主要完成系统用户配置。
|
||||||
- [x] 🧑🔧字典管理:对系统中经常使用的一些较为固定的数据进行维护。
|
|
||||||
|
- [ ] 🏡个人主页:配置用户个人信息,密码修改等。
|
||||||
|
|
||||||
|
- [x] 📚字典管理:对系统中经常使用的一些较为固定的数据进行维护。
|
||||||
|
|
||||||
- [ ] 📁附件管理:对平台上所有文件、图片等进行统一管理。
|
- [ ] 📁附件管理:对平台上所有文件、图片等进行统一管理。
|
||||||
|
|
||||||
- [ ] 🗓️登录日志:用户登录日志记录和查询。
|
- [ ] 🗓️登录日志:用户登录日志记录和查询。
|
||||||
|
|
||||||
- [ ] 🗓️操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
|
- [ ] 🗓️操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
|
||||||
|
|
||||||
|
- [ ] 🔒登录认证:目前支持用户使用手机号+密码方式登录。
|
||||||
|
|
||||||
|
说明:新建用户密码默认为手机号后六位;
|
||||||
|
|
||||||
|
说明:用户在第一次登录时,必须修改当前用户密码。
|
||||||
|
|
||||||
## 前序准备
|
## 前序准备
|
||||||
|
|
||||||
- [FastAPI](https://fastapi.tiangolo.com/zh/) - 熟悉后台接口 Web 框架
|
- [FastAPI](https://fastapi.tiangolo.com/zh/) - 熟悉后台接口 Web 框架
|
||||||
@ -104,8 +118,19 @@ else:
|
|||||||
|
|
||||||
3. 迁移数据库
|
3. 迁移数据库
|
||||||
|
|
||||||
```
|
```shell
|
||||||
|
# 初次生成迁移文件
|
||||||
|
alembic revision -m "生成迁移文件"
|
||||||
|
|
||||||
|
# 通过该命令可以将模型迁移到数据库
|
||||||
|
alembic upgrade head
|
||||||
|
|
||||||
|
# 如果有更新,则可以使用这个命令再次生成迁移文件,初次也可以使用
|
||||||
|
alembic revision --autogenerate -m "update"
|
||||||
|
# --autogenerate:自动将当前模型的修改,生成迁移脚本。
|
||||||
|
|
||||||
|
# 通过该命令可以将模型迁移到数据库
|
||||||
|
alembic upgrade head
|
||||||
```
|
```
|
||||||
|
|
||||||
4. 数据化数据库数据
|
4. 数据化数据库数据
|
||||||
@ -147,12 +172,35 @@ pnpm run build:pro
|
|||||||
- 访问地址:http://localhost:5000 (默认为此地址,如有修改请按照配置文件)
|
- 访问地址:http://localhost:5000 (默认为此地址,如有修改请按照配置文件)
|
||||||
- 账号:`superadmin` 密码:`admin123456`
|
- 账号:`superadmin` 密码:`admin123456`
|
||||||
|
|
||||||
## 参与贡献
|
## 如何贡献
|
||||||
|
|
||||||
1. Fork 本仓库
|
你可以[提一个 issue](https://gitee.com/link?target=https%3A%2F%2Fgithub.com%2Fkailong321200875%2Fvue-element-plus-admin%2Fissues%2Fnew) 或者提交一个 Pull Request。
|
||||||
2. 新建 Feat_xxx 分支
|
|
||||||
3. 提交代码
|
**Pull Request:**
|
||||||
4. 新建 Pull Request
|
|
||||||
|
1. Fork 代码
|
||||||
|
2. 创建自己的分支: `git checkout -b feat/xxxx`
|
||||||
|
3. 提交你的修改: `git commit -am 'feat(function): add xxxxx'`
|
||||||
|
4. 推送您的分支: `git push origin feat/xxxx`
|
||||||
|
5. 提交 `pull request`
|
||||||
|
|
||||||
|
## Git 贡献提交规范
|
||||||
|
|
||||||
|
- `feat` 新功能
|
||||||
|
- `fix` 修补 bug
|
||||||
|
- `docs` 文档
|
||||||
|
- `style` 格式、样式(不影响代码运行的变动)
|
||||||
|
- `refactor` 重构(即不是新增功能,也不是修改 BUG 的代码)
|
||||||
|
- `perf` 优化相关,比如提升性能、体验
|
||||||
|
- `test` 添加测试
|
||||||
|
- `build` 编译相关的修改,对项目构建或者依赖的改动
|
||||||
|
- `ci` 持续集成修改
|
||||||
|
- `chore` 构建过程或辅助工具的变动
|
||||||
|
- `revert` 回滚到上一个版本
|
||||||
|
- `workflow` 工作流改进
|
||||||
|
- `mod` 不确定分类的修改
|
||||||
|
- `wip` 开发中
|
||||||
|
- `types` 类型
|
||||||
|
|
||||||
## 浏览器支持
|
## 浏览器支持
|
||||||
|
|
||||||
@ -166,4 +214,18 @@ pnpm run build:pro
|
|||||||
|
|
||||||
## 许可证
|
## 许可证
|
||||||
|
|
||||||
[MIT](https://gitee.com/kailong110120130/vue-element-plus-admin/blob/master/LICENSE)
|
[MIT](https://gitee.com/kailong110120130/vue-element-plus-admin/blob/master/LICENSE)
|
||||||
|
|
||||||
|
## 演示图
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
BIN
images/image-20221009145928678.png
Normal file
BIN
images/image-20221009145928678.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 75 KiB |
BIN
images/image-20221009150108827.png
Normal file
BIN
images/image-20221009150108827.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 92 KiB |
BIN
images/image-20221009150256166.png
Normal file
BIN
images/image-20221009150256166.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 53 KiB |
BIN
images/image-20221009150311662.png
Normal file
BIN
images/image-20221009150311662.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 74 KiB |
BIN
images/image-20221009150349965.png
Normal file
BIN
images/image-20221009150349965.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 57 KiB |
BIN
images/image-20221009150414100.png
Normal file
BIN
images/image-20221009150414100.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 82 KiB |
@ -8,4 +8,4 @@ VITE_API_BASEPATH=base
|
|||||||
VITE_BASE_PATH=/
|
VITE_BASE_PATH=/
|
||||||
|
|
||||||
# 标题
|
# 标题
|
||||||
VITE_APP_TITLE=ElementAdmin
|
VITE_APP_TITLE=KInit
|
||||||
|
@ -20,4 +20,4 @@ VITE_SOURCEMAP=true
|
|||||||
VITE_OUT_DIR=dist-dev
|
VITE_OUT_DIR=dist-dev
|
||||||
|
|
||||||
# 标题
|
# 标题
|
||||||
VITE_APP_TITLE=ElementAdmin
|
VITE_APP_TITLE=KInit
|
||||||
|
@ -5,7 +5,7 @@ NODE_ENV=production
|
|||||||
VITE_API_BASEPATH=pro
|
VITE_API_BASEPATH=pro
|
||||||
|
|
||||||
# 打包路径
|
# 打包路径
|
||||||
VITE_BASE_PATH=/vue-element-plus-admin/
|
VITE_BASE_PATH=/kinit/
|
||||||
|
|
||||||
# 是否删除debugger
|
# 是否删除debugger
|
||||||
VITE_DROP_DEBUGGER=true
|
VITE_DROP_DEBUGGER=true
|
||||||
@ -20,4 +20,4 @@ VITE_SOURCEMAP=false
|
|||||||
VITE_OUT_DIR=dist-pro
|
VITE_OUT_DIR=dist-pro
|
||||||
|
|
||||||
# 标题
|
# 标题
|
||||||
VITE_APP_TITLE=ElementAdmin
|
VITE_APP_TITLE=KInit
|
||||||
|
@ -19,3 +19,7 @@ export const putUserListApi = (data: any): Promise<IResponse> => {
|
|||||||
export const getUserApi = (dataId: number): Promise<IResponse> => {
|
export const getUserApi = (dataId: number): Promise<IResponse> => {
|
||||||
return request.get({ url: `/vadmin/auth/users/${dataId}/` })
|
return request.get({ url: `/vadmin/auth/users/${dataId}/` })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const postCurrentUserResetPassword = (data: any): Promise<IResponse> => {
|
||||||
|
return request.get({ url: `/vadmin/auth/user/current/reset/password/`, data })
|
||||||
|
}
|
||||||
|
@ -28,13 +28,10 @@ const loginOut = () => {
|
|||||||
type: 'warning'
|
type: 'warning'
|
||||||
})
|
})
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
const res = await loginOutApi().catch(() => {})
|
wsCache.clear()
|
||||||
if (res) {
|
tagsViewStore.delAllViews()
|
||||||
wsCache.clear()
|
resetRouter() // 重置静态路由表
|
||||||
tagsViewStore.delAllViews()
|
replace('/login')
|
||||||
resetRouter() // 重置静态路由表
|
|
||||||
replace('/login')
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch(() => {})
|
.catch(() => {})
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,16 @@ export const constantRouterMap: AppRouteRecordRaw[] = [
|
|||||||
noTagsView: true
|
noTagsView: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/reset/password',
|
||||||
|
component: () => import('@/views/Reset/Reset.vue'),
|
||||||
|
name: 'Reset',
|
||||||
|
meta: {
|
||||||
|
hidden: true,
|
||||||
|
title: '重置密码',
|
||||||
|
noTagsView: true
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/404',
|
path: '/404',
|
||||||
component: () => import('@/views/Error/404.vue'),
|
component: () => import('@/views/Error/404.vue'),
|
||||||
|
@ -125,8 +125,14 @@ const signIn = async () => {
|
|||||||
const authStore = useAuthStoreWithOut()
|
const authStore = useAuthStoreWithOut()
|
||||||
const res = await authStore.login(formData)
|
const res = await authStore.login(formData)
|
||||||
if (res) {
|
if (res) {
|
||||||
// 是否使用动态路由
|
console.log(res)
|
||||||
getMenu()
|
if (!res.data.is_reset_password) {
|
||||||
|
// 重置密码
|
||||||
|
push({ path: '/reset/password' })
|
||||||
|
} else {
|
||||||
|
// 是否使用动态路由
|
||||||
|
getMenu()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
|
192
kinit-admin/src/views/Reset/Reset.vue
Normal file
192
kinit-admin/src/views/Reset/Reset.vue
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, unref, ref, watch } from 'vue'
|
||||||
|
import { Form } from '@/components/Form'
|
||||||
|
import { ElButton, ElCheckbox, ElLink } from 'element-plus'
|
||||||
|
import { useForm } from '@/hooks/web/useForm'
|
||||||
|
import { getRoleMenusApi } from '@/api/login'
|
||||||
|
import { useAuthStoreWithOut } from '@/store/modules/auth'
|
||||||
|
import { usePermissionStore } from '@/store/modules/permission'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import type { RouteRecordRaw, RouteLocationNormalizedLoaded } from 'vue-router'
|
||||||
|
import { UserLoginType } from '@/api/login/types'
|
||||||
|
import { useValidator } from '@/hooks/web/useValidator'
|
||||||
|
import { useCache } from '@/hooks/web/useCache'
|
||||||
|
import { useAppStore } from '@/store/modules/app'
|
||||||
|
import { Footer } from '@/components/Footer'
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
const appStore = useAppStore()
|
||||||
|
|
||||||
|
const { required } = useValidator()
|
||||||
|
|
||||||
|
const footer = computed(() => appStore.getFooter)
|
||||||
|
|
||||||
|
const permissionStore = usePermissionStore()
|
||||||
|
|
||||||
|
const { addRoute, push, currentRoute } = useRouter()
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
password_one: [required()],
|
||||||
|
password_two: [required()]
|
||||||
|
}
|
||||||
|
|
||||||
|
const schema = reactive<FormSchema[]>([
|
||||||
|
{
|
||||||
|
field: 'title',
|
||||||
|
colProps: {
|
||||||
|
span: 24
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'password_one',
|
||||||
|
label: '新密码',
|
||||||
|
component: 'InputPassword',
|
||||||
|
colProps: {
|
||||||
|
span: 24
|
||||||
|
},
|
||||||
|
componentProps: {
|
||||||
|
style: {
|
||||||
|
width: '100%'
|
||||||
|
},
|
||||||
|
placeholder: '请输入新密码'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'password_two',
|
||||||
|
label: '再次输入新密码',
|
||||||
|
component: 'InputPassword',
|
||||||
|
colProps: {
|
||||||
|
span: 24
|
||||||
|
},
|
||||||
|
componentProps: {
|
||||||
|
style: {
|
||||||
|
width: '100%'
|
||||||
|
},
|
||||||
|
placeholder: '请再次输入新密码'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'reset',
|
||||||
|
colProps: {
|
||||||
|
span: 24
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const { register, elFormRef, methods } = useForm()
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
const redirect = ref<string>('')
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => currentRoute.value,
|
||||||
|
(route: RouteLocationNormalizedLoaded) => {
|
||||||
|
redirect.value = route?.query?.redirect as string
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// 提交
|
||||||
|
const save = async () => {
|
||||||
|
const formRef = unref(elFormRef)
|
||||||
|
await formRef?.validate(async (isValid) => {
|
||||||
|
if (isValid) {
|
||||||
|
loading.value = true
|
||||||
|
const { getFormData } = methods
|
||||||
|
const formData = await getFormData<UserLoginType>()
|
||||||
|
|
||||||
|
try {
|
||||||
|
const authStore = useAuthStoreWithOut()
|
||||||
|
const res = await authStore.login(formData)
|
||||||
|
if (res) {
|
||||||
|
// 是否使用动态路由
|
||||||
|
getMenu()
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户菜单信息
|
||||||
|
const getMenu = async () => {
|
||||||
|
const res = await getRoleMenusApi()
|
||||||
|
if (res) {
|
||||||
|
const { wsCache } = useCache()
|
||||||
|
const routers = res.data || []
|
||||||
|
wsCache.set('roleRouters', routers)
|
||||||
|
await permissionStore.generateRoutes(routers).catch(() => {})
|
||||||
|
permissionStore.getAddRouters.forEach((route) => {
|
||||||
|
addRoute(route as RouteRecordRaw) // 动态添加可访问路由表
|
||||||
|
})
|
||||||
|
permissionStore.setIsAddRouters(true)
|
||||||
|
push({ path: redirect.value || permissionStore.addRouters[0].path })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="main-container">
|
||||||
|
<div class="form-container">
|
||||||
|
<Form
|
||||||
|
:schema="schema"
|
||||||
|
:rules="rules"
|
||||||
|
label-position="top"
|
||||||
|
hide-required-asterisk
|
||||||
|
size="large"
|
||||||
|
class="dark:(border-1 border-[var(--el-border-color)] border-solid)"
|
||||||
|
@register="register"
|
||||||
|
>
|
||||||
|
<template #title>
|
||||||
|
<h2 class="text-2xl font-bold text-center w-[100%]">第一次登录系统,需先重置密码</h2>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #reset>
|
||||||
|
<div class="w-[100%]">
|
||||||
|
<ElButton :loading="loading" type="primary" class="w-[100%]" @click="save">
|
||||||
|
重置密码
|
||||||
|
</ElButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
<div class="footer-container">
|
||||||
|
<Footer v-if="footer" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
:deep(.anticon) {
|
||||||
|
&:hover {
|
||||||
|
color: var(--el-color-primary) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-top: 20px;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: var(--app-content-bg-color);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-container .form-container {
|
||||||
|
width: 500px;
|
||||||
|
align-self: center;
|
||||||
|
padding: 30px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-container {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
@ -65,14 +65,14 @@ ALLOW_HEADERS = ["*"]
|
|||||||
"""
|
"""
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
# 测试库
|
# 测试库
|
||||||
SQLALCHEMY_DATABASE_URL = "mysql+asyncmy://root:123456@127.0.0.1:3306/kinit"
|
SQLALCHEMY_DATABASE_URL = "mysql+asyncmy://root:Ktianc123@rm-bp181adf0phw2o0r05o.mysql.rds.aliyuncs.com:3306/kinit"
|
||||||
|
# SQLALCHEMY_DATABASE_URL = "mysql+asyncmy://root:123456@127.0.0.1:3306/kinit"
|
||||||
SQLALCHEMY_DATABASE_TYPE = "mysql"
|
SQLALCHEMY_DATABASE_TYPE = "mysql"
|
||||||
else:
|
else:
|
||||||
# 正式库
|
# 正式库
|
||||||
SQLALCHEMY_DATABASE_URL = "mysql+asyncmy://root:123456@127.0.0.1:3306/kinit"
|
SQLALCHEMY_DATABASE_URL = "mysql+asyncmy://root:123456@127.0.0.1:3306/kinit"
|
||||||
SQLALCHEMY_DATABASE_TYPE = "mysql"
|
SQLALCHEMY_DATABASE_TYPE = "mysql"
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
中间件配置
|
中间件配置
|
||||||
"""
|
"""
|
||||||
|
@ -6,11 +6,13 @@
|
|||||||
# @IDE : PyCharm
|
# @IDE : PyCharm
|
||||||
# @desc : 增删改查
|
# @desc : 增删改查
|
||||||
from typing import List
|
from typing import List
|
||||||
|
from core.exception import CustomException
|
||||||
from fastapi.encoders import jsonable_encoder
|
from fastapi.encoders import jsonable_encoder
|
||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
from core.crud import DalBase
|
from core.crud import DalBase
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from utils.tools import test_password
|
||||||
from . import models, schemas
|
from . import models, schemas
|
||||||
from application import settings
|
from application import settings
|
||||||
|
|
||||||
@ -40,6 +42,19 @@ class UserDal(DalBase):
|
|||||||
return schema.from_orm(obj).dict()
|
return schema.from_orm(obj).dict()
|
||||||
return self.out_dict(obj)
|
return self.out_dict(obj)
|
||||||
|
|
||||||
|
async def reset_current_password(self, user: models.VadminUser, data: schemas.ResetPwd):
|
||||||
|
"""
|
||||||
|
重置密码
|
||||||
|
"""
|
||||||
|
if data.password != data.password_two:
|
||||||
|
raise CustomException(msg="两次密码不一致", code=400)
|
||||||
|
result = test_password(data.password)
|
||||||
|
if isinstance(result, str):
|
||||||
|
raise CustomException(msg=result, code=400)
|
||||||
|
self.db.add(user)
|
||||||
|
await self.db.flush()
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class RoleDal(DalBase):
|
class RoleDal(DalBase):
|
||||||
|
|
||||||
@ -203,7 +218,3 @@ class MenuDal(DalBase):
|
|||||||
router["children"] = self.generate_tree_options(menus, sons)
|
router["children"] = self.generate_tree_options(menus, sons)
|
||||||
data.append(router)
|
data.append(router)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,6 +50,11 @@ async def get_user(data_id: int, auth: Auth = Depends(login_auth)):
|
|||||||
return SuccessResponse(await crud.UserDal(auth.db).get_data(data_id, options, schema))
|
return SuccessResponse(await crud.UserDal(auth.db).get_data(data_id, options, schema))
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/user/current/reset/password/", summary="重置当前用户密码")
|
||||||
|
async def user_current_reset_password(data: schemas.ResetPwd, auth: Auth = Depends(login_auth)):
|
||||||
|
return SuccessResponse(await crud.UserDal(auth.db).reset_current_password(auth.user, data))
|
||||||
|
|
||||||
|
|
||||||
###########################################################
|
###########################################################
|
||||||
# 角色管理
|
# 角色管理
|
||||||
###########################################################
|
###########################################################
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# @version : 1.0
|
|
||||||
# @Creaet Time : 2022/2/24 17:02
|
|
||||||
# @File : crawle.py
|
|
||||||
# @IDE : PyCharm
|
|
||||||
# @desc : 爬虫
|
|
||||||
|
|
||||||
import requests
|
|
||||||
from core.logger import logger
|
|
||||||
|
|
||||||
|
|
||||||
def get_schedule_data():
|
|
||||||
"""
|
|
||||||
获取足球赛程表
|
|
||||||
"""
|
|
||||||
logger.info("开始获取足球赛程")
|
|
||||||
url = "https://webapi.sporttery.cn/gateway/jc/football/getMatchCalculatorV1.qry?poolCode=hhad,had&channel=c"
|
|
||||||
res = requests.get(url)
|
|
||||||
if res.status_code != 200:
|
|
||||||
logger.error("获取足球赛程失败!")
|
|
||||||
return False
|
|
||||||
data = res.json()
|
|
||||||
if data.get("errorCode") != "0":
|
|
||||||
logger.error("获取足球赛程失败!")
|
|
||||||
return False
|
|
||||||
return data.get("value").get("matchInfoList")
|
|
@ -8,9 +8,10 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import os
|
import os
|
||||||
from application.settings import TEMP_DIR
|
from application.settings import TEMP_DIR
|
||||||
|
from fastapi import UploadFile
|
||||||
|
|
||||||
|
|
||||||
def save_tmp_file(file, data):
|
def save_tmp_file(file: UploadFile, data):
|
||||||
"""
|
"""
|
||||||
保存临时文件
|
保存临时文件
|
||||||
"""
|
"""
|
||||||
@ -19,4 +20,4 @@ def save_tmp_file(file, data):
|
|||||||
if not os.path.exists(file_dir):
|
if not os.path.exists(file_dir):
|
||||||
os.mkdir(file_dir)
|
os.mkdir(file_dir)
|
||||||
with open(os.path.join(file_dir, file.filename), "wb") as f:
|
with open(os.path.join(file_dir, file.filename), "wb") as f:
|
||||||
f.write(data)
|
f.write(data)
|
||||||
|
34
kinit-api/utils/tools.py
Normal file
34
kinit-api/utils/tools.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @version : 1.0
|
||||||
|
# @Creaet Time : 2022/10/9 17:09
|
||||||
|
# @File : tools.py
|
||||||
|
# @IDE : PyCharm
|
||||||
|
# @desc : 工具类
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
def test_password(password: str):
|
||||||
|
"""
|
||||||
|
检测密码强度
|
||||||
|
"""
|
||||||
|
if len(password) < 8 or len(password) > 16:
|
||||||
|
return '长度需为8-16个字符,请重新输入。'
|
||||||
|
else:
|
||||||
|
for i in password:
|
||||||
|
if 0x4e00 <= ord(i) <= 0x9fa5 or ord(i) == 0x20: # Ox4e00等十六进制数分别为中文字符和空格的Unicode编码
|
||||||
|
return '不能使用空格、中文,请重新输入。'
|
||||||
|
else:
|
||||||
|
key = 0
|
||||||
|
key += 1 if bool(re.search(r'\d', password)) else 0
|
||||||
|
key += 1 if bool(re.search(r'[A-Za-z]', password)) else 0
|
||||||
|
key += 1 if bool(re.search(r"\W", password)) else 0
|
||||||
|
if key >= 2:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return '至少含数字/字母/字符2种组合,请重新输入。'
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print(test_password("123456121a"))
|
Loading…
x
Reference in New Issue
Block a user