diff --git a/README.md b/README.md index 98eab81..02d7b52 100644 --- a/README.md +++ b/README.md @@ -10,19 +10,19 @@ 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 数据库。 -- 👫权限认证使用[使用(哈希)密码和 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)。 - 开箱即用的中后台解决方案,可以用来作为项目的启动模版,也可用于学习参考。并且时刻关注着最新技术动向,尽可能的第一时间更新。 ## 在线体验 -👩‍👧‍👦演示地址:[http://demo.django-vue-admin.com](https://gitee.com/link?target=http%3A%2F%2Fdemo.django-vue-admin.com) +👩‍👧‍👦演示地址:正在部署中。。。。。 -- 账号:superadmin -- 密码:admin123456 +- 账号:admin +- 密码:123456 ## 源码地址 @@ -33,13 +33,27 @@ github地址:https://gitee.com/ktianc/kinit👩‍👦‍👦 ## 内置功能 - [x] 👨‍⚕️菜单管理:配置系统菜单,操作权限,按钮权限标识、后端接口权限等。 + - [x] 👩‍⚕️角色管理:角色菜单权限分配。 + - [x] 👨‍🎓用户管理:用户是系统操作者,该功能主要完成系统用户配置。 -- [x] 🧑‍🔧字典管理:对系统中经常使用的一些较为固定的数据进行维护。 + +- [ ] 🏡个人主页:配置用户个人信息,密码修改等。 + +- [x] 📚字典管理:对系统中经常使用的一些较为固定的数据进行维护。 + - [ ] 📁附件管理:对平台上所有文件、图片等进行统一管理。 + - [ ] 🗓️登录日志:用户登录日志记录和查询。 + - [ ] 🗓️操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 +- [ ] 🔒登录认证:目前支持用户使用手机号+密码方式登录。 + + 说明:新建用户密码默认为手机号后六位; + + 说明:用户在第一次登录时,必须修改当前用户密码。 + ## 前序准备 - [FastAPI](https://fastapi.tiangolo.com/zh/) - 熟悉后台接口 Web 框架 @@ -104,8 +118,19 @@ else: 3. 迁移数据库 -``` +```shell +# 初次生成迁移文件 +alembic revision -m "生成迁移文件" +# 通过该命令可以将模型迁移到数据库 +alembic upgrade head + +# 如果有更新,则可以使用这个命令再次生成迁移文件,初次也可以使用 +alembic revision --autogenerate -m "update" +# --autogenerate:自动将当前模型的修改,生成迁移脚本。 + +# 通过该命令可以将模型迁移到数据库 +alembic upgrade head ``` 4. 数据化数据库数据 @@ -147,12 +172,35 @@ pnpm run build:pro - 访问地址:http://localhost:5000 (默认为此地址,如有修改请按照配置文件) - 账号:`superadmin` 密码:`admin123456` -## 参与贡献 +## 如何贡献 -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request +你可以[提一个 issue](https://gitee.com/link?target=https%3A%2F%2Fgithub.com%2Fkailong321200875%2Fvue-element-plus-admin%2Fissues%2Fnew) 或者提交一个 Pull Request。 + +**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) \ No newline at end of file +[MIT](https://gitee.com/kailong110120130/vue-element-plus-admin/blob/master/LICENSE) + +## 演示图 + +![image-20221009145928678](images\image-20221009145928678.png) + +![image-20221009150108827](images\image-20221009150108827.png) + +![image-20221009150256166](images\image-20221009150256166.png) + +![image-20221009150311662](images\image-20221009150311662.png) + +![image-20221009150349965](images\image-20221009150349965.png) + +![image-20221009150414100](images\image-20221009150414100.png) \ No newline at end of file diff --git a/images/image-20221009145928678.png b/images/image-20221009145928678.png new file mode 100644 index 0000000..b52175f Binary files /dev/null and b/images/image-20221009145928678.png differ diff --git a/images/image-20221009150108827.png b/images/image-20221009150108827.png new file mode 100644 index 0000000..ecbd750 Binary files /dev/null and b/images/image-20221009150108827.png differ diff --git a/images/image-20221009150256166.png b/images/image-20221009150256166.png new file mode 100644 index 0000000..56a1718 Binary files /dev/null and b/images/image-20221009150256166.png differ diff --git a/images/image-20221009150311662.png b/images/image-20221009150311662.png new file mode 100644 index 0000000..29503ad Binary files /dev/null and b/images/image-20221009150311662.png differ diff --git a/images/image-20221009150349965.png b/images/image-20221009150349965.png new file mode 100644 index 0000000..9ede55a Binary files /dev/null and b/images/image-20221009150349965.png differ diff --git a/images/image-20221009150414100.png b/images/image-20221009150414100.png new file mode 100644 index 0000000..3d7bd72 Binary files /dev/null and b/images/image-20221009150414100.png differ diff --git a/kinit-admin/.env.base b/kinit-admin/.env.base index 8a8d91c..a0f0f80 100644 --- a/kinit-admin/.env.base +++ b/kinit-admin/.env.base @@ -8,4 +8,4 @@ VITE_API_BASEPATH=base VITE_BASE_PATH=/ # 标题 -VITE_APP_TITLE=ElementAdmin +VITE_APP_TITLE=KInit diff --git a/kinit-admin/.env.dev b/kinit-admin/.env.dev index 6a641a3..5dd7ac3 100644 --- a/kinit-admin/.env.dev +++ b/kinit-admin/.env.dev @@ -20,4 +20,4 @@ VITE_SOURCEMAP=true VITE_OUT_DIR=dist-dev # 标题 -VITE_APP_TITLE=ElementAdmin +VITE_APP_TITLE=KInit diff --git a/kinit-admin/.env.gitee b/kinit-admin/.env.gitee index c55b595..90e1b80 100644 --- a/kinit-admin/.env.gitee +++ b/kinit-admin/.env.gitee @@ -5,7 +5,7 @@ NODE_ENV=production VITE_API_BASEPATH=pro # 打包路径 -VITE_BASE_PATH=/vue-element-plus-admin/ +VITE_BASE_PATH=/kinit/ # 是否删除debugger VITE_DROP_DEBUGGER=true @@ -20,4 +20,4 @@ VITE_SOURCEMAP=false VITE_OUT_DIR=dist-pro # 标题 -VITE_APP_TITLE=ElementAdmin +VITE_APP_TITLE=KInit diff --git a/kinit-admin/src/api/vadmin/auth/user.ts b/kinit-admin/src/api/vadmin/auth/user.ts index ddfb1fe..690d90b 100644 --- a/kinit-admin/src/api/vadmin/auth/user.ts +++ b/kinit-admin/src/api/vadmin/auth/user.ts @@ -19,3 +19,7 @@ export const putUserListApi = (data: any): Promise => { export const getUserApi = (dataId: number): Promise => { return request.get({ url: `/vadmin/auth/users/${dataId}/` }) } + +export const postCurrentUserResetPassword = (data: any): Promise => { + return request.get({ url: `/vadmin/auth/user/current/reset/password/`, data }) +} diff --git a/kinit-admin/src/components/UserInfo/src/UserInfo.vue b/kinit-admin/src/components/UserInfo/src/UserInfo.vue index 3d35f55..afa5eef 100644 --- a/kinit-admin/src/components/UserInfo/src/UserInfo.vue +++ b/kinit-admin/src/components/UserInfo/src/UserInfo.vue @@ -28,13 +28,10 @@ const loginOut = () => { type: 'warning' }) .then(async () => { - const res = await loginOutApi().catch(() => {}) - if (res) { - wsCache.clear() - tagsViewStore.delAllViews() - resetRouter() // 重置静态路由表 - replace('/login') - } + wsCache.clear() + tagsViewStore.delAllViews() + resetRouter() // 重置静态路由表 + replace('/login') }) .catch(() => {}) } diff --git a/kinit-admin/src/router/index.ts b/kinit-admin/src/router/index.ts index 5c02ea5..eb203ed 100644 --- a/kinit-admin/src/router/index.ts +++ b/kinit-admin/src/router/index.ts @@ -43,6 +43,16 @@ export const constantRouterMap: AppRouteRecordRaw[] = [ noTagsView: true } }, + { + path: '/reset/password', + component: () => import('@/views/Reset/Reset.vue'), + name: 'Reset', + meta: { + hidden: true, + title: '重置密码', + noTagsView: true + } + }, { path: '/404', component: () => import('@/views/Error/404.vue'), diff --git a/kinit-admin/src/views/Login/components/LoginForm.vue b/kinit-admin/src/views/Login/components/LoginForm.vue index 09adc1f..0c46f7e 100644 --- a/kinit-admin/src/views/Login/components/LoginForm.vue +++ b/kinit-admin/src/views/Login/components/LoginForm.vue @@ -125,8 +125,14 @@ const signIn = async () => { const authStore = useAuthStoreWithOut() const res = await authStore.login(formData) if (res) { - // 是否使用动态路由 - getMenu() + console.log(res) + if (!res.data.is_reset_password) { + // 重置密码 + push({ path: '/reset/password' }) + } else { + // 是否使用动态路由 + getMenu() + } } } finally { loading.value = false diff --git a/kinit-admin/src/views/Reset/Reset.vue b/kinit-admin/src/views/Reset/Reset.vue new file mode 100644 index 0000000..8eb5f92 --- /dev/null +++ b/kinit-admin/src/views/Reset/Reset.vue @@ -0,0 +1,192 @@ + + + + + diff --git a/kinit-api/application/settings.py b/kinit-api/application/settings.py index 4fe5b78..b5c1923 100644 --- a/kinit-api/application/settings.py +++ b/kinit-api/application/settings.py @@ -65,14 +65,14 @@ ALLOW_HEADERS = ["*"] """ 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" else: # 正式库 SQLALCHEMY_DATABASE_URL = "mysql+asyncmy://root:123456@127.0.0.1:3306/kinit" SQLALCHEMY_DATABASE_TYPE = "mysql" - """ 中间件配置 """ diff --git a/kinit-api/apps/vadmin/auth/crud.py b/kinit-api/apps/vadmin/auth/crud.py index a7f7661..319a554 100644 --- a/kinit-api/apps/vadmin/auth/crud.py +++ b/kinit-api/apps/vadmin/auth/crud.py @@ -6,11 +6,13 @@ # @IDE : PyCharm # @desc : 增删改查 from typing import List - +from core.exception import CustomException from fastapi.encoders import jsonable_encoder from sqlalchemy import select from core.crud import DalBase from sqlalchemy.ext.asyncio import AsyncSession + +from utils.tools import test_password from . import models, schemas from application import settings @@ -40,6 +42,19 @@ class UserDal(DalBase): return schema.from_orm(obj).dict() 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): @@ -203,7 +218,3 @@ class MenuDal(DalBase): router["children"] = self.generate_tree_options(menus, sons) data.append(router) return data - - - - diff --git a/kinit-api/apps/vadmin/auth/views.py b/kinit-api/apps/vadmin/auth/views.py index 24f1fbb..22b550a 100644 --- a/kinit-api/apps/vadmin/auth/views.py +++ b/kinit-api/apps/vadmin/auth/views.py @@ -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)) +@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)) + + ########################################################### # 角色管理 ########################################################### diff --git a/kinit-api/utils/crawle.py b/kinit-api/utils/crawle.py deleted file mode 100644 index 99dda1b..0000000 --- a/kinit-api/utils/crawle.py +++ /dev/null @@ -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") diff --git a/kinit-api/utils/save_file.py b/kinit-api/utils/save_file.py index e6aea2b..9cb2565 100644 --- a/kinit-api/utils/save_file.py +++ b/kinit-api/utils/save_file.py @@ -8,9 +8,10 @@ from datetime import datetime import os 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): os.mkdir(file_dir) with open(os.path.join(file_dir, file.filename), "wb") as f: - f.write(data) \ No newline at end of file + f.write(data) diff --git a/kinit-api/utils/tools.py b/kinit-api/utils/tools.py new file mode 100644 index 0000000..bc73830 --- /dev/null +++ b/kinit-api/utils/tools.py @@ -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"))