localhost-front/src/components/wordDict/DictCard.vue
2025-04-04 14:04:10 +09:00

186 lines
5.7 KiB
Vue

<template>
<li class="card p-5 mb-2">
<DictWrite
v-if="writeStore.isItemActive(item.WRDDICSEQ)"
@close="writeStore.closeAll();"
:dataList="cateList"
@addWord="editWord"
:NumValue="item.WRDDICSEQ"
:formValue="item.WRDDICCAT"
:titleValue="item.WRDDICTTL"
:contentValue="item.WRDDICCON"
:isDisabled="true"
:showEditBtn="true"
@toggleEdit="toggleEdit"
/>
<div v-else>
<div class="d-flex align-items-center justify-content-between">
<div class="d-flex align-items-center">
<span class="btn btn-primary pe-none m-1"
style="writing-mode: horizontal-tb;">{{ item.category }}</span>
{{ item.WRDDICTTL }}
</div>
<EditBtn
@click="toggleEdit"
:isToggleEnabled="true"
:isActive="writeStore.isItemActive(item.WRDDICSEQ)"
/>
</div>
<p class="mt-5 dict-content-wrap" v-html="$common.contentToHtml(item.WRDDICCON)"></p>
<div class="d-flex align-items-start">
<!-- 최초 작성자 -->
<div class="d-flex flex-wrap align-items-center me-4">
<div class="avatar me-2">
<img
class="rounded-circle user-avatar"
:src="getProfileImage(item.author.profileImage)"
alt="최초 작성자"
:style="{ borderColor: item.author.color }"
@error="setDefaultImage"
/>
</div>
<div>
<p class="mb-0 small fw-medium">{{ $common.dateFormatter(item.author.createdAt) }}</p>
</div>
</div>
<!-- 최근 작성자 (조건부) -->
<div
v-if="item.author.createdAt !== item.lastEditor.updatedAt"
class="d-flex flex-wrap align-items-center"
>
<div class="avatar me-2">
<img
class="rounded-circle user-avatar"
:src="getProfileImage(item.lastEditor.profileImage)"
alt="최근 작성자"
:style="{ borderColor: item.lastEditor.color }"
@error="setDefaultImage"
/>
</div>
<div>
<p class="mb-0 small fw-medium">{{ $common.dateFormatter(item.lastEditor.updatedAt) }}</p>
</div>
</div>
</div>
</div>
</li>
</template>
<script setup>
import axios from "@api";
import { useToastStore } from '@s/toastStore';
import { getCurrentInstance, nextTick, ref } from 'vue';
import EditBtn from '@/components/button/EditBtn.vue';
import $api from '@api';
import DictWrite from './DictWrite.vue';
import { useUserInfoStore } from '@s/useUserInfoStore';
import { useWriteVisibleStore } from '@s/writeVisible';
const writeStore = useWriteVisibleStore();
const writeButton = ref(null);
// 유저 구분
const userStore = useUserInfoStore();
const toastStore = useToastStore();
const { appContext } = getCurrentInstance();
const $common = appContext.config.globalProperties.$common;
// Props
const props = defineProps({
item: {
type: Object,
required: true
},
cateList: {
type: Array,
required: false,
}
});
// cateList emit
const emit = defineEmits(['update:cateList','refreshWordList', 'updateChecked']);
// 용어집 수정
const editWord = (data) => {
if (!data.id) {
console.error('❌ 수정할 데이터의 ID가 없습니다.');
toastStore.onToast('수정할 용어의 ID가 필요합니다.', 'e');
return;
}
axios.patch('worddict/updateWord', {
WRDDICSEQ: data.id,
WRDDICCAT: data.category,
WRDDICTTL: data.title,
WRDDICCON: $common.deltaAsJson(data.content),
})
.then((res) => {
if (res.data.data === 1) {
toastStore.onToast('용어가 수정되었습니다.', 's');
writeStore.closeAll();
if (writeButton.value) {
writeButton.value.resetButton();
}
emit('refreshWordList',data.category);
} else {
console.warn('⚠️ 서버 응답이 예상과 다릅니다:', res.data);
toastStore.onToast('용어 수정이 정상적으로 처리되지 않았습니다.', 'e');
}
})
.catch((err) => {
console.error('❌ 용어 수정 중 오류 발생:', err.response?.data || err.message);
toastStore.onToast(`용어 수정 실패: ${err.response?.data?.message || '알 수 없는 오류'}`, 'e');
});
};
const baseUrl = $api.defaults.baseURL.replace(/api\/$/, '');
// 프로필 이미지
const defaultProfile = "/img/icons/icon.png";
const getProfileImage = (profilePath) => {
return profilePath && profilePath.trim() ? `${baseUrl}upload/img/profile/${profilePath}` : defaultProfile;
};
const setDefaultImage = (event) => {
event.target.src = defaultProfile;
};
const toggleEdit = async () => {
writeStore.toggleItem(props.item.WRDDICSEQ);
};
</script>
<style scoped>
.avatar {
cursor: default;
}
.user-avatar {
border: 3px solid;
padding: 0.1px;
}
.edit-btn {
position: absolute;
right: 0.7rem;
top: 1.2rem;
}
.admin-chk {
position: absolute;
left: -0.5rem;
top: -0.5rem;
--bs-form-check-bg: #fff;
}
.btn.btn-primary {
writing-mode: horizontal-tb;
}
</style>