수정: 인사 명령에서 유저장을 먼저 정렬
This commit is contained in:
@@ -175,6 +175,7 @@ const inputOptions = {
|
||||
{
|
||||
value: 3,
|
||||
label: '여포NPC (업)',
|
||||
npcState: 2,
|
||||
gold: 3000,
|
||||
rice: 500,
|
||||
crew: 1500,
|
||||
@@ -199,6 +200,7 @@ const inputOptions = {
|
||||
{
|
||||
value: 3,
|
||||
label: '여포NPC (청룡대 · 업)',
|
||||
npcState: 2,
|
||||
crew: 1500,
|
||||
troopId: 2,
|
||||
description: '금 3,000 · 쌀 500 · 병력 1,500',
|
||||
@@ -208,6 +210,7 @@ const inputOptions = {
|
||||
{
|
||||
value: 3,
|
||||
label: '여포NPC (아국 · 업)',
|
||||
npcState: 2,
|
||||
availableNow: true,
|
||||
crew: 1500,
|
||||
troopId: 2,
|
||||
@@ -2513,10 +2516,10 @@ test('offers Ref amount presets and rich, command-specific general lists', async
|
||||
let generalList = form.getByTestId('general-target-list');
|
||||
await expect(form.locator('#command-arg-destGeneralId option')).toHaveText([
|
||||
'관우 (업)',
|
||||
'여포NPC (업)',
|
||||
'장수 (업)',
|
||||
'여포NPC (업)',
|
||||
]);
|
||||
await expect(generalList.locator('.target-option strong')).toHaveText(['관우 (업)', '여포NPC (업)', '장수 (업)']);
|
||||
await expect(generalList.locator('.target-option strong')).toHaveText(['관우 (업)', '장수 (업)', '여포NPC (업)']);
|
||||
await expect(generalList.locator('.target-option').filter({ hasText: '여포NPC' }).locator('strong')).toHaveCSS(
|
||||
'color',
|
||||
'rgb(0, 255, 255)'
|
||||
@@ -2525,7 +2528,7 @@ test('offers Ref amount presets and rich, command-specific general lists', async
|
||||
await expect(generalList).not.toContainText('아국');
|
||||
await expect(generalList).not.toContainText('탑승 부대');
|
||||
await form.getByRole('button', { name: '쌀', exact: true }).click();
|
||||
await expect(generalList.locator('.target-option strong')).toHaveText(['장수 (업)', '여포NPC (업)', '관우 (업)']);
|
||||
await expect(generalList.locator('.target-option strong')).toHaveText(['장수 (업)', '관우 (업)', '여포NPC (업)']);
|
||||
await generalList.locator('.target-option').filter({ hasText: '여포NPC' }).click();
|
||||
const awardResponse = page.waitForResponse((response) => response.url().includes('turns.reserved.setNationBulk'));
|
||||
await picker.getByRole('button', { name: '입력', exact: true }).click();
|
||||
@@ -2540,10 +2543,10 @@ test('offers Ref amount presets and rich, command-specific general lists', async
|
||||
generalList = form.getByTestId('general-target-list');
|
||||
await expect(form.locator('#command-arg-destGeneralId option')).toHaveText([
|
||||
'장수 (업)',
|
||||
'여포NPC (업)',
|
||||
'관우 (업)',
|
||||
'여포NPC (업)',
|
||||
]);
|
||||
await expect(generalList.locator('.target-option strong')).toHaveText(['장수 (업)', '여포NPC (업)', '관우 (업)']);
|
||||
await expect(generalList.locator('.target-option strong')).toHaveText(['장수 (업)', '관우 (업)', '여포NPC (업)']);
|
||||
await expect(generalList).not.toContainText('아국');
|
||||
await expect(generalList).not.toContainText('탑승 부대');
|
||||
await page.goto('/che/chief-center');
|
||||
@@ -2574,9 +2577,13 @@ test('offers Ref amount presets and rich, command-specific general lists', async
|
||||
await picker.getByRole('button', { name: /부대 탈퇴 지시/ }).click();
|
||||
form = picker.getByTestId('command-argument-form');
|
||||
generalList = form.getByTestId('general-target-list');
|
||||
await expect(generalList.locator('.target-option strong').first()).toHaveText('여포NPC (아국 · 업)');
|
||||
await expect(generalList.locator('.target-option').first().locator('.target-state')).toHaveText('우선 대상');
|
||||
await expect(generalList.locator('.target-option').nth(1).locator('.target-state')).toHaveText('현재 불가');
|
||||
await expect(generalList.locator('.target-option strong')).toHaveText([
|
||||
'장수 (아국 · 업)',
|
||||
'관우 (아국 · 업)',
|
||||
'여포NPC (아국 · 업)',
|
||||
]);
|
||||
await expect(generalList.locator('.target-option').first().locator('.target-state')).toHaveText('현재 불가');
|
||||
await expect(generalList.locator('.target-option').nth(2).locator('.target-state')).toHaveText('우선 대상');
|
||||
|
||||
await page.goto('/che/chief-center');
|
||||
await page.getByRole('button', { name: '5턴 명령 입력', exact: true }).click();
|
||||
@@ -2603,8 +2610,8 @@ test('offers Ref amount presets and rich, command-specific general lists', async
|
||||
|
||||
await page.setViewportSize({ width: 500, height: 900 });
|
||||
const mobilePersonnelCases = [
|
||||
{ turn: 5, command: '포상', labels: ['관우 (업)', '여포NPC (업)', '장수 (업)'] },
|
||||
{ turn: 6, command: '몰수', labels: ['장수 (업)', '여포NPC (업)', '관우 (업)'] },
|
||||
{ turn: 5, command: '포상', labels: ['관우 (업)', '장수 (업)', '여포NPC (업)'] },
|
||||
{ turn: 6, command: '몰수', labels: ['장수 (업)', '관우 (업)', '여포NPC (업)'] },
|
||||
{
|
||||
turn: 7,
|
||||
command: '발령',
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import type { CommandOption } from './types';
|
||||
|
||||
const npcStateOf = (option: CommandOption): number => option.npcState ?? 0;
|
||||
|
||||
/** 장수 선택지는 유저장부터 NPC 종류순으로 묶고, 명령별 우선순위는 같은 종류 안에서만 적용한다. */
|
||||
export const sortCommandGeneralOptions = (
|
||||
commandKey: string,
|
||||
options: readonly CommandOption[],
|
||||
isGold: boolean
|
||||
): CommandOption[] => {
|
||||
const resourceKey = isGold ? 'gold' : 'rice';
|
||||
return options
|
||||
.map((option, index) => ({ option, index }))
|
||||
.sort((left, right) => {
|
||||
const typeOrder = npcStateOf(left.option) - npcStateOf(right.option);
|
||||
if (typeOrder !== 0) return typeOrder;
|
||||
|
||||
if (commandKey === 'che_포상') {
|
||||
const resourceOrder = (left.option[resourceKey] ?? 0) - (right.option[resourceKey] ?? 0);
|
||||
if (resourceOrder !== 0) return resourceOrder;
|
||||
}
|
||||
if (commandKey === 'che_몰수') {
|
||||
const resourceOrder = (right.option[resourceKey] ?? 0) - (left.option[resourceKey] ?? 0);
|
||||
if (resourceOrder !== 0) return resourceOrder;
|
||||
}
|
||||
if (commandKey === 'che_부대탈퇴지시') {
|
||||
const availabilityOrder = Number(right.option.availableNow) - Number(left.option.availableNow);
|
||||
if (availabilityOrder !== 0) return availabilityOrder;
|
||||
}
|
||||
return left.index - right.index;
|
||||
})
|
||||
.map(({ option }) => option);
|
||||
};
|
||||
@@ -4,6 +4,7 @@ import MapViewer from './MapViewer.vue';
|
||||
import NationColorSelect from './NationColorSelect.vue';
|
||||
import { commandArgumentPresentation, resolveCommandArgumentMapTarget } from '../command/commandArgumentPresentation';
|
||||
import { commandCityOptions } from '../command/commandArgumentOptions';
|
||||
import { sortCommandGeneralOptions } from '../command/commandGeneralOptions';
|
||||
import {
|
||||
commandArgumentFieldContract,
|
||||
shouldPreserveCommandArgumentValue,
|
||||
@@ -44,18 +45,7 @@ const visibleFields = computed(() => props.fields.filter((entry) => entry.kind !
|
||||
const amountPreset = computed(() => props.options.amountPresets?.[props.commandKey]);
|
||||
|
||||
const sortGeneralOptions = (options: CommandOption[]): CommandOption[] => {
|
||||
const result = [...options];
|
||||
const resourceKey = values.isGold === false ? 'rice' : 'gold';
|
||||
if (props.commandKey === 'che_포상') {
|
||||
return result.sort((left, right) => (left[resourceKey] ?? 0) - (right[resourceKey] ?? 0));
|
||||
}
|
||||
if (props.commandKey === 'che_몰수') {
|
||||
return result.sort((left, right) => (right[resourceKey] ?? 0) - (left[resourceKey] ?? 0));
|
||||
}
|
||||
if (props.commandKey === 'che_부대탈퇴지시') {
|
||||
return result.sort((left, right) => Number(right.availableNow) - Number(left.availableNow));
|
||||
}
|
||||
return result;
|
||||
return sortCommandGeneralOptions(props.commandKey, options, values.isGold !== false);
|
||||
};
|
||||
|
||||
const optionsFor = (field: CommandInputField): CommandOption[] => {
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
|
||||
import { sortCommandGeneralOptions } from '../src/components/command/commandGeneralOptions.ts';
|
||||
import type { CommandOption } from '../src/components/command/types.ts';
|
||||
|
||||
const option = (value: number, npcState: number | undefined, fields: Partial<CommandOption> = {}): CommandOption => ({
|
||||
value,
|
||||
label: String(value),
|
||||
npcState,
|
||||
...fields,
|
||||
});
|
||||
|
||||
void test('puts user generals before possessed and NPC types for general target commands', () => {
|
||||
const options = [option(4, 3), option(3, 2), option(2, 1), option(1, 0), option(5, undefined)];
|
||||
|
||||
assert.deepEqual(
|
||||
sortCommandGeneralOptions('che_발령', options, true).map(({ value }) => value),
|
||||
[1, 5, 2, 3, 4]
|
||||
);
|
||||
assert.deepEqual(
|
||||
options.map(({ value }) => value),
|
||||
[4, 3, 2, 1, 5]
|
||||
);
|
||||
});
|
||||
|
||||
void test('keeps reward and confiscation resource order inside each general type', () => {
|
||||
const options = [
|
||||
option(3, 2, { gold: 300, rice: 500 }),
|
||||
option(1, 0, { gold: 500, rice: 100 }),
|
||||
option(4, 2, { gold: 100, rice: 900 }),
|
||||
option(2, 0, { gold: 200, rice: 400 }),
|
||||
];
|
||||
|
||||
assert.deepEqual(
|
||||
sortCommandGeneralOptions('che_포상', options, true).map(({ value }) => value),
|
||||
[2, 1, 4, 3]
|
||||
);
|
||||
assert.deepEqual(
|
||||
sortCommandGeneralOptions('che_포상', options, false).map(({ value }) => value),
|
||||
[1, 2, 3, 4]
|
||||
);
|
||||
assert.deepEqual(
|
||||
sortCommandGeneralOptions('che_몰수', options, true).map(({ value }) => value),
|
||||
[1, 2, 3, 4]
|
||||
);
|
||||
});
|
||||
|
||||
void test('keeps troop-exit availability order inside each general type', () => {
|
||||
const options = [
|
||||
option(3, 2, { availableNow: true }),
|
||||
option(1, 0, { availableNow: false }),
|
||||
option(4, 2, { availableNow: false }),
|
||||
option(2, 0, { availableNow: true }),
|
||||
];
|
||||
|
||||
assert.deepEqual(
|
||||
sortCommandGeneralOptions('che_부대탈퇴지시', options, true).map(({ value }) => value),
|
||||
[2, 1, 3, 4]
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user