PasswordModal.vue 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. <template>
  2. <div class="admin--modal-overlay" @click.self="close">
  3. <div class="admin--modal admin--modal-sm">
  4. <div class="admin--modal-header">
  5. <h4>비밀번호 변경</h4>
  6. <button @click="close" class="admin--modal-close">&times;</button>
  7. </div>
  8. <div class="admin--modal-body">
  9. <div class="admin--info-box">
  10. <p><strong>관리자:</strong> {{ admin.name }} ({{ admin.username }})</p>
  11. </div>
  12. <form @submit.prevent="save">
  13. <div class="admin--form-group" v-if="isCurrentUser">
  14. <label class="admin--label">현재 비밀번호</label>
  15. <input
  16. v-model="formData.current_password"
  17. type="password"
  18. class="admin--input"
  19. placeholder="현재 비밀번호 입력"
  20. />
  21. <small class="admin--help-text">본인 계정의 경우 현재 비밀번호를 입력해주세요.</small>
  22. </div>
  23. <div class="admin--form-group">
  24. <label class="admin--label">새 비밀번호 *</label>
  25. <input
  26. v-model="formData.new_password"
  27. type="password"
  28. class="admin--input"
  29. required
  30. placeholder="최소 8자 이상"
  31. minlength="8"
  32. />
  33. </div>
  34. <div class="admin--form-group">
  35. <label class="admin--label">새 비밀번호 확인 *</label>
  36. <input
  37. v-model="formData.new_password_confirm"
  38. type="password"
  39. class="admin--input"
  40. required
  41. placeholder="새 비밀번호 재입력"
  42. minlength="8"
  43. />
  44. </div>
  45. <div class="admin--modal-footer">
  46. <button type="button" @click="close" class="admin--btn-secondary">
  47. 취소
  48. </button>
  49. <button type="submit" class="admin--btn-primary" :disabled="saving">
  50. {{ saving ? '변경 중...' : '변경' }}
  51. </button>
  52. </div>
  53. </form>
  54. </div>
  55. </div>
  56. </div>
  57. </template>
  58. <script setup>
  59. import { ref, computed } from 'vue'
  60. const props = defineProps({
  61. admin: {
  62. type: Object,
  63. required: true
  64. }
  65. })
  66. const emit = defineEmits(['close', 'saved'])
  67. const { post } = useApi()
  68. const saving = ref(false)
  69. // 현재 로그인한 관리자 ID
  70. const currentAdminId = computed(() => {
  71. if (typeof window === 'undefined') return null
  72. const user = localStorage.getItem('admin_user')
  73. if (!user) return null
  74. try {
  75. return JSON.parse(user).id
  76. } catch {
  77. return null
  78. }
  79. })
  80. const isCurrentUser = computed(() => {
  81. return currentAdminId.value === props.admin.id
  82. })
  83. const formData = ref({
  84. current_password: '',
  85. new_password: '',
  86. new_password_confirm: ''
  87. })
  88. const close = () => {
  89. emit('close')
  90. }
  91. const save = async () => {
  92. // 비밀번호 확인
  93. if (formData.value.new_password !== formData.value.new_password_confirm) {
  94. emit('saved', '새 비밀번호가 일치하지 않습니다.')
  95. return
  96. }
  97. if (formData.value.new_password.length < 8) {
  98. emit('saved', '비밀번호는 최소 8자 이상이어야 합니다.')
  99. return
  100. }
  101. saving.value = true
  102. try {
  103. const requestData = {
  104. new_password: formData.value.new_password
  105. }
  106. // 본인 계정인 경우 현재 비밀번호 포함
  107. if (isCurrentUser.value && formData.value.current_password) {
  108. requestData.current_password = formData.value.current_password
  109. }
  110. const { data, error } = await post(`/admin/${props.admin.id}/password`, requestData)
  111. if (error) {
  112. console.error('[PasswordModal] 변경 실패:', error)
  113. const errorMessage = error.response?.data?.message || '비밀번호 변경에 실패했습니다.'
  114. emit('saved', errorMessage)
  115. return
  116. }
  117. if (data?.success) {
  118. emit('saved', '비밀번호가 변경되었습니다.')
  119. }
  120. } finally {
  121. saving.value = false
  122. }
  123. }
  124. </script>