feat(WIP): processing을 vue로 전환
This commit is contained in:
+13
-38
@@ -77,55 +77,30 @@ $cssList = $commandObj->getCSSFiles();
|
|||||||
<meta name="viewport" content="width=1024" />
|
<meta name="viewport" content="width=1024" />
|
||||||
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
|
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
|
||||||
<?= WebUtil::printJS('d_shared/base_map.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>
|
<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>
|
</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" />
|
<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
|
<?php
|
||||||
foreach ($cssList as $css) {
|
foreach ($cssList as $css) {
|
||||||
print(WebUtil::printCSS($css));
|
print(WebUtil::printCSS($css));
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<?= WebUtil::printDist('ts', ['common', 'processing']) ?>
|
<?= WebUtil::printDist('vue', ['v_processing'], true) ?>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="img_back">
|
<body class="img_back">
|
||||||
<table class="tb_layout bg0" style="width:1000px;margin:auto;">
|
<div id="container"></div>
|
||||||
<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>
|
|
||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</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;
|
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)
|
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>";
|
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
|
function printCitiesBasedOnDistance(int $cityNo, int $maxDistance = 1): string
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -225,6 +225,14 @@ function formatName(string $name, int $npc): string
|
|||||||
return $name;
|
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)
|
function getMapHtml(?string $mapTheme = null)
|
||||||
{
|
{
|
||||||
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
|
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
|
||||||
|
|||||||
@@ -478,6 +478,9 @@ abstract class BaseCommand{
|
|||||||
public function getJSPlugins():array {
|
public function getJSPlugins():array {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
public function exportJSVars():array {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
public function getCSSFiles():array {
|
public function getCSSFiles():array {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use \sammo\GameUnitConst;
|
|||||||
use \sammo\LastTurn;
|
use \sammo\LastTurn;
|
||||||
use \sammo\Command;
|
use \sammo\Command;
|
||||||
|
|
||||||
|
use function sammo\getMapTheme;
|
||||||
use function \sammo\printCitiesBasedOnDistance;
|
use function \sammo\printCitiesBasedOnDistance;
|
||||||
use function sammo\tryUniqueItemLottery;
|
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
|
public function getForm(): string
|
||||||
{
|
{
|
||||||
$currentCityID = $this->generalObj->getCityID();
|
$currentCityID = $this->generalObj->getCityID();
|
||||||
@@ -187,7 +197,7 @@ class che_강행 extends Command\GeneralCommand
|
|||||||
선택된 도시로 강행합니다.<br>
|
선택된 도시로 강행합니다.<br>
|
||||||
최대 3칸내 도시로만 강행이 가능합니다.<br>
|
최대 3칸내 도시로만 강행이 가능합니다.<br>
|
||||||
목록을 선택하거나 도시를 클릭하세요.<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>
|
<?= \sammo\optionsForCities() ?><br>
|
||||||
</select> <input type=button id="commonSubmit" value="<?= $this->getName() ?>"><br>
|
</select> <input type=button id="commonSubmit" value="<?= $this->getName() ?>"><br>
|
||||||
<br>
|
<br>
|
||||||
|
|||||||
@@ -184,6 +184,13 @@ class che_이동 extends Command\GeneralCommand
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function exportJSVars(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'cities' => \sammo\JSOptionsForCities()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public function getForm(): string
|
public function getForm(): string
|
||||||
{
|
{
|
||||||
$currentCityID = $this->generalObj->getCityID();
|
$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",
|
"install": "install.ts",
|
||||||
"battle_simulator": "battle_simulator.ts",
|
"battle_simulator": "battle_simulator.ts",
|
||||||
"recent_map": "recent_map.ts",
|
"recent_map": "recent_map.ts",
|
||||||
"processing": "processing.ts",
|
|
||||||
"select_npc": "select_npc.ts",
|
"select_npc": "select_npc.ts",
|
||||||
"betting": "betting.ts",
|
"betting": "betting.ts",
|
||||||
"bossInfo": "bossInfo.ts",
|
"bossInfo": "bossInfo.ts",
|
||||||
@@ -27,7 +26,7 @@
|
|||||||
"v_NPCControl": "v_NPCControl.ts",
|
"v_NPCControl": "v_NPCControl.ts",
|
||||||
"v_join": "v_join.ts",
|
"v_join": "v_join.ts",
|
||||||
"v_main": "v_main.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 { reloadWorldMap } from "@/map";
|
||||||
import { unwrap_any } from "@util/unwrap_any";
|
|
||||||
|
declare let vueReactive_destCityID: number|undefined;
|
||||||
|
|
||||||
export function defaultSelectCityByMap(): void {
|
export function defaultSelectCityByMap(): void {
|
||||||
const $target = $("#destCityID");
|
|
||||||
console.log('city', $target);
|
|
||||||
void reloadWorldMap({
|
void reloadWorldMap({
|
||||||
isDetailMap: false,
|
isDetailMap: false,
|
||||||
clickableAll: true,
|
clickableAll: true,
|
||||||
neutralView: true,
|
neutralView: true,
|
||||||
useCachedMap: true,
|
useCachedMap: true,
|
||||||
selectCallback: function (city) {
|
selectCallback: function (city) {
|
||||||
const currVal = unwrap_any<string>($target.val());
|
if(vueReactive_destCityID === undefined){
|
||||||
$target.val(city.id);
|
console.error('아직 초기화 되지 않음');
|
||||||
$target.trigger("change");
|
return false;
|
||||||
if ($target.val() === null) {
|
|
||||||
$target.val(currVal).trigger("change").blur();
|
|
||||||
}
|
}
|
||||||
|
vueReactive_destCityID = city.id;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { reloadWorldMap } from "@/map";
|
import { reloadWorldMap } from "@/map";
|
||||||
import { unwrap_any } from "@util/unwrap_any";
|
|
||||||
|
declare let vueReactive_destNationID: number|undefined;
|
||||||
|
|
||||||
export function defaultSelectNationByMap(): void{
|
export function defaultSelectNationByMap(): void{
|
||||||
const $target = $("#destNationID");
|
const $target = $("#destNationID");
|
||||||
@@ -9,15 +10,12 @@ export function defaultSelectNationByMap(): void{
|
|||||||
clickableAll: true,
|
clickableAll: true,
|
||||||
neutralView: true,
|
neutralView: true,
|
||||||
useCachedMap: true,
|
useCachedMap: true,
|
||||||
selectCallback: (city)=>{
|
selectCallback: function (city) {
|
||||||
const currVal = unwrap_any<string>($target.val());
|
if(typeof vueReactive_destNationID === 'undefined'){
|
||||||
if(!city.nationID){
|
console.error('아직 초기화 되지 않음');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$target.val(city.nationID).trigger("change");
|
vueReactive_destNationID = city.nationID;
|
||||||
if ($target.val() === null) {
|
|
||||||
$target.val(currVal).trigger("change");
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
+13
-10
@@ -1,11 +1,12 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import { extend, isNumber } from 'lodash';
|
import { extend, isNumber, merge } from 'lodash';
|
||||||
import { convColorValue, convertDictById, stringFormat } from '@/common_legacy';
|
import { convColorValue, convertDictById, stringFormat } from '@/common_legacy';
|
||||||
import { InvalidResponse } from '@/defs';
|
import { InvalidResponse } from '@/defs';
|
||||||
import { unwrap } from "@util/unwrap";
|
import { unwrap } from "@util/unwrap";
|
||||||
import { convertFormData } from '@util/convertFormData';
|
import { convertFormData } from '@util/convertFormData';
|
||||||
import { exportWindow } from '@util/exportWindow';
|
import { exportWindow } from '@util/exportWindow';
|
||||||
|
import { htmlReady } from './util/htmlReady';
|
||||||
|
|
||||||
declare const serverNick: string;
|
declare const serverNick: string;
|
||||||
declare const serverID: string;
|
declare const serverID: string;
|
||||||
@@ -57,7 +58,7 @@ type MapCityParsedRegionLevelText = MapCityParsedClickable & {
|
|||||||
text: string,
|
text: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
type MapCityParsed = MapCityParsedRegionLevelText;
|
export type MapCityParsed = MapCityParsedRegionLevelText;
|
||||||
|
|
||||||
type MapCityDrawable = {
|
type MapCityDrawable = {
|
||||||
cityList: MapCityParsed[],
|
cityList: MapCityParsed[],
|
||||||
@@ -107,7 +108,7 @@ function is_touch_device(): boolean {
|
|||||||
return mq(query);
|
return mq(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
type loadMapOption = {
|
export type loadMapOption = {
|
||||||
isDetailMap?: boolean, //복잡 지도, 단순 지도
|
isDetailMap?: boolean, //복잡 지도, 단순 지도
|
||||||
clickableAll?: boolean, //어떤 경우든 클릭을 가능하게 함. 해당 동작의 동작 가능성 여부와는 별도.
|
clickableAll?: boolean, //어떤 경우든 클릭을 가능하게 함. 해당 동작의 동작 가능성 여부와는 별도.
|
||||||
selectCallback?: (city: MapCityParsed) => void, //callback을 지정시 clickable과 관계 없이 해당 함수를 실행.
|
selectCallback?: (city: MapCityParsed) => void, //callback을 지정시 clickable과 관계 없이 해당 함수를 실행.
|
||||||
@@ -160,7 +161,7 @@ export async function reloadWorldMap(option: loadMapOption, drawTarget = '.world
|
|||||||
startYear: undefined,
|
startYear: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
option = extend({}, defaultOption, option);
|
option = merge({}, defaultOption, option);
|
||||||
|
|
||||||
const useCachedMap = option.useCachedMap;
|
const useCachedMap = option.useCachedMap;
|
||||||
const isDetailMap = option.isDetailMap;
|
const isDetailMap = option.isDetailMap;
|
||||||
@@ -671,7 +672,6 @@ export async function reloadWorldMap(option: loadMapOption, drawTarget = '.world
|
|||||||
|
|
||||||
const $hideCityNameBtn = $world_map.find('.map_toggle_cityname');
|
const $hideCityNameBtn = $world_map.find('.map_toggle_cityname');
|
||||||
if (localStorage.getItem('sam.hideMapCityName') == 'yes') {
|
if (localStorage.getItem('sam.hideMapCityName') == 'yes') {
|
||||||
console.log('tryHide!');
|
|
||||||
$world_map.addClass('hide_cityname');
|
$world_map.addClass('hide_cityname');
|
||||||
$hideCityNameBtn.addClass('active').attr('aria-pressed', 'true');
|
$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';
|
const state = localStorage.getItem('sam.hideMapCityName') == 'no';
|
||||||
if (state) {
|
if (state) {
|
||||||
console.log('tryHide!');
|
|
||||||
$world_map.addClass('hide_cityname');
|
$world_map.addClass('hide_cityname');
|
||||||
localStorage.setItem('sam.hideMapCityName', 'yes');
|
localStorage.setItem('sam.hideMapCityName', 'yes');
|
||||||
} else {
|
} else {
|
||||||
@@ -789,8 +788,12 @@ export async function reloadWorldMap(option: loadMapOption, drawTarget = '.world
|
|||||||
}
|
}
|
||||||
|
|
||||||
exportWindow(reloadWorldMap, 'reloadWorldMap');
|
exportWindow(reloadWorldMap, 'reloadWorldMap');
|
||||||
$(function ($) {
|
htmlReady(function(){
|
||||||
if (is_touch_device()) {
|
if( is_touch_device()){
|
||||||
$('.map_body .map_toggle_single_tap').show();
|
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';
|
import { auto500px } from './util/auto500px';
|
||||||
|
|
||||||
setAxiosXMLHttpRequest();
|
setAxiosXMLHttpRequest();
|
||||||
|
auto500px();
|
||||||
createApp(PartialReservedCommand).use(BootstrapVue3).component('v-multiselect', Multiselect).mount('#reservedCommandList');
|
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