feat(WIP): processing을 vue로 전환
This commit is contained in:
+13
-38
@@ -77,55 +77,30 @@ $cssList = $commandObj->getCSSFiles();
|
||||
<meta name="viewport" content="width=1024" />
|
||||
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
|
||||
<?= WebUtil::printJS('d_shared/base_map.js') ?>
|
||||
<?= WebUtil::printStaticValues([
|
||||
'serverNick' => DB::prefix(),
|
||||
'serverID' => UniqueConst::$serverID,
|
||||
'commandName' => $commandObj->getName(),
|
||||
'turnList' => $turnList,
|
||||
'currentCity' => $general->getCityID(),
|
||||
'currentNation' => $general->getNationID(),
|
||||
'entryInfo' => [$isChiefTurn?'Nation':'General', $commandType]
|
||||
])?>
|
||||
<?= WebUtil::printStaticValues($commandObj->exportJSVars(), false) ?>
|
||||
<script>
|
||||
window.serverNick = '<?= DB::prefix() ?>';
|
||||
window.serverID = '<?= UniqueConst::$serverID ?>';
|
||||
window.command = '<?= $commandType ?>';
|
||||
window.turnList = [<?= join(', ', $turnList) ?>];
|
||||
window.isChiefTurn = <?= $isChiefTurn ? 'true' : 'false' ?>;
|
||||
var jsPlugins = <?= Json::encode($jsList) ?>;
|
||||
|
||||
</script>
|
||||
<?= WebUtil::printCSS('../e_lib/select2/select2.min.css') ?>
|
||||
<?= WebUtil::printCSS('../e_lib/select2/select2-bootstrap4.css') ?>
|
||||
<?= WebUtil::printCSS('../d_shared/common.css') ?>
|
||||
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
|
||||
<?= WebUtil::printCSS('css/main.css') ?>
|
||||
<?= WebUtil::printCSS('css/map.css') ?>
|
||||
<?= WebUtil::printCSS('css/processing.css') ?>
|
||||
<?php
|
||||
foreach ($cssList as $css) {
|
||||
print(WebUtil::printCSS($css));
|
||||
}
|
||||
?>
|
||||
<?= WebUtil::printDist('ts', ['common', 'processing']) ?>
|
||||
<?= WebUtil::printDist('vue', ['v_processing'], true) ?>
|
||||
</head>
|
||||
|
||||
<body class="img_back">
|
||||
<table class="tb_layout bg0" style="width:1000px;margin:auto;">
|
||||
<tr>
|
||||
<td class="bg1" style='text-align:center;'><?= $commandObj->getName() ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input type=button value='돌아가기' onclick="history.back();"><br>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="tb_layout bg0" style="width:1000px;margin:auto;padding-bottom:2em;border:solid 1px gray;">
|
||||
<?= $commandObj->getForm() ?>
|
||||
</div>
|
||||
|
||||
<table class="tb_layout bg0" style="width:1000px;margin:auto;">
|
||||
<tr>
|
||||
<td>
|
||||
<input type=button value='돌아가기' onclick="history.back();"><br>
|
||||
<?= banner() ?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<div id="container"></div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,11 +0,0 @@
|
||||
#amount {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
#colorType {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.no-padding .select2-results__option {
|
||||
padding: 0;
|
||||
}
|
||||
@@ -52,6 +52,18 @@ function bar($per, $h = 7)
|
||||
return $str;
|
||||
}
|
||||
|
||||
function JSOptionsForCities(callable $infoCall = null){
|
||||
$result = [];
|
||||
foreach (CityConst::all() as $city) {
|
||||
$item = [$city->id, $city->name];
|
||||
|
||||
if($infoCall){
|
||||
$item[2] = $infoCall($city);
|
||||
}
|
||||
$result[] = $item;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function optionsForCities(callable $infoCall = null)
|
||||
{
|
||||
@@ -116,6 +128,15 @@ function closeButton()
|
||||
return "<button type='button' class='btn btn-primary back_btn' onclick=window.close()>창 닫기</button><br>";
|
||||
}
|
||||
|
||||
function JSCitiesBasedOnDistance(int $cityNo, int $maxDistance = 1): array{
|
||||
$distanceList = searchDistance($cityNo, $maxDistance, true);
|
||||
$result = [];
|
||||
for ($dist = 1; $dist <= $maxDistance; $dist++) {
|
||||
$result[$dist] = Util::array_get($distanceList[$dist], []);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
function printCitiesBasedOnDistance(int $cityNo, int $maxDistance = 1): string
|
||||
{
|
||||
|
||||
@@ -225,6 +225,14 @@ function formatName(string $name, int $npc): string
|
||||
return $name;
|
||||
}
|
||||
|
||||
function getMapTheme(): string
|
||||
{
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$mapTheme = $gameStor->map_theme ?? 'che';
|
||||
return $mapTheme;
|
||||
}
|
||||
|
||||
function getMapHtml(?string $mapTheme = null)
|
||||
{
|
||||
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
|
||||
|
||||
@@ -478,6 +478,9 @@ abstract class BaseCommand{
|
||||
public function getJSPlugins():array {
|
||||
return [];
|
||||
}
|
||||
public function exportJSVars():array {
|
||||
return [];
|
||||
}
|
||||
public function getCSSFiles():array {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ use \sammo\GameUnitConst;
|
||||
use \sammo\LastTurn;
|
||||
use \sammo\Command;
|
||||
|
||||
use function sammo\getMapTheme;
|
||||
use function \sammo\printCitiesBasedOnDistance;
|
||||
use function sammo\tryUniqueItemLottery;
|
||||
|
||||
@@ -176,6 +177,15 @@ class che_강행 extends Command\GeneralCommand
|
||||
];
|
||||
}
|
||||
|
||||
public function exportJSVars(): array
|
||||
{
|
||||
return [
|
||||
'cities' => \sammo\JSOptionsForCities(),
|
||||
'mapTheme' => getMapTheme(),
|
||||
'distanceList' => \sammo\JSCitiesBasedOnDistance($this->generalObj->getCityID(), 3),
|
||||
];
|
||||
}
|
||||
|
||||
public function getForm(): string
|
||||
{
|
||||
$currentCityID = $this->generalObj->getCityID();
|
||||
@@ -187,7 +197,7 @@ class che_강행 extends Command\GeneralCommand
|
||||
선택된 도시로 강행합니다.<br>
|
||||
최대 3칸내 도시로만 강행이 가능합니다.<br>
|
||||
목록을 선택하거나 도시를 클릭하세요.<br>
|
||||
<?= $currentCityName ?> => <select class='formInput' name="destCityID" id="destCityID" size='1' style='color:white;background-color:black;'><br>
|
||||
<?= $currentCityName ?> => <div id="setDestCityIDForm"></div><br>
|
||||
<?= \sammo\optionsForCities() ?><br>
|
||||
</select> <input type=button id="commonSubmit" value="<?= $this->getName() ?>"><br>
|
||||
<br>
|
||||
|
||||
@@ -184,6 +184,13 @@ class che_이동 extends Command\GeneralCommand
|
||||
];
|
||||
}
|
||||
|
||||
public function exportJSVars(): array
|
||||
{
|
||||
return [
|
||||
'cities' => \sammo\JSOptionsForCities()
|
||||
];
|
||||
}
|
||||
|
||||
public function getForm(): string
|
||||
{
|
||||
$currentCityID = $this->generalObj->getCityID();
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
@import "./common/break_500px.scss";
|
||||
@import "./common/bootstrap5.scss";
|
||||
@import "./editor_component.scss";
|
||||
@import "./common_legacy.scss";
|
||||
|
||||
#amount {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
#colorType {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.no-padding .select2-results__option {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
#container {
|
||||
width: 1000px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
body {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
#container {
|
||||
width: 500px;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 100px;
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@
|
||||
"install": "install.ts",
|
||||
"battle_simulator": "battle_simulator.ts",
|
||||
"recent_map": "recent_map.ts",
|
||||
"processing": "processing.ts",
|
||||
"select_npc": "select_npc.ts",
|
||||
"betting": "betting.ts",
|
||||
"bossInfo": "bossInfo.ts",
|
||||
@@ -27,7 +26,7 @@
|
||||
"v_NPCControl": "v_NPCControl.ts",
|
||||
"v_join": "v_join.ts",
|
||||
"v_main": "v_main.ts",
|
||||
"v_dipcenter": "v_dipcenter.ts"
|
||||
|
||||
"v_dipcenter": "v_dipcenter.ts",
|
||||
"v_processing": "v_processing.ts"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
<template>
|
||||
<div
|
||||
:id="uuid"
|
||||
:class="['world_map', `map_theme_${mapTheme}`, 'draw_required']"
|
||||
>
|
||||
<div
|
||||
class="map_title obj_tooltip"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
data-tooltip-class="map_title_tooltiptext"
|
||||
>
|
||||
<span class="map_title_text"> </span>
|
||||
<span class="tooltiptext"></span>
|
||||
</div>
|
||||
<div class="map_body">
|
||||
<div class="map_bglayer1"></div>
|
||||
<div class="map_bglayer2"></div>
|
||||
<div class="map_bgroad"></div>
|
||||
<div class="map_button_stack">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary map_toggle_cityname btn-sm btn-minimum"
|
||||
data-bs-toggle="button"
|
||||
aria-pressed="false"
|
||||
autocomplete="off"
|
||||
>
|
||||
도시명 표기</button
|
||||
><br />
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary map_toggle_single_tap btn-sm btn-minimum"
|
||||
data-bs-toggle="button"
|
||||
aria-pressed="false"
|
||||
autocomplete="off"
|
||||
>
|
||||
두번 탭 해 도시 이동
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="city_tooltip">
|
||||
<div class="city_name"></div>
|
||||
<div class="nation_name"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { reloadWorldMap, loadMapOption, MapCityParsed } from "@/map";
|
||||
import { defineComponent, onMounted, PropType, ref } from "vue";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
export type { MapCityParsed };
|
||||
export default defineComponent({
|
||||
props: {
|
||||
mapTheme: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
isDetailMap: { type: Boolean, default: undefined },
|
||||
clickableAll: { type: Boolean, default: undefined },
|
||||
selectCallback: {
|
||||
type: Function as PropType<loadMapOption["selectCallback"]>,
|
||||
required: false,
|
||||
},
|
||||
hrefTemplate: { type: String, default: undefined },
|
||||
useCachedMap: { type: Boolean, default: undefined },
|
||||
|
||||
year: { type: Number, default: undefined },
|
||||
month: { type: Number, default: undefined },
|
||||
aux: Object as PropType<loadMapOption["aux"]>,
|
||||
neutralView: { type: Boolean, default: undefined },
|
||||
showMe: { type: Boolean, default: undefined },
|
||||
|
||||
targetJson: { type: String, default: undefined },
|
||||
reqType: {
|
||||
type: String as PropType<loadMapOption["reqType"]>,
|
||||
default: undefined,
|
||||
},
|
||||
dynamicMapTheme: { type: Boolean, default: undefined },
|
||||
callback: {
|
||||
type: Function as PropType<loadMapOption["callback"]>,
|
||||
default: undefined,
|
||||
},
|
||||
startYear: { type: Number, default: undefined },
|
||||
|
||||
modelValue: {
|
||||
type: Object as PropType<MapCityParsed>,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
emits: ["update:modelValue", "loaded"],
|
||||
setup(props, { emit }) {
|
||||
const uuid = uuidv4();
|
||||
const modelValue = ref(props.modelValue);
|
||||
|
||||
onMounted(async () => {
|
||||
const option: loadMapOption = {
|
||||
isDetailMap: props.isDetailMap,
|
||||
clickableAll: props.clickableAll,
|
||||
selectCallback: (city) => {
|
||||
modelValue.value = city;
|
||||
emit("update:modelValue", city);
|
||||
},
|
||||
hrefTemplate: props.hrefTemplate,
|
||||
useCachedMap: props.useCachedMap,
|
||||
|
||||
year: props.year,
|
||||
month: props.month,
|
||||
aux: props.aux,
|
||||
neutralView: props.neutralView,
|
||||
showMe: props.showMe,
|
||||
|
||||
targetJson: props.targetJson,
|
||||
reqType: props.reqType,
|
||||
dynamicMapTheme: props.dynamicMapTheme,
|
||||
callback: (a, rawObject) => {
|
||||
emit("loaded", [a, rawObject]);
|
||||
},
|
||||
|
||||
startYear: props.startYear,
|
||||
};
|
||||
|
||||
console.log(option);
|
||||
await reloadWorldMap(option, `#${uuid}`);
|
||||
});
|
||||
|
||||
return {
|
||||
uuid,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -1,21 +1,19 @@
|
||||
import { reloadWorldMap } from "@/map";
|
||||
import { unwrap_any } from "@util/unwrap_any";
|
||||
|
||||
declare let vueReactive_destCityID: number|undefined;
|
||||
|
||||
export function defaultSelectCityByMap(): void {
|
||||
const $target = $("#destCityID");
|
||||
console.log('city', $target);
|
||||
void reloadWorldMap({
|
||||
isDetailMap: false,
|
||||
clickableAll: true,
|
||||
neutralView: true,
|
||||
useCachedMap: true,
|
||||
selectCallback: function (city) {
|
||||
const currVal = unwrap_any<string>($target.val());
|
||||
$target.val(city.id);
|
||||
$target.trigger("change");
|
||||
if ($target.val() === null) {
|
||||
$target.val(currVal).trigger("change").blur();
|
||||
if(vueReactive_destCityID === undefined){
|
||||
console.error('아직 초기화 되지 않음');
|
||||
return false;
|
||||
}
|
||||
vueReactive_destCityID = city.id;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { reloadWorldMap } from "@/map";
|
||||
import { unwrap_any } from "@util/unwrap_any";
|
||||
|
||||
declare let vueReactive_destNationID: number|undefined;
|
||||
|
||||
export function defaultSelectNationByMap(): void{
|
||||
const $target = $("#destNationID");
|
||||
@@ -9,15 +10,12 @@ export function defaultSelectNationByMap(): void{
|
||||
clickableAll: true,
|
||||
neutralView: true,
|
||||
useCachedMap: true,
|
||||
selectCallback: (city)=>{
|
||||
const currVal = unwrap_any<string>($target.val());
|
||||
if(!city.nationID){
|
||||
selectCallback: function (city) {
|
||||
if(typeof vueReactive_destNationID === 'undefined'){
|
||||
console.error('아직 초기화 되지 않음');
|
||||
return false;
|
||||
}
|
||||
$target.val(city.nationID).trigger("change");
|
||||
if ($target.val() === null) {
|
||||
$target.val(currVal).trigger("change");
|
||||
}
|
||||
vueReactive_destNationID = city.nationID;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
+13
-10
@@ -1,11 +1,12 @@
|
||||
import axios from 'axios';
|
||||
import $ from 'jquery';
|
||||
import { extend, isNumber } from 'lodash';
|
||||
import { extend, isNumber, merge } from 'lodash';
|
||||
import { convColorValue, convertDictById, stringFormat } from '@/common_legacy';
|
||||
import { InvalidResponse } from '@/defs';
|
||||
import { unwrap } from "@util/unwrap";
|
||||
import { convertFormData } from '@util/convertFormData';
|
||||
import { exportWindow } from '@util/exportWindow';
|
||||
import { htmlReady } from './util/htmlReady';
|
||||
|
||||
declare const serverNick: string;
|
||||
declare const serverID: string;
|
||||
@@ -57,7 +58,7 @@ type MapCityParsedRegionLevelText = MapCityParsedClickable & {
|
||||
text: string,
|
||||
}
|
||||
|
||||
type MapCityParsed = MapCityParsedRegionLevelText;
|
||||
export type MapCityParsed = MapCityParsedRegionLevelText;
|
||||
|
||||
type MapCityDrawable = {
|
||||
cityList: MapCityParsed[],
|
||||
@@ -107,7 +108,7 @@ function is_touch_device(): boolean {
|
||||
return mq(query);
|
||||
}
|
||||
|
||||
type loadMapOption = {
|
||||
export type loadMapOption = {
|
||||
isDetailMap?: boolean, //복잡 지도, 단순 지도
|
||||
clickableAll?: boolean, //어떤 경우든 클릭을 가능하게 함. 해당 동작의 동작 가능성 여부와는 별도.
|
||||
selectCallback?: (city: MapCityParsed) => void, //callback을 지정시 clickable과 관계 없이 해당 함수를 실행.
|
||||
@@ -160,7 +161,7 @@ export async function reloadWorldMap(option: loadMapOption, drawTarget = '.world
|
||||
startYear: undefined,
|
||||
};
|
||||
|
||||
option = extend({}, defaultOption, option);
|
||||
option = merge({}, defaultOption, option);
|
||||
|
||||
const useCachedMap = option.useCachedMap;
|
||||
const isDetailMap = option.isDetailMap;
|
||||
@@ -671,7 +672,6 @@ export async function reloadWorldMap(option: loadMapOption, drawTarget = '.world
|
||||
|
||||
const $hideCityNameBtn = $world_map.find('.map_toggle_cityname');
|
||||
if (localStorage.getItem('sam.hideMapCityName') == 'yes') {
|
||||
console.log('tryHide!');
|
||||
$world_map.addClass('hide_cityname');
|
||||
$hideCityNameBtn.addClass('active').attr('aria-pressed', 'true');
|
||||
}
|
||||
@@ -680,7 +680,6 @@ export async function reloadWorldMap(option: loadMapOption, drawTarget = '.world
|
||||
//이전 상태 확인
|
||||
const state = localStorage.getItem('sam.hideMapCityName') == 'no';
|
||||
if (state) {
|
||||
console.log('tryHide!');
|
||||
$world_map.addClass('hide_cityname');
|
||||
localStorage.setItem('sam.hideMapCityName', 'yes');
|
||||
} else {
|
||||
@@ -789,8 +788,12 @@ export async function reloadWorldMap(option: loadMapOption, drawTarget = '.world
|
||||
}
|
||||
|
||||
exportWindow(reloadWorldMap, 'reloadWorldMap');
|
||||
$(function ($) {
|
||||
if (is_touch_device()) {
|
||||
$('.map_body .map_toggle_single_tap').show();
|
||||
htmlReady(function(){
|
||||
if( is_touch_device()){
|
||||
const target = document.querySelector('.map_body .map_toggle_single_tap') as HTMLElement | null;
|
||||
if(!target){
|
||||
return;
|
||||
}
|
||||
target.style.display = 'block';
|
||||
}
|
||||
})
|
||||
});
|
||||
@@ -1,300 +0,0 @@
|
||||
import $ from 'jquery';
|
||||
exportWindow($, '$');
|
||||
import { exportWindow } from '@util/exportWindow';
|
||||
import axios from 'axios';
|
||||
import 'bootstrap';
|
||||
import 'select2/dist/js/select2.full.js'
|
||||
import { setAxiosXMLHttpRequest } from '@util/setAxiosXMLHttpRequest';
|
||||
import { convertFormData } from '@util/convertFormData';
|
||||
import { InvalidResponse } from '@/defs';
|
||||
import { unwrap_any } from '@util/unwrap_any';
|
||||
import { DataFormat, IdTextPair, OptionData } from 'select2';
|
||||
import { unwrap } from "@util/unwrap";
|
||||
import { defaultSelectCityByMap } from '@/defaultSelectCityByMap';
|
||||
import { defaultSelectNationByMap } from '@/defaultSelectNationByMap';
|
||||
import { colorSelect } from '@/colorSelect';
|
||||
import { recruitCrewForm } from '@/recruitCrewForm';
|
||||
|
||||
declare const isChiefTurn: boolean;
|
||||
declare const jsPlugins: string[];
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
submitAction: () => Promise<void>;
|
||||
turnList: number[],
|
||||
command: string,
|
||||
}
|
||||
}
|
||||
|
||||
async function reserveTurn(turnList: number[], command: string, arg: Record<string, unknown>) {
|
||||
const target = isChiefTurn ? 'j_set_chief_command.php' : 'j_set_general_command.php';
|
||||
|
||||
let data: InvalidResponse;
|
||||
try {
|
||||
const response = await axios({
|
||||
url: target,
|
||||
responseType: 'json',
|
||||
method: 'post',
|
||||
data: convertFormData({
|
||||
action: command,
|
||||
turnList: turnList,
|
||||
arg: JSON.stringify(arg)
|
||||
})
|
||||
});
|
||||
data = response.data;
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e);
|
||||
alert(`에러가 발생했습니다: ${e}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.result) {
|
||||
alert(data.reason);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isChiefTurn) {
|
||||
window.location.href = './';
|
||||
} else {
|
||||
window.location.href = 'b_chiefcenter.php';
|
||||
}
|
||||
}
|
||||
|
||||
$(function ($) {
|
||||
setAxiosXMLHttpRequest();
|
||||
//checkCommandArg 참고
|
||||
const availableArgumentList = {
|
||||
'string': [
|
||||
'nationName', 'optionText', 'itemType', 'nationType', 'itemCode', 'commandType',
|
||||
],
|
||||
'int': [
|
||||
'crewType', 'destGeneralID', 'destCityID', 'destNationID',
|
||||
'amount', 'colorType',
|
||||
'year', 'month',
|
||||
'srcArmType', 'destArmType', //숙련전환 전용
|
||||
],
|
||||
'boolean': [
|
||||
'isGold', 'buyRice',
|
||||
],
|
||||
'integerArray': [
|
||||
'destNationIDList', 'destGeneralIDList', 'amountList'
|
||||
]
|
||||
}
|
||||
|
||||
type argTypes = keyof typeof availableArgumentList;
|
||||
type argValues = string | number | boolean | number[];
|
||||
|
||||
const handlerList: Record<argTypes, ($obj: JQuery<HTMLInputElement>) => argValues> = {
|
||||
'string': function ($obj: JQuery<HTMLInputElement>) {
|
||||
return $.trim(unwrap_any<string>($obj.eq(0).val()));
|
||||
},
|
||||
'int': function ($obj: JQuery<HTMLInputElement>) {
|
||||
return parseInt(unwrap_any<string>($obj.eq(0).val()));
|
||||
},
|
||||
'boolean': function ($obj: JQuery<HTMLInputElement>) {
|
||||
switch (unwrap_any<string>($obj.eq(0).val()).toLowerCase()) {
|
||||
case "true":
|
||||
case "yes":
|
||||
case "1":
|
||||
return true;
|
||||
case "false":
|
||||
case "no":
|
||||
case "0":
|
||||
return false;
|
||||
default:
|
||||
throw new Error("Boolean.parse: Cannot convert string to boolean.");
|
||||
}
|
||||
},
|
||||
'integerArray': function ($obj: JQuery<HTMLInputElement>) {
|
||||
const result: number[] = [];
|
||||
$obj.each(function () {
|
||||
result.push(parseInt(unwrap_any<string>($(this).val())));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
window.submitAction = async function (): Promise<void> {
|
||||
const argument: Record<string, argValues> = {};
|
||||
for (const typeName of Object.keys(availableArgumentList) as argTypes[]) {
|
||||
const typeKeys = availableArgumentList[typeName];
|
||||
for (const typeKey of typeKeys) {
|
||||
let $obj = $('#' + typeKey) as JQuery<HTMLInputElement>;
|
||||
if ($obj.length == 0) {
|
||||
$obj = $('.' + typeKey);
|
||||
if ($obj.length == 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
argument[typeKey] = handlerList[typeName]($obj);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(argument);
|
||||
await reserveTurn(window.turnList, window.command, argument);
|
||||
};
|
||||
|
||||
$('#commonSubmit').on('click', window.submitAction);
|
||||
|
||||
const $colorType = $('#colorType');
|
||||
if ($colorType.length) {
|
||||
$colorType.select2({
|
||||
theme: 'bootstrap4',
|
||||
placeholder: "색상을 선택해 주세요.",
|
||||
language: "ko",
|
||||
containerCss: {
|
||||
display: "inline-block !important",
|
||||
color: 'white !important',
|
||||
},
|
||||
templateSelection: function (item) {
|
||||
if ((item as DataFormat).disabled) {
|
||||
return item.text;
|
||||
}
|
||||
const element = (item as OptionData).element;
|
||||
if (!element) {
|
||||
throw 'invalid type';
|
||||
}
|
||||
const bgcolor = unwrap(element.dataset.color);
|
||||
const fgcolor = unwrap(element.dataset.fontColor);
|
||||
// eslint-disable-next-line no-irregular-whitespace
|
||||
return $(`<span><span style='background-color:${bgcolor};color:${fgcolor};'> </span> ${item.text}</span>`);
|
||||
},
|
||||
templateResult: function (item) {
|
||||
if ((item as DataFormat).disabled) {
|
||||
return item.text;
|
||||
}
|
||||
const element = (item as OptionData).element;
|
||||
if (!element) {
|
||||
throw 'invalid type';
|
||||
}
|
||||
const bgcolor = unwrap(element.dataset.color);
|
||||
const fgcolor = unwrap(element.dataset.fontColor);
|
||||
return $(`<div style='padding: 0.75rem 0.375rem; background-color:${bgcolor};color:${fgcolor};'>${item.text}</div>`);
|
||||
},
|
||||
containerCssClass: 'simple-select2-align-center bg-secondary text-secondary',
|
||||
dropdownCssClass: 'no-padding simple-select2-align-center bg-secondary text-secondary',
|
||||
});
|
||||
}
|
||||
|
||||
const $nationType = $('#nationType');
|
||||
if ($nationType.length) {
|
||||
$nationType.select2({
|
||||
theme: 'bootstrap4',
|
||||
language: "ko",
|
||||
containerCss: {
|
||||
display: "inline-block !important",
|
||||
color: 'white !important',
|
||||
},
|
||||
containerCssClass: 'simple-select2-align-center bg-secondary text-secondary',
|
||||
dropdownCssClass: 'simple-select2-align-center bg-secondary text-secondary',
|
||||
});
|
||||
}
|
||||
|
||||
const $destCityID = $('#destCityID');
|
||||
if ($destCityID.length) {
|
||||
$destCityID.select2({
|
||||
theme: 'bootstrap4',
|
||||
placeholder: "도시를 선택해 주세요.",
|
||||
language: "ko",
|
||||
containerCss: {
|
||||
display: "inline-block !important",
|
||||
color: 'white !important',
|
||||
},
|
||||
containerCssClass: 'simple-select2-align-center bg-secondary text-secondary',
|
||||
dropdownCssClass: 'simple-select2-align-center bg-secondary text-secondary',
|
||||
});
|
||||
}
|
||||
|
||||
const $destNationID = $('#destNationID');
|
||||
if ($destNationID.length) {
|
||||
$destNationID.select2({
|
||||
theme: 'bootstrap4',
|
||||
placeholder: "국가를 선택해 주세요.",
|
||||
language: "ko",
|
||||
containerCss: {
|
||||
display: "inline-block !important",
|
||||
color: 'white !important',
|
||||
},
|
||||
containerCssClass: 'simple-select2-align-center bg-secondary text-secondary',
|
||||
dropdownCssClass: 'simple-select2-align-center bg-secondary text-secondary',
|
||||
});
|
||||
}
|
||||
|
||||
const $destGeneralID = $('#destGeneralID');
|
||||
if ($destGeneralID.length) {
|
||||
$destGeneralID.select2({
|
||||
theme: 'bootstrap4',
|
||||
placeholder: "장수를 선택해 주세요.",
|
||||
language: "ko",
|
||||
containerCss: {
|
||||
display: "inline-block !important",
|
||||
color: 'white !important',
|
||||
},
|
||||
containerCssClass: 'simple-select2-align-center bg-secondary text-secondary',
|
||||
dropdownCssClass: 'simple-select2-align-center bg-secondary text-secondary',
|
||||
});
|
||||
}
|
||||
|
||||
const $isGold = $('#isGold');
|
||||
if ($isGold.length) {
|
||||
$isGold.select2({
|
||||
theme: 'bootstrap4',
|
||||
placeholder: "분량을 지정해 주세요.",
|
||||
language: "ko",
|
||||
containerCss: {
|
||||
display: "inline-block !important",
|
||||
color: 'white !important',
|
||||
},
|
||||
minimumResultsForSearch: -1,
|
||||
containerCssClass: 'simple-select2-align-center bg-secondary text-secondary',
|
||||
dropdownCssClass: 'simple-select2-align-center bg-secondary text-secondary',
|
||||
});
|
||||
}
|
||||
|
||||
const $amount = $('#amount:not([type=hidden])');
|
||||
if ($amount.length) {
|
||||
$amount.select2({
|
||||
theme: 'bootstrap4',
|
||||
placeholder: "분량을 지정해 주세요.",
|
||||
allowClear: false,
|
||||
language: "ko",
|
||||
containerCss: {
|
||||
display: "inline-block !important",
|
||||
color: 'white !important',
|
||||
},
|
||||
tags: true,
|
||||
sorter: function (items) {
|
||||
(items as IdTextPair[]).sort(function (lhs, rhs) {
|
||||
return parseInt(lhs.id) - parseInt(rhs.id);
|
||||
})
|
||||
return items;
|
||||
},
|
||||
containerCssClass: 'simple-select2-align-center bg-secondary text-secondary',
|
||||
dropdownCssClass: 'select2-only-number simple-select2-align-center bg-secondary text-secondary',
|
||||
})
|
||||
}
|
||||
|
||||
$(document).on('keypress', '.select2-only-number .select2-search__field', function (e) {
|
||||
$(this).val(unwrap_any<string>($(this).val()).replace(/[^\d].+/, ""));
|
||||
if ((e.which < 48 || e.which > 57)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
const pluginMap:Record<string, ()=>void> = {
|
||||
'defaultSelectCityByMap': defaultSelectCityByMap,
|
||||
'defaultSelectNationByMap': defaultSelectNationByMap,
|
||||
'colorSelect': colorSelect,
|
||||
'recruitCrewForm': recruitCrewForm,
|
||||
};
|
||||
for (const jsPlugin of jsPlugins) {
|
||||
if (jsPlugin in pluginMap) {
|
||||
pluginMap[jsPlugin]()
|
||||
}
|
||||
else{
|
||||
console.error(`'${jsPlugin}' is not supported`);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<div v-for="(cityList, distance) in distanceList" :key="distance">
|
||||
{{ distance }}칸 떨어진 도시:
|
||||
<template v-for="(cityID, key) in cityList" :key="key">
|
||||
<template v-if="key !== 0">, </template>
|
||||
<a :style="{ color: colorMap[distance] ?? undefined, textDecoration:'underline' }" @click="$emit('selected', cityID)">{{
|
||||
citiesMap.get(cityID)?.name
|
||||
}}</a>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
distanceList: {
|
||||
type: Object as PropType<Record<number, number[]>>,
|
||||
required: true,
|
||||
},
|
||||
citiesMap: {
|
||||
type: Object as PropType<Map<number, { name: string }>>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
emits: ['selected'],
|
||||
data() {
|
||||
return {
|
||||
colorMap: {
|
||||
1: "magenta",
|
||||
2: "orange",
|
||||
3: "yellow",
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<v-multiselect
|
||||
v-model="selectedCity"
|
||||
:allow-empty="false"
|
||||
:options="citiesForFind"
|
||||
:group-select="false"
|
||||
label="searchText"
|
||||
track-by="value"
|
||||
open-direction="bottom"
|
||||
:show-labels="false"
|
||||
selectLabel="선택(엔터)"
|
||||
selectGroupLabel=""
|
||||
selectedLabel="선택됨"
|
||||
deselectLabel="해제(엔터)"
|
||||
deselectGroupLabel=""
|
||||
placeholder="턴 선택"
|
||||
:maxHeight="400"
|
||||
:searchable="searchMode"
|
||||
>
|
||||
<template v-slot:option="props">
|
||||
{{ props.option.title }}
|
||||
<span v-if="props.option.info">({{ props.option.info }})</span>
|
||||
</template>
|
||||
<template v-slot:singleLabel="props">
|
||||
{{ props.option.simpleName }}
|
||||
</template>
|
||||
</v-multiselect>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { filter초성withAlphabet } from "@/util/filter초성withAlphabet";
|
||||
import { defineComponent, PropType } from "vue";
|
||||
|
||||
type SelectedCity = {
|
||||
value: number;
|
||||
searchText: string;
|
||||
title: string;
|
||||
simpleName: string;
|
||||
info?: string;
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
cities: {
|
||||
type: Map as PropType<Map<number, { name: string; info?: string }>>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
emits: ["update:modelValue"],
|
||||
watch: {
|
||||
modelValue(val: number) {
|
||||
const target = this.targets.get(val);
|
||||
this.selectedCity = target;
|
||||
},
|
||||
selectedCity(val: SelectedCity){
|
||||
this.$emit('update:modelValue', val.value);
|
||||
}
|
||||
},
|
||||
data() {
|
||||
const citiesForFind = [];
|
||||
const targets = new Map<number, SelectedCity>();
|
||||
let selectedCity;
|
||||
for (const [value, { name, info }] of this.cities.entries()) {
|
||||
const [filteredTextH, filteredTextA] = filter초성withAlphabet(name);
|
||||
const obj: SelectedCity = {
|
||||
value,
|
||||
title: name,
|
||||
info: info,
|
||||
simpleName: name,
|
||||
searchText: `${name} ${filteredTextH} ${filteredTextA}`
|
||||
};
|
||||
if (value == this.modelValue) {
|
||||
selectedCity = obj;
|
||||
}
|
||||
citiesForFind.push(obj);
|
||||
targets.set(value, obj);
|
||||
}
|
||||
return {
|
||||
selectedCity,
|
||||
searchMode: true,
|
||||
citiesForFind,
|
||||
targets,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<MapLegacyTemplate
|
||||
:isDetailMap="false"
|
||||
:clickableAll="true"
|
||||
:neutralView="true"
|
||||
:useCachedMap="true"
|
||||
:mapTheme="mapTheme"
|
||||
v-model="selectedCityObj"
|
||||
/>
|
||||
<div>
|
||||
선택된 도시로 강행합니다.<br />
|
||||
최대 3칸내 도시로만 강행이 가능합니다.<br />
|
||||
목록을 선택하거나 도시를 클릭하세요.<br />
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<CitySelect :cities="citiesMap" :modelValue="selectedCityID" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<b-button @click="submit">{{ commandName }}</b-button>
|
||||
</div>
|
||||
</div>
|
||||
<CityBasedOnDistance
|
||||
:citiesMap="citiesMap"
|
||||
:distanceList="distanceList"
|
||||
@selected="selected"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import "@/../css/map.css";
|
||||
import MapLegacyTemplate, {
|
||||
MapCityParsed,
|
||||
} from "@/components/MapLegacyTemplate.vue";
|
||||
import CitySelect from "@/processing/CitySelect.vue";
|
||||
import CityBasedOnDistance from "@/processing/CitiesBasedOnDistance.vue";
|
||||
import { defineComponent, ref } from "vue";
|
||||
import { unwrap } from "@/util/unwrap";
|
||||
import { Args } from "@/processing/args";
|
||||
declare const mapTheme: string;
|
||||
declare const cities: [number, string][];
|
||||
declare const currentCity: number;
|
||||
declare const distanceList: Record<number, number[]>;
|
||||
declare const commandName: string;
|
||||
export default defineComponent({
|
||||
name: "che_강행",
|
||||
components: {
|
||||
MapLegacyTemplate,
|
||||
CitySelect,
|
||||
CityBasedOnDistance,
|
||||
},
|
||||
watch: {
|
||||
selectedCityObj(city: MapCityParsed) {
|
||||
this.selectedCityID = city.id;
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
console.log("start!");
|
||||
const citiesMap = new Map<
|
||||
number,
|
||||
{
|
||||
name: string;
|
||||
info?: string;
|
||||
}
|
||||
>();
|
||||
for (const [id, name] of cities) {
|
||||
citiesMap.set(id, { name });
|
||||
}
|
||||
console.log(citiesMap);
|
||||
|
||||
const selectedCityID = ref(currentCity);
|
||||
|
||||
function selected(cityID: number) {
|
||||
selectedCityID.value = cityID;
|
||||
}
|
||||
|
||||
async function submit(e: Event) {
|
||||
const event = new CustomEvent<Args>("customSubmit", {
|
||||
detail: {
|
||||
destCityID: selectedCityID.value,
|
||||
},
|
||||
});
|
||||
unwrap(e.target).dispatchEvent(event);
|
||||
}
|
||||
|
||||
return {
|
||||
mapTheme: ref(mapTheme),
|
||||
citiesMap: ref(citiesMap),
|
||||
selectedCityID,
|
||||
selectedCityObj: ref(undefined as MapCityParsed | undefined),
|
||||
distanceList,
|
||||
commandName,
|
||||
selected,
|
||||
submit,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1 @@
|
||||
export { default as che_강행 } from "./che_강행.vue";
|
||||
@@ -0,0 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
});
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
});
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,2 @@
|
||||
export * as che_발령 from "./che_발령.vue";
|
||||
export * as che_포상 from "./che_포상.vue";
|
||||
@@ -0,0 +1,83 @@
|
||||
import { isArray, isBoolean, isInteger, isString } from "lodash";
|
||||
|
||||
|
||||
const stringArgs = [
|
||||
'nationName', 'optionText', 'itemType', 'nationType', 'itemCode', 'commandType',
|
||||
] as const;
|
||||
const intArgs = [
|
||||
'crewType', 'destGeneralID', 'destCityID', 'destNationID',
|
||||
'amount', 'colorType',
|
||||
'year', 'month',
|
||||
'srcArmType', 'destArmType', //숙련전환 전용
|
||||
] as const;
|
||||
|
||||
const booleanArgs = [
|
||||
'isGold', 'buyRice',
|
||||
] as const;
|
||||
|
||||
const integerArrayArgs = [
|
||||
'destNationIDList', 'destGeneralIDList', 'amountList'
|
||||
] as const;
|
||||
|
||||
type StringKeys = typeof stringArgs[number];
|
||||
type IntKeys = typeof intArgs[number];
|
||||
type BooleanKeys = typeof booleanArgs[number];
|
||||
type IntegerArrayKeys = typeof integerArrayArgs[number];
|
||||
|
||||
|
||||
export type Args = {
|
||||
[key in StringKeys]?: string;
|
||||
} & {
|
||||
[key in IntKeys]?: number;
|
||||
} & {
|
||||
[key in BooleanKeys]?: boolean;
|
||||
} & {
|
||||
[key in IntegerArrayKeys]?: number[]
|
||||
};
|
||||
|
||||
|
||||
|
||||
export function testSubmitArgs(args: Args): true | ['int' | 'string' | 'boolean' | 'int[]', keyof Args, number | string | boolean | number[]] {
|
||||
for (const intKey of intArgs) {
|
||||
const testVal = args[intKey];
|
||||
if (testVal === undefined) {
|
||||
continue;
|
||||
}
|
||||
if (!isInteger(testVal)) {
|
||||
return ['int', intKey, testVal];
|
||||
}
|
||||
}
|
||||
for (const stringKey of stringArgs) {
|
||||
const testVal = args[stringKey];
|
||||
if (testVal === undefined) {
|
||||
continue;
|
||||
}
|
||||
if (!isString(testVal)) {
|
||||
return ['string', stringKey, testVal];
|
||||
}
|
||||
}
|
||||
for (const booleanKey of booleanArgs) {
|
||||
const testVal = args[booleanKey];
|
||||
if (testVal === undefined) {
|
||||
continue;
|
||||
}
|
||||
if (!isBoolean(testVal)) {
|
||||
return ['boolean', booleanKey, testVal];
|
||||
}
|
||||
}
|
||||
for (const integerArrayKey of integerArrayArgs) {
|
||||
const testVal = args[integerArrayKey];
|
||||
if (testVal === undefined) {
|
||||
continue;
|
||||
}
|
||||
if (!isArray(args[integerArrayKey])) {
|
||||
return ['int[]', integerArrayKey, testVal];
|
||||
}
|
||||
for (const value of testVal) {
|
||||
if (!isInteger(value)) {
|
||||
return ['int[]', integerArrayKey, testVal];
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
+1
-3
@@ -15,7 +15,5 @@ import "@/legacy/main";
|
||||
import { auto500px } from './util/auto500px';
|
||||
|
||||
setAxiosXMLHttpRequest();
|
||||
|
||||
auto500px();
|
||||
createApp(PartialReservedCommand).use(BootstrapVue3).component('v-multiselect', Multiselect).mount('#reservedCommandList');
|
||||
|
||||
auto500px();
|
||||
@@ -0,0 +1,112 @@
|
||||
import '@scss/processing.scss';
|
||||
|
||||
import $ from 'jquery';
|
||||
exportWindow($, '$');
|
||||
import { exportWindow } from '@util/exportWindow';
|
||||
import axios from 'axios';
|
||||
import { setAxiosXMLHttpRequest } from '@util/setAxiosXMLHttpRequest';
|
||||
import { convertFormData } from '@util/convertFormData';
|
||||
import { InvalidResponse } from '@/defs';
|
||||
import { unwrap } from "@util/unwrap";
|
||||
import { defaultSelectCityByMap } from '@/defaultSelectCityByMap';
|
||||
import { defaultSelectNationByMap } from '@/defaultSelectNationByMap';
|
||||
import { colorSelect } from '@/colorSelect';
|
||||
import { recruitCrewForm } from '@/recruitCrewForm';
|
||||
import BootstrapVue3 from 'bootstrap-vue-3'
|
||||
import Multiselect from 'vue-multiselect';
|
||||
import * as GeneralActions from "@/processing/General";
|
||||
import * as NationActions from "@/processing/Nation";
|
||||
import { App, createApp } from 'vue';
|
||||
import { auto500px } from './util/auto500px';
|
||||
import { isString } from 'lodash';
|
||||
import { Args, testSubmitArgs } from './processing/args';
|
||||
|
||||
declare const turnList: number[];
|
||||
|
||||
setAxiosXMLHttpRequest();
|
||||
|
||||
async function submitCommand<T>(isChiefTurn: boolean, turnList: number[], command: string, args: Args): Promise<T> {
|
||||
|
||||
|
||||
const target = isChiefTurn ? 'j_set_chief_command.php' : 'j_set_general_command.php';
|
||||
|
||||
try {
|
||||
const testResult = testSubmitArgs(args);
|
||||
if (testResult !== true) {
|
||||
throw new TypeError(`Invalied Type ${testResult[0]}, ${testResult[2]} should be ${testResult[1]}`);
|
||||
}
|
||||
console.log('trySubmit', args);
|
||||
const response = await axios({
|
||||
url: target,
|
||||
responseType: 'json',
|
||||
method: 'post',
|
||||
data: convertFormData({
|
||||
action: command,
|
||||
turnList: turnList,
|
||||
arg: JSON.stringify(args)
|
||||
})
|
||||
});
|
||||
const data = response.data as InvalidResponse;
|
||||
if (!data.result) {
|
||||
throw data.reason;
|
||||
}
|
||||
|
||||
if (!isChiefTurn) {
|
||||
window.location.href = './';
|
||||
} else {
|
||||
window.location.href = 'b_chiefcenter.php';
|
||||
}
|
||||
|
||||
return data as unknown as T;
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e);
|
||||
if (isString(e)) {
|
||||
alert(e);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
declare const entryInfo: ['General', keyof typeof GeneralActions] | ['Nation', keyof typeof NationActions];
|
||||
|
||||
console.log('entry', entryInfo);
|
||||
|
||||
auto500px();
|
||||
const app: App<Element> | undefined = (function () {
|
||||
//NOTE: route를 쓴다?
|
||||
const groupName = entryInfo[0];
|
||||
if (groupName == 'General') {
|
||||
const moduleName = entryInfo[1];
|
||||
if (!(moduleName in GeneralActions)) {
|
||||
console.error(`${moduleName}이 ${groupName}에 없음`);
|
||||
}
|
||||
return createApp(GeneralActions[moduleName]);
|
||||
}
|
||||
if (groupName == 'Nation') {
|
||||
const moduleName = entryInfo[1];
|
||||
if (!(moduleName in GeneralActions)) {
|
||||
console.error(`${moduleName}이 ${groupName}에 없음`);
|
||||
}
|
||||
return createApp(NationActions[moduleName]);
|
||||
}
|
||||
|
||||
console.error('알수')
|
||||
return undefined;
|
||||
}());
|
||||
console.log(app);
|
||||
if (app === undefined) {
|
||||
console.error(`모듈이 지정되지 않음`, entryInfo);
|
||||
}
|
||||
else {
|
||||
|
||||
const div = unwrap(document.querySelector('#container'));
|
||||
div.addEventListener('customSubmit', (e: Event) => {
|
||||
const {detail} = e as unknown as CustomEvent<Args>;
|
||||
void submitCommand(entryInfo[0] == 'Nation', turnList, entryInfo[1], detail);
|
||||
}, true);
|
||||
|
||||
app.use(BootstrapVue3).component('v-multiselect', Multiselect).mount('#container');
|
||||
}
|
||||
Reference in New Issue
Block a user