feat: complete admin panel and backend admin api migration
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
/**
|
||||
* Ported from legacy henza_admin/src/components/x-table/model/{XTbl,Xtc}.js
|
||||
* and src/table/index.js (ColCreator).
|
||||
*
|
||||
* The fluent column API is preserved exactly — `new Xtc(key, title).filterText()
|
||||
* .renderSlot('x').noSort()` builds the same shape the legacy table schemas used,
|
||||
* so the 18 schema files port over with only their import path changed.
|
||||
*
|
||||
* Legacy had FOUR near-duplicate XTable forks (x-table/, x-table_select/,
|
||||
* custom-xtable-select/, backup-table/, ~1,300 LOC). Per the agreed decision this
|
||||
* port keeps ONE — the x-table/ variant, which is the most complete (it is the
|
||||
* only one with QuerySelectTableFilter).
|
||||
*/
|
||||
|
||||
export type FilterType = 'default' | 'switch' | 'query' | 'date' | 'number' | 'select';
|
||||
|
||||
export interface ColumnSlots {
|
||||
customRender?: string;
|
||||
filterDropdown?: string;
|
||||
filterIcon?: string;
|
||||
}
|
||||
|
||||
/** Port of legacy Xtc — one column definition. */
|
||||
export class Xtc {
|
||||
key: string;
|
||||
title: string;
|
||||
dataIndex: string;
|
||||
show = true;
|
||||
/** legacy `__sorter`: sortable unless noSort() was called */
|
||||
__sorter = true;
|
||||
filtered = false;
|
||||
filterType?: FilterType;
|
||||
filterAction?: string;
|
||||
/** legacy `filterItems`: a value -> label map for select filters */
|
||||
filterItems?: Record<string | number, string>;
|
||||
scopedSlots?: ColumnSlots;
|
||||
/** legacy filterKey()/master — filter against a different field than dataIndex */
|
||||
__fkey?: string;
|
||||
width?: string | number;
|
||||
|
||||
constructor(key: string, title: string) {
|
||||
this.key = key;
|
||||
this.title = title;
|
||||
this.dataIndex = key;
|
||||
}
|
||||
|
||||
private __filter() {
|
||||
this.filtered = true;
|
||||
if (!this.scopedSlots) this.scopedSlots = {};
|
||||
this.scopedSlots.filterDropdown = `${this.key}_filterDropdown`;
|
||||
this.scopedSlots.filterIcon = `${this.key}_filterIcon`;
|
||||
}
|
||||
|
||||
/** legacy filterKey(key) */
|
||||
filterKey(key: string) {
|
||||
this.__fkey = key;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** legacy renderSlot(name) — render this cell through a named slot */
|
||||
renderSlot(name: string) {
|
||||
if (!this.scopedSlots) this.scopedSlots = {};
|
||||
this.scopedSlots.customRender = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
filterText() {
|
||||
this.__filter();
|
||||
this.filterType = 'default';
|
||||
return this;
|
||||
}
|
||||
|
||||
filterSwitch() {
|
||||
this.__filter();
|
||||
this.filterType = 'switch';
|
||||
return this;
|
||||
}
|
||||
|
||||
filterQuery(action: string) {
|
||||
this.__filter();
|
||||
this.filterType = 'query';
|
||||
this.filterAction = action;
|
||||
return this;
|
||||
}
|
||||
|
||||
filterDate() {
|
||||
this.__filter();
|
||||
this.filterType = 'date';
|
||||
return this;
|
||||
}
|
||||
|
||||
filterNumber() {
|
||||
this.__filter();
|
||||
this.filterType = 'number';
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* legacy filterSelect(items) — `items` is an OBJECT MAP of value -> label,
|
||||
* e.g. { 0: 'معلق', 1: 'ثبت سفارش' }, stored on `filterItems`. The shape is
|
||||
* kept exactly so the ported table models pass their maps unchanged.
|
||||
*
|
||||
* Legacy also permitted calling it with no argument at all (TaminListModel does
|
||||
* this), which left filterItems undefined and rendered an empty dropdown.
|
||||
* Preserved: the parameter is optional here too.
|
||||
*/
|
||||
filterSelect(items?: Record<string | number, string>) {
|
||||
this.__filter();
|
||||
this.filterType = 'select';
|
||||
this.filterItems = items;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** legacy noSort() */
|
||||
noSort() {
|
||||
this.__sorter = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** legacy hidden() — column exists but starts unchecked in the column picker */
|
||||
hidden() {
|
||||
this.show = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
setWidth(w: string | number) {
|
||||
this.width = w;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export interface DefaultFilter {
|
||||
field: string;
|
||||
op: string;
|
||||
value: unknown;
|
||||
}
|
||||
|
||||
/** Port of legacy XTbl — a table definition: endpoint + title + columns. */
|
||||
export class XTbl {
|
||||
url: string;
|
||||
title: string;
|
||||
cols: Xtc[] = [];
|
||||
defaultFilters?: DefaultFilter[];
|
||||
_hidePagination = false;
|
||||
_hideSearch = false;
|
||||
_noFilters = false;
|
||||
|
||||
constructor(url: string, title: string) {
|
||||
this.url = url;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
add(col: Xtc) {
|
||||
this.cols.push(col);
|
||||
return this;
|
||||
}
|
||||
|
||||
addDefaultFilter(filter: DefaultFilter) {
|
||||
if (!this.defaultFilters) this.defaultFilters = [];
|
||||
this.defaultFilters.push(filter);
|
||||
return this;
|
||||
}
|
||||
|
||||
hidePagination() {
|
||||
this._hidePagination = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: legacy's hideSearch() set `_hidePageination` (sic) instead of a search
|
||||
* flag — a copy-paste bug, so calling it hid PAGINATION, not the search box.
|
||||
* Fixed here to set the intended flag; no ported schema calls it, so nothing
|
||||
* changes in behaviour. Recorded in docs/ADMIN-PORT-PLAN.md.
|
||||
*/
|
||||
hideSearch() {
|
||||
this._hideSearch = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** legacy noFilters(): hides the filter bar entirely (walletTbl uses this). */
|
||||
noFilters() {
|
||||
this._noFilters = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
getSortFields() {
|
||||
return this.cols.filter((c) => c.__sorter);
|
||||
}
|
||||
}
|
||||
|
||||
export default XTbl;
|
||||
Reference in New Issue
Block a user