[598][@ant] refactor: списание — общий хелпер proposalDisplay (positionsLabel/proposalTitle) — убрать дубль из страницы и диалога
Склонение «позиций» и имя проекта по дате повторялись в AdminWriteoffsPage и WriteoffProposalDetailsDialog — вынес в ../lib/proposalDisplay по правилу DRY.
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
import type { MarketplaceWriteoffProposalView } from '../api';
|
||||
|
||||
// Русское склонение «позиция / позиции / позиций».
|
||||
export function positionsLabel(n: number): string {
|
||||
const mod10 = n % 10;
|
||||
const mod100 = n % 100;
|
||||
let word = 'позиций';
|
||||
if (mod10 === 1 && mod100 !== 11) word = 'позиция';
|
||||
else if (mod10 >= 2 && mod10 <= 4 && (mod100 < 10 || mod100 >= 20)) word = 'позиции';
|
||||
return `${n} ${word}`;
|
||||
}
|
||||
|
||||
function formatDate(value: string | null | undefined): string {
|
||||
if (!value) return '—';
|
||||
const d = new Date(value);
|
||||
return Number.isNaN(d.getTime()) ? '—' : d.toLocaleDateString('ru-RU');
|
||||
}
|
||||
|
||||
// Человеческое имя проекта списания — по дате подачи/цикла, не «N позиций».
|
||||
export function proposalTitle(p: MarketplaceWriteoffProposalView): string {
|
||||
return `Списание от ${formatDate(p.submitted_at ?? p.cycle_started_at ?? p.updated_at)}`;
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
type MarketplaceWriteoffCandidateView,
|
||||
type MarketplaceWriteoffProposalView,
|
||||
} from '../api';
|
||||
import { positionsLabel, proposalTitle } from '../lib/proposalDisplay';
|
||||
import SubmitToCouncilDialog from './SubmitToCouncilDialog.vue';
|
||||
import WriteoffProposalDetailsDialog from './WriteoffProposalDetailsDialog.vue';
|
||||
|
||||
@@ -206,21 +207,6 @@ function proposalDate(p: MarketplaceWriteoffProposalView): string | null | undef
|
||||
return p.executed_at ?? p.rejected_at ?? p.submitted_at ?? p.updated_at;
|
||||
}
|
||||
|
||||
// Русское склонение «позиция/позиции/позиций».
|
||||
function positionsLabel(n: number): string {
|
||||
const mod10 = n % 10;
|
||||
const mod100 = n % 100;
|
||||
let word = 'позиций';
|
||||
if (mod10 === 1 && mod100 !== 11) word = 'позиция';
|
||||
else if (mod10 >= 2 && mod10 <= 4 && (mod100 < 10 || mod100 >= 20)) word = 'позиции';
|
||||
return `${n} ${word}`;
|
||||
}
|
||||
|
||||
// Человеческое имя проекта — по дате подачи/цикла, не «N позиций».
|
||||
function proposalTitle(p: MarketplaceWriteoffProposalView): string {
|
||||
const date = formatDate(p.submitted_at ?? p.cycle_started_at ?? p.updated_at);
|
||||
return `Списание от ${date}`;
|
||||
}
|
||||
|
||||
// Три состояния позиции на складе:
|
||||
// · нет даты годности (гарантия 0) → «Без гарантии» — ручное списание сразу;
|
||||
|
||||
+2
-13
@@ -3,6 +3,7 @@ import { computed } from 'vue';
|
||||
import { formatAsset2Digits } from 'src/shared/lib/utils/formatAsset2Digits';
|
||||
import { BaseDialog, BaseBadge } from 'src/shared/ui/base';
|
||||
import type { MarketplaceWriteoffProposalView } from '../api';
|
||||
import { positionsLabel, proposalTitle } from '../lib/proposalDisplay';
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean;
|
||||
@@ -24,15 +25,6 @@ function fmtDateTime(value: string | null | undefined): string {
|
||||
return Number.isNaN(d.getTime()) ? '—' : d.toLocaleString('ru-RU');
|
||||
}
|
||||
|
||||
function positionsLabel(n: number): string {
|
||||
const mod10 = n % 10;
|
||||
const mod100 = n % 100;
|
||||
let word = 'позиций';
|
||||
if (mod10 === 1 && mod100 !== 11) word = 'позиция';
|
||||
else if (mod10 >= 2 && mod10 <= 4 && (mod100 < 10 || mod100 >= 20)) word = 'позиции';
|
||||
return `${n} ${word}`;
|
||||
}
|
||||
|
||||
function humanStatus(status: MarketplaceWriteoffProposalView['status']): string {
|
||||
switch (status) {
|
||||
case 'DRAFT':
|
||||
@@ -84,10 +76,7 @@ function humanLog(action: string): string {
|
||||
return LOG_LABELS[action] ?? action;
|
||||
}
|
||||
|
||||
const title = computed(() => {
|
||||
const p = props.proposal;
|
||||
return `Списание от ${fmtDate(p.submitted_at ?? p.cycle_started_at ?? p.updated_at)}`;
|
||||
});
|
||||
const title = computed(() => proposalTitle(props.proposal));
|
||||
|
||||
const shortHash = computed(() => {
|
||||
const h = props.proposal.proposal_hash;
|
||||
|
||||
Reference in New Issue
Block a user