V0.26.0.250618_alpha:完成了用户管理页面
This commit is contained in:
parent
d494ba6e1b
commit
f0b97d210e
212
Login/login.cpp
212
Login/login.cpp
@ -191,7 +191,7 @@ extern "C" LOGIN_EXPORT int validateUser(const char *username_buffer, size_t use
|
||||
return -1;
|
||||
}
|
||||
|
||||
fs::path dbPath = fs::path(xnCorePath) / "database" / "XNSim.db";
|
||||
fs::path dbPath = fs::path(xnCorePath) / "database" / "UserInfo.db";
|
||||
|
||||
sqlite3 *db;
|
||||
if (sqlite3_open(dbPath.string().c_str(), &db) != SQLITE_OK) {
|
||||
@ -230,7 +230,7 @@ extern "C" LOGIN_EXPORT int getUserInfo(int user_id, char *result, int result_le
|
||||
return -1;
|
||||
}
|
||||
|
||||
fs::path dbPath = fs::path(xnCorePath) / "database" / "XNSim.db";
|
||||
fs::path dbPath = fs::path(xnCorePath) / "database" / "UserInfo.db";
|
||||
|
||||
sqlite3 *db;
|
||||
if (sqlite3_open(dbPath.string().c_str(), &db) != SQLITE_OK) {
|
||||
@ -290,14 +290,21 @@ extern "C" LOGIN_EXPORT int getUserInfo(int user_id, char *result, int result_le
|
||||
std::string jsonData = userInfo.dump();
|
||||
if (result_length >= jsonData.size() + 1) {
|
||||
std::strcpy(result, jsonData.c_str());
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_close(db);
|
||||
return 0;
|
||||
} else {
|
||||
std::cout << "result_length: " << result_length << std::endl;
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_close(db);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// 用户不存在
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_close(db);
|
||||
return -2; // 用户不存在
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_close(db);
|
||||
@ -336,7 +343,7 @@ int checkUsernameExists(const void *username_buffer, size_t username_length)
|
||||
return -1;
|
||||
}
|
||||
|
||||
fs::path dbPath = fs::path(xnCorePath) / "database" / "XNSim.db";
|
||||
fs::path dbPath = fs::path(xnCorePath) / "database" / "UserInfo.db";
|
||||
std::string connectionName =
|
||||
"usercheck_"
|
||||
+ std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
@ -428,12 +435,7 @@ extern "C" LOGIN_EXPORT int registerUser(const char *username_buffer, int userna
|
||||
return -1;
|
||||
}
|
||||
|
||||
fs::path dbPath = fs::path(xnCorePath) / "database" / "XNSim.db";
|
||||
std::string connectionName =
|
||||
"userreg_"
|
||||
+ std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count());
|
||||
fs::path dbPath = fs::path(xnCorePath) / "database" / "UserInfo.db";
|
||||
|
||||
int newUserId = -1;
|
||||
{
|
||||
@ -497,12 +499,7 @@ extern "C" LOGIN_EXPORT int changePassword(int user_id, const char *old_password
|
||||
return -1;
|
||||
}
|
||||
|
||||
fs::path dbPath = fs::path(xnCorePath) / "database" / "XNSim.db";
|
||||
std::string connectionName =
|
||||
"changepwd_"
|
||||
+ std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count());
|
||||
fs::path dbPath = fs::path(xnCorePath) / "database" / "UserInfo.db";
|
||||
|
||||
{
|
||||
sqlite3 *db;
|
||||
@ -548,11 +545,16 @@ extern "C" LOGIN_EXPORT int changePassword(int user_id, const char *old_password
|
||||
if (sqlite3_step(stmt) == SQLITE_DONE) {
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_close(db);
|
||||
return 1; // 密码修改成功
|
||||
return 0; // 密码修改成功
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
} else {
|
||||
// 用户不存在
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_close(db);
|
||||
return -2; // 用户不存在
|
||||
}
|
||||
}
|
||||
|
||||
@ -565,6 +567,81 @@ extern "C" LOGIN_EXPORT int changePassword(int user_id, const char *old_password
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" LOGIN_EXPORT int resetPassword(int user_id)
|
||||
{
|
||||
try {
|
||||
const char *xnCorePath = std::getenv("XNCore");
|
||||
if (!xnCorePath) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fs::path dbPath = fs::path(xnCorePath) / "database" / "UserInfo.db";
|
||||
{
|
||||
sqlite3 *db;
|
||||
if (sqlite3_open(dbPath.string().c_str(), &db) != SQLITE_OK) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
// 首先查询用户名
|
||||
sqlite3_stmt *stmt;
|
||||
const char *queryStr = "SELECT username FROM users WHERE id = ?";
|
||||
|
||||
if (sqlite3_prepare_v2(db, queryStr, -1, &stmt, nullptr) != SQLITE_OK) {
|
||||
sqlite3_close(db);
|
||||
return -3; // SELECT 语句准备失败
|
||||
}
|
||||
|
||||
sqlite3_bind_int(stmt, 1, user_id);
|
||||
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
std::string username = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0));
|
||||
|
||||
// 生成新的加密密码
|
||||
std::string salt = generateSalt(username);
|
||||
std::string new_password_str = "123456";
|
||||
std::string encryptedNewPassword = encryptPassword(new_password_str, salt);
|
||||
|
||||
// 更新密码
|
||||
sqlite3_finalize(stmt);
|
||||
stmt = nullptr;
|
||||
queryStr = "UPDATE users SET password = ? WHERE id = ?";
|
||||
|
||||
if (sqlite3_prepare_v2(db, queryStr, -1, &stmt, nullptr) != SQLITE_OK) {
|
||||
sqlite3_close(db);
|
||||
return -4; // UPDATE 语句准备失败
|
||||
}
|
||||
|
||||
sqlite3_bind_text(stmt, 1, encryptedNewPassword.c_str(), -1, SQLITE_STATIC);
|
||||
sqlite3_bind_int(stmt, 2, user_id);
|
||||
|
||||
if (sqlite3_step(stmt) == SQLITE_DONE) {
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_close(db);
|
||||
return 0; // 密码重置成功
|
||||
} else {
|
||||
// 获取具体的错误信息
|
||||
int error_code = sqlite3_errcode(db);
|
||||
const char *error_msg = sqlite3_errmsg(db);
|
||||
std::cout << "UPDATE failed with error code: " << error_code
|
||||
<< ", message: " << (error_msg ? error_msg : "unknown") << std::endl;
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_close(db);
|
||||
return -5; // UPDATE 语句执行失败
|
||||
}
|
||||
} else {
|
||||
// 用户不存在
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_close(db);
|
||||
return -6; // 用户不存在
|
||||
}
|
||||
}
|
||||
|
||||
return -7; // 其他错误
|
||||
} catch (const std::exception &) {
|
||||
return -8;
|
||||
}
|
||||
}
|
||||
|
||||
// 更新用户信息
|
||||
extern "C" LOGIN_EXPORT int updateUserInfo(int user_id, const char *userinfo_buffer,
|
||||
int userinfo_length)
|
||||
@ -586,12 +663,7 @@ extern "C" LOGIN_EXPORT int updateUserInfo(int user_id, const char *userinfo_buf
|
||||
return -1;
|
||||
}
|
||||
|
||||
fs::path dbPath = fs::path(xnCorePath) / "database" / "XNSim.db";
|
||||
std::string connectionName =
|
||||
"userupdate_"
|
||||
+ std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count());
|
||||
fs::path dbPath = fs::path(xnCorePath) / "database" / "UserInfo.db";
|
||||
|
||||
int result = -1;
|
||||
{
|
||||
@ -607,7 +679,7 @@ extern "C" LOGIN_EXPORT int updateUserInfo(int user_id, const char *userinfo_buf
|
||||
if (sqlite3_prepare_v2(db, checkQueryStr, -1, &stmt, nullptr) == SQLITE_OK) {
|
||||
sqlite3_bind_int(stmt, 1, user_id);
|
||||
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
if (sqlite3_step(stmt) != SQLITE_ROW) {
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_close(db);
|
||||
return -2; // 用户不存在
|
||||
@ -622,20 +694,35 @@ extern "C" LOGIN_EXPORT int updateUserInfo(int user_id, const char *userinfo_buf
|
||||
"WHERE id = ?";
|
||||
|
||||
if (sqlite3_prepare_v2(db, queryStr, -1, &stmt, nullptr) == SQLITE_OK) {
|
||||
sqlite3_bind_text(stmt, 1, userInfo["full_name"].get<std::string>().c_str(), -1,
|
||||
SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 2, userInfo["phone"].get<std::string>().c_str(), -1,
|
||||
SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 3, userInfo["email"].get<std::string>().c_str(), -1,
|
||||
SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 4, userInfo["department"].get<std::string>().c_str(), -1,
|
||||
SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 5, userInfo["position"].get<std::string>().c_str(), -1,
|
||||
SQLITE_STATIC);
|
||||
// 安全地获取字符串值,处理null情况
|
||||
std::string full_name =
|
||||
userInfo.contains("full_name") && !userInfo["full_name"].is_null()
|
||||
? userInfo["full_name"].get<std::string>()
|
||||
: "";
|
||||
std::string phone = userInfo.contains("phone") && !userInfo["phone"].is_null()
|
||||
? userInfo["phone"].get<std::string>()
|
||||
: "";
|
||||
std::string email = userInfo.contains("email") && !userInfo["email"].is_null()
|
||||
? userInfo["email"].get<std::string>()
|
||||
: "";
|
||||
std::string department =
|
||||
userInfo.contains("department") && !userInfo["department"].is_null()
|
||||
? userInfo["department"].get<std::string>()
|
||||
: "";
|
||||
std::string position =
|
||||
userInfo.contains("position") && !userInfo["position"].is_null()
|
||||
? userInfo["position"].get<std::string>()
|
||||
: "";
|
||||
|
||||
sqlite3_bind_text(stmt, 1, full_name.c_str(), -1, SQLITE_TRANSIENT);
|
||||
sqlite3_bind_text(stmt, 2, phone.c_str(), -1, SQLITE_TRANSIENT);
|
||||
sqlite3_bind_text(stmt, 3, email.c_str(), -1, SQLITE_TRANSIENT);
|
||||
sqlite3_bind_text(stmt, 4, department.c_str(), -1, SQLITE_TRANSIENT);
|
||||
sqlite3_bind_text(stmt, 5, position.c_str(), -1, SQLITE_TRANSIENT);
|
||||
sqlite3_bind_int(stmt, 6, user_id);
|
||||
|
||||
if (sqlite3_step(stmt) == SQLITE_DONE) {
|
||||
result = 1; // 更新成功
|
||||
result = 0; // 更新成功
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
@ -655,7 +742,7 @@ extern "C" LOGIN_EXPORT int updateUserAccessLevel(int user_id, int access_level)
|
||||
{
|
||||
try {
|
||||
// 验证权限级别
|
||||
if (access_level < 0 || access_level >= 3) {
|
||||
if (access_level < 0 || access_level > 3) {
|
||||
return -3; // 无效的权限级别
|
||||
}
|
||||
|
||||
@ -665,12 +752,7 @@ extern "C" LOGIN_EXPORT int updateUserAccessLevel(int user_id, int access_level)
|
||||
return -1;
|
||||
}
|
||||
|
||||
fs::path dbPath = fs::path(xnCorePath) / "database" / "XNSim.db";
|
||||
std::string connectionName =
|
||||
"useraccess_"
|
||||
+ std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count());
|
||||
fs::path dbPath = fs::path(xnCorePath) / "database" / "UserInfo.db";
|
||||
|
||||
int result = -1;
|
||||
{
|
||||
@ -686,7 +768,7 @@ extern "C" LOGIN_EXPORT int updateUserAccessLevel(int user_id, int access_level)
|
||||
if (sqlite3_prepare_v2(db, checkQueryStr, -1, &stmt, nullptr) == SQLITE_OK) {
|
||||
sqlite3_bind_int(stmt, 1, user_id);
|
||||
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
if (sqlite3_step(stmt) != SQLITE_ROW) {
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_close(db);
|
||||
return -2; // 用户不存在
|
||||
@ -725,7 +807,7 @@ extern "C" LOGIN_EXPORT int updateUserAccessLevel(int user_id, int access_level)
|
||||
sqlite3_bind_int(stmt, 2, user_id);
|
||||
|
||||
if (sqlite3_step(stmt) == SQLITE_DONE) {
|
||||
result = 1; // 更新成功
|
||||
result = 0; // 更新成功
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
@ -748,24 +830,25 @@ extern "C" LOGIN_EXPORT int getAllUsersSimpleInfo(char *result, int result_lengt
|
||||
if (!xnCorePath) {
|
||||
return -1;
|
||||
}
|
||||
fs::path dbPath = fs::path(xnCorePath) / "database" / "XNSim.db";
|
||||
fs::path dbPath = fs::path(xnCorePath) / "database" / "UserInfo.db";
|
||||
sqlite3 *db;
|
||||
if (sqlite3_open(dbPath.string().c_str(), &db) != SQLITE_OK) {
|
||||
return -1;
|
||||
}
|
||||
const char *queryStr = "SELECT username, full_name, access_level FROM users";
|
||||
const char *queryStr = "SELECT id, username, full_name, access_level FROM users";
|
||||
sqlite3_stmt *stmt;
|
||||
json arr = json::array();
|
||||
if (sqlite3_prepare_v2(db, queryStr, -1, &stmt, nullptr) == SQLITE_OK) {
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
json userInfo;
|
||||
std::string username = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0));
|
||||
userInfo["id"] = sqlite3_column_int(stmt, 0);
|
||||
std::string username = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1));
|
||||
userInfo["username"] = username;
|
||||
userInfo["full_name"] =
|
||||
reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1));
|
||||
reinterpret_cast<const char *>(sqlite3_column_text(stmt, 2));
|
||||
// access_level 解密
|
||||
std::string accessLevelEnc =
|
||||
reinterpret_cast<const char *>(sqlite3_column_text(stmt, 2));
|
||||
reinterpret_cast<const char *>(sqlite3_column_text(stmt, 3));
|
||||
std::vector<unsigned char> iv_and_ciphertext = hex2bin(accessLevelEnc);
|
||||
if (iv_and_ciphertext.size() < 16) {
|
||||
userInfo["access_level"] = nullptr;
|
||||
@ -799,3 +882,32 @@ extern "C" LOGIN_EXPORT int getAllUsersSimpleInfo(char *result, int result_lengt
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" LOGIN_EXPORT int deleteUser(int user_id)
|
||||
{
|
||||
try {
|
||||
const char *xnCorePath = std::getenv("XNCore");
|
||||
if (!xnCorePath) {
|
||||
return -1;
|
||||
}
|
||||
fs::path dbPath = fs::path(xnCorePath) / "database" / "UserInfo.db";
|
||||
sqlite3 *db;
|
||||
if (sqlite3_open(dbPath.string().c_str(), &db) != SQLITE_OK) {
|
||||
return -1;
|
||||
}
|
||||
const char *queryStr = "DELETE FROM users WHERE id = ?";
|
||||
sqlite3_stmt *stmt;
|
||||
if (sqlite3_prepare_v2(db, queryStr, -1, &stmt, nullptr) == SQLITE_OK) {
|
||||
sqlite3_bind_int(stmt, 1, user_id);
|
||||
if (sqlite3_step(stmt) == SQLITE_DONE) {
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_close(db);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
sqlite3_close(db);
|
||||
return -1;
|
||||
} catch (const std::exception &) {
|
||||
return -1;
|
||||
}
|
||||
}
|
BIN
Release/database/UserInfo.db
Normal file
BIN
Release/database/UserInfo.db
Normal file
Binary file not shown.
Binary file not shown.
@ -2,10 +2,205 @@ class UserManagement extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.attachShadow({ mode: 'open' });
|
||||
this.users = [];
|
||||
this.currentUser = null;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.render();
|
||||
this.fetchUsers();
|
||||
}
|
||||
|
||||
async fetchUsers() {
|
||||
try {
|
||||
const response = await fetch('/api/all-users');
|
||||
const data = await response.json();
|
||||
if (data.success) {
|
||||
this.users = data.users.filter(user => user.id !== 1);
|
||||
this.render();
|
||||
} else {
|
||||
console.error('获取用户列表失败:', data.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取用户列表出错:', error);
|
||||
}
|
||||
}
|
||||
|
||||
showError(message) {
|
||||
this.shadowRoot.querySelector('.error-message').textContent = message;
|
||||
this.shadowRoot.querySelector('.error-message').style.display = 'block';
|
||||
}
|
||||
|
||||
async handleEditInfo(userId) {
|
||||
try {
|
||||
const response = await fetch(`/api/user-info/${userId}`);
|
||||
const data = await response.json();
|
||||
if (data.success) {
|
||||
this.currentUser = data.user;
|
||||
this.showEditModal();
|
||||
} else {
|
||||
alert('获取用户信息失败: ' + data.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取用户信息出错:', error);
|
||||
alert('获取用户信息失败');
|
||||
}
|
||||
}
|
||||
|
||||
showEditModal() {
|
||||
this.shadowRoot.querySelector('.modal').style.display = 'flex';
|
||||
this.populateForm();
|
||||
}
|
||||
|
||||
hideEditModal() {
|
||||
this.shadowRoot.querySelector('.modal').style.display = 'none';
|
||||
this.currentUser = null;
|
||||
}
|
||||
|
||||
populateForm() {
|
||||
const form = this.shadowRoot.querySelector('.edit-form');
|
||||
form.username.value = this.currentUser.username || '';
|
||||
form.full_name.value = this.currentUser.full_name || '';
|
||||
form.email.value = this.currentUser.email || '';
|
||||
form.phone.value = this.currentUser.phone || '';
|
||||
form.department.value = this.currentUser.department || '';
|
||||
form.position.value = this.currentUser.position || '';
|
||||
}
|
||||
|
||||
async handleSaveUserInfo() {
|
||||
const form = this.shadowRoot.querySelector('.edit-form');
|
||||
const userInfo = {
|
||||
full_name: form.full_name.value,
|
||||
email: form.email.value,
|
||||
phone: form.phone.value,
|
||||
department: form.department.value,
|
||||
position: form.position.value
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/update-user-info', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
userId: this.currentUser.id,
|
||||
userInfo: userInfo
|
||||
})
|
||||
});
|
||||
const data = await response.json();
|
||||
if (data.success) {
|
||||
alert('用户信息更新成功');
|
||||
this.hideEditModal();
|
||||
this.fetchUsers(); // 刷新用户列表
|
||||
} else {
|
||||
alert('用户信息更新失败: ' + data.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('更新用户信息出错:', error);
|
||||
alert('更新用户信息失败');
|
||||
}
|
||||
}
|
||||
|
||||
handleChangeAccessLevel(userId) {
|
||||
this.currentUser = { id: userId };
|
||||
this.showAccessModal();
|
||||
}
|
||||
|
||||
showAccessModal() {
|
||||
this.shadowRoot.querySelector('.access-modal').style.display = 'flex';
|
||||
}
|
||||
|
||||
hideAccessModal() {
|
||||
this.shadowRoot.querySelector('.access-modal').style.display = 'none';
|
||||
this.currentUser = null;
|
||||
}
|
||||
|
||||
async handleSaveAccessLevel() {
|
||||
const form = this.shadowRoot.querySelector('.access-form');
|
||||
const accessLevel = parseInt(form.access_level.value);
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/update-access-level', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
userId: this.currentUser.id,
|
||||
accessLevel: accessLevel
|
||||
})
|
||||
});
|
||||
const data = await response.json();
|
||||
if (data.success) {
|
||||
alert('权限级别更新成功');
|
||||
this.hideAccessModal();
|
||||
this.fetchUsers(); // 刷新用户列表
|
||||
} else {
|
||||
alert('权限级别更新失败: ' + data.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('更新权限级别出错:', error);
|
||||
alert('更新权限级别失败');
|
||||
}
|
||||
}
|
||||
|
||||
async handleResetPassword(userId) {
|
||||
if (confirm('确定要重置该用户的密码吗?')) {
|
||||
try {
|
||||
const response = await fetch('/api/reset-password', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ userId: parseInt(userId) })
|
||||
});
|
||||
const data = await response.json();
|
||||
if (data.success) {
|
||||
alert('密码重置成功');
|
||||
} else {
|
||||
alert('密码重置失败: ' + data.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('重置密码出错:', error);
|
||||
alert('重置密码失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async handleDelete(userId) {
|
||||
if (confirm('确定要删除该用户吗?此操作不可恢复!')) {
|
||||
try {
|
||||
const response = await fetch('/api/delete-user', {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ userId: parseInt(userId) })
|
||||
});
|
||||
const data = await response.json();
|
||||
if (data.success) {
|
||||
alert('用户删除成功');
|
||||
// 重新获取用户列表
|
||||
this.fetchUsers();
|
||||
} else {
|
||||
alert('用户删除失败: ' + data.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('删除用户出错:', error);
|
||||
alert('删除用户失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getAccessLevelName(level) {
|
||||
const accessLevels = {
|
||||
0: '访客',
|
||||
1: '用户',
|
||||
2: '开发人员',
|
||||
3: '组长'
|
||||
};
|
||||
return accessLevels[level] || level;
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -42,12 +237,406 @@ class UserManagement extends HTMLElement {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.users-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.users-table th,
|
||||
.users-table td {
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.users-table th {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.users-table tr:hover {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.col-id {
|
||||
width: 8%;
|
||||
}
|
||||
|
||||
.col-username {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.col-fullname {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.col-access {
|
||||
width: 12%;
|
||||
}
|
||||
|
||||
.col-actions {
|
||||
width: 35%;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
display: none;
|
||||
color: #ff4d4f;
|
||||
margin: 16px 0;
|
||||
padding: 8px;
|
||||
background-color: #fff2f0;
|
||||
border: 1px solid #ffccc7;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
padding: 6px 12px;
|
||||
margin: 0 4px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
color: white;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.edit-info {
|
||||
background-color: #1890ff;
|
||||
}
|
||||
|
||||
.change-access {
|
||||
background-color: #52c41a;
|
||||
}
|
||||
|
||||
.reset-password {
|
||||
background-color: #faad14;
|
||||
}
|
||||
|
||||
.delete {
|
||||
background-color: #ff4d4f;
|
||||
}
|
||||
|
||||
.action-button:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.action-button:active {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
padding: 24px;
|
||||
width: 500px;
|
||||
max-width: 90%;
|
||||
max-height: 90%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.close-button {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.close-button:hover {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-input:focus {
|
||||
outline: none;
|
||||
border-color: #1890ff;
|
||||
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
|
||||
}
|
||||
|
||||
.form-input:read-only {
|
||||
background-color: #f5f5f5;
|
||||
color: #666;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.form-input:read-only:focus {
|
||||
border-color: #d9d9d9;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
margin-top: 24px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 8px 16px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #1890ff;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: #f5f5f5;
|
||||
color: #333;
|
||||
border: 1px solid #d9d9d9;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.access-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.access-modal-content {
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
padding: 24px;
|
||||
width: 400px;
|
||||
max-width: 90%;
|
||||
}
|
||||
|
||||
.access-modal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.access-modal-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.access-close-button {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.access-close-button:hover {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.access-form-group {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.access-form-label {
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.access-form-select {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
box-sizing: border-box;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.access-form-select:focus {
|
||||
outline: none;
|
||||
border-color: #1890ff;
|
||||
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
|
||||
}
|
||||
|
||||
.access-modal-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
margin-top: 24px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid #e0e0e0;
|
||||
}
|
||||
</style>
|
||||
<div class="users-container">
|
||||
<div class="users-header">
|
||||
<div class="users-title">用户管理</div>
|
||||
</div>
|
||||
<div>用户管理组件内容(待实现)</div>
|
||||
<div class="error-message"></div>
|
||||
${this.users.length === 0 ?
|
||||
'<div class="loading">正在加载用户数据...</div>' :
|
||||
`<table class="users-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-id">ID</th>
|
||||
<th class="col-username">用户名</th>
|
||||
<th class="col-fullname">姓名</th>
|
||||
<th class="col-access">权限等级</th>
|
||||
<th class="col-actions">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${this.users.map(user => `
|
||||
<tr>
|
||||
<td class="col-id">${user.id}</td>
|
||||
<td class="col-username">${user.username}</td>
|
||||
<td class="col-fullname">${user.full_name || '-'}</td>
|
||||
<td class="col-access">${this.getAccessLevelName(user.access_level)}</td>
|
||||
<td class="col-actions">
|
||||
<button class="action-button edit-info" onclick="this.getRootNode().host.handleEditInfo(${user.id})">更改信息</button>
|
||||
<button class="action-button change-access" onclick="this.getRootNode().host.handleChangeAccessLevel(${user.id})">调整权限</button>
|
||||
<button class="action-button reset-password" onclick="this.getRootNode().host.handleResetPassword(${user.id})">重置密码</button>
|
||||
<button class="action-button delete" onclick="this.getRootNode().host.handleDelete(${user.id})">删除</button>
|
||||
</td>
|
||||
</tr>
|
||||
`).join('')}
|
||||
</tbody>
|
||||
</table>`
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- 编辑用户信息模态对话框 -->
|
||||
<div class="modal">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">编辑用户信息</div>
|
||||
<button class="close-button" onclick="this.getRootNode().host.hideEditModal()">×</button>
|
||||
</div>
|
||||
<form class="edit-form">
|
||||
<div class="form-group">
|
||||
<label class="form-label">用户名</label>
|
||||
<input type="text" class="form-input" name="username" required readonly>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">姓名</label>
|
||||
<input type="text" class="form-input" name="full_name">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">邮箱</label>
|
||||
<input type="email" class="form-input" name="email">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">电话</label>
|
||||
<input type="text" class="form-input" name="phone">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">部门</label>
|
||||
<input type="text" class="form-input" name="department">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">职位</label>
|
||||
<input type="text" class="form-input" name="position">
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" onclick="this.getRootNode().host.hideEditModal()">取消</button>
|
||||
<button class="btn btn-primary" onclick="this.getRootNode().host.handleSaveUserInfo()">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 调整权限级别模态对话框 -->
|
||||
<div class="access-modal">
|
||||
<div class="access-modal-content">
|
||||
<div class="access-modal-header">
|
||||
<div class="access-modal-title">调整权限级别</div>
|
||||
<button class="access-close-button" onclick="this.getRootNode().host.hideAccessModal()">×</button>
|
||||
</div>
|
||||
<form class="access-form">
|
||||
<div class="access-form-group">
|
||||
<label class="access-form-label">权限级别</label>
|
||||
<select class="access-form-select" name="access_level" required>
|
||||
<option value="0">访客</option>
|
||||
<option value="1">用户</option>
|
||||
<option value="2">开发人员</option>
|
||||
<option value="3">组长</option>
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
<div class="access-modal-footer">
|
||||
<button class="btn btn-secondary" onclick="this.getRootNode().host.hideAccessModal()">取消</button>
|
||||
<button class="btn btn-primary" onclick="this.getRootNode().host.handleSaveAccessLevel()">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
@ -289,6 +289,7 @@ router.post('/update-access-level', (req, res) => {
|
||||
if (result === 0) {
|
||||
res.json({ success: true, message: '用户权限级别更新成功' });
|
||||
} else {
|
||||
console.error('更新用户权限级别',accessLevel,'失败,错误码:', result);
|
||||
res.status(400).json({ success: false, message: '用户权限级别更新失败', error: `错误码:${result}` });
|
||||
}
|
||||
} catch (error) {
|
||||
@ -328,4 +329,91 @@ router.get('/all-users', (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// 重置用户密码路由
|
||||
router.post('/reset-password', (req, res) => {
|
||||
const { userId } = req.body;
|
||||
|
||||
if (!userId) {
|
||||
return res.status(400).json({ success: false, message: '用户ID不能为空' });
|
||||
}
|
||||
|
||||
try {
|
||||
if (!loginLib) {
|
||||
throw new Error('动态库未正确加载');
|
||||
}
|
||||
|
||||
const result = loginLib.resetPassword(parseInt(userId));
|
||||
|
||||
if (result === 0) {
|
||||
res.json({ success: true, message: '密码重置成功' });
|
||||
} else {
|
||||
res.status(400).json({ success: false, message: '密码重置失败', error: `错误码:${result}` });
|
||||
}
|
||||
} catch (error) {
|
||||
res.status(500).json({ success: false, message: '服务器内部错误', error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 删除用户路由
|
||||
router.delete('/delete-user', (req, res) => {
|
||||
const { userId } = req.body;
|
||||
|
||||
if (!userId) {
|
||||
return res.status(400).json({ success: false, message: '用户ID不能为空' });
|
||||
}
|
||||
|
||||
try {
|
||||
if (!loginLib) {
|
||||
throw new Error('动态库未正确加载');
|
||||
}
|
||||
|
||||
const result = loginLib.deleteUser(parseInt(userId));
|
||||
|
||||
if (result === 0) {
|
||||
res.json({ success: true, message: '用户删除成功' });
|
||||
} else {
|
||||
res.status(400).json({ success: false, message: '用户删除失败', error: `错误码:${result}` });
|
||||
}
|
||||
} catch (error) {
|
||||
res.status(500).json({ success: false, message: '服务器内部错误', error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 获取用户信息路由
|
||||
router.get('/user-info/:userId', (req, res) => {
|
||||
const { userId } = req.params;
|
||||
|
||||
if (!userId) {
|
||||
return res.status(400).json({ success: false, message: '用户ID不能为空' });
|
||||
}
|
||||
|
||||
try {
|
||||
if (!loginLib) {
|
||||
throw new Error('动态库未正确加载');
|
||||
}
|
||||
|
||||
const userInfoBuffer = Buffer.alloc(1024);
|
||||
const result = loginLib.getUserInfo(parseInt(userId), userInfoBuffer, userInfoBuffer.length);
|
||||
|
||||
if (result === 0) {
|
||||
// 找到字符串结束位置
|
||||
const zeroIndex = userInfoBuffer.indexOf(0);
|
||||
const userInfoStr = userInfoBuffer.toString('utf8', 0, zeroIndex >= 0 ? zeroIndex : userInfoBuffer.length);
|
||||
|
||||
try {
|
||||
const userInfo = JSON.parse(userInfoStr);
|
||||
res.json({ success: true, user: userInfo });
|
||||
} catch (parseError) {
|
||||
console.error('解析用户信息失败:', parseError);
|
||||
res.status(500).json({ success: false, message: '解析用户信息失败', error: parseError.message });
|
||||
}
|
||||
} else {
|
||||
res.status(400).json({ success: false, message: '获取用户信息失败', error: `错误码:${result}` });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取用户信息过程出错:', error);
|
||||
res.status(500).json({ success: false, message: '服务器内部错误', error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
@ -37,7 +37,9 @@ try {
|
||||
'changePassword': ['int', ['int', StringType, 'int', StringType, 'int']],
|
||||
'updateUserInfo': ['int', ['int', StringType, 'int']],
|
||||
'updateUserAccessLevel': ['int', ['int', 'int']],
|
||||
'getAllUsersSimpleInfo': ['int', [StringType, 'int']]
|
||||
'getAllUsersSimpleInfo': ['int', [StringType, 'int']],
|
||||
'resetPassword': ['int', ['int']],
|
||||
'deleteUser': ['int', ['int']]
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`加载 ${loginLibName} 失败:`, error);
|
||||
@ -566,6 +568,40 @@ function stopCollectData() {
|
||||
}
|
||||
}
|
||||
|
||||
// 重置用户密码
|
||||
function resetPassword(userId) {
|
||||
if (!loginLib) {
|
||||
return '登录库未加载';
|
||||
}
|
||||
try {
|
||||
const result = loginLib.resetPassword(userId);
|
||||
if (result === 0) {
|
||||
return '密码重置成功';
|
||||
} else {
|
||||
return `密码重置失败,错误码:${result}`;
|
||||
}
|
||||
} catch (error) {
|
||||
return `密码重置失败: ${error.message}`;
|
||||
}
|
||||
}
|
||||
|
||||
// 删除用户
|
||||
function deleteUser(userId) {
|
||||
if (!loginLib) {
|
||||
return '登录库未加载';
|
||||
}
|
||||
try {
|
||||
const result = loginLib.deleteUser(userId);
|
||||
if (result === 0) {
|
||||
return '用户删除成功';
|
||||
} else {
|
||||
return `用户删除失败,错误码:${result}`;
|
||||
}
|
||||
} catch (error) {
|
||||
return `用户删除失败: ${error.message}`;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
loginLib,
|
||||
monitorLib,
|
||||
@ -595,5 +631,7 @@ module.exports = {
|
||||
getCsvDataInjectStatus,
|
||||
startCollectData,
|
||||
getCollectDataStatus,
|
||||
stopCollectData
|
||||
stopCollectData,
|
||||
resetPassword,
|
||||
deleteUser
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user