From c00abb103fbadc14d396f83b75c88271454988a5 Mon Sep 17 00:00:00 2001 From: Yu Sung <hwchon1234@gmail.com> Date: Tue, 12 Mar 2024 14:46:19 +0900 Subject: [PATCH] =?UTF-8?q?=EC=8B=9C=EA=B7=B8=EB=8B=88=EC=B2=98=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C/=EB=93=B1=EB=A1=9D/=EC=88=98=EC=A0=95/?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/signature.js | 23 + src/components/SideMenu.vue | 7 +- src/router/index.js | 5 + src/views/Signature/SignatureManagement.vue | 530 ++++++++++++++++++++ 4 files changed, 561 insertions(+), 4 deletions(-) create mode 100644 src/api/signature.js create mode 100644 src/views/Signature/SignatureManagement.vue diff --git a/src/api/signature.js b/src/api/signature.js new file mode 100644 index 0000000..10a61da --- /dev/null +++ b/src/api/signature.js @@ -0,0 +1,23 @@ +import Vue from 'vue' + +async function getSignatureList(page) { + return Vue.axios.get('/creator-admin/signature?page=' + (page - 1) + "&size=20"); +} + +async function createSignature(formData) { + return Vue.axios.post('/creator-admin/signature', formData, { + headers: { + "Content-Type": "multipart/form-data", + }, + }); +} + +async function modifySignature(formData) { + return Vue.axios.put('/creator-admin/signature', formData, { + headers: { + "Content-Type": "multipart/form-data", + }, + }); +} + +export { getSignatureList, createSignature, modifySignature } diff --git a/src/components/SideMenu.vue b/src/components/SideMenu.vue index 1cc3222..ba7ea0a 100644 --- a/src/components/SideMenu.vue +++ b/src/components/SideMenu.vue @@ -20,11 +20,10 @@ :to="item.route" active-class="blue white--text" > - <v-list-item-icon> - <v-icon>{{ item.icon }}</v-icon> - </v-list-item-icon> - <v-list-item-title>{{ item.title }}</v-list-item-title> + <v-list-item-icon> + <v-icon>mdi-chevron-right</v-icon> + </v-list-item-icon> </v-list-item> </div> diff --git a/src/router/index.js b/src/router/index.js index 5ef7e7e..9e3d825 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -45,6 +45,11 @@ const routes = [ name: 'CalculateContentDonation', component: () => import(/* webpackChunkName: "calculate" */ '../views/Calculate/CalculateContentDonation.vue') }, + { + path: '/signature', + name: 'SignatureManagement', + component: () => import(/* webpackChunkName: "signature" */ '../views/Signature/SignatureManagement.vue') + } ] }, { diff --git a/src/views/Signature/SignatureManagement.vue b/src/views/Signature/SignatureManagement.vue new file mode 100644 index 0000000..db3d7aa --- /dev/null +++ b/src/views/Signature/SignatureManagement.vue @@ -0,0 +1,530 @@ +<template> + <div> + <v-toolbar dark> + <v-spacer /> + <v-toolbar-title>시그니처 관리</v-toolbar-title> + <v-spacer /> + </v-toolbar> + <v-container> + <v-row> + <v-col cols="10" /> + <v-col> + <v-btn + block + color="#3bb9f1" + dark + depressed + @click="showWriteDialog" + > + 시그니처 등록 + </v-btn> + </v-col> + </v-row> + <v-row> + <v-col> + <v-data-table + :headers="headers" + :items="signature_list" + :loading="is_loading" + :items-per-page="-1" + item-key="id" + class="elevation-1" + hide-default-footer + > + <template v-slot:item.can="{ item }"> + {{ item.can }} + </template> + + <template v-slot:item.image="{ item }"> + <v-img + :src="item.image" + max-width="200" + max-height="200" + align="center" + class="center-image" + /> + </template> + <template v-slot:item.management="{ item }"> + <v-row> + <v-col /> + <v-col> + <v-btn + :disabled="is_loading" + @click="showModifyDialog(item)" + > + 수정 + </v-btn> + </v-col> + <v-col> + <v-btn + :disabled="is_loading" + @click="showDeleteConfirm(item)" + > + 삭제 + </v-btn> + </v-col> + <v-col /> + </v-row> + </template> + </v-data-table> + </v-col> + </v-row> + <v-row class="text-center"> + <v-col> + <v-pagination + v-model="page" + :length="total_page" + circle + @input="next" + /> + </v-col> + </v-row> + </v-container> + <v-row> + <v-dialog + v-model="show_write_dialog" + max-width="1000px" + persistent + > + <v-card> + <v-card-title> + 시그니처 캔 등록 + </v-card-title> + <v-card-text> + <v-row align="center"> + <v-col cols="4"> + 캔 + </v-col> + <v-col cols="8"> + <v-text-field + v-model="can" + label="캔" + /> + </v-col> + </v-row> + </v-card-text> + + <v-card-text> + <v-row align="center"> + <v-col cols="4"> + 이미지 + </v-col> + <v-col cols="8"> + <div class="image-select"> + <label for="image"> + 이미지 불러오기 + </label> + <v-file-input + id="image" + v-model="image" + @change="imageAdd" + /> + </div> + <img + v-if="image_url" + :src="image_url" + alt="" + class="image-preview" + > + </v-col> + </v-row> + </v-card-text> + + <v-card-actions v-show="!is_loading"> + <v-spacer /> + <v-btn + color="blue darken-1" + text + @click="cancel" + > + 취소 + </v-btn> + <v-btn + color="blue darken-1" + text + @click="validate" + > + 등록 + </v-btn> + </v-card-actions> + </v-card> + </v-dialog> + </v-row> + <v-row> + <v-dialog + v-model="show_modify_dialog" + max-width="1000px" + persistent + > + <v-card> + <v-card-title> + 시그니처 캔 수정 + </v-card-title> + <v-card-text> + <v-row align="center"> + <v-col cols="4"> + 캔 + </v-col> + <v-col cols="8"> + {{ selected_signature_can.can }} 캔 + </v-col> + </v-row> + </v-card-text> + + <v-card-text> + <v-row align="center"> + <v-col cols="4"> + 이미지 + </v-col> + <v-col cols="8"> + <div class="image-select"> + <label for="image"> + 이미지 불러오기 + </label> + <v-file-input + id="image" + v-model="image" + @change="imageAdd" + /> + </div> + <img + v-if="image_url" + :src="image_url" + alt="" + class="image-preview" + > + </v-col> + </v-row> + </v-card-text> + + <v-card-actions v-show="!is_loading"> + <v-spacer /> + <v-btn + color="blue darken-1" + text + @click="cancel" + > + 취소 + </v-btn> + <v-btn + color="blue darken-1" + text + @click="modifySignatureCan" + > + 수정 + </v-btn> + </v-card-actions> + </v-card> + </v-dialog> + </v-row> + <v-row> + <v-dialog + v-model="show_delete_confirm_dialog" + max-width="400px" + persistent + > + <v-card> + <v-card-text /> + <v-card-text> + 삭제하시겠습니까? + </v-card-text> + <v-card-actions v-show="!is_loading"> + <v-spacer /> + <v-btn + color="blue darken-1" + text + @click="cancel" + > + 취소 + </v-btn> + <v-btn + color="blue darken-1" + text + @click="deleteSignature" + > + 확인 + </v-btn> + </v-card-actions> + </v-card> + </v-dialog> + </v-row> + </div> +</template> + +<script> +import * as api from "@/api/signature"; + +export default { + name: "SignatureManagement", + + data() { + return { + is_loading: false, + is_modify: false, + show_write_dialog: false, + show_modify_dialog: false, + show_delete_confirm_dialog: false, + + signature_list: [], + + page: 1, + total_page: 0, + + can: 0, + image: null, + image_url: null, + is_active: null, + selected_signature_can: {}, + + headers: [ + { + text: '캔', + align: 'center', + sortable: false, + value: 'can', + }, + { + text: '이미지', + align: 'center', + sortable: false, + value: 'image', + }, + { + text: '관리', + align: 'center', + sortable: false, + value: 'management', + }, + ], + } + }, + + async created() { + await this.getSignatureList(); + }, + + methods: { + notifyError(message) { + this.$dialog.notify.error(message) + }, + + notifySuccess(message) { + this.$dialog.notify.success(message) + }, + + imageAdd(payload) { + const file = payload; + if (file) { + this.image_url = URL.createObjectURL(file) + URL.revokeObjectURL(file) + } else { + this.image_url = null + } + }, + + showWriteDialog() { + this.show_write_dialog = true + }, + + validate() { + if ( + this.can === 0 || + this.image === null + ) { + this.notifyError('내용을 입력하세요') + } else { + this.submit() + } + }, + + cancel() { + this.show_write_dialog = false + this.show_modify_dialog = false + this.show_delete_confirm_dialog = false + this.image = null + this.image_url = null + this.can = 0 + this.is_active = null + this.selected_signature_can = {} + }, + + showDeleteConfirm(item) { + this.selected_signature_can = item + this.show_delete_confirm_dialog = true + }, + + showModifyDialog(item) { + this.image_url = item.image + this.selected_signature_can = item + this.show_modify_dialog = true + }, + + async getSignatureList() { + this.isLoading = true + + try { + let res = await api.getSignatureList(this.page); + + if (res.status === 200 && res.data.success === true) { + const data = res.data.data + + const total_page = Math.ceil(data.totalCount / 20) + this.signature_list = data.items + + if (total_page <= 0) + this.total_page = 1 + else + this.total_page = total_page + } + } catch (e) { + this.notifyError("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.") + } finally { + this.isLoading = false + } + }, + + async submit() { + if (this.is_loading) return; + + this.is_loading = true + + try { + const formData = new FormData() + formData.append("can", this.can) + formData.append("image", this.image) + + const res = await api.createSignature(formData) + if (res.status === 200 && res.data.success === true) { + this.cancel() + this.notifySuccess(res.data.message || '등록되었습니다.') + + this.page = 1 + await this.getSignatureList() + } else { + this.is_loading = false + this.notifyError(res.data.message || '알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.') + } + } catch (e) { + this.notifyError('알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.') + this.is_loading = false + } finally { + this.is_loading = false + } + }, + + async modifySignatureCan() { + if (this.image === null) { + this.notifyError('수정사항이 없습니다.') + return; + } + + if (this.is_loading) return; + + this.is_loading = true + + try { + const formData = new FormData() + formData.append("id", this.selected_signature_can.id) + formData.append("image", this.image) + + const res = await api.modifySignature(formData) + if (res.status === 200 && res.data.success === true) { + this.cancel() + this.notifySuccess(res.data.message || '수정되었습니다.') + + this.page = 1 + await this.getSignatureList() + } else { + this.is_loading = false + this.notifyError(res.data.message || '알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.') + } + } catch (e) { + this.notifyError('알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.') + this.is_loading = false + } finally { + this.is_loading = false + } + }, + + async deleteSignature() { + if (this.is_loading) return; + + this.is_loading = true + + try { + const formData = new FormData() + formData.append("id", this.selected_signature_can.id) + formData.append("isActive", false) + + const res = await api.modifySignature(formData) + if (res.status === 200 && res.data.success === true) { + this.cancel() + this.notifySuccess(res.data.message || '등록되었습니다.') + + this.page = 1 + await this.getSignatureList() + } else { + this.is_loading = false + this.notifyError(res.data.message || '알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.') + } + } catch (e) { + this.notifyError('알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.') + this.is_loading = false + } finally { + this.is_loading = false + } + }, + + async next() { + await this.getSignatureList(); + } + } +} +</script> + +<style scoped> +.image-select label { + display: inline-block; + padding: 10px 20px; + background-color: #232d4a; + color: #fff; + vertical-align: middle; + font-size: 15px; + cursor: pointer; + border-radius: 5px; +} + +.v-file-input { + position: absolute; + width: 0; + height: 0; + padding: 0; + overflow: hidden; + border: 0; +} + +.image-preview { + max-width: 100%; + width: 250px; + object-fit: cover; + margin-top: 10px; +} + +.v-card__text { + margin-top: 20px; +} + +.v-card__actions { + margin-top: 100px; +} + +.v-card__actions > .v-btn { + font-size: 20px; + +} + +.center-image { + display: block; + margin: 0 auto; +} +</style>