diff --git a/hwe/sammo/API/Nation/GeneralList.php b/hwe/sammo/API/Nation/GeneralList.php
index d29ab73d..9dea5450 100644
--- a/hwe/sammo/API/Nation/GeneralList.php
+++ b/hwe/sammo/API/Nation/GeneralList.php
@@ -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,
];
diff --git a/hwe/ts/PageNationGeneral.vue b/hwe/ts/PageNationGeneral.vue
index d5ac1313..b1ba3c60 100644
--- a/hwe/ts/PageNationGeneral.vue
+++ b/hwe/ts/PageNationGeneral.vue
@@ -1,7 +1,8 @@
-
+
+
@@ -25,46 +26,57 @@ import GeneralList from "./components/GeneralList.vue";
import { type GameConstStore, getGameConstStore } from "./GameConstStore";
const generalList = ref([]);
-const envVal = ref({
+const troopList = ref>({});
+const envVal = ref({
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();
-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 () => {
\ No newline at end of file
+
diff --git a/hwe/ts/components/GeneralList.vue b/hwe/ts/components/GeneralList.vue
index f122a5e3..eeac4d8f 100644
--- a/hwe/ts/components/GeneralList.vue
+++ b/hwe/ts/components/GeneralList.vue
@@ -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>,
+ 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());
+
+function refineGeneralList(list: GeneralListItem[]) {
+ const map = new Map();
+ for (const general of list) {
+ map.set(general.no, general);
+ }
+ generalByID.value = map;
+}
+refineGeneralList(props.list);
+watch(() => props.list, refineGeneralList);
+
const gridApi = ref();
const columnApi = ref();
@@ -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
};
return style as CellStyle;
},
+ filterValueGetter: ({ data }) => convertSearch초성(data.name),
cellClass: defaultCellClass,
filter: true,
},
@@ -269,10 +320,10 @@ const columnRawDefs = ref
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
},
],
},
- 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()} 금
${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}
[${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
];
})(),
},
+ columnGroupShow: "closed",
},
{
headerName: "훈/사",
@@ -341,6 +501,57 @@ const columnRawDefs = ref
}
return `${data.train}
${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
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
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
sortable: true,
filter: true,
columnGroupShow: "open",
- },
- ],
- },
- years: {
- headerName: "연도",
- children: [
- {
- headerName: "요약",
- width: 60,
- cellRenderer: ({ data }: GenValueParams) => {
- return `${data.age}세
${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
},
],
},
+ 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}세
${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();
});
-