vue: board

This commit is contained in:
2021-09-05 17:52:39 +09:00
parent 9871559227
commit 53df6bbcc6
7 changed files with 197 additions and 69 deletions
+116 -46
View File
@@ -18,56 +18,61 @@
type="text"
maxlength="250"
placeholder="제목"
v-model="newArticle.title"
/>
</td>
</tr>
<tr>
<th class="bg1">내용</th>
<td class="boardArticle">
<textarea class="contentInput autosize" placeholder="내용"></textarea>
<textarea
class="contentInput autosize"
ref="newArticleTextForm"
placeholder="내용"
v-model="newArticle.text"
@input="autoResizeTextarea"
/>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="2">
<button type="button" id="submitArticle">등록</button>
<button type="button" id="submitArticle" @click="submitArticle">
등록
</button>
</td>
</tr>
</tfoot>
</table>
<div id="board">
<!--<suspense>
<template #default>-->
<board-article
v-for="article in articles"
:key="article.no"
:article="article"
/>
<!--</template>
<template #fallback>
<span>불러오는 중입니다...</span>
</template>
</suspense>-->
<template v-if="articles && articles.length">
<board-article
v-for="article in articles"
:key="article.no"
:article="article"
@submit-comment="reloadArticles"
/>
</template>
<template v-else> 게시물이 없습니다. </template>
</div>
</template>
<script lang="ts">
import { defineComponent, PropType, reactive, toRef } from "vue";
import "../scss/bootstrap5.scss";
import "../scss/inheritPoint.scss";
import "../scss/game_bg.scss";
import "../../css/config.css";
import { defineComponent, onMounted, reactive, ref } from "vue";
import TopBackBar from "./components/TopBackBar.vue";
import BoardArticle from "./components/BoardArticle.vue";
import _, { isArray } from "lodash";
import { ref } from "vue";
import axios from "axios";
import { convertFormData } from "./util/convertFormData";
import axios from "axios";
import { InvalidResponse } from "./defs";
import { delay } from "./util/delay";
declare const isSecretBoard: boolean;
import { autoResizeTextarea } from "./util/autoResizeTextarea";
import { unwrap } from "./util/unwrap";
export type BoardResponse = {
result: true;
articles: Record<number, BoardArticleItem>;
@@ -103,36 +108,101 @@ export default defineComponent({
TopBackBar,
BoardArticle,
},
async setup() {
let boardResponse: BoardResponse;
try {
const response = await axios({
url: "j_board_get_articles.php",
responseType: "json",
method: "post",
data: convertFormData({
isSecret: isSecretBoard,
}),
});
const result: InvalidResponse | BoardResponse = response.data;
if (!result.result) {
throw result.reason;
props: {
isSecretBoard: {
type: Boolean,
required: true,
},
},
data() {
return {
title: this.isSecretBoard ? "기밀실" : "회의실",
newArticle: {
title: "",
text: "",
},
};
},
methods: {
autoResizeTextarea,
async submitArticle() {
const { title, text } = this.newArticle;
if (!title && !text) {
return;
}
boardResponse = result;
} catch (e) {
console.error(e);
alert(`에러: ${e}`);
return;
}
//const articles = reactive();
console.log(boardResponse);
const articles:BoardResponse['articles'] = isArray(boardResponse.articles)?{}:boardResponse;
let result: InvalidResponse;
try {
const response = await axios({
url: "j_board_article_add.php",
method: "post",
responseType: "json",
data: convertFormData({
isSecret: this.isSecretBoard,
title,
text,
}),
});
result = response.data;
if (!result.result) {
throw result.reason;
}
} catch (e) {
console.error(e);
alert(`실패했습니다. :${e}`);
return;
}
this.newArticle = { title: "", text: "" };
const newArticleTextForm = unwrap(this.newArticleTextForm);
newArticleTextForm.style.height = 'auto';
await this.reloadArticles();
},
},
setup(props) {
const newArticleTextForm = ref<HTMLInputElement>();
const articles = reactive<BoardArticleItem[]>([]);
const reloadArticles = async () => {
let boardResponse: BoardResponse;
try {
const response = await axios({
url: "j_board_get_articles.php",
responseType: "json",
method: "post",
data: convertFormData({
isSecret: props.isSecretBoard,
}),
});
const result: InvalidResponse | BoardResponse = response.data;
if (!result.result) {
throw result.reason;
}
boardResponse = result;
} catch (e) {
console.error(e);
alert(`에러: ${e}`);
return;
}
articles.length = 0;
articles.push(...Object.values(boardResponse.articles));
articles.reverse();
};
onMounted(async () => {
await reloadArticles();
});
return {
title: isSecretBoard ? "기밀실" : "회의실",
newArticleTextForm,
articles,
reloadArticles,
};
},
});
+62 -16
View File
@@ -2,15 +2,22 @@
<table class="articleFrame bg0">
<thead>
<tr class="bg1">
<th class="authorName"></th>
<th class="articleTitle"></th>
<th class="date"></th>
<th class="authorName">{{ article.author }}</th>
<th class="articleTitle">{{ article.title }}</th>
<th class="date">{{ article.date }}</th>
</tr>
</thead>
<tbody>
<tr>
<td><img class="authorIcon generalIcon" width="64" height="64" /></td>
<td class="text" colspan="2"></td>
<td>
<img
class="authorIcon generalIcon"
width="64"
height="64"
:src="article.author_icon"
/>
</td>
<td class="text" colspan="2">{{ article.text }}</td>
</tr>
</tbody>
<tbody class="commentList">
@@ -29,19 +36,26 @@
type="text"
maxlength="250"
placeholder="새 댓글 내용"
:value="newCommentText"
v-model.trim="newCommentText"
@keyup.enter="submitComment"
/>
</td>
<td><button type="button" class="submitComment">등록</button></td>
<td>
<button type="button" class="submitComment" @click="submitComment">
등록
</button>
</td>
</tr>
</tfoot>
</table>
</template>
<script lang="ts">
import { BoardArticleItem } from "board.vue";
import { BoardArticleItem } from "../Board.vue";
import BoardComment from "./BoardComment.vue";
import { defineComponent, PropType } from "vue";
import axios from "axios";
import { convertFormData } from "../util/convertFormData";
import { InvalidResponse } from "../defs";
export default defineComponent({
name: "BoardArticle",
components: {
@@ -58,15 +72,47 @@ export default defineComponent({
required: true,
},
},
emits: ["submit-comment"],
methods: {
submitComment() {
console.log(this.newCommentText);
async submitComment() {
const comment = this.newCommentText;
if (!comment) {
return;
}
const articleNo = this.article.no;
let result: InvalidResponse;
try {
const response = await axios({
url: "j_board_comment_add.php",
method: "post",
responseType: "json",
data: convertFormData({
articleNo: articleNo,
text: comment,
}),
});
result = response.data;
if (!result.result) {
throw result.reason;
}
} catch (e) {
console.error(e);
alert(`실패했습니다: ${e}`);
return;
}
this.newCommentText = "";
this.$emit("submit-comment");
},
},
/*
setup(props) {
toRef(props, "article");
},
*/
});
</script>
<style>
td.text {
white-space: pre;
}
</style>
+1 -1
View File
@@ -7,7 +7,7 @@
</tr>
</template>
<script lang="ts">
import { BoardCommentItem } from "board.vue";
import { BoardCommentItem } from "../Board.vue";
import { defineComponent, PropType } from "vue";
export default defineComponent({
+7
View File
@@ -0,0 +1,7 @@
import { unwrap } from "./unwrap";
export function autoResizeTextarea(e: InputEvent): void {
const el = unwrap(e.target) as HTMLInputElement;
el.style.height = 'auto';
el.style.height = `${el.scrollHeight + 1}px`;
}
+6 -1
View File
@@ -2,5 +2,10 @@ import { createApp } from 'vue'
import Board from './Board.vue';
import { setAxiosXMLHttpRequest } from './util/setAxiosXMLHttpRequest';
declare const isSecretBoard: boolean;
setAxiosXMLHttpRequest();
createApp(Board).mount('#app')
createApp(Board, {
isSecretBoard
}).mount('#app')
+3 -3
View File
@@ -45,9 +45,9 @@ $boardName = $isSecretBoard ? '기밀실' : '회의실';
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" />
<?= WebUtil::printCSS('dist_css/common_vue.css') ?>
<?= ""??WebUtil::printCSS('dist_css/v_board.css') ?>
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printJS('dist_js/vendors_vue.js') ?>
<?= WebUtil::printCSS('dist_css/v_board.css') ?>
<?= WebUtil::printJS('../d_shared/common_path.js', true) ?>
<?= WebUtil::printJS('dist_js/vendors_vue.js', true) ?>
<?= WebUtil::printJS('dist_js/v_board.js', true) ?>
<?= WebUtil::printStaticValues([
'isSecretBoard' => $isSecretBoard,
+2 -2
View File
@@ -30,8 +30,8 @@ foreach (array_keys(General::INHERITANCE_KEY) as $key) {
<meta name="viewport" content="width=1024" />
<?= WebUtil::printCSS('dist_css/common_vue.css') ?>
<?= WebUtil::printCSS('dist_css/v_inheritPoint.css') ?>
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printJS('dist_js/vendors_vue.js') ?>
<?= WebUtil::printJS('../d_shared/common_path.js', true) ?>
<?= WebUtil::printJS('dist_js/vendors_vue.js', true) ?>
<?= WebUtil::printJS('dist_js/v_inheritPoint.js', true) ?>
<?= WebUtil::printStaticValues([
'items' => $items