반응형
댓글의 삭제 버튼을 클릭하면 댓글을 삭제하는 걸 해보도록 하자. 뷰부터 수정한다.
/resources/views/boards/view.blade.php
@extends('boards.layout')
@section('header')
@include('boards.toptitle', ['toptitle'=>'게시판 보기', 'multi'=>$boards->multi])
@endsection
@section('content')
<table class="table table-striped table-hover">
<tbody>
<tr>
<th width="200">제목</th>
<td>{{ $boards->subject }}</td>
</tr>
<tr>
<td colspan="2">글쓴이 : {{ $boards->userid }} / 조회수 : {{ number_format($boards->cnt) }} / 등록일 : {{ $boards->regdate }}</td>
</tr>
<tr>
<th width="200">내용</th>
<td>{!! nl2br($boards->content) !!}</td>
</tr>
@if(count($attaches)>0)
<tr>
<th width="200">첨부 이미지</th>
<td>
<div class="row row-cols-1 row-cols-md-6 g-4" id="attachFiles" style="margin-left:0px;">
@foreach ($attaches as $att)
<div id='af_{{ $att->id }}' class='card h-100' style='width:120px;margin-right: 10px;margin-bottom: 10px;'><a href="#" onclick="window.open('/boards/imgpop/{{ $att->filename }}','imgpop','width=600,height=400,scrollbars=yes');"><img src='/images/{{ $att->filename }}' width='100' /></a></div>
@endforeach
</div>
</td>
</tr>
@endif
</tbody>
</table>
<div align="right">
@auth()
@if($boards->userid==auth()->user()->userid)
<a href="/boards/write/{{ $boards->multi }}/{{ $boards->bid }}"><button type="button" class="btn btn-secondary">수정</button></a>
<a href="/boards/delete/{{ $boards->bid }}/{{ $boards->pagenumber }}" class="btn btn-secondary" onclick="return confirm('삭제하시겠습니까?');">삭제</a>
@endif
@endauth
<a href="/boards/{{ $boards->multi }}/?page={{ $boards->pagenumber }}" class="btn btn-primary">목록</a>
</div>
<div style="padding:10px;">
</div>
<!--댓글 리스트 시작 -->
<div id="reply">
@foreach ($memos as $m)
<div class="card mt-2">
<div class="card-header p-2">
<table>
<tbody>
<tr class="align-middle">
<td rowspan="2" class="pr-2">
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" fill="currentColor" class="bi bi-chat-square-dots" viewBox="0 0 16 16">
<path d="M14 1a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1h-2.5a2 2 0 0 0-1.6.8L8 14.333 6.1 11.8a2 2 0 0 0-1.6-.8H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1zM2 0a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h2.5a1 1 0 0 1 .8.4l1.9 2.533a1 1 0 0 0 1.6 0l1.9-2.533a1 1 0 0 1 .8-.4H14a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z"/>
<path d="M5 6a1 1 0 1 1-2 0 1 1 0 0 1 2 0m4 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0m4 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0"/>
</svg>
</td>
<td class="ml">{{ $m->userid }}</td>
</tr>
<tr>
<td>
{{ disptime($m->created_at) }}
</td>
</tr>
</tbody>
</table>
</div>
<div class="card-body" id="{{ 'memolist_'.$m->id }}">
<p class="card-text">
@if($m->filename)
<img src='/images/{{ $m->filename }}' width='100' />
@endif
{!! nl2br($m->memo) !!}
</p>
@auth()
<span style="float:right;">
@if($m->userid==auth()->user()->userid)
<span class="badge bg-dark" style="cursor:pointer;padding:10px;"><a onclick="memo_modify('{{ $m->id }}')">수정</a></span>
<span class="badge bg-dark" style="cursor:pointer;padding:10px;"><a onclick="memo_delete('{{ $m->id }}','{{ $boards->bid }}')">삭제</a></span>
@endif
</span>
@endauth
</div>
</div>
@endforeach
</div>
<!-- 댓글 리스트 끝 -->
<!-- 댓글 입력 -->
<div class="input-group" id="firstmemo" style="margin-top:10px;margin-bottom:10px;">
<span class="input-group-text" id="memo_image_view" style="display:none;"></span>
<button type="button" id="attmemoimg" class="btn btn-secondary">이미지첨부</button>
<input type="hidden" name="memopid" id="memopid" value="{{ time() }}">
<input type="hidden" name="modimemoid" id="modimemoid" value="0">
<input type="hidden" name="memo_file" id="memo_file">
<input type="file" name="upfile" id="upfile" accept="image/*" style="display:none;">
<textarea class="form-control" aria-label="With textarea" style="height:100px;" name="memo" id="memo" placeholder="댓글을 입력해주세요"></textarea>
@auth()
<button type="button" class="btn btn-secondary" style="float:right;" id="memo_submit" onclick="memoup()">입력</button>
@else
<button type="button" class="btn btn-secondary" style="float:right;" id="memo_submit" onclick="alert('로그인 하셔야 입력할 수 있습니다.');">입력</button>
@endauth
</div>
<!-- 댓글 입력 끝-->
<div style="padding:20px;">
</div>
<script>
function memoup(){
var memo=$("#memo").val();
var memo_file=$("#memo_file").val();
var data = {
memo : memo,
memo_file : memo_file,
bid : {{ $boards->bid }}
};
$.ajax({
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
type: 'post',
url: '{{ route('boards.memoup') }}',
dataType: 'json',
data: data,
success: function(data) {
location.reload();
},
error: function(data) {
console.log("error" +JSON.stringify(data));
}
});
}
function memoatt(m){
$("#modimemoid").val(m);
$('#upfile').click();
}
$("#attmemoimg").click(function () {
$('#upfile').click();
});
$("#upfile").change(function(){
var formData = new FormData();
var files = $('#upfile').prop('files');
for(var i=0; i < files.length; i++) {
attachFile(files[i]);
}
});
function attachFile(file) {
var memopid = $("#memopid").val();
var modimemoid = $("#modimemoid").val();
console.log("modimemoid:"+modimemoid);
var formData = new FormData();
formData.append("file", file);
formData.append("pid", memopid);
formData.append("code", "memoattach");
formData.append("modimemoid", modimemoid);
$.ajax({
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
url: '{{ route('boards.saveimage') }}',
data: formData,
cache: false,
contentType: false,
processData: false,
dataType : 'json' ,
type: 'POST',
success: function (return_data) {
var html = "<img src='/images/"+return_data.fn+"' style='max-width:100%;height:88px;'>";
if(modimemoid>0){
$("#modi_att_view_"+modimemoid).html(html);
$("#modi_att_view_"+modimemoid).show();
$("#modimemoimg_"+modimemoid).hide();
}else{
$("#memo_image_view").html(html);
$("#memo_image_view").show();
$("#attmemoimg").hide();
$("#memo_file").val(return_data.fn);
}
}
, beforeSend: function () {
if(modimemoid>0){
$("#modimemoimg_"+modimemoid).hide();
$("#modi_att_view_"+modimemoid).show();
$('#modi_att_view_'+modimemoid).html('<div class="spinner-border text-dark" role="status"><span class="visually-hidden">Loading...</span></div>');
}else{
$("#attmemoimg").hide();
$("#memo_image_view").show();
$('#memo_image_view').html('<div class="spinner-border text-dark" role="status"><span class="visually-hidden">Loading...</span></div>');
}
}
, complete: function () {
}
});
}
function memo_modify(m){
var data = {
memoid : m
};
$.ajax({
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
type: 'post',
url: '{{ route('boards.memomodi') }}',
dataType: 'json',
data: data,
success: function(data) {
if(data.attfile == true){
var html='<div class="input-group" id="modifymemo" style="margin-top:10px;margin-bottom:10px;"><div id="af_'+data.att.id+'" class="card h-100" style="text-align:center;"><img src="/images/'+data.att.filename+'" width="80" /><a href="javascript:;" onclick=\'memodeletefile("'+data.att.filename+'","'+data.att.id+'","'+data.att.pid+'")\'><span class="badge text-bg-warning">삭제</span></a></div><input type="hidden" name="memopid" id="memopid" value="'+m+'"><input type="hidden" name="memo_modi_file" id="memo_modi_file"><textarea class="form-control" aria-label="With textarea" style="height:100px;" name="memomodify_'+m+'" id="memomodify_'+m+'">'+data.memos.memo+'</textarea><button type="button" class="btn btn-secondary" style="float:right;" id="memo_modifyup" onclick="memomodifyup('+m+')">수정</button></div>';
}else{
var html='<div class="input-group" id="modifymemo" style="margin-top:10px;margin-bottom:10px;"><span class="input-group-text" id="modi_att_view_'+m+'" style="display:none;"></span><button type="button" id="modimemoimg_'+m+'" class="btn btn-secondary" onclick="memoatt('+m+')">이미지첨부</button><input type="hidden" name="memopid" id="memopid" value="'+m+'"><input type="hidden" name="memo_modi_file" id="memo_modi_file"><textarea class="form-control" aria-label="With textarea" style="height:100px;" name="memomodify_'+m+'" id="memomodify_'+m+'">'+data.memos.memo+'</textarea><button type="button" class="btn btn-secondary" style="float:right;" id="memo_modifyup" onclick="memomodifyup('+m+')">수정</button></div>';
}
$("#memolist_"+m).html(html);
},
error: function(data) {
console.log("error" +JSON.stringify(data));
}
});
}
function memomodifyup(m){
var memo=$("#memomodify_"+m).val();
var data = {
memo : memo,
memoid : m
};
$.ajax({
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
type: 'post',
url: '{{ route('boards.memomodifyup') }}',
dataType: 'json',
data: data,
success: function(data) {
location.reload();
},
error: function(data) {
console.log("error" +JSON.stringify(data));
}
});
}
function memodeletefile(fn,fid,pid){
if(!confirm('삭제하시겠습니까?')){
return false;
}
var data = {
fn : fn,
fid : fid,
pid : pid
};
$.ajax({
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
type: 'post',
url: '{{ route('boards.memodeletefile') }}',
dataType: 'json',
data: data,
success: function(data) {
alert("삭제했습니다.");
memo_modify(pid);
},
error: function(data) {
console.log("error" +JSON.stringify(data));
}
});
}
function memo_delete(m, b){
if(!confirm('삭제하시겠습니까?')){
return false;
}
var data = {
id : m,
bid : b
};
$.ajax({
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
type: 'post',
url: '{{ route('boards.memodelete') }}',
dataType: 'json',
data: data,
success: function(data) {
location.reload();
},
error: function(data) {
console.log("error" +JSON.stringify(data));
}
});
}
</script>
@endsection
이제 라우터와 콘트롤러를 추가해보자.
/routes/web.php
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\BoardController;
use App\Http\Controllers\MemberController;
Route::get('/', function () {
return view('welcome');
});
//게시판
Route::get('/boards/{multi?}', [BoardController::class, 'index'])->name('boards.index');
Route::get('/boards/show/{id}/{page}', [BoardController::class, 'show'])->name('boards.show');
Route::middleware('auth') -> group(function (){
Route::get('/boards/write/{multi}/{bid?}', [BoardController::class, 'write'])->name('boards.write');
Route::post('/boards/create', [BoardController::class, 'create'])->name('boards.create');
Route::post('/boards/saveimage', [BoardController::class, 'saveimage'])->name('boards.saveimage');
Route::post('/boards/deletefile', [BoardController::class, 'deletefile'])->name('boards.deletefile');
Route::get('/boards/imgpop/{imgfile}', [BoardController::class, 'imgpop'])->name('boards.imgpop');
Route::post('/boards/update', [BoardController::class, 'update'])->name('boards.update');
Route::get('/boards/delete/{bid}/{page}', [BoardController::class, 'delete'])->name('boards.delete');
Route::get('/boards/summernote/{multi}/{bid?}', [BoardController::class, 'summernote'])->name('boards.summernote');
Route::post('/boards/memoup', [BoardController::class, 'memoup'])->name('boards.memoup');
Route::post('/boards/memomodi', [BoardController::class, 'memomodi'])->name('boards.memomodi');
Route::post('/boards/memomodifyup', [BoardController::class, 'memomodifyup'])->name('boards.memomodifyup');
Route::post('/boards/memodeletefile', [BoardController::class, 'memodeletefile'])->name('boards.memodeletefile');
Route::post('/boards/memodelete', [BoardController::class, 'memodelete'])->name('boards.memodelete');
});
//회원
Route::get('/login', [MemberController::class, 'login'])->name('auth.login');
Route::get('/signup', [MemberController::class, 'signup'])->name('auth.signup');
Route::post('/signupok', [MemberController::class, 'signupok'])->name('auth.signupok');
Route::post('/emailcheck', [MemberController::class, 'emailcheck'])->name('auth.emailcheck');
Route::post('/loginok', [MemberController::class, 'loginok']) -> name('auth.loginok');
Route::post('/logout', [MemberController::class, 'logout']) -> name('auth.logout');
/app/Http/Controllers/BoardController.php
public function memodelete(Request $request)
{
$data = Memos::findOrFail($request->id);
if(Auth::user()->userid==$data->userid){
$rs = Memos::where('id', $request->id)->update(array('status' => 0));
if($rs){
Board::find($request->bid)->decrement('memo_cnt');
$fs=FileTables::where('pid', $data->id)->get();
if($fs){
foreach($fs as $f){
if(FileTables::where('id', $f->id)->where('userid', Auth::user()->userid)->update(array('status' => 0))){
unlink(public_path('images')."/".$f->filename);
}
}
}
}
return response()->json(array('msg'=> "succ", 'num'=>$rs), 200);
}else{
return response()->json(array('msg'=> "fail"), 200);
}
}
메모 테이블에서 status를 0으로 바꾸고 첨부한 파일이 있으면 파일을 삭제하고 파일 테이블에서 status를 0으로 바꿔주면 된다.
다음시간엔 댓글에 댓글을 다는걸 해보자. 일명 대댓글이란걸 해보려고 한다.
반응형
'PHP강좌 > [라라벨]게시판만들기강좌' 카테고리의 다른 글
[라라벨+mysql]게시판 만들기 강좌 #29. 함수를 이용해서 새글, 첨부파일, 댓글 수 표시 (0) | 2024.08.13 |
---|---|
[라라벨+mysql]게시판 만들기 강좌 #28. 대댓글 (0) | 2024.08.13 |
[라라벨+mysql]게시판 만들기 강좌 #26. 댓글 수정하기 2/2 (0) | 2024.08.09 |
[라라벨+mysql]게시판 만들기 강좌 #25. 댓글 수정하기 1/2 (0) | 2024.08.07 |
[라라벨+mysql]게시판 만들기 강좌 #24. 댓글에 첨부한 이미지 표시 (0) | 2024.08.06 |