feat(web): el stock por almacén muestra el nombre del almacén y la lista de artículos el nombre del grupo (columna nameOf en las tablas de filas)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5253ef4cb7
commit
8af3b11ac2
4 files changed
+29
-3
No files matched your search
@@ -70,6 +70,11 @@ export interface DetailColumn {
|
||||
lookupFor?: (row: Record<string, unknown>) => VhLookup | undefined;
|
||||
/** La celda no se edita en esta fila. */
|
||||
readonlyFor?: (row: Record<string, unknown>) => boolean;
|
||||
/**
|
||||
* La columna muestra el nombre de lo que identifica el código de otra columna (`WarehouseCode` → nombre del almacén);
|
||||
* el catálogo se consulta una sola vez. No es un campo que se guarde.
|
||||
*/
|
||||
nameOf?: { codeKey: string; resource: string; valueField: string; labelField: string };
|
||||
/** Texto calculado de la fila (solo se muestra; no es un campo que se guarde). */
|
||||
computed?: (row: Record<string, unknown>) => string;
|
||||
/** Campos de la fila que cambian además del propio al elegir o escribir un valor de la lista (la cuenta elegida primero completa el «Cuenta / socio»). */
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
import { ChangeDetectionStrategy, Component, computed, effect, inject, input, model, signal } from '@angular/core';
|
||||
import { API_URL } from '../../core/api';
|
||||
import { formatNumber, parseDecimal } from '../../core/format';
|
||||
import { SlLookupApi } from '../../core/sl/sl-lookup';
|
||||
import type { ListRow } from '../list/list.types';
|
||||
@@ -151,8 +153,24 @@ export class RowsTable {
|
||||
readonly emptyText = input('Sin filas.');
|
||||
|
||||
private readonly lookupApi = inject(SlLookupApi);
|
||||
private readonly http = inject(HttpClient);
|
||||
/** Nombres de los catálogos de las columnas `nameOf`, por recurso. */
|
||||
private readonly names = signal<Record<string, Map<string, string>>>({});
|
||||
private readonly requested = new Set<string>();
|
||||
|
||||
constructor() {
|
||||
effect(() => {
|
||||
for (const c of this.columns()) {
|
||||
const n = c.nameOf;
|
||||
if (!n || this.requested.has(n.resource)) continue;
|
||||
this.requested.add(n.resource);
|
||||
const params = new HttpParams().set('$select', `${n.valueField},${n.labelField}`).set('$top', 500);
|
||||
this.http.get<{ value?: Record<string, unknown>[] }>(`${API_URL}/sl/${n.resource}`, { params }).subscribe({
|
||||
next: (res) => this.names.update((m) => ({ ...m, [n.resource]: new Map((res.value ?? []).map((x) => [String(x[n.valueField]), String(x[n.labelField] ?? '')])) })),
|
||||
error: () => undefined, // sin nombres, la columna queda vacía
|
||||
});
|
||||
}
|
||||
});
|
||||
// las celdas de código con texto propio (la cuenta con su formato) piden los textos de las filas que se cargan
|
||||
effect(() => {
|
||||
const rows = this.rows();
|
||||
@@ -210,11 +228,12 @@ export class RowsTable {
|
||||
}
|
||||
|
||||
protected locked(c: DetailColumn, row?: Row): boolean {
|
||||
return this.readonly() || !!c.readonly || !!c.computed || (!!row && !!c.readonlyFor?.(row));
|
||||
return this.readonly() || !!c.readonly || !!c.computed || !!c.nameOf || (!!row && !!c.readonlyFor?.(row));
|
||||
}
|
||||
|
||||
protected text(row: Row, c: DetailColumn): string {
|
||||
if (c.computed) return c.computed(row);
|
||||
if (c.nameOf) return this.names()[c.nameOf.resource]?.get(String(row[c.nameOf.codeKey] ?? '')) ?? '';
|
||||
const v = row[c.key];
|
||||
if (c.type === 'date') return dateOnly(v);
|
||||
if (c.type === 'number') return v === null || v === undefined || v === '' ? '' : formatNumber(v, c.decimals);
|
||||
|
||||
Reference in new issue
Block a user