feat(wip): 1차 기능 완성

This commit is contained in:
2022-04-07 03:03:38 +09:00
parent c07c481a6c
commit 7645ae7ee8
2 changed files with 674 additions and 132 deletions
+107 -132
View File
@@ -1,16 +1,25 @@
<template>
<Teleport v-if="toolbarID" :to="`#${toolbarID}`">
<BButtonGroup class="d-flex general-list-toolbar">
<BDropdown class="w-50" variant="primary" text="보기 모드">
<BDropdownItem></BDropdownItem>
<BDropdownItem></BDropdownItem>
<BDropdown class="w-50" menuClass="view-mode-list" variant="primary" text="보기 모드">
<BDropdownItem @click="setDisplaySetting(defaultDisplaySetting.normal)">기본</BDropdownItem>
<BDropdownItem @click="setDisplaySetting(defaultDisplaySetting.war)">전투</BDropdownItem>
<BDropdownDivider />
<BDropdownItem></BDropdownItem>
<BDropdownItem></BDropdownItem>
<BDropdownItem @click="storeDisplaySetting"><i class="bi bi-bookmark-plus-fill" />&nbsp;보관하기</BDropdownItem>
<BDropdownDivider />
<BDropdownItem
v-for="[key, setting] of displaySettings.entries()"
:key="key"
@click="setDisplaySetting(setting)"
><div class="row gx-0">
<div class="col-9 text-wrap"><span class="align-middle">{{ key }}</span></div>
<div class="col-3"><div class="d-grid"><BButton size="sm" @click="deleteDisplaySetting(key)">삭제</BButton></div></div>
</div></BDropdownItem
>
</BDropdown>
<BDropdown class="w-50" variant="info" text="열 선택" menuClass="column-menu" right>
<template v-for="[colID, col, depth] of getColumnList()" :key="[colID, depth]">
<BDropdownItem v-if="col instanceof ColumnGroup" disabled>
<BDropdownItem v-if="col instanceof ProvidedColumnGroup" disabled>
<span :style="{ marginLeft: depth ? `${12 * depth}px` : undefined }">
{{ col.getColGroupDef()?.headerName }}</span
></BDropdownItem
@@ -48,6 +57,7 @@
:columnDefs="columnDefs"
:rowData="list"
:defaultColDef="defaultColDef"
:suppressColumnMoveAnimation="suppressColumnMoveAnimation"
@grid-ready="onGridReady"
/>
</div>
@@ -70,7 +80,7 @@ import type {
GridReadyEvent,
RowNode,
} from "ag-grid-community";
import { ColumnGroup } from "ag-grid-community";
import { ProvidedColumnGroup } from "ag-grid-community";
import { getNpcColor } from "@/common_legacy";
import type { BaseWithValueColDefParams, ValueGetterParams } from "ag-grid-community/dist/lib/entities/colDef";
import type { GameConstStore } from "@/GameConstStore";
@@ -81,21 +91,19 @@ import { formatConnectScore } from "@/utilGame/formatConnectScore";
import { convertSearch초성 } from "@/util/convertSearch초성";
import { isString } from "lodash";
import { formatDefenceTrain } from "@/utilGame/formatDefenceTrain";
import { BDropdownItem, BDropdownDivider, BButtonGroup, BDropdown } from "bootstrap-vue-3";
import { BDropdownItem, BDropdownDivider, BButtonGroup, BDropdown, BButton } from "bootstrap-vue-3";
import { unwrap_err } from "@/util/unwrap_err";
import { RuntimeError } from "@/util/RuntimeError";
import { defaultDisplaySetting, type GridDisplaySetting } from "@/defs/gridDefs";
const props = defineProps({
list: {
type: Array as PropType<GeneralListItem[]>,
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,
@@ -105,7 +113,6 @@ const props = defineProps({
type: Object as PropType<GeneralListResponse["env"]>,
required: true,
},
toolbarID: {
type: String,
required: false,
@@ -113,19 +120,17 @@ const props = defineProps({
},
});
const suppressColumnMoveAnimation = ref(true);
const gameConstStore = unwrap(inject<Ref<GameConstStore>>("gameConstStore"));
//debug
watch(
() => props.list,
() => {
setTimeout(() => {
//debug
gridApi.value?.redrawRows();
}, 0);
}
);
watch(
() => props.height,
(val) => {
@@ -136,9 +141,7 @@ watch(
}
}
);
const generalByID = ref(new Map<number, GeneralListItem>());
function refineGeneralList(list: GeneralListItem[]) {
const map = new Map<number, GeneralListItem>();
for (const general of list) {
@@ -148,55 +151,107 @@ function refineGeneralList(list: GeneralListItem[]) {
}
refineGeneralList(props.list);
watch(() => props.list, refineGeneralList);
const gridApi = ref<GridApi>();
const columnApi = ref<ColumnApi>();
const rowHeight = ref(68);
function getRowId(params: GetRowIdParams): string {
const genID = (params.data as GeneralListItem).no;
return `${genID}`;
}
function setDisplaySetting(setting: GridDisplaySetting) {
if (!columnApi.value) {
console.error("nyc?");
return;
}
columnApi.value.applyColumnState({ state: setting.column, applyOrder: true });
columnApi.value.setColumnGroupState(setting.columnGroup);
}
const displaySettings = ref(new Map<string, GridDisplaySetting>());
const displaySettingVersion = 1; //추가되는 걸로 버전 올리지 말고, 사용할 수 없게 될때만 올리기
const displaySettingsKey = "GeneralListDisplaySetting";
function loadDisplaySetting() {
const rawSettings = localStorage.getItem(displaySettingsKey);
if (!rawSettings) {
return;
}
const settings: { version: number; settings: [string, GridDisplaySetting][] } = JSON.parse(rawSettings);
if (settings.version != displaySettingVersion) {
localStorage.removeItem(displaySettingsKey);
return;
}
displaySettings.value = new Map(settings.settings);
}
loadDisplaySetting();
watch(
displaySettings,
(newSettings) => {
const settings = Array.from(newSettings.entries());
localStorage.setItem(
displaySettingsKey,
JSON.stringify({
version: displaySettingVersion,
settings,
})
);
console.log("저장!", Array.from(newSettings.keys()));
},
{ deep: true }
);
function deleteDisplaySetting(key: string){
if (!confirm(`${key} 설정을 지울까요?`)) {
return;
}
displaySettings.value.delete(key);
}
function storeDisplaySetting() {
if (!columnApi.value) {
console.error("nyc?");
return;
}
const nickName = prompt("선택한 설정의 별명을 지어주세요");
if (!nickName) {
return;
}
if (displaySettings.value.has(nickName)) {
if (!confirm("이미 있는 이름입니다. 덮어쓸까요?")) {
return;
}
}
const setting: GridDisplaySetting = {
column: columnApi.value.getColumnState(),
columnGroup: columnApi.value.getColumnGroupState(),
};
displaySettings.value.set(nickName, setting);
}
function onGridReady(params: GridReadyEvent) {
gridApi.value = params.api;
columnApi.value = params.columnApi;
setRowHeight();
if (props.height === "static") {
params.api.setDomLayout("autoHeight");
} else {
params.api.setDomLayout("normal");
}
}
function setRowHeight() {
if (columnApi.value === undefined) {
console.error("아직 준비 안됨?");
return;
}
/*
let height = gridApi.value?.getSizesForCurrentTheme().rowHeight ?? 28;
if (columnApi.value.getColumn("icon")?.isVisible()) {
height = Math.max(height, 64 + 4);
}
if (columnApi.value.getColumn("reservedCommand")?.isVisible()) {
height = Math.max(height, 64 + 4);
}
if(rowHeight.value != height){
rowHeight.value = height;
gridApi.value?.redrawRows();
}
*/
setDisplaySetting(defaultDisplaySetting.normal);
setTimeout(() => {
suppressColumnMoveAnimation.value = false;
}, 1);
}
function getRowHeight(): number {
return rowHeight.value;
}
type headerType =
| keyof Omit<GeneralListItemP2, "no" | "imgsvr" | "picture" | "lbonus">
| "stat"
@@ -209,19 +264,15 @@ type headerType =
| "reservedCommandShort"
| "killturnAndConnect"
| "years";
interface GenValueParams extends BaseWithValueColDefParams {
data: GeneralListItem;
}
interface GenValueGetterParams extends ValueGetterParams {
data: GeneralListItem;
}
interface GenRowNode extends RowNode {
data: GeneralListItem;
}
interface GenColDef extends ColDef {
colId: headerType;
field?: headerType;
@@ -230,19 +281,16 @@ interface GenColDef extends ColDef {
filterValueGetter?: string | ((params: GenValueGetterParams) => unknown);
valueGetter?: string | ((params: GenValueGetterParams) => unknown);
}
interface GenColGroupDef extends ColGroupDef {
headerName: string;
children: GenColDef[]; //1단만 할꺼다!
groupId: headerType;
}
interface GenCellClassParams extends CellClassParams {
data: GeneralListItem;
}
function getColumnList(): [headerType, ColumnGroup | Column, number?][] {
const result: [headerType, ColumnGroup | Column, number?][] = [];
function getColumnList(): [headerType, ProvidedColumnGroup | Column, number?][] {
const result: [headerType, ProvidedColumnGroup | Column, number?][] = [];
if (!columnApi.value) {
return result;
}
@@ -255,9 +303,8 @@ function getColumnList(): [headerType, ColumnGroup | Column, number?][] {
result.push([rawColDef.colId, col]);
continue;
}
const colGroup = unwrap_err(
columnApi.value.getColumnGroup(rawColDef.groupId),
columnApi.value.getProvidedColumnGroup(rawColDef.groupId),
RuntimeError,
`no colGroup: ${rawColDef.groupId}`
);
@@ -273,7 +320,6 @@ function getColumnList(): [headerType, ColumnGroup | Column, number?][] {
}
return result;
}
function naiveCheClassNameFilter(value: string): string {
const text = value.split("_").pop() ?? "None";
if (text === "None") {
@@ -281,7 +327,6 @@ function naiveCheClassNameFilter(value: string): string {
}
return text;
}
function numberFormatter(unit?: string) {
if (unit) {
return (value: GenValueParams): string => {
@@ -293,7 +338,6 @@ function numberFormatter(unit?: string) {
return (value.value as number).toLocaleString();
};
}
function extractTroopInfo(value: GeneralListItem): [string, GeneralListItemP2] | undefined {
if (value.permission == 0 || value.permission == 1) {
return undefined;
@@ -309,11 +353,9 @@ function extractTroopInfo(value: GeneralListItem): [string, GeneralListItemP2] |
}
return [troopName, troopLeader];
}
function toggleColumn(colID: headerType, col: Column) {
const newState = !col.isVisible();
const target: string[] = [colID];
const parent = col.getParent();
if (newState) {
for (const child of (parent.getChildren() ?? []) as Column[]) {
@@ -336,15 +378,12 @@ function toggleColumn(colID: headerType, col: Column) {
stillVisible = true;
break;
}
if (!stillVisible && header) {
target.push(header);
}
}
columnApi.value?.setColumnsVisible(target, newState);
setRowHeight();
}
const defaultCellClass = ["cell-middle"];
const centerCellClass = [...defaultCellClass, "cell-center"];
const rightAlignClass = [...defaultCellClass, "cell-right"];
@@ -361,9 +400,7 @@ const defaultColDef = ref<ColDef>({
cellClass: centerCellClass,
floatingFilter: true,
width: 80,
//initialHide: true,
});
const columnRawDefs = ref<Partial<Record<headerType, GenColDef | GenColGroupDef>>>({
icon: {
colId: "icon",
@@ -410,7 +447,6 @@ const columnRawDefs = ref<Partial<Record<headerType, GenColDef | GenColGroupDef>
colId: "stat",
headerName: "통|무|지",
width: 88,
cellRenderer: (obj: GenValueParams) => {
const gen = obj.data;
return `${gen.leadership}|${gen.strength}|${gen.intel}`;
@@ -555,7 +591,6 @@ const columnRawDefs = ref<Partial<Record<headerType, GenColDef | GenColGroupDef>
},
],
},
city: {
colId: "city",
headerName: "도시",
@@ -576,7 +611,6 @@ const columnRawDefs = ref<Partial<Record<headerType, GenColDef | GenColGroupDef>
return convertSearch초성(gameConstStore.value.cityConst[data.city].name);
},
},
troop: {
colId: "troop",
headerName: "부대",
@@ -586,7 +620,6 @@ const columnRawDefs = ref<Partial<Record<headerType, GenColDef | GenColGroupDef>
if (troopInfo === undefined) {
return "-";
}
const [troopName, troopLeader] = troopInfo;
const cityName = gameConstStore.value.cityConst[troopLeader.city].name;
return [troopName, cityName];
@@ -613,7 +646,6 @@ const columnRawDefs = ref<Partial<Record<headerType, GenColDef | GenColGroupDef>
if (troopInfoRhs === undefined) {
return -1;
}
return troopInfoLhs[0].localeCompare(troopInfoRhs[0]);
},
filter: true,
@@ -624,11 +656,9 @@ const columnRawDefs = ref<Partial<Record<headerType, GenColDef | GenColGroupDef>
}
const [troopName, troopLeader] = troopInfo;
const cityName = gameConstStore.value.cityConst[troopLeader.city].name;
return convertSearch초성(`${troopName}$${cityName}`);
},
},
crewtypeAndCrew: {
groupId: "crewtypeAndCrew",
headerName: "보유 병력",
@@ -933,128 +963,73 @@ const columnRawDefs = ref<Partial<Record<headerType, GenColDef | GenColGroupDef>
],
},
});
type DisplaySetting = {
showColumnOrder?: headerType[];
openedGroup?: headerType[];
explicitHide?: headerType[];
sort?: [headerType, "asc" | "desc" | null][];
};
const defaultSettings: Record<"war" | "light", DisplaySetting> = {
war: {
showColumnOrder: [
"stat",
"troop",
"goldRice",
"city",
"defence_train",
"crew",
"reservedCommand",
"killturn",
"turntime",
],
openedGroup: ["goldRice", "crew"],
sort: [["turntime", "asc"]],
},
light: {
showColumnOrder: [
"icon",
"officerLevel",
"expDedLv",
"stat",
"goldRice",
"specials",
"years",
"killturnAndConnect",
],
openedGroup: ["expDedLv", "stat", "goldRice", "specials", "years", "killturnAndConnect"],
explicitHide: ["killturn"],
sort: [["connect", "desc"]],
},
};
const defaultSettingID: keyof typeof defaultSettings = "war";
const columnDefs = ref([...Object.values(columnRawDefs.value)]);
watch(columnRawDefs, (val) => {
setRowHeight();
columnDefs.value = [...Object.values(val)];
gridApi.value?.refreshCells();
});
</script>
<style scoped lang="scss">
.g-tr {
border-bottom: solid gray 1px;
}
.g-thead-tr {
position: sticky;
top: 0px;
z-index: 5;
}
</style>
:deep(.view-mode-list){
width:180px;
}
</style>
<style lang="scss">
.component-general-list {
.ag-root-wrapper .cell-middle {
display: flex;
align-items: center;
}
.ag-root-wrapper {
font-family: "Pretendard", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic";
font-size: 14px;
overflow: auto;
}
.ag-root {
overflow: auto;
}
.ag-header {
position: sticky;
top: 0;
z-index: 10;
}
.cell-center {
justify-content: space-around;
text-align: center;
}
.cell-right {
justify-content: flex-end;
text-align: right;
}
.cell-sp .col {
min-width: 30px;
}
.ag-header-cell,
.ag-header-group-cell,
.ag-cell {
padding-left: 4px;
padding-right: 4px;
}
.ag-header-cell-label,
.ag-header-group-cell-label {
justify-content: center;
}
.ag-ltr .ag-floating-filter-button {
margin-left: 2px;
}
.ag-rtl .ag-floating-filter-button {
margin-right: 2px;
}
}
.general-list-toolbar {
.column-menu {
column-count: 3;
+567
View File
@@ -0,0 +1,567 @@
import type { ColumnState } from "ag-grid-community";
export type GridDisplaySetting = {
column: ColumnState[];
columnGroup: {
groupId: string;
open: boolean;
}[];
};
export const defaultDisplaySetting: Record<"war" | "normal", GridDisplaySetting> = {
war: {
column: [
{
colId: "icon",
width: 80,
hide: true,
sort: null,
},
{
colId: "name",
width: 126,
hide: false,
sort: null,
},
{
colId: "stat_1",
width: 88,
hide: false,
sort: null,
},
{
colId: "troop",
width: 90,
hide: false,
sort: null,
},
{
colId: "leadership",
width: 60,
hide: false,
sort: null,
},
{
colId: "strength",
width: 60,
hide: false,
sort: null,
},
{
colId: "intel",
width: 60,
hide: false,
sort: null,
},
{
colId: "officerLevel",
width: 70,
hide: true,
sort: null,
},
{
colId: "expDedLv_1",
width: 60,
hide: true,
sort: null,
},
{
colId: "explevel",
width: 60,
hide: true,
sort: null,
},
{
colId: "dedlevel",
width: 70,
hide: true,
sort: null,
},
{
colId: "goldRice_1",
width: 80,
hide: false,
sort: null,
},
{
colId: "gold",
width: 70,
hide: false,
sort: null,
},
{
colId: "rice",
width: 70,
hide: false,
sort: null,
},
{
colId: "city",
width: 60,
hide: false,
sort: null,
},
{
colId: "crewtypeAndCrew_1",
width: 80,
hide: false,
sort: null,
},
{
colId: "crewtype",
width: 80,
hide: false,
sort: null,
},
{
colId: "crew",
width: 70,
hide: false,
sort: null,
},
{
colId: "trainAtmos_1",
width: 60,
hide: false,
sort: null,
},
{
colId: "train",
width: 70,
hide: false,
sort: null,
},
{
colId: "atmos",
width: 70,
hide: false,
sort: null,
},
{
colId: "defence_train",
width: 50,
hide: false,
sort: null,
},
{
colId: "specials_1",
width: 80,
hide: true,
sort: null,
},
{
colId: "personal",
width: 60,
hide: true,
sort: null,
},
{
colId: "specialDomestic",
width: 60,
hide: true,
sort: null,
},
{
colId: "specialWar",
width: 60,
hide: true,
sort: null,
},
{
colId: "reservedCommandShort_1",
width: 70,
hide: false,
sort: null,
},
{
colId: "reservedCommand",
width: 120,
hide: false,
sort: null,
},
{
colId: "turntime",
width: 60,
hide: false,
sort: "asc",
sortIndex: 0,
},
{
colId: "years_1",
width: 60,
hide: true,
sort: null,
},
{
colId: "age",
width: 60,
hide: true,
sort: null,
},
{
colId: "belong",
width: 60,
hide: true,
sort: null,
},
{
colId: "killturnAndConnect_1",
width: 70,
hide: false,
sort: null,
},
{
colId: "killturn",
width: 70,
hide: false,
sort: null,
},
{
colId: "connect",
width: 70,
hide: true,
sort: null,
},
],
columnGroup: [
{
groupId: "0",
open: false,
},
{
groupId: "1",
open: false,
},
{
groupId: "stat",
open: false,
},
{
groupId: "2",
open: false,
},
{
groupId: "expDedLv",
open: false,
},
{
groupId: "goldRice",
open: true,
},
{
groupId: "3",
open: false,
},
{
groupId: "4",
open: false,
},
{
groupId: "crewtypeAndCrew",
open: false,
},
{
groupId: "trainAtmos",
open: false,
},
{
groupId: "specials",
open: false,
},
{
groupId: "reservedCommandShort",
open: true,
},
{
groupId: "5",
open: false,
},
{
groupId: "years",
open: false,
},
{
groupId: "killturnAndConnect",
open: true,
},
],
},
normal: {
column: [
{
colId: "icon",
width: 80,
hide: false,
pinned: "left",
sort: null,
},
{
colId: "name",
width: 126,
hide: false,
pinned: "left",
sort: null,
},
{
colId: "officerLevel",
width: 70,
hide: false,
sort: null,
},
{
colId: "expDedLv_1",
width: 60,
hide: false,
sort: null,
},
{
colId: "dedlevel",
width: 70,
hide: false,
sort: null,
},
{
colId: "explevel",
width: 60,
hide: false,
sort: null,
},
{
colId: "stat_1",
width: 88,
hide: false,
sort: null,
},
{
colId: "leadership",
width: 60,
hide: false,
sort: null,
},
{
colId: "strength",
width: 60,
hide: false,
sort: null,
},
{
colId: "intel",
width: 60,
hide: false,
sort: null,
},
{
colId: "troop",
width: 90,
hide: true,
sort: null,
},
{
colId: "goldRice_1",
width: 80,
hide: false,
sort: null,
},
{
colId: "gold",
width: 70,
hide: false,
sort: null,
},
{
colId: "rice",
width: 70,
hide: false,
sort: null,
},
{
colId: "city",
width: 60,
hide: true,
sort: null,
},
{
colId: "crewtypeAndCrew_1",
width: 80,
hide: true,
sort: null,
},
{
colId: "crewtype",
width: 80,
hide: true,
sort: null,
},
{
colId: "crew",
width: 70,
hide: true,
sort: null,
},
{
colId: "trainAtmos_1",
width: 60,
hide: true,
sort: null,
},
{
colId: "train",
width: 70,
hide: true,
sort: null,
},
{
colId: "atmos",
width: 70,
hide: true,
sort: null,
},
{
colId: "defence_train",
width: 50,
hide: true,
sort: null,
},
{
colId: "specials_1",
width: 80,
hide: false,
sort: null,
},
{
colId: "personal",
width: 60,
hide: false,
sort: null,
},
{
colId: "specialDomestic",
width: 60,
hide: false,
sort: null,
},
{
colId: "specialWar",
width: 60,
hide: false,
sort: null,
},
{
colId: "reservedCommandShort_1",
width: 70,
hide: true,
sort: null,
},
{
colId: "reservedCommand",
width: 120,
hide: true,
sort: null,
},
{
colId: "turntime",
width: 60,
hide: true,
sort: null,
},
{
colId: "years_1",
width: 60,
hide: false,
sort: null,
},
{
colId: "age",
width: 60,
hide: false,
sort: null,
},
{
colId: "belong",
width: 60,
hide: false,
sort: null,
},
{
colId: "killturnAndConnect_1",
width: 70,
hide: false,
sort: null,
},
{
colId: "killturn",
width: 70,
hide: true,
sort: null,
},
{
colId: "connect",
width: 70,
hide: false,
sort: "desc",
sortIndex: 0,
}
],
columnGroup: [
{
groupId: "0",
open: false
},
{
groupId: "1",
open: false
},
{
groupId: "stat",
open: true
},
{
groupId: "2",
open: false
},
{
groupId: "expDedLv",
open: true
},
{
groupId: "goldRice",
open: true
},
{
groupId: "3",
open: false
},
{
groupId: "4",
open: false
},
{
groupId: "crewtypeAndCrew",
open: false
},
{
groupId: "trainAtmos",
open: false
},
{
groupId: "specials",
open: false
},
{
groupId: "reservedCommandShort",
open: true
},
{
groupId: "5",
open: false
},
{
groupId: "years",
open: false
},
{
groupId: "killturnAndConnect",
open: true
}
],
},
};