This commit is contained in:
2026-04-07 14:50:23 +09:00
commit b4e485502b
4778 changed files with 2017091 additions and 0 deletions

View File

@@ -0,0 +1,372 @@
<template>
<!-- Comments-->
<section aria-labelledby="notes-title">
<div
class="border border-gray-300 shadow sm:rounded-lg sm:overflow-hidden"
>
<div class="divide-y divide-gray-200">
<div class="px-4 py-5 sm:px-6">
<h2
id="notes-title"
class="text-lg font-medium text-gray-900"
>
{{ title }}
</h2>
</div>
<div class="px-4 py-6 sm:px-6">
<ul role="list" class="space-y-8">
<li
v-for="commentItem in listData"
:key="commentItem.serial"
>
<div class="flex space-x-3">
<div class="flex-shrink-0 items-center">
<BaseAvater1
:image-size="2"
:image-url="commentItem.profile_url"
/>
</div>
<div>
<div class="text-sm">
<a
:href="
'/user/profile/' +
commentItem.pid
"
class="font-medium text-gray-900"
>{{ commentItem.nick }}</a
>
</div>
<div
class="mt-1 text-sm text-gray-700 break-all"
>
<p>{{ commentItem.comment }}</p>
</div>
<div class="mt-2 text-sm space-x-2">
<span
class="text-gray-500 font-medium"
>{{
$dayjs(
commentItem.created
).fromNow()
}}</span
>
{{ ' ' }}
<span
v-if="!readOnlyFlag"
class="text-gray-500 font-medium"
>&middot;</span
>
{{ ' ' }}
<span
v-if="commentItem.like_count != 0"
class="text-gray-500 font-medium"
>{{
'좋아요 ' +
_utils.formatNumberInBytesStyle(
commentItem.like_count,
0
) +
'개'
}}</span
>
<span
v-if="
commentItem.dislike_count != 0
"
class="text-gray-500 font-medium"
>{{
'싫어요 ' +
_utils.formatNumberInBytesStyle(
commentItem.dislike_count,
0
) +
'개'
}}</span
>
<span
v-if="commentItem.report_count != 0"
class="text-gray-500 font-medium"
>{{
'신고 ' +
_utils.formatNumberInBytesStyle(
commentItem.report_count,
0
) +
'개'
}}</span
>
<button
v-if="
commentItem.myFlag == true &&
!readOnlyFlag
"
type="button"
class="text-gray-900 font-medium"
@click="
doAction(
'delete',
commentItem.cid
)
"
>
삭제
</button>
<button
v-if="!readOnlyFlag"
type="button"
class="text-gray-900 font-medium"
@click="
doAction(
'like',
commentItem.cid
)
"
>
좋아요
</button>
<button
v-if="!readOnlyFlag"
type="button"
class="text-gray-900 font-medium"
@click="
doAction(
'dislike',
commentItem.cid
)
"
>
싫어요
</button>
<button
v-if="!readOnlyFlag"
type="button"
class="text-gray-900 font-medium"
@click="
doAction(
'report',
commentItem.cid
)
"
>
신고
</button>
<button
v-if="!readOnlyFlag"
type="button"
class="text-gray-900 font-medium"
@click="
doAction(
'cancel',
commentItem.cid
)
"
>
신고 취소
</button>
</div>
</div>
</div>
</li>
<li v-if="listData.length == 0">
<div>등록된 댓글이 없습니다.</div>
</li>
</ul>
</div>
<BasePagination1
class="mb-5 px-4 sm:px-6"
:total-page-count="totalPageCount"
:current-page-number="currentPageNumber"
:page-size="pageSize"
:records-total="recordsTotal"
:page-move="pageMove"
/>
</div>
<div v-if="!readOnlyFlag" class="bg-gray-50 px-4 py-6 sm:px-6">
<div class="flex space-x-3">
<div class="flex-shrink-0">
<BaseUserProfileImage :image-size="2" />
</div>
<div class="min-w-0 flex-1">
<form>
<div>
<label for="comment" class="sr-only">{{
title
}}</label>
<textarea
id="comment"
v-model="comment"
style="resize: none"
name="comment"
rows="3"
class="shadow-sm block w-full focus:ring-blue-500 focus:border-blue-500 sm:text-sm border border-gray-300 rounded-md"
placeholder="댓글 내용을 입력하세요."
/>
</div>
<div class="mt-3 flex items-center justify-between">
<a
href="#"
class="group inline-flex items-start text-sm space-x-2 text-gray-500 hover:text-gray-900"
>
<QuestionMarkCircleIcon
class="flex-shrink-0 h-5 w-5 text-gray-400 group-hover:text-gray-500"
aria-hidden="true"
/>
<span>
모욕적인 표현이 포함된 댓글은 등록이
거부될 수 있습니다.
</span>
</a>
<button
type="button"
class="inline-flex items-center justify-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
@click="addComment()"
>
댓글 등록
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</section>
</template>
<script setup lang="ts">
import { QuestionMarkCircleIcon } from '@heroicons/vue/24/solid';
const comment = ref('');
const props = defineProps({
tid: { type: String, required: true },
title: { type: String, default: '댓글' },
readOnlyFlag: { type: Boolean, required: true },
});
// console.log('huk props = ', props);
const title = ref(props.title);
console.log('title = ', title.value);
const listData = ref([]);
const readOnlyFlag = ref(props.readOnlyFlag);
const totalPageCount = ref(1);
const currentPageNumber = ref(Number.MAX_SAFE_INTEGER);
const pageSize = ref(3);
const recordsTotal = ref(0);
function pageMove(targetPageIdex) {
// console.log('on pageMove(), targetPageIdex=', targetPageIdex);
currentPageNumber.value = targetPageIdex;
refresh();
}
async function addComment() {
if (comment.value.trim() != '') {
const responseJson = await _crossCtl.doComm('insert', 'comment', {
hero: props.tid,
comment: comment.value,
for: 'board',
});
if (responseJson['responseCode'] != 200) {
alert(responseJson['responseMessage']);
} else {
console.log('responseJson=', responseJson);
comment.value = '';
refresh();
}
}
}
async function refresh() {
if (props.tid != '') {
const responseJson = await _crossCtl.doComm('list', 'comment:active', {
hero: props.tid,
start: (currentPageNumber.value - 1) * pageSize.value,
length: pageSize.value,
});
if (responseJson['responseCode'] != 200) {
alert(responseJson['responseMessage']);
} else {
console.log('responseJson=', responseJson);
currentPageNumber.value = responseJson['currentPageNumber'];
totalPageCount.value = responseJson['totalPageCount'];
pageSize.value = parseInt(responseJson['pageSize']);
recordsTotal.value = responseJson['recordsTotal'];
listData.value = responseJson['data'];
}
}
}
if (props.tid != '' && _crossCtl.isAuthenticated) {
const responseJson = await _crossCtl.doComm('list', 'like', {
hero: props.tid,
start: 0,
length: -1,
});
if (responseJson['responseCode'] != 200) {
alert(responseJson['responseMessage']);
} else {
console.log('like responseJson=', responseJson);
refresh();
}
}
async function doAction(tag, target) {
console.log('in doAction(), tag =', tag, ', target =', target);
let tmpResponseJson = null;
switch (tag) {
case 'like':
case 'dislike':
tmpResponseJson = await _crossCtl.doComm('update', 'like', {
domain: props.tid,
hero: target,
for: 'comment',
tag: tag,
});
refresh();
break;
case 'report':
tmpResponseJson = await _crossCtl.doComm('update', 'report', {
domain: props.tid,
hero: target,
for: 'comment',
tag: tag,
});
refresh();
break;
case 'cancel':
tmpResponseJson = await _crossCtl.doComm('update', 'report', {
domain: props.tid,
hero: target,
for: 'comment',
tag: tag,
});
refresh();
break;
case 'delete':
tmpResponseJson = await _crossCtl.doComm('delete', 'comment', {
hero: target,
tid: props.tid,
from: 'board',
});
refresh();
break;
}
}
</script>