feat: 국방, 임관메시지 에디터에 TipTap 적용
This commit is contained in:
+4
-4
@@ -7,8 +7,8 @@ include "func.php";
|
|||||||
// $btn, $msg, $scoutmsg, $rate, $bill, $secretlimit
|
// $btn, $msg, $scoutmsg, $rate, $bill, $secretlimit
|
||||||
|
|
||||||
$btn = Util::getPost('btn');
|
$btn = Util::getPost('btn');
|
||||||
$msg = Util::getPost('msg');
|
//$msg = Util::getPost('msg');
|
||||||
$scoutmsg = Util::getPost('scoutMsg');
|
//$scoutmsg = Util::getPost('scoutMsg');
|
||||||
$rate = Util::getPost('rate', 'int');
|
$rate = Util::getPost('rate', 'int');
|
||||||
$bill = Util::getPost('bill', 'int');
|
$bill = Util::getPost('bill', 'int');
|
||||||
$secretlimit = Util::getPost('secretlimit', 'int');
|
$secretlimit = Util::getPost('secretlimit', 'int');
|
||||||
@@ -34,14 +34,14 @@ if ($permission < 0) {
|
|||||||
$nationID = $me['nation'];
|
$nationID = $me['nation'];
|
||||||
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
|
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
|
||||||
|
|
||||||
if ($btn == "국가방침 수정") {
|
/*if ($btn == "국가방침 수정") {
|
||||||
$msg = mb_substr($msg, 0, 16384);
|
$msg = mb_substr($msg, 0, 16384);
|
||||||
//$msg = StringUtil::
|
//$msg = StringUtil::
|
||||||
$nationStor->notice = WebUtil::htmlPurify($msg);
|
$nationStor->notice = WebUtil::htmlPurify($msg);
|
||||||
} elseif ($btn == "임관 권유문 수정") {
|
} elseif ($btn == "임관 권유문 수정") {
|
||||||
$scoutmsg = mb_substr($scoutmsg, 0, 1000);
|
$scoutmsg = mb_substr($scoutmsg, 0, 1000);
|
||||||
$nationStor->scout_msg = WebUtil::htmlPurify($scoutmsg);
|
$nationStor->scout_msg = WebUtil::htmlPurify($scoutmsg);
|
||||||
} elseif ($btn == "세율") {
|
} else*/if ($btn == "세율") {
|
||||||
$rate = Util::valueFit($rate, 5, 30);
|
$rate = Util::valueFit($rate, 5, 30);
|
||||||
$db->update('nation', [
|
$db->update('nation', [
|
||||||
'rate' => $rate,
|
'rate' => $rate,
|
||||||
|
|||||||
@@ -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
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
@@ -1,53 +1,123 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>국 가 방 침 & 임관 권유 메시지</div>
|
<div>국 가 방 침 & 임관 권유 메시지</div>
|
||||||
<div id="noticeForm">흠</div>
|
<div id="noticeForm">
|
||||||
<!--<b-button>국가방침 수정</b-button><b-button>취소</b-button>-->
|
|
||||||
<!--<div id="noticeForm">
|
|
||||||
<div class="bg1" style="display: flex; justify-content: space-around">
|
<div class="bg1" style="display: flex; justify-content: space-around">
|
||||||
<div style="flex: 1 1 auto">국가 방침</div>
|
<div style="flex: 1 1 auto">국가 방침</div>
|
||||||
<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>
|
</div>
|
||||||
<div class="edit_form viewer"></div>
|
<TipTap v-model="nationMsg" :editable="inEditNationMsg" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="scoutMsgForm">
|
<div id="scoutMsgForm">
|
||||||
<div class="bg1" style="display: flex; justify-content: space-around">
|
<div class="bg1" style="display: flex; justify-content: space-around">
|
||||||
<div style="flex: 1 1 auto">임관 권유</div>
|
<div style="flex: 1 1 auto">임관 권유</div>
|
||||||
<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>
|
</div>
|
||||||
<div style="border-bottom: solid gray 0.5px">
|
<div style="border-bottom: solid gray 0.5px">
|
||||||
870px x 200px를 넘어서는 내용은 표시되지 않습니다.
|
870px x 200px를 넘어서는 내용은 표시되지 않습니다.
|
||||||
</div>
|
</div>
|
||||||
<div style="width: 870px; margin-left: auto">
|
<div style="width: 870px; margin-left: auto">
|
||||||
<div class="edit_form viewer"></div>
|
<TipTap v-model="scoutMsg" :editable="inEditScoutMsg" />
|
||||||
</div>
|
</div>
|
||||||
</div>!-->
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import "@scss/dipcenter.scss";
|
import "@scss/dipcenter.scss";
|
||||||
import "@scss/common_legacy.scss";
|
import "@scss/common_legacy.scss";
|
||||||
|
import TipTap from "./components/TipTap.vue";
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent, reactive, ref } from "vue";
|
||||||
|
import { sammoAPI } from "./util/sammoAPI";
|
||||||
|
import { isString } from "lodash";
|
||||||
declare const editable: boolean;
|
declare const editable: boolean;
|
||||||
declare const nationMsg: string;
|
declare const nationMsg: string;
|
||||||
declare const scoutMsg: string;
|
declare const scoutMsg: string;
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "PartialDipcenter",
|
name: "PartialDipcenter",
|
||||||
components: {},
|
components: {
|
||||||
|
TipTap,
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
console.log(editable, ",", nationMsg, ",", scoutMsg);
|
|
||||||
return {
|
return {
|
||||||
editable,
|
editable,
|
||||||
|
oldNationMsg: nationMsg,
|
||||||
|
oldScoutMsg: scoutMsg,
|
||||||
nationMsg,
|
nationMsg,
|
||||||
scoutMsg,
|
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>
|
</script>
|
||||||
@@ -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>
|
||||||
@@ -19,9 +19,14 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"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/bootstrap": "^5.1.6",
|
||||||
"@types/downloadjs": "^1.4.2",
|
"@types/downloadjs": "^1.4.2",
|
||||||
"@types/linkifyjs": "^2.1.4",
|
"@types/linkifyjs": "^2.1.4",
|
||||||
|
"@types/quill": "^2.0.9",
|
||||||
"@types/select2": "^4.0.54",
|
"@types/select2": "^4.0.54",
|
||||||
"@vueup/vue-quill": "^1.0.0-beta.7",
|
"@vueup/vue-quill": "^1.0.0-beta.7",
|
||||||
"async-validator": "^4.0.7",
|
"async-validator": "^4.0.7",
|
||||||
|
|||||||
Reference in New Issue
Block a user