feat(wip): 세력장수/암행부 컬럼 모두 등록 완료

This commit is contained in:
2022-04-07 03:03:38 +09:00
parent 35eafa36d6
commit 9133bbc3d4
4 changed files with 316 additions and 55 deletions
+10 -2
View File
@@ -147,7 +147,7 @@ class GeneralList extends \sammo\BaseAPI
[$queryColumns, $rankColumns] = General::mergeQueryColumn(array_keys(static::$viewColumns), 1);
$rawGeneralList = Util::convertArrayToDict($db->query('SELECT %l from general WHERE nation = %i', Util::formatListOfBackticks($queryColumns), $nationID), 'no');
$rawGeneralList = Util::convertArrayToDict($db->query('SELECT %l from general WHERE nation = %i ORDER BY turntime ASC', Util::formatListOfBackticks($queryColumns), $nationID), 'no');
$reservedCommand = [];
if ($this->permission >= 2) {
@@ -200,7 +200,6 @@ class GeneralList extends \sammo\BaseAPI
$getRankVar = fn ($key) => (fn ($rawGeneral) => (($rankList[$rawGeneral['no']] ?? [])[$key] ?? 0));
$specialViewFilter = [
'officerLevel' => fn ($rawGeneral) => $this->getOfficerLevel($rawGeneral),
'officerLevelText' => fn ($rawGeneral) => getOfficerLevelText($this->getOfficerLevel($rawGeneral), $nationArr['level']),
@@ -262,11 +261,20 @@ class GeneralList extends \sammo\BaseAPI
$generalList[] = $item;
}
if($this->permission >= 2){
$troops = $db->queryAllLists('SELECT troop_leader,name FROM troop WHERE nation = %i', $nationID);
}
else{
$troops = null;
}
$result = [
'result' => true,
'permission' => $this->permission,
'column' => array_keys($resultColumns),
'list' => $generalList,
'troops' => $troops,
'env' => $env,
];
+28 -14
View File
@@ -1,7 +1,8 @@
<template>
<BContainer id="container" :toast="{ root: true }" class="pageNationGeneral bg0">
<TopBackBar :title="title" />
<GeneralList v-if="asyncReady" :list="generalList" :env="envVal" :height="'fill'" />
<!-- eslint-disable-next-line vue/max-attributes-per-line -->
<GeneralList v-if="asyncReady" :list="generalList" :troops="troopList" :env="envVal" :height="'fill'" />
<BottomBar />
</BContainer>
</template>
@@ -25,46 +26,57 @@ import GeneralList from "./components/GeneralList.vue";
import { type GameConstStore, getGameConstStore } from "./GameConstStore";
const generalList = ref<GeneralListItem[]>([]);
const envVal = ref<GeneralListResponse['env']>({
const troopList = ref<Record<number, string>>({});
const envVal = ref<GeneralListResponse["env"]>({
year: 1,
month: 1,
turnterm: 1,
turntime: '2022-02-22 22:22:22.22222'
turntime: "2022-02-22 22:22:22.22222",
});
const gameConstStore = ref<GameConstStore>();
provide('gameConstStore', gameConstStore);
provide("gameConstStore", gameConstStore);
const asyncReady = ref(false);
const title = "세력 장수";
const storeP = getGameConstStore().then((store)=>{
const storeP = getGameConstStore().then((store) => {
gameConstStore.value = store;
});
void Promise.all([storeP]).then(()=>{
void Promise.all([storeP]).then(() => {
asyncReady.value = true;
});
onMounted(async () => {
try {
const { column, list, permission, env } = await SammoAPI.Nation.GeneralList();
const { column, list, permission, troops, env } = await SammoAPI.Nation.GeneralList();
troopList.value = {};
//XXX: 로직상 똑같은데....
if (permission == 0) {
const rawGeneralList = merge2DArrToObjectArr(column, list);
generalList.value = rawGeneralList.map((v) => {return { permission, ...v }});
generalList.value = rawGeneralList.map((v) => {
return { permission, ...v };
});
} else if (permission == 1) {
const rawGeneralList = merge2DArrToObjectArr(column, list);
generalList.value = rawGeneralList.map((v) => {return { permission, ...v }});
generalList.value = rawGeneralList.map((v) => {
return { permission, ...v };
});
} else if ([2, 3, 4].includes(permission)) {
const rawGeneralList = merge2DArrToObjectArr(column, list);
generalList.value = rawGeneralList.map((v) => {return { permission, ...v }});
generalList.value = rawGeneralList.map((v) => {
return { permission, ...v };
});
for(const [troopLeader, troopName] of troops){
troopList.value[troopLeader] = troopName;
}
} else {
throw `?? ${permission}`;
}
envVal.value = env;
} catch (e) {
console.error(e);
throw e;
@@ -73,13 +85,15 @@ onMounted(async () => {
</script>
<style lang="scss">
html, body, #app {
html,
body,
#app {
height: 100%;
}
.pageNationGeneral{
.pageNationGeneral {
display: grid;
grid-template-rows: auto 1fr auto;
height: 100%;
}
</style>
</style>
+275 -39
View File
@@ -32,6 +32,7 @@ import type {
GetRowIdParams,
GridApi,
GridReadyEvent,
RowNode,
} from "ag-grid-community";
import { getNpcColor } from "@/common_legacy";
import type { BaseWithValueColDefParams, ValueGetterParams } from "ag-grid-community/dist/lib/entities/colDef";
@@ -40,6 +41,9 @@ import { unwrap } from "@/util/unwrap";
import SimpleTooltipCell from "@/gridCellRenderer/SimpleTooltipCell.vue";
import GridTooltipCell, { type GridCellInfo } from "@/gridCellRenderer/GridTooltipCell.vue";
import { formatConnectScore } from "@/utilGame/formatConnectScore";
import { convertSearch초성 } from "@/util/convertSearch초성";
import { isString } from "lodash";
import { formatDefenceTrain } from "@/utilGame/formatDefenceTrain";
const props = defineProps({
list: {
@@ -47,6 +51,11 @@ const props = defineProps({
required: true,
},
troops: {
type: Object as PropType<Record<number, string>>,
required: true,
},
height: {
type: String as PropType<"static" | "fill" | number | `${number}px` | `${number}%`>,
required: false,
@@ -82,6 +91,18 @@ watch(
}
);
const generalByID = ref(new Map<number, GeneralListItem>());
function refineGeneralList(list: GeneralListItem[]) {
const map = new Map<number, GeneralListItem>();
for (const general of list) {
map.set(general.no, general);
}
generalByID.value = map;
}
refineGeneralList(props.list);
watch(() => props.list, refineGeneralList);
const gridApi = ref<GridApi>();
const columnApi = ref<ColumnApi>();
@@ -133,10 +154,15 @@ interface GenValueGetterParams extends ValueGetterParams {
data: GeneralListItem;
}
interface GenRowNode extends RowNode {
data: GeneralListItem;
}
interface GenColDef extends ColDef {
field?: headerType;
valueFormatter?: string | ((params: GenValueParams) => string);
filterValueGetter?: string | ((params: GenValueGetterParams) => string);
filterValueGetter?: string | ((params: GenValueGetterParams) => unknown);
valueGetter?: string | ((params: GenValueGetterParams) => unknown);
}
interface GenColGroupDef extends ColGroupDef {
@@ -156,8 +182,32 @@ function naiveCheClassNameFilter(value: string): string {
return text;
}
function numberFormatter(value: GenValueParams): string {
return (value.value as number).toLocaleString();
function numberFormatter(unit?: string) {
if (unit) {
return (value: GenValueParams): string => {
const valueText = (value.value as number).toLocaleString();
return `${valueText} ${unit}`;
};
}
return (value: GenValueParams): string => {
return (value.value as number).toLocaleString();
};
}
function extractTroopInfo(value: GeneralListItem): [string, GeneralListItemP2] | undefined {
if (value.permission == 0 || value.permission == 1) {
return undefined;
}
const troopID = value.troop;
if (!(troopID in props.troops)) {
return undefined;
}
const troopName = props.troops[troopID];
const troopLeader = generalByID.value.get(troopID) as GeneralListItemP2 | undefined;
if (troopLeader === undefined) {
return undefined;
}
return [troopName, troopLeader];
}
const defaultCellClass = ["cell-middle"];
@@ -206,6 +256,7 @@ const columnRawDefs = ref<Partial<Record<headerType, GenColDef | GenColGroupDef>
};
return style as CellStyle;
},
filterValueGetter: ({ data }) => convertSearch초성(data.name),
cellClass: defaultCellClass,
filter: true,
},
@@ -269,10 +320,10 @@ const columnRawDefs = ref<Partial<Record<headerType, GenColDef | GenColGroupDef>
const dataP2 = data as GeneralListItemP2;
if (2 <= dataP2.officerLevel && dataP2.officerLevel <= 4) {
const cityName = gameConstStore.value.cityConst[dataP2.officer_city].name;
return `${cityName} ${dataP2.officerLevelText}`;
return convertSearch초성(`${cityName} ${dataP2.officerLevelText}`);
}
}
return data.officerLevelText;
return convertSearch초성(data.officerLevelText);
},
filter: true,
cellClass: centerCellClass,
@@ -315,8 +366,116 @@ const columnRawDefs = ref<Partial<Record<headerType, GenColDef | GenColGroupDef>
},
],
},
gold: { headerName: "금", field: "gold", ...sortableNumber, valueFormatter: numberFormatter, width: 70 },
rice: { headerName: "쌀", field: "rice", ...sortableNumber, valueFormatter: numberFormatter, width: 70 },
goldRice: {
headerName: "자금",
children: [
{
headerName: "금/쌀",
cellRenderer: ({ data }: GenValueParams) => {
return `${data.gold.toLocaleString()} 금<br>${data.rice.toLocaleString()}`;
},
width: 80,
cellClass: rightAlignClass,
columnGroupShow: "closed",
sortable: true,
sortingOrder: ["desc", "asc", null],
comparator(_a, _b, { data: lhs }: GenRowNode, { data: rhs }: GenRowNode) {
const lhsAmount = lhs.gold + lhs.rice;
const rhsAmount = rhs.gold + rhs.rice;
return lhsAmount - rhsAmount;
},
},
{
headerName: "금",
field: "gold",
...sortableNumber,
valueFormatter: numberFormatter("금"),
width: 70,
columnGroupShow: "open",
},
{
headerName: "쌀",
field: "rice",
...sortableNumber,
valueFormatter: numberFormatter("쌀"),
width: 70,
columnGroupShow: "open",
},
],
},
city: {
headerName: "도시",
field: "city",
valueGetter: ({ data }) => {
if (data.permission == 0 || data.permission == 1) {
return "-";
}
return gameConstStore.value.cityConst[data.city].name;
},
filter: true,
sortable: true,
width: 60,
filterValueGetter: ({ data }) => {
if (data.permission == 0 || data.permission == 1) {
return "-";
}
return convertSearch초성(gameConstStore.value.cityConst[data.city].name);
},
},
troop: {
headerName: "부대",
field: "troop",
valueGetter: ({ data }: GenValueGetterParams) => {
const troopInfo = extractTroopInfo(data);
if (troopInfo === undefined) {
return "-";
}
const [troopName, troopLeader] = troopInfo;
const cityName = gameConstStore.value.cityConst[troopLeader.city].name;
return [troopName, cityName];
},
cellRenderer: ({ value }: { value: [string, string] | string }) => {
if (isString(value)) {
return value;
}
const [troopName, cityName] = value;
return `${troopName}<br>[${cityName}]`;
},
width: 90,
sortable: true,
comparator: (valX, valB, { data: lhs }: GenRowNode, { data: rhs }: GenRowNode) => {
const troopInfoLhs = extractTroopInfo(lhs);
const troopInfoRhs = extractTroopInfo(rhs);
console.log(troopInfoLhs, troopInfoRhs);
if (troopInfoLhs === troopInfoRhs) {
return 0;
}
if (troopInfoLhs === undefined) {
return 1;
}
if (troopInfoRhs === undefined) {
return -1;
}
return troopInfoLhs[0].localeCompare(troopInfoRhs[0]);
},
filter: true,
filterValueGetter: ({ data }) => {
const troopInfo = extractTroopInfo(data);
if (troopInfo === undefined) {
return "-";
}
const [troopName, troopLeader] = troopInfo;
const cityName = gameConstStore.value.cityConst[troopLeader.city].name;
return convertSearch초성(`${troopName}$${cityName}`);
},
},
crew: {
headerName: "보유 병력",
children: [
@@ -331,6 +490,7 @@ const columnRawDefs = ref<Partial<Record<headerType, GenColDef | GenColGroupDef>
];
})(),
},
columnGroupShow: "closed",
},
{
headerName: "훈/사",
@@ -341,6 +501,57 @@ const columnRawDefs = ref<Partial<Record<headerType, GenColDef | GenColGroupDef>
}
return `${data.train}<br>${data.atmos}`;
},
columnGroupShow: "closed",
},
{
headerName: "병종",
field: "crewtype",
cellRenderer: SimpleTooltipCell,
cellRendererParams: {
iActionMap: gameConstStore.value.iActionInfo.crewtype,
},
sortable: true,
columnGroupShow: "open",
filter: true,
filterValueGetter: ({ data }) => {
if (data.permission == 0 || data.permission == 1) {
return "-";
}
const name = gameConstStore.value.iActionInfo.crewtype[data.crewtype].name;
return convertSearch초성(name);
},
},
{
headerName: "병력",
field: "crew",
...sortableNumber,
valueFormatter: numberFormatter("명"),
width: 70,
columnGroupShow: "open",
},
{
headerName: "훈련",
field: "train",
...sortableNumber,
valueFormatter: numberFormatter(),
width: 70,
columnGroupShow: "open",
},
{
headerName: "병력",
field: "atmos",
...sortableNumber,
valueFormatter: numberFormatter(),
width: 70,
columnGroupShow: "open",
},
{
headerName: "수비",
field: "defence_train",
sortable: true,
sortingOrder: ["desc", "asc", null],
valueFormatter: ({ value }) => formatDefenceTrain(value as number),
width: 50,
},
],
},
@@ -375,6 +586,10 @@ const columnRawDefs = ref<Partial<Record<headerType, GenColDef | GenColGroupDef>
sortable: true,
filter: true,
columnGroupShow: "open",
filterValueGetter: ({ data }) => {
const name = gameConstStore.value.iActionInfo.personality[data.personal].name;
return convertSearch초성(name);
},
},
{
headerName: "내특",
@@ -387,6 +602,10 @@ const columnRawDefs = ref<Partial<Record<headerType, GenColDef | GenColGroupDef>
sortable: true,
filter: true,
columnGroupShow: "open",
filterValueGetter: ({ data }) => {
const name = gameConstStore.value.iActionInfo.specialDomestic[data.specialDomestic].name;
return convertSearch초성(name);
},
},
{
headerName: "전특",
@@ -399,38 +618,10 @@ const columnRawDefs = ref<Partial<Record<headerType, GenColDef | GenColGroupDef>
sortable: true,
filter: true,
columnGroupShow: "open",
},
],
},
years: {
headerName: "연도",
children: [
{
headerName: "요약",
width: 60,
cellRenderer: ({ data }: GenValueParams) => {
return `${data.age}세<br>${data.belong}`;
filterValueGetter: ({ data }) => {
const name = gameConstStore.value.iActionInfo.specialWar[data.specialWar].name;
return convertSearch초성(name);
},
cellClass: centerCellClass,
columnGroupShow: "closed",
},
{
headerName: "연령",
field: "age",
...sortableNumber,
valueFormatter: (v: GenValueParams) => `${v.value}`,
width: 60,
cellClass: centerCellClass,
columnGroupShow: "open",
},
{
headerName: "사관",
field: "belong",
...sortableNumber,
valueFormatter: (v: GenValueParams) => `${v.value}`,
width: 60,
cellClass: centerCellClass,
columnGroupShow: "open",
},
],
},
@@ -477,6 +668,52 @@ const columnRawDefs = ref<Partial<Record<headerType, GenColDef | GenColGroupDef>
},
],
},
turntime: {
headerName: "턴",
field: 'turntime',
width: 60,
valueFormatter: ({value, data}) => {
if(data.permission == 0 || data.permission == 1){
return '-';
}
const turntime = value as string;
return turntime.substring(14, 19);
},
sortable: true,
cellClass: centerCellClass,
},
years: {
headerName: "연도",
children: [
{
headerName: "요약",
width: 60,
cellRenderer: ({ data }: GenValueParams) => {
return `${data.age}세<br>${data.belong}`;
},
cellClass: centerCellClass,
columnGroupShow: "closed",
},
{
headerName: "연령",
field: "age",
...sortableNumber,
valueFormatter: (v: GenValueParams) => `${v.value}`,
width: 60,
cellClass: centerCellClass,
columnGroupShow: "open",
},
{
headerName: "사관",
field: "belong",
...sortableNumber,
valueFormatter: (v: GenValueParams) => `${v.value}`,
width: 60,
cellClass: centerCellClass,
columnGroupShow: "open",
},
],
},
killturnAndConnect: {
headerName: "기타",
children: [
@@ -521,7 +758,6 @@ watch(columnRawDefs, (val) => {
columnDefs.value = [...Object.values(val)];
gridApi.value?.redrawRows();
});
</script>
<style scoped lang="scss">
+3
View File
@@ -88,6 +88,7 @@ export type RawGeneralListP0 = ValidResponse & {
permission: 0,
column: (keyof GeneralListItemP0)[],
list: ValuesOf<GeneralListItemP0>[][],
troops?: null,
env: ResponseEnv,
}
@@ -95,6 +96,7 @@ export type RawGeneralListP1 = ValidResponse & {
permission: 1,
column: (keyof GeneralListItemP1)[],
list: ValuesOf<GeneralListItemP1>[][],
troops?: null,
env: ResponseEnv,
}
@@ -102,6 +104,7 @@ export type RawGeneralListP2 = ValidResponse & {
permission: 2 | 3 | 4,
column: (keyof GeneralListItemP2)[],
list: ValuesOf<GeneralListItemP2>[][],
troops: [number, string][],
env: ResponseEnv,
}