
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
<template>
<div class="content management">
<div class="sub-title-area mb-30">
<h2>회원관리</h2>
<div class="breadcrumb-list">
<ul>
<li><img :src="homeicon" alt="Home Icon">
<p>회원관리</p>
</li>
<li><img :src="righticon" alt=""></li>
<li>회원관리</li>
</ul>
</div>
</div>
<div class="flex-sp-bw">
<div class="left-con">
<div class="search-wrap mb-20">
<div class="search-area">
<div class="select-box">
<select v-model="searchReqDTO.searchType">
<option value="" selected>전체</option>
<option value="id">아이디</option>
<option value="nm">이름</option>
</select>
</div>
<div class="wfull" style="height: 100%;">
<input type="text" v-model="searchReqDTO.searchText" @keyup.enter="searchUsers">
</div>
<button class="search-btn" @click="searchUsers">
<img :src="searchicon" alt="">
</button>
</div>
</div>
<table class="mb-10" style="width: 100%;">
<thead>
<tr>
<th style="width: 30%">아이디</th>
<th style="width: 40%">이름</th>
<th style="width: 30%">권한</th>
</tr>
</thead>
<tbody>
<tr v-if="selectedUsers.length === 0">
<td colspan="3" style="text-align: center;">등록된 사용자가 없습니다.</td>
</tr>
<tr v-for="(item, index) in selectedUsers" :key="index"
:class="{ 'delete-member': item.useAt === 'N' }" @click="selectUser(item)">
<td>{{ item.loginId }}</td>
<td>{{ item.userNm }}</td>
<td>
<span v-if="item.authorList.length > 0">{{ item.authorList[0].authorNm }}</span>
<span v-else>없음</span>
</td>
</tr>
</tbody>
</table>
</div>
<div class="righi-con wfull">
<div class="btn-group-small flex-end mb-20">
<div v-if="copySelectedUser.useAt === 'N' && isNewInsert && userId != null"
class="button green-line" @click="updateByUseAtUser">복구</div>
<div v-if="copySelectedUser.useAt === 'Y' && isNewInsert && userId != null" class="button red-line"
@click="updateByUseAtUser">회원탈퇴</div>
<div v-if="newInsertCheck" class="button gray-line" @click="restPassword">비밀번호 초기화</div>
<div v-if="newInsertCheck" class="button pink-line-bg flex align-center" @click="resetUser"><img
:src="check_pink" alt="">
<p>신규등록</p>
</div>
<div class="button blue-line-bg flex align-center" @click="insertByUpdateUser"><img
:src="check_blue" alt="">
{{ newInsertCheck ? "수정" : "등록" }}
</div>
<div class="button gray-bg" @click="cancelUser">취소</div>
</div>
<form action="" class="insert-form mb-50">
<dl>
<dd>
<label for="id" class="require">아이디</label>
<input type="text" id="id" v-model="loginId" :readonly="isNewInsert">
</dd>
<div class="hr"></div>
<template v-if="!newInsertCheck">
<dd>
<label for="pw" class="require">비밀번호</label>
<input type="password" id="pw" v-model="password" :disabled="isNewInsert"
:placeholder="isNewInsert ? '' : '비밀번호를 입력하세요'" @input="validatePassword">
<div class="invalid-feedback border" v-if="!isPasswordValid && password !== null">
<img :src="erroricon" alt="">
<span>영문, 숫자, 특수문자를 최소 한 가지씩 조합하고 9자 이상 ~ 20자 이내로 입력해주세요.</span>
</div>
</dd>
<div class="hr"></div>
<dd>
<label for="pwcheck" class="require">비밀번호 확인</label>
<input type="password" id="pwcheck" v-model="passwordCheck" :disabled="isNewInsert"
:placeholder="isNewInsert ? '' : '비밀번호를 재입력하세요'">
<div class="invalid-feedback border" v-if="passwordCheck !== null && !passwordsMatch">
<img :src="erroricon" alt="">
<span>비밀번호가 일치하지 않습니다.</span>
</div>
</dd>
<div class="hr"></div>
</template>
<dd>
<label for="name" class="require">이름</label>
<input type="text" id="name" v-model="selectedUser.userNm">
</dd>
<div class="hr"></div>
<dd>
<label for="gwonhan" class="require">권한</label>
<div class="select-box">
<select v-model="selectedUser.authorList[0].authorCode">
<option value="ROLE_ADMIN" selected>관리자</option>
<option value="ROLE_USER">사용자</option>
</select>
</div>
</dd>
<div class="hr"></div>
<dd>
<label for="use" class="require">사용여부</label>
<div class="switch">
<input type="checkbox" id="switch" :checked="selectedUser.useAt === 'Y'"
@change="toggleUseAt"
:disabled="!isNewInsert || (this.userId !== null || this.userId !== '')" />
<label for="switch">Toggle</label>
</div>
<div class="invalid-feedback border" v-if="!newInsertCheck">
<img :src="erroricon" alt="">
<span>등록시 사용유무는 변경 하실 수 없습니다.</span>
</div>
<div class="invalid-feedback border" v-if="selectedUser.useAt === 'Y' && newInsertCheck">
<img :src="erroricon" alt="">
<span>삭제버튼을 누를 시 사용여부가 변경됩니다.</span>
</div>
<div class="invalid-feedback border" v-if="selectedUser.useAt === 'N' && newInsertCheck">
<img :src="erroricon" alt="">
<span>복구버튼을 누를 시 사용여부가 변경됩니다.</span>
</div>
</dd>
</dl>
</form>
</div>
</div>
</div>
</template>
<script>
import { DoubleLeftOutlined, LeftOutlined, RightOutlined, DoubleRightOutlined } from '@ant-design/icons-vue';
import { findAllUsers, updateUsers, updatePassword, join } from "../../../resources/api/user";
export default {
components: {
DoubleLeftOutlined,
LeftOutlined,
RightOutlined,
DoubleRightOutlined,
},
data() {
return {
homeicon: 'client/resources/images/icon/home.png',
erroricon: 'client/resources/images/icon/error.png',
righticon: 'client/resources/images/icon/right.png',
check_pink: 'client/resources/images/checkbox_pink.png',
check_blue: 'client/resources/images/checkbox_blue.png',
searchicon: 'client/resources/images/icon/search.png',
selectedUsers: [],
newInsertCheck: false,
//사용자 로그인 아이다
loginId: null,
//사용자 아이디
userId: null,
// 비밀번호 추가
password: null,
// 비밀번호 확인 추가
passwordCheck: null,
// 비밀번호 유효성 체크를 위한 변수
isPasswordValid: false,
// 비밀번호 초기화
passwordResetAt: {
oldPassword: "qwer1234!",
newPassword: "qwer1234!",
resetAt: true
},
// 선택된 사용자 수정
selectedUser: {
userNm: null,
useAt: null,
authorUpdateCheck: false,
authorList: [
{ authorCode: "ROLE_ADMIN" }
]
},
// 선택된 사용자 복사
copySelectedUser: {
userNm: null,
useAt: null,
authorList: [
{ authorCode: "ROLE_ADMIN" }
]
},
//회원가입
joinDTO: {
loginId: null,
userNm: null,
password: null,
authorList: []
},
// 사용자 검색 객체
searchReqDTO: {
searchType: "",
searchText: null,
userSttus: null,
useAt: null
},
// 신규등록 체크
isNewInsert: true,
};
},
methods: {
cancelUser() {
if (confirm("초기값으로 변경하시겠습니까?")) {
if (this.userId === null || this.userId === "") {
this.loginId = null;
this.password = null;
this.passwordCheck = null;
this.selectedUser = {
userNm: null,
useAt: "Y",
authorUpdateCheck: false,
authorList: [{ authorCode: "ROLE_ADMIN" }]
};
} else {
this.selectedUser = {
userNm: this.copySelectedUser.userNm,
useAt: this.copySelectedUser.useAt,
authorUpdateCheck: false,
authorList: [{ authorCode: this.copySelectedUser.authorList[0].authorCode }] // 배열 형태로 설정
};
}
}
},
//등록 함수
updateUser() {
this.joinDTO.loginId = this.loginId;
this.joinDTO.userNm = this.selectedUser.userNm;
this.joinDTO.password = this.password;
this.joinDTO.authorList = [this.selectedUser.authorList[0]];
},
// 등록 및 수정
async insertByUpdateUser() {
if (!this.newInsertCheck) {
if (this.userId == null || this.userId == '') {
this.updateUser();
if (confirm("회원가입을 하시겠습니까?")) {
if (this.$isEmpty(this.joinDTO.loginId)) {
alert("아이디를 확인해주세요.")
} else if (this.joinDTO.loginId) {
const regex = /^[a-z0-9]+$/; // 소문자와 숫자만 허용하는 정규 표현식
if (!regex.test(this.joinDTO.loginId)) {
alert("아이디는 소문자와 숫자 조합만 가능합니다.");
}
} else if (this.$isEmpty(this.password) && this.$isEmpty(this.passwordCheck)) {
alert("비밀번호를 확인해주세요.")
} else if (this.password != this.passwordCheck) {
alert("비밀번호가 일치하지 않습니다.")
} else if (this.$isEmpty(this.joinDTO.userNm)) {
alert("이름을 확인해주세요.")
} else {
try {
const response = await join(this.joinDTO);
if (response.status === 200) {
alert("회원가입되었습니다.");
window.location.reload();
}
} catch (error) {
// HTTP 오류가 발생한 경우
const errorMessage = error.response?.data?.message || "회원가입이 실패하였습니다.";
alert(errorMessage); // 오류 메시지 표시
this.searchUsers();
}
}
}
} else {
// 권한이 변경되었는지 확인
const isAuthorChanged = this.copySelectedUser.authorList[0].authorCode !== this.selectedUser.authorList[0].authorCode;
if (isAuthorChanged) {
this.selectedUser.authorUpdateCheck = true; // 권한 변경 체크
if (confirm("회원 수정을 하시겠습니까?")) {
try {
const response = await updateUsers(this.userId, this.selectedUser);
if (response.status === 200) {
alert("수정되었습니다.");
this.searchUsers();
}
} catch (error) {
// HTTP 오류가 발생한 경우
const errorMessage = error.response?.data?.message || "수정이 실패하였습니다.";
alert(errorMessage); // 오류 메시지 표시
this.searchUsers();
}
}
} else {
// 권한이 변경되지 않았다면 기존 수정 로직 실행
if (confirm("회원 수정을 하시겠습니까?")) {
try {
const response = await updateUsers(this.userId, this.selectedUser);
if (response.status === 200) {
alert("수정되었습니다.");
this.searchUsers();
}
} catch (error) {
// HTTP 오류가 발생한 경우
const errorMessage = error.response?.data?.message || "수정이 실패하였습니다.";
alert(errorMessage); // 오류 메시지 표시
this.searchUsers();
}
}
}
}
} else {
alert("필수 항목 값을 입력해주세요");
}
},
validatePassword() {
// 빈 문자열이나 null 체크
if (!this.password) {
this.isPasswordValid = false; // 빈 문자열일 경우 유효성 false
return;
}
// 정규식: 영문, 숫자, 특수문자를 최소 한 가지씩 조합하고 8자 이상 20자 이내
const passwordRegex = /^(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[!@#$%^&*])[A-Za-z\d!@#$%^&*]{9,20}$/;
this.isPasswordValid = passwordRegex.test(this.password);
},
// 사용자 전체조회
async searchUsers() {
try {
const response = await findAllUsers(this.searchReqDTO);
if (response.status === 200) {
this.selectedUsers = response.data.data.users;
}
} catch (error) {
console.error("검색 중 오류 발생:", error);
}
},
// 선택한 사용자
selectUser(item) {
this.newInsertCheck = true,
this.isNewInsert = true;
this.loginId = item.loginId;
this.userId = item.userId;
this.password = null;
this.passwordCheck = null;
this.selectedUser = {
userNm: item.userNm,
useAt: item.useAt,
authorList: [item.authorList[0]]
};
// 깊은 복사를 통해 copySelectedUser를 설정
this.copySelectedUser = JSON.parse(JSON.stringify(this.selectedUser));
},
// 스위치 사용여부
toggleUseAt() {
this.selectedUser.useAt = this.selectedUser.useAt === 'Y' ? 'N' : 'Y';
},
// 삭제 또는 복구 로직
async updateByUseAtUser() {
if (this.selectedUser.useAt === 'Y') {
if (confirm("선택한 사용자를 탈퇴 하시겠습니까?")) {
try {
this.selectedUser.useAt = 'N'
this.copySelectedCategory = 'N'
const response = await updateUsers(this.userId, this.selectedUser);
if (response.status === 200) {
alert("탈퇴되었습니다.");
this.copySelectedUser.useAt = 'N';
this.searchUsers();
}
} catch (error) {
alert("탈퇴가 실패하였습니다.");
this.searchUsers();
}
}
} else {
if (confirm("선택한 사용자를 복구 하시겠습니까?")) {
try {
this.selectedUser.useAt = 'Y'
this.copySelectedCategory = 'Y'
const response = await updateUsers(this.userId, this.selectedUser);
if (response.status === 200) {
alert("복구되었습니다.");
this.copySelectedUser.useAt = 'Y';
this.searchUsers();
}
} catch (error) {
alert("복구가 실패하였습니다.");
this.searchUsers();
}
}
}
},
// 비밀번호 초기화
async restPassword() {
if (confirm("비밀번호 초기화를 하시겠습니까?")) {
if (this.userId == null || this.userId == '') {
alert("신규등록은 초기화가 불가능합니다.")
} else {
try {
const response = await updatePassword(this.userId, this.passwordResetAt);
if (response.status === 200) {
alert("초기화되었습니다.");
this.searchUsers();
}
} catch (error) {
// HTTP 오류가 발생한 경우
const errorMessage = error.response?.data?.message || "비밀번호 초기화에 실패하였습니다.";
alert(errorMessage); // 오류 메시지 표시
this.searchUsers();
}
}
}
},
// 사용자 초기화
resetUser() {
this.newInsertCheck = false;
this.isNewInsert = false;
this.loginId = null;
this.userId = null;
this.selectedUser = {
userNm: null,
useAt: "Y",
authorList: [
{ authorCode: "ROLE_ADMIN" }
]
};
this.copySelectedUser = {
userNm: null,
useAt: null,
authorList: [
{ authorCode: "ROLE_ADMIN" }
]
};
},
},
computed: {
passwordsMatch() {
return this.password === this.passwordCheck;
}
},
mounted() {
this.searchUsers(); // 컴포넌트가 마운트될 때 사용자 목록을 조회
this.resetUser();
}
};
</script>