create.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. <template>
  2. <div class="admin--page-content">
  3. <div class="admin--form">
  4. <form @submit.prevent="handleSubmit" class="">
  5. <!-- 낚시분야 -->
  6. <table class="admin--form--table">
  7. <colgroup>
  8. <col style="width: 120px;">
  9. <col>
  10. </colgroup>
  11. <tbody>
  12. <tr>
  13. <th>
  14. <div>
  15. 분야 <span class="admin--required">*</span>
  16. </div>
  17. </th>
  18. <td>
  19. <div class="input--wrap">
  20. <input
  21. v-model="formData.name"
  22. type="text"
  23. class="admin--form-input"
  24. placeholder="예: 갯바위낚시"
  25. required
  26. />
  27. <p>낚시 종류 분류명. 1~30자 이내. 중복 불가</p>
  28. </div>
  29. </td>
  30. </tr>
  31. <tr>
  32. <th>
  33. <div>
  34. 가중치 <span class="admin--required">*</span>
  35. </div>
  36. </th>
  37. <td>
  38. <div class="input--wrap">
  39. <input
  40. v-model="formData.weight"
  41. type="text"
  42. class="admin--form-input w--120"
  43. placeholder="0.0 ~ 1.0"
  44. required
  45. />
  46. <p>0.0 ~ 1.0 사이 소수점 1자리 (최대값 1.0 = 100% 확률). 물고기 잡을 때 아이템 지급 확률</p>
  47. </div>
  48. </td>
  49. </tr>
  50. </tbody>
  51. </table>
  52. <div class="admin--info--box">
  53. <h3>💡 가중치 안내</h3>
  54. <ul>
  55. <li>가중치 = 해당 분야에서 물고기 잡았을 때 아이템이 지급될 확률 (최대값 1.0 = 100%)</li>
  56. <li>예: 0.8 = 80% 확률로 아이템 드롭. 분야별 난이도/희소성에 맞춰 신중히 설정</li>
  57. </ul>
  58. </div>
  59. <!-- 버튼 영역 -->
  60. <div class="admin--form-actions">
  61. <button type="button" class="admin--btn" @click="goToList">
  62. ← 목록으로
  63. </button>
  64. <!-- <button type="button" class="admin--btn admin--btn-red-border ml--auto" @click="">
  65. 삭제
  66. </button> -->
  67. <button type="submit" class="admin--btn admin--btn-red ml--auto" :disabled="isSaving">
  68. {{ isSaving ? "저장 중..." : "저장" }}
  69. </button>
  70. </div>
  71. <!-- 성공/에러 메시지 -->
  72. <div v-if="successMessage" class="admin--alert admin--alert-success">
  73. {{ successMessage }}
  74. </div>
  75. <div v-if="errorMessage" class="admin--alert admin--alert-error">
  76. {{ errorMessage }}
  77. </div>
  78. </form>
  79. </div>
  80. </div>
  81. </template>
  82. <script setup>
  83. import { ref } from "vue";
  84. import { useRouter } from "vue-router";
  85. definePageMeta({
  86. layout: "admin",
  87. middleware: ["auth"],
  88. });
  89. const router = useRouter();
  90. const { post } = useApi();
  91. const isSaving = ref(false);
  92. const successMessage = ref("");
  93. const errorMessage = ref("");
  94. const formData = ref({
  95. name: "",
  96. weight: "",
  97. });
  98. // 가중치 형식: 0.0 ~ 1.0, 소수점 1자리
  99. const WEIGHT_PATTERN = /^(0(\.\d)?|1(\.0)?)$/;
  100. // 폼 제출
  101. const handleSubmit = async () => {
  102. successMessage.value = "";
  103. errorMessage.value = "";
  104. const name = formData.value.name.trim();
  105. const weight = formData.value.weight.trim();
  106. // 유효성 검사
  107. if (!name) {
  108. errorMessage.value = "분야명을 입력하세요.";
  109. return;
  110. }
  111. if (name.length > 30) {
  112. errorMessage.value = "분야명은 30자 이내로 입력하세요.";
  113. return;
  114. }
  115. if (!weight) {
  116. errorMessage.value = "가중치를 입력하세요.";
  117. return;
  118. }
  119. if (!WEIGHT_PATTERN.test(weight)) {
  120. errorMessage.value = "가중치는 0.0 ~ 1.0 사이 소수점 1자리로 입력하세요.";
  121. return;
  122. }
  123. isSaving.value = true;
  124. try {
  125. const { data, error } = await post("/field", { name, weight });
  126. if (error || !data?.success) {
  127. errorMessage.value = error?.message || data?.message || "등록에 실패했습니다.";
  128. } else {
  129. successMessage.value = data.message || "낚시분야가 등록되었습니다.";
  130. setTimeout(() => {
  131. router.push("/site-manager/field/list");
  132. }, 1000);
  133. }
  134. } catch (error) {
  135. errorMessage.value = "서버 오류가 발생했습니다.";
  136. console.error("Save error:", error);
  137. } finally {
  138. isSaving.value = false;
  139. }
  140. };
  141. // 목록으로 이동
  142. const goToList = () => {
  143. router.push("/site-manager/field/list");
  144. };
  145. </script>