feat: 국방, 임관메시지 에디터에 TipTap 적용

This commit is contained in:
2021-12-13 02:03:54 +09:00
parent 34321ad89f
commit cafde950a4
6 changed files with 342 additions and 18 deletions
+4 -4
View File
@@ -7,8 +7,8 @@ include "func.php";
// $btn, $msg, $scoutmsg, $rate, $bill, $secretlimit
$btn = Util::getPost('btn');
$msg = Util::getPost('msg');
$scoutmsg = Util::getPost('scoutMsg');
//$msg = Util::getPost('msg');
//$scoutmsg = Util::getPost('scoutMsg');
$rate = Util::getPost('rate', 'int');
$bill = Util::getPost('bill', 'int');
$secretlimit = Util::getPost('secretlimit', 'int');
@@ -34,14 +34,14 @@ if ($permission < 0) {
$nationID = $me['nation'];
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
if ($btn == "국가방침 수정") {
/*if ($btn == "국가방침 수정") {
$msg = mb_substr($msg, 0, 16384);
//$msg = StringUtil::
$nationStor->notice = WebUtil::htmlPurify($msg);
} elseif ($btn == "임관 권유문 수정") {
$scoutmsg = mb_substr($scoutmsg, 0, 1000);
$nationStor->scout_msg = WebUtil::htmlPurify($scoutmsg);
} elseif ($btn == "세율") {
} else*/if ($btn == "세율") {
$rate = Util::valueFit($rate, 5, 30);
$db->update('nation', [
'rate' => $rate,
+58
View File
@@ -0,0 +1,58 @@
<?php
namespace sammo\API\Nation;
use sammo\Session;
use DateTimeInterface;
use sammo\DB;
use sammo\KVStorage;
use sammo\Validator;
use sammo\WebUtil;
use function sammo\checkSecretPermission;
class SetNotice extends \sammo\BaseAPI
{
public function validateArgs(): ?string
{
$v = new Validator($this->args);
$v->rule('required', [
'msg',
])->rule('lengthMax', 'msg', 16384);
if (!$v->validate()) {
return $v->errorStr();
}
return null;
}
public function getRequiredSessionMode(): int
{
return static::REQ_GAME_LOGIN | static::REQ_READ_ONLY;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
{
$msg = $this->args['msg'];
$userID = $session->userID;
$db = DB::db();
$me = $db->queryFirstRow('SELECT `no`,nation,`officer_level`,permission,penalty FROM general WHERE `owner`=%i', $userID);
$permission = checkSecretPermission($me, false);
if($permission < 0){
return "권한이 부족합니다.";
}
if ($me['officer_level'] < 5 && $permission != 4){
return "권한이 부족합니다.";
}
$nationID = $me['nation'];
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
$nationStor->notice = WebUtil::htmlPurify($msg);
return [
'result' => true
];
}
}
+58
View File
@@ -0,0 +1,58 @@
<?php
namespace sammo\API\Nation;
use sammo\Session;
use DateTimeInterface;
use sammo\DB;
use sammo\KVStorage;
use sammo\Validator;
use sammo\WebUtil;
use function sammo\checkSecretPermission;
class SetScoutMsg extends \sammo\BaseAPI
{
public function validateArgs(): ?string
{
$v = new Validator($this->args);
$v->rule('required', [
'msg',
])->rule('lengthMax', 'msg', 1000);
if (!$v->validate()) {
return $v->errorStr();
}
return null;
}
public function getRequiredSessionMode(): int
{
return static::REQ_GAME_LOGIN | static::REQ_READ_ONLY;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
{
$msg = $this->args['msg'];
$userID = $session->userID;
$db = DB::db();
$me = $db->queryFirstRow('SELECT `no`,nation,`officer_level`,permission,penalty FROM general WHERE `owner`=%i', $userID);
$permission = checkSecretPermission($me, false);
if($permission < 0){
return "권한이 부족합니다.";
}
if ($me['officer_level'] < 5 && $permission != 4){
return "권한이 부족합니다.";
}
$nationID = $me['nation'];
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
$nationStor->scout_msg = WebUtil::htmlPurify($msg);
return [
'result' => true
];
}
}
+84 -14
View File
@@ -1,53 +1,123 @@
<template>
<div> &amp; 임관 권유 메시지</div>
<div id="noticeForm"></div>
<!--<b-button>국가방침 수정</b-button><b-button>취소</b-button>-->
<!--<div id="noticeForm">
<div id="noticeForm">
<div class="bg1" style="display: flex; justify-content: space-around">
<div style="flex: 1 1 auto">국가 방침</div>
<div>
<b-button>국가방침 수정</b-button><b-button>취소</b-button>
<b-button
@click="enableEditNationMsg"
v-if="editable && !inEditNationMsg"
>국가방침 수정</b-button
>
<b-button @click="saveNationMsg" v-if="editable && inEditNationMsg"
>저장</b-button
>
<b-button v-if="editable && inEditNationMsg" @click="rollbackNationMsg"
>취소</b-button
>
</div>
</div>
<div class="edit_form viewer"></div>
<TipTap v-model="nationMsg" :editable="inEditNationMsg" />
</div>
<div id="scoutMsgForm">
<div class="bg1" style="display: flex; justify-content: space-around">
<div style="flex: 1 1 auto">임관 권유</div>
<div>
<b-button>임관 권유문 수정</b-button><b-button>취소</b-button>
<b-button
@click="enableEditScoutMsg"
v-if="editable && !inEditScoutMsg"
>임관 권유문 수정</b-button
>
<b-button @click="saveScoutMsg" v-if="editable && inEditScoutMsg"
>저장</b-button
>
<b-button v-if="editable && inEditScoutMsg" @click="rollbackScoutMsg"
>취소</b-button
>
</div>
</div>
<div style="border-bottom: solid gray 0.5px">
870px x 200px를 넘어서는 내용은 표시되지 않습니다.
</div>
<div style="width: 870px; margin-left: auto">
<div class="edit_form viewer"></div>
<TipTap v-model="scoutMsg" :editable="inEditScoutMsg" />
</div>
</div>!-->
</div>
</template>
<script lang="ts">
import "@scss/dipcenter.scss";
import "@scss/common_legacy.scss";
import { defineComponent } from "vue";
import TipTap from "./components/TipTap.vue";
import { defineComponent, reactive, ref } from "vue";
import { sammoAPI } from "./util/sammoAPI";
import { isString } from "lodash";
declare const editable: boolean;
declare const nationMsg: string;
declare const scoutMsg: string;
export default defineComponent({
name: "PartialDipcenter",
components: {},
components: {
TipTap,
},
data() {
console.log(editable, ",", nationMsg, ",", scoutMsg);
return {
editable,
oldNationMsg: nationMsg,
oldScoutMsg: scoutMsg,
nationMsg,
scoutMsg,
inEditNationMsg: false,
inEditScoutMsg: false,
};
},
/*methods: {},*/
methods: {
enableEditNationMsg() {
this.inEditNationMsg = true;
},
rollbackNationMsg() {
this.inEditNationMsg = false;
this.nationMsg = this.oldNationMsg;
},
async saveNationMsg() {
const msg = this.nationMsg;
try {
await sammoAPI("Nation/SetNotice", {
msg,
});
this.oldNationMsg = msg;
this.inEditNationMsg = false;
} catch (e) {
if (isString(e)) {
alert(e);
}
console.error(e);
}
},
enableEditScoutMsg() {
this.inEditScoutMsg = true;
},
rollbackScoutMsg() {
this.inEditScoutMsg = false;
this.scoutMsg = this.oldScoutMsg;
},
async saveScoutMsg() {
const msg = this.scoutMsg;
try {
await sammoAPI("Nation/SetScoutMsg", {
msg,
});
this.oldScoutMsg = msg;
this.inEditScoutMsg = false;
} catch (e) {
if (isString(e)) {
alert(e);
}
console.error(e);
}
},
},
});
</script>
+133
View File
@@ -0,0 +1,133 @@
<template>
<b-button-toolbar key-nav v-if="editable && editor" class="bg-dark">
<!-- 뒤로, 앞으로 -->
<b-button-group class="mx-1">
<b-button
@click="editor.chain().focus().toggleBold().run()"
:class="{ 'is-active': editor.isActive('bold') }"
><i class="bi bi-type-bold" v-b-tooltip.hover title="진하게"></i
></b-button>
<b-button
@click="editor.chain().focus().toggleItalic().run()"
:class="{ 'is-active': editor.isActive('italic') }"
><i class="bi bi-type-italic" v-b-tooltip.hover title="기울이기"></i
></b-button>
<!-- 밑줄, 효과 지우기 -->
</b-button-group>
<b-button-group class="mx-1">
<!-- 글꼴, 크기 -->
</b-button-group>
<b-button-group class="mx-1">
<b-button
@click="editor.chain().focus().toggleStrike().run()"
:class="{ 'is-active': editor.isActive('strike') }"
><i
class="bi bi-type-strikethrough"
v-b-tooltip.hover
title="가로선"
></i
></b-button>
<!-- 윗첨자, 아랫첨자 -->
</b-button-group>
<b-button-group class="mx-1">
<!-- 마지막으로 사용한 -->
<!-- 배경색, 글자색 -->
</b-button-group>
<b-button-group class="mx-1">
<!-- 이미지추가 -->
<!-- 링크 -->
<!-- 영상링크 -->
<!-- -->
<!-- 구분선 삽입 -->
</b-button-group>
<b-button-group class="mx-1">
<!-- 글머리 기호 -->
<!-- 번호 매기기 -->
<!-- 문단정렬(, , , )(내어, 들여) -->
</b-button-group>
<b-button-group class="mx-1">
<!-- 줄간격 (1.0, 1.2, 1.4, 1.5, 1.6, 1.8, 2.0, 3.0) -->
</b-button-group>
<b-button-group class="mx-1">
<!-- 원본 코드 -->
</b-button-group>
</b-button-toolbar>
<editor-content :editor="editor" />
</template>
<script lang="ts">
//import "@scss/common/bootstrap5.scss";
import { defineComponent } from "vue";
import { Editor, EditorContent } from "@tiptap/vue-3";
import StarterKit from "@tiptap/starter-kit";
import {BButtonGroup, BButtonToolbar, BButton} from "bootstrap-vue-3";
const compoment = defineComponent({
components: {
EditorContent,
BButtonGroup,
BButtonToolbar,
BButton,
},
props: {
modelValue: {
type: String,
default: "",
},
editable: {
type: Boolean,
default: true,
},
},
data() {
return {
editor: null as unknown as InstanceType<typeof Editor>,
};
},
watch: {
modelValue(value: string) {
const isSame = this.editor.getHTML() === value;
if (isSame) {
return;
}
this.editor.commands.setContent(value, false);
},
editable(value: boolean) {
this.editor.options.editable = value;
if(value == true){
this.editor.commands.focus();
}
},
},
mounted() {
this.editor = new Editor({
extensions: [StarterKit],
editable: this.editable,
content: this.modelValue,
onUpdate: () => {
this.$emit("update:modelValue", this.editor.getHTML());
},
});
},
beforeUnmount() {
this.editor.destroy();
},
});
export default compoment;
</script>
+5
View File
@@ -19,9 +19,14 @@
"license": "MIT",
"type": "module",
"dependencies": {
"@tiptap/extension-image": "^2.0.0-beta.24",
"@tiptap/extension-link": "^2.0.0-beta.33",
"@tiptap/starter-kit": "^2.0.0-beta.156",
"@tiptap/vue-3": "^2.0.0-beta.83",
"@types/bootstrap": "^5.1.6",
"@types/downloadjs": "^1.4.2",
"@types/linkifyjs": "^2.1.4",
"@types/quill": "^2.0.9",
"@types/select2": "^4.0.54",
"@vueup/vue-quill": "^1.0.0-beta.7",
"async-validator": "^4.0.7",