Merge branch 'main' of github.com:zstar1003/ragflow-plus
This commit is contained in:
commit
41d575221f
|
@ -81,6 +81,9 @@ RAGFLOWPLUS_MANAGEMENT_SERVER_IMAGE=zstar1003/ragflowplus-management-server:v0.2
|
||||||
# The local time zone.
|
# The local time zone.
|
||||||
TIMEZONE='Asia/Shanghai'
|
TIMEZONE='Asia/Shanghai'
|
||||||
|
|
||||||
|
# 后端允许上传的最大文件大小
|
||||||
|
MAX_CONTENT_LENGTH=10737418240 # 10GB
|
||||||
|
|
||||||
# 管理系统用户名和密码
|
# 管理系统用户名和密码
|
||||||
MANAGEMENT_ADMIN_USERNAME=admin
|
MANAGEMENT_ADMIN_USERNAME=admin
|
||||||
MANAGEMENT_ADMIN_PASSWORD=12345678
|
MANAGEMENT_ADMIN_PASSWORD=12345678
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from flask import jsonify, request
|
from flask import jsonify, request
|
||||||
from services.users.service import get_users_with_pagination, delete_user, create_user, update_user
|
from services.users.service import get_users_with_pagination, delete_user, create_user, update_user, reset_user_password
|
||||||
from .. import users_bp
|
from .. import users_bp
|
||||||
|
|
||||||
@users_bp.route('', methods=['GET'])
|
@users_bp.route('', methods=['GET'])
|
||||||
|
@ -72,3 +72,38 @@ def get_current_user():
|
||||||
},
|
},
|
||||||
"message": "获取用户信息成功"
|
"message": "获取用户信息成功"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@users_bp.route('/<string:user_id>/reset-password', methods=['PUT'])
|
||||||
|
def reset_password_route(user_id):
|
||||||
|
"""
|
||||||
|
重置用户密码的API端点
|
||||||
|
Args:
|
||||||
|
user_id (str): 需要重置密码的用户ID
|
||||||
|
Returns:
|
||||||
|
Response: JSON响应
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
data = request.json
|
||||||
|
new_password = data.get('password')
|
||||||
|
|
||||||
|
# 校验密码是否存在
|
||||||
|
if not new_password:
|
||||||
|
return jsonify({"code": 400, "message": "缺少新密码参数 'password'"}), 400
|
||||||
|
|
||||||
|
# 调用 service 函数重置密码
|
||||||
|
success = reset_user_password(user_id=user_id, new_password=new_password)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
return jsonify({
|
||||||
|
"code": 0,
|
||||||
|
"message": f"用户密码重置成功"
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
# service 层可能因为用户不存在或其他原因返回 False
|
||||||
|
return jsonify({"code": 404, "message": f"用户未找到或密码重置失败"}), 404
|
||||||
|
except Exception as e:
|
||||||
|
# 统一处理异常
|
||||||
|
return jsonify({
|
||||||
|
"code": 500,
|
||||||
|
"message": f"重置密码失败: {str(e)}"
|
||||||
|
}), 500
|
|
@ -229,7 +229,7 @@ class KnowledgebaseService:
|
||||||
|
|
||||||
# 设置默认值
|
# 设置默认值
|
||||||
default_parser_config = json.dumps({
|
default_parser_config = json.dumps({
|
||||||
"layout_recognize": "DeepDOC",
|
"layout_recognize": "MinerU",
|
||||||
"chunk_token_num": 512,
|
"chunk_token_num": 512,
|
||||||
"delimiter": "\n!?;。;!?",
|
"delimiter": "\n!?;。;!?",
|
||||||
"auto_keywords": 0,
|
"auto_keywords": 0,
|
||||||
|
@ -557,7 +557,7 @@ class KnowledgebaseService:
|
||||||
# 设置默认值
|
# 设置默认值
|
||||||
default_parser_id = "naive"
|
default_parser_id = "naive"
|
||||||
default_parser_config = json.dumps({
|
default_parser_config = json.dumps({
|
||||||
"layout_recognize": "DeepDOC",
|
"layout_recognize": "MinerU",
|
||||||
"chunk_token_num": 512,
|
"chunk_token_num": 512,
|
||||||
"delimiter": "\n!?;。;!?",
|
"delimiter": "\n!?;。;!?",
|
||||||
"auto_keywords": 0,
|
"auto_keywords": 0,
|
||||||
|
|
|
@ -288,3 +288,60 @@ def update_user(user_id, user_data):
|
||||||
except mysql.connector.Error as err:
|
except mysql.connector.Error as err:
|
||||||
print(f"更新用户错误: {err}")
|
print(f"更新用户错误: {err}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def reset_user_password(user_id, new_password):
|
||||||
|
"""
|
||||||
|
重置指定用户的密码
|
||||||
|
Args:
|
||||||
|
user_id (str): 用户ID
|
||||||
|
new_password (str): 新的明文密码
|
||||||
|
Returns:
|
||||||
|
bool: 操作是否成功
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
conn = mysql.connector.connect(**DB_CONFIG)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# 加密新密码
|
||||||
|
encrypted_password = encrypt_password(new_password) # 使用与创建用户时相同的加密方法
|
||||||
|
update_time = int(datetime.now().timestamp() * 1000)
|
||||||
|
update_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
|
# 更新用户密码
|
||||||
|
update_query = """
|
||||||
|
UPDATE user
|
||||||
|
SET password = %s, update_time = %s, update_date = %s
|
||||||
|
WHERE id = %s
|
||||||
|
"""
|
||||||
|
cursor.execute(update_query, (encrypted_password, update_time, update_date, user_id))
|
||||||
|
|
||||||
|
# 检查是否有行被更新
|
||||||
|
if cursor.rowcount == 0:
|
||||||
|
conn.rollback() # 如果没有更新,回滚
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
print(f"用户 {user_id} 未找到,密码未更新。")
|
||||||
|
return False # 用户不存在
|
||||||
|
|
||||||
|
conn.commit() # 提交事务
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
print(f"用户 {user_id} 密码已成功重置。")
|
||||||
|
return True
|
||||||
|
|
||||||
|
except mysql.connector.Error as err:
|
||||||
|
print(f"重置密码时数据库错误: {err}")
|
||||||
|
# 可以在这里添加更详细的日志记录
|
||||||
|
# 如果 conn 存在且打开,尝试回滚
|
||||||
|
if 'conn' in locals() and conn.is_connected():
|
||||||
|
conn.rollback()
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"重置密码时发生未知错误: {e}")
|
||||||
|
if 'conn' in locals() and conn.is_connected():
|
||||||
|
conn.rollback()
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
return False
|
|
@ -35,3 +35,17 @@ export function getTableDataApi(params: Tables.TableRequestData) {
|
||||||
params
|
params
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置用户密码
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param password 新密码
|
||||||
|
* @returns BaseResponse
|
||||||
|
*/
|
||||||
|
export function resetPasswordApi(userId: number, password: string) {
|
||||||
|
return request({
|
||||||
|
url: `api/v1/users/${userId}/reset-password`,
|
||||||
|
method: "put",
|
||||||
|
data: { password } // 发送新密码
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { CreateOrUpdateTableRequestData, TableData } from "@@/apis/tables/type"
|
import type { CreateOrUpdateTableRequestData, TableData } from "@@/apis/tables/type"
|
||||||
import type { FormInstance, FormRules } from "element-plus"
|
import type { FormInstance, FormRules } from "element-plus"
|
||||||
import { createTableDataApi, deleteTableDataApi, getTableDataApi, updateTableDataApi } from "@@/apis/tables"
|
import { createTableDataApi, deleteTableDataApi, getTableDataApi, resetPasswordApi, updateTableDataApi } from "@@/apis/tables"
|
||||||
import { usePagination } from "@@/composables/usePagination"
|
import { usePagination } from "@@/composables/usePagination"
|
||||||
import { CirclePlus, Delete, Refresh, RefreshRight, Search } from "@element-plus/icons-vue"
|
import { CirclePlus, Delete, Edit, Key, Refresh, RefreshRight, Search } from "@element-plus/icons-vue"
|
||||||
import { cloneDeep } from "lodash-es"
|
import { cloneDeep } from "lodash-es"
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
|
@ -36,10 +36,23 @@ const formRules: FormRules<CreateOrUpdateTableRequestData> = {
|
||||||
],
|
],
|
||||||
password: [{ required: true, trigger: "blur", message: "请输入密码" }]
|
password: [{ required: true, trigger: "blur", message: "请输入密码" }]
|
||||||
}
|
}
|
||||||
|
// #region 重置密码
|
||||||
|
const resetPasswordDialogVisible = ref<boolean>(false)
|
||||||
|
const resetPasswordFormRef = ref<FormInstance | null>(null)
|
||||||
|
const currentUserId = ref<number | undefined>(undefined) // 用于存储当前要重置密码的用户ID
|
||||||
|
const resetPasswordFormData = reactive({
|
||||||
|
password: ""
|
||||||
|
})
|
||||||
|
const resetPasswordFormRules: FormRules = {
|
||||||
|
password: [
|
||||||
|
{ required: true, message: "请输入新密码", trigger: "blur" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
// #endregion
|
||||||
function handleCreateOrUpdate() {
|
function handleCreateOrUpdate() {
|
||||||
formRef.value?.validate((valid) => {
|
formRef.value?.validate((valid) => {
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
ElMessage.error("表单校验不通过")
|
ElMessage.error("登录校验不通过")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
loading.value = true
|
loading.value = true
|
||||||
|
@ -59,6 +72,60 @@ function resetForm() {
|
||||||
}
|
}
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
|
// #region 重置密码处理
|
||||||
|
/**
|
||||||
|
* 打开重置密码对话框
|
||||||
|
* @param {TableData} row - 当前行用户数据
|
||||||
|
*/
|
||||||
|
function handleResetPassword(row: TableData) {
|
||||||
|
currentUserId.value = row.id
|
||||||
|
resetPasswordFormData.password = "" // 清空上次输入
|
||||||
|
resetPasswordDialogVisible.value = true
|
||||||
|
// 清除之前的校验状态
|
||||||
|
nextTick(() => {
|
||||||
|
resetPasswordFormRef.value?.clearValidate()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交重置密码表单
|
||||||
|
*/
|
||||||
|
function submitResetPassword() {
|
||||||
|
resetPasswordFormRef.value?.validate((valid) => {
|
||||||
|
if (!valid) {
|
||||||
|
ElMessage.error("表单校验不通过")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (currentUserId.value === undefined) {
|
||||||
|
ElMessage.error("用户ID丢失,无法重置密码")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
loading.value = true
|
||||||
|
// 调用后端API重置密码
|
||||||
|
resetPasswordApi(currentUserId.value, resetPasswordFormData.password)
|
||||||
|
.then(() => {
|
||||||
|
ElMessage.success("密码重置成功")
|
||||||
|
resetPasswordDialogVisible.value = false
|
||||||
|
})
|
||||||
|
.catch((error: any) => {
|
||||||
|
console.error("重置密码失败:", error)
|
||||||
|
ElMessage.error("密码重置失败")
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭重置密码对话框时重置状态
|
||||||
|
*/
|
||||||
|
function resetPasswordDialogClosed() {
|
||||||
|
currentUserId.value = undefined
|
||||||
|
resetPasswordFormRef.value?.resetFields() // 重置表单字段
|
||||||
|
}
|
||||||
|
// #endregion
|
||||||
|
|
||||||
// #region 删
|
// #region 删
|
||||||
function handleDelete(row: TableData) {
|
function handleDelete(row: TableData) {
|
||||||
ElMessageBox.confirm(`正在删除用户:${row.username},确认删除?`, "提示", {
|
ElMessageBox.confirm(`正在删除用户:${row.username},确认删除?`, "提示", {
|
||||||
|
@ -198,12 +265,15 @@ watch([() => paginationData.currentPage, () => paginationData.pageSize], getTabl
|
||||||
<el-table-column prop="email" label="邮箱" align="center" />
|
<el-table-column prop="email" label="邮箱" align="center" />
|
||||||
<el-table-column prop="createTime" label="创建时间" align="center" />
|
<el-table-column prop="createTime" label="创建时间" align="center" />
|
||||||
<el-table-column prop="updateTime" label="更新时间" align="center" />
|
<el-table-column prop="updateTime" label="更新时间" align="center" />
|
||||||
<el-table-column fixed="right" label="操作" width="150" align="center">
|
<el-table-column fixed="right" label="操作" width="300" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button type="primary" text bg size="small" @click="handleUpdate(scope.row)">
|
<el-button type="primary" text bg size="small" :icon="Edit" @click="handleUpdate(scope.row)">
|
||||||
修改
|
修改用户名
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="danger" text bg size="small" @click="handleDelete(scope.row)">
|
<el-button type="warning" text bg size="small" :icon="Key" @click="handleResetPassword(scope.row)">
|
||||||
|
重置密码
|
||||||
|
</el-button>
|
||||||
|
<el-button type="danger" text bg size="small" :icon="Delete" @click="handleDelete(scope.row)">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
@ -250,6 +320,28 @@ watch([() => paginationData.currentPage, () => paginationData.pageSize], getTabl
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 重置密码对话框 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="resetPasswordDialogVisible"
|
||||||
|
title="重置密码"
|
||||||
|
width="30%"
|
||||||
|
@closed="resetPasswordDialogClosed"
|
||||||
|
>
|
||||||
|
<el-form ref="resetPasswordFormRef" :model="resetPasswordFormData" :rules="resetPasswordFormRules" label-width="100px" label-position="left">
|
||||||
|
<el-form-item prop="password" label="新密码">
|
||||||
|
<el-input v-model="resetPasswordFormData.password" type="password" show-password placeholder="请输入新密码" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="resetPasswordDialogVisible = false">
|
||||||
|
取消
|
||||||
|
</el-button>
|
||||||
|
<el-button type="primary" :loading="loading" @click="submitResetPassword">
|
||||||
|
确认重置
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,8 @@ declare module 'vue' {
|
||||||
ElPagination: typeof import('element-plus/es')['ElPagination']
|
ElPagination: typeof import('element-plus/es')['ElPagination']
|
||||||
ElPopover: typeof import('element-plus/es')['ElPopover']
|
ElPopover: typeof import('element-plus/es')['ElPopover']
|
||||||
ElProgress: typeof import('element-plus/es')['ElProgress']
|
ElProgress: typeof import('element-plus/es')['ElProgress']
|
||||||
|
ElRadio: typeof import('element-plus/es')['ElRadio']
|
||||||
|
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
||||||
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
|
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
|
||||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||||
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
|
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
|
||||||
|
|
Loading…
Reference in New Issue