Cascading sistem AI tarafından elde geçirildi.
This commit is contained in:
parent
81b2202df0
commit
021ddd03d1
7 changed files with 101 additions and 304 deletions
7
.github/instructions/lowcode.instructions.md
vendored
7
.github/instructions/lowcode.instructions.md
vendored
|
|
@ -1352,8 +1352,8 @@ cascade eksik yetenek değildir ve analizde `Ready to Start`'ı engellemez. Tam
|
||||||
| `DataSourceType` | `1` StaticData · `2` Query · `3` WebService |
|
| `DataSourceType` | `1` StaticData · `2` Query · `3` WebService |
|
||||||
| `ValueExpr` / `DisplayExpr` | Varsayılan `Key` / `Name` |
|
| `ValueExpr` / `DisplayExpr` | Varsayılan `Key` / `Name` |
|
||||||
| `LookupQuery` | Kaynağın kendisi (tipe göre biçim değişir, aşağıda) |
|
| `LookupQuery` | Kaynağın kendisi (tipe göre biçim değişir, aşağıda) |
|
||||||
| `CascadeParentFields` | **Çocuk alanda** doldurulur; değerleri sorguya taşınacak ebeveyn alan(lar), virgülle. Sırayla `@param0`, `@param1`… olur (`Query`/`WebService`); gelmeyen parametre `NULL` bağlanır |
|
| `CascadeParentFields` | **Çocuk alanda** doldurulur; değerleri sorguya taşınacak ebeveyn alan(lar), virgülle. Sırayla `@param0`, `@param1`… olur (`Query`/`WebService`); boş ya da gelmeyen ebeveyn `NULL` bağlanır. Değer her zaman **metin** parametre olarak bağlanır (`ListFormSelectAppService.ToLookupParameter`), sayı anahtarlı ebeveyn de çalışır; dönüşümü kolon tipine göre veritabanı yapar. `WebService` gövdesine değer JSON kaçışlı yazılır |
|
||||||
| `CascadeRelationField` | **Çocuk alanda** doldurulur; `StaticData`'da ebeveynin değeriyle karşılaştırılan alan (öğedeki `group`) |
|
| `CascadeRelationField` | **Çocuk alanda**, yalnızca `StaticData`'da anlamlıdır: öğede ilk ebeveynin değeriyle karşılaştırılan alan; boşsa `group`. Ebeveyn boşken liste süzülmez |
|
||||||
| `CascadeFilterOperator` | `StaticData` cascade filtresinin operatörü; varsayılan `=` |
|
| `CascadeFilterOperator` | `StaticData` cascade filtresinin operatörü; varsayılan `=` |
|
||||||
| `CascadeEmptyFields` | **Ebeveyn alanda** doldurulur; bu alan değişince boşaltılacak çocuk alanlar, virgülle. Ara halka (İl) hem çocuk hem ebeveyn olduğu için iki tarafı birden taşır |
|
| `CascadeEmptyFields` | **Ebeveyn alanda** doldurulur; bu alan değişince boşaltılacak çocuk alanlar, virgülle. Ara halka (İl) hem çocuk hem ebeveyn olduğu için iki tarafı birden taşır |
|
||||||
|
|
||||||
|
|
@ -1409,7 +1409,8 @@ ya da `EditorOptions`'ta `grouped: true` vardır ve öğeler `group` alanı taş
|
||||||
`[Key]` + `[Name]` takma adlarını döndürür ve `ValueExpr: "Key"`, `DisplayExpr: "Name"` yazılır.
|
`[Key]` + `[Name]` takma adlarını döndürür ve `ValueExpr: "Key"`, `DisplayExpr: "Name"` yazılır.
|
||||||
Bağımlı liste `grouped` ile değil cascade ile kurulur.
|
Bağımlı liste `grouped` ile değil cascade ile kurulur.
|
||||||
|
|
||||||
> Lookup verisi önbelleklenir; aynı sorgu aynı filtrelerle bir kez yüklenir.
|
> Lookup verisi önbelleklenir; aynı sorgu aynı filtrelerle bir kez yüklenir. Grid, Tree, Card ve
|
||||||
|
> Form aynı veri kaynağını kullanır (`views/form/useLookupDataSource.ts`); cascade kuralı tek yerdedir.
|
||||||
|
|
||||||
### 4.3.5 Varsayılan değerler — `*FieldsDefaultValueJson`
|
### 4.3.5 Varsayılan değerler — `*FieldsDefaultValueJson`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ public class LookupRequestDto
|
||||||
{
|
{
|
||||||
public string ListFormCode { get; set; }
|
public string ListFormCode { get; set; }
|
||||||
public string ListFormFieldName { get; set; }
|
public string ListFormFieldName { get; set; }
|
||||||
public string[] Filters { get; set; }
|
/// <summary>Cascade ebeveyn degerleri, <c>CascadeParentFields</c> sirasiyla; sayi ya da metin olabilir.</summary>
|
||||||
|
public object[] Filters { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -418,22 +418,17 @@ public class ListFormSelectAppService : PlatformAppService, IListFormSelectAppSe
|
||||||
var lookup = JsonSerializer.Deserialize<LookupDto>(field.LookupJson);
|
var lookup = JsonSerializer.Deserialize<LookupDto>(field.LookupJson);
|
||||||
if (!string.IsNullOrWhiteSpace(lookup?.LookupQuery))
|
if (!string.IsNullOrWhiteSpace(lookup?.LookupQuery))
|
||||||
{
|
{
|
||||||
var parameters = new Dictionary<string, object>();
|
// Cascade ebeveyn degerleri @param0… olarak baglanir; gelmeyen ebeveyn NULL olur ki
|
||||||
if (input.Filters != null)
|
// sorgu "(Kolon = @param0 OR @param0 IS NULL)" kalibiyla tum listeyi donsun.
|
||||||
{
|
|
||||||
for (int i = 0; i < input.Filters.Length; i++)
|
|
||||||
{
|
|
||||||
parameters.Add("@param" + i, input.Filters[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var cascadeParameterCount = lookup.CascadeParentFields?
|
var cascadeParameterCount = lookup.CascadeParentFields?
|
||||||
.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
||||||
.Length ?? 0;
|
.Length ?? 0;
|
||||||
|
var parameterCount = Math.Max(input.Filters?.Length ?? 0, cascadeParameterCount);
|
||||||
|
|
||||||
for (int i = input.Filters?.Length ?? 0; i < cascadeParameterCount; i++)
|
var parameters = new Dictionary<string, object>();
|
||||||
|
for (var i = 0; i < parameterCount; i++)
|
||||||
{
|
{
|
||||||
parameters.Add("@param" + i, null!);
|
parameters.Add("@param" + i, ToLookupParameter(input.Filters, i)!);
|
||||||
}
|
}
|
||||||
|
|
||||||
var lookupQuery = defaultValueHelper.GetDefaultValue(lookup.LookupQuery);
|
var lookupQuery = defaultValueHelper.GetDefaultValue(lookup.LookupQuery);
|
||||||
|
|
@ -444,6 +439,26 @@ public class ListFormSelectAppService : PlatformAppService, IListFormSelectAppSe
|
||||||
return new List<LookupDataDto>();
|
return new List<LookupDataDto>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ebeveyn degeri istemcide sayi, metin ya da bool olabilir; parametre her zaman metin olarak
|
||||||
|
/// baglanir ki sorgudaki kolon tipine gore veritabani donustursun (int kolona "5" de gider).
|
||||||
|
/// </summary>
|
||||||
|
private static string? ToLookupParameter(object[]? filters, int index)
|
||||||
|
{
|
||||||
|
var value = filters is not null && index < filters.Length ? filters[index] : null;
|
||||||
|
|
||||||
|
return value switch
|
||||||
|
{
|
||||||
|
null => null,
|
||||||
|
JsonElement { ValueKind: JsonValueKind.Null or JsonValueKind.Undefined } => null,
|
||||||
|
JsonElement { ValueKind: JsonValueKind.String } element => NullIfEmpty(element.GetString()),
|
||||||
|
JsonElement element => element.GetRawText(),
|
||||||
|
_ => NullIfEmpty(Convert.ToString(value, CultureInfo.InvariantCulture))
|
||||||
|
};
|
||||||
|
|
||||||
|
static string? NullIfEmpty(string? text) => string.IsNullOrEmpty(text) ? null : text;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<string> GetNextSequenceValueAsync(string SequenceName)
|
public async Task<string> GetNextSequenceValueAsync(string SequenceName)
|
||||||
{
|
{
|
||||||
var sequenceManager = LazyServiceProvider.LazyGetRequiredService<SequenceManager>();
|
var sequenceManager = LazyServiceProvider.LazyGetRequiredService<SequenceManager>();
|
||||||
|
|
@ -451,93 +466,6 @@ public class ListFormSelectAppService : PlatformAppService, IListFormSelectAppSe
|
||||||
return await sequenceManager.GetNextSequenceAsync(SequenceName);
|
return await sequenceManager.GetNextSequenceAsync(SequenceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string WrapLookupQueryWithInFilter(
|
|
||||||
string lookupQuery,
|
|
||||||
string listFormSelectCommand,
|
|
||||||
string listFormFieldName)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(lookupQuery))
|
|
||||||
throw new ArgumentException("LookupQuery boş olamaz.");
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(listFormSelectCommand))
|
|
||||||
throw new ArgumentException("SelectCommand boş olamaz.");
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(listFormFieldName))
|
|
||||||
throw new ArgumentException("ListFormFieldName boş olamaz.");
|
|
||||||
|
|
||||||
return $@"
|
|
||||||
SELECT *
|
|
||||||
FROM (
|
|
||||||
{lookupQuery}
|
|
||||||
) t
|
|
||||||
WHERE ""Key"" IN (
|
|
||||||
SELECT ""{listFormFieldName}""
|
|
||||||
FROM ""{listFormSelectCommand}""
|
|
||||||
GROUP BY ""{listFormFieldName}""
|
|
||||||
)";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string AddCascadeWhereCondition(
|
|
||||||
string sql,
|
|
||||||
string cascadeParentFields,
|
|
||||||
int paramStartIndex = 0)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(sql))
|
|
||||||
throw new ArgumentException("SQL boş olamaz.");
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(cascadeParentFields))
|
|
||||||
return sql;
|
|
||||||
|
|
||||||
var fields = cascadeParentFields
|
|
||||||
.Split(',', StringSplitOptions.RemoveEmptyEntries)
|
|
||||||
.Select(f => f.Trim())
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
if (!fields.Any())
|
|
||||||
return sql;
|
|
||||||
|
|
||||||
var conditions = new List<string>();
|
|
||||||
for (int i = 0; i < fields.Length; i++)
|
|
||||||
{
|
|
||||||
var field = fields[i];
|
|
||||||
|
|
||||||
// Zaten " ile başlıyorsa dokunma
|
|
||||||
if (!field.StartsWith("\""))
|
|
||||||
field = $"\"{field}\"";
|
|
||||||
|
|
||||||
conditions.Add($"{field} = @param{paramStartIndex + i}");
|
|
||||||
}
|
|
||||||
|
|
||||||
string whereClause = string.Join(" AND ", conditions);
|
|
||||||
var upperSql = sql.ToUpperInvariant();
|
|
||||||
|
|
||||||
if (upperSql.Contains(" WHERE "))
|
|
||||||
{
|
|
||||||
return InsertBeforeClause(sql, "AND " + whereClause);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return InsertBeforeClause(sql, "WHERE " + whereClause);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string InsertBeforeClause(string sql, string insertText)
|
|
||||||
{
|
|
||||||
var upperSql = sql.ToUpperInvariant();
|
|
||||||
string[] clauses = { " GROUP BY ", " ORDER BY ", " HAVING " };
|
|
||||||
|
|
||||||
foreach (var clause in clauses)
|
|
||||||
{
|
|
||||||
int index = upperSql.IndexOf(clause);
|
|
||||||
if (index > -1)
|
|
||||||
{
|
|
||||||
return sql.Insert(index, " " + insertText + " ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sql + " " + insertText;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Workflow kriterlerini alma
|
//Workflow kriterlerini alma
|
||||||
private async Task<List<ListFormWorkflowCriteriaDto>> GetWorkflowCriteriaAsync(string listFormCode)
|
private async Task<List<ListFormWorkflowCriteriaDto>> GetWorkflowCriteriaAsync(string listFormCode)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ type BuildFormItemsParams = {
|
||||||
mode: RowMode
|
mode: RowMode
|
||||||
columns?: GridColumnData[]
|
columns?: GridColumnData[]
|
||||||
/** Lookup alanları için DevExtreme dataSource üretici. */
|
/** Lookup alanları için DevExtreme dataSource üretici. */
|
||||||
getLookupDataSource: (options: any, colData: ColumnFormatDto, formData: any) => any
|
getLookupDataSource: (colData: ColumnFormatDto, formData: any) => any
|
||||||
formData: any
|
formData: any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,7 +57,7 @@ const toFormItem = (
|
||||||
|
|
||||||
const lookupEditorOptions = colFormat.lookupDto?.dataSourceType
|
const lookupEditorOptions = colFormat.lookupDto?.dataSourceType
|
||||||
? {
|
? {
|
||||||
dataSource: getLookupDataSource(colFormat.editorOptions, colFormat, formData),
|
dataSource: getLookupDataSource(colFormat, formData),
|
||||||
valueExpr: colFormat.lookupDto?.valueExpr?.toLowerCase(),
|
valueExpr: colFormat.lookupDto?.valueExpr?.toLowerCase(),
|
||||||
displayExpr: colFormat.lookupDto?.displayExpr?.toLowerCase(),
|
displayExpr: colFormat.lookupDto?.displayExpr?.toLowerCase(),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -262,7 +262,7 @@ const useGridData = (props: {
|
||||||
...item.editorOptions,
|
...item.editorOptions,
|
||||||
dataSource: keepCustomDataSource
|
dataSource: keepCustomDataSource
|
||||||
? currentDataSource
|
? currentDataSource
|
||||||
: getLookupDataSource(colData?.editorOptions, colData, formData || null),
|
: getLookupDataSource(colData, formData || null),
|
||||||
valueExpr:
|
valueExpr:
|
||||||
item.editorOptions?.valueExpr ?? colData?.lookupDto?.valueExpr?.toLowerCase(),
|
item.editorOptions?.valueExpr ?? colData?.lookupDto?.valueExpr?.toLowerCase(),
|
||||||
displayExpr:
|
displayExpr:
|
||||||
|
|
|
||||||
|
|
@ -14,17 +14,48 @@ export { clearLookupCache } from '../shared/lookupCache'
|
||||||
const isLookupAllowed = (listFormCode?: string, isSubForm?: boolean) =>
|
const isLookupAllowed = (listFormCode?: string, isSubForm?: boolean) =>
|
||||||
isSubForm || !listFormCode || window.location.pathname.includes(listFormCode)
|
isSubForm || !listFormCode || window.location.pathname.includes(listFormCode)
|
||||||
|
|
||||||
const createLookupStaticDataSource = (
|
const splitFields = (value?: string | null) =>
|
||||||
|
(value ?? '')
|
||||||
|
.split(',')
|
||||||
|
.map((field) => field.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
|
||||||
|
const isEmptyValue = (value: unknown) => value === undefined || value === null || value === ''
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cascade filtresi. Query/WebService için ebeveyn değerleri sırayla `@param0…` olur; boş ebeveyn
|
||||||
|
* `null` gider ve sorgu `(Kolon = @param0 OR @param0 IS NULL)` kalıbıyla tüm listeyi döner.
|
||||||
|
* StaticData için öğelerdeki `CascadeRelationField` alanı (varsayılan `group`) ilk ebeveynin
|
||||||
|
* değeriyle karşılaştırılır; ebeveyn boşsa süzülmez.
|
||||||
|
*/
|
||||||
|
export const buildCascadeFilters = (lookupDto: any, rowData: any): any[] | null => {
|
||||||
|
const parentFields = splitFields(lookupDto?.cascadeParentFields)
|
||||||
|
if (!parentFields.length) return null
|
||||||
|
|
||||||
|
if (lookupDto.dataSourceType == UiLookupDataSourceTypeEnum.StaticData) {
|
||||||
|
const parentValue = rowData?.[parentFields[0]]
|
||||||
|
if (isEmptyValue(parentValue)) return null
|
||||||
|
|
||||||
|
return [
|
||||||
|
lookupDto.cascadeRelationField || 'group',
|
||||||
|
lookupDto.cascadeFilterOperator || '=',
|
||||||
|
parentValue,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
return parentFields.map((field) => (isEmptyValue(rowData?.[field]) ? null : rowData[field]))
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createLookupStaticDataSource = (
|
||||||
load: () => any,
|
load: () => any,
|
||||||
filter: any = null,
|
filter: any[] | null,
|
||||||
key: any = 'static',
|
cacheKey: string,
|
||||||
sort: any = 'name',
|
sort = 'name',
|
||||||
) => ({
|
) => ({
|
||||||
store: new CustomStore({
|
store: new CustomStore({
|
||||||
key,
|
|
||||||
loadMode: 'raw',
|
loadMode: 'raw',
|
||||||
load: () =>
|
load: () =>
|
||||||
cachedLookupLoad(`static:${key}`, async () => {
|
cachedLookupLoad(`static:${cacheKey}`, async () => {
|
||||||
const result = await Promise.resolve(load())
|
const result = await Promise.resolve(load())
|
||||||
if (result === undefined || result === null) return []
|
if (result === undefined || result === null) return []
|
||||||
return Array.isArray(result) ? result : [result]
|
return Array.isArray(result) ? result : [result]
|
||||||
|
|
@ -34,10 +65,10 @@ const createLookupStaticDataSource = (
|
||||||
filter,
|
filter,
|
||||||
})
|
})
|
||||||
|
|
||||||
const createLookupQueryDataSource = (
|
export const createLookupQueryDataSource = (
|
||||||
listFormCode?: string,
|
listFormCode?: string,
|
||||||
listFormFieldName?: string,
|
listFormFieldName?: string,
|
||||||
filters?: any[],
|
filters?: any[] | null,
|
||||||
isSubForm?: boolean,
|
isSubForm?: boolean,
|
||||||
) =>
|
) =>
|
||||||
new CustomStore({
|
new CustomStore({
|
||||||
|
|
@ -72,10 +103,13 @@ const createLookupQueryDataSource = (
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const createLookupApiDataSource = (
|
/** Gövde JSON şablonudur; değer tırnak içine yerleştiği için JSON kaçışlı yazılır. */
|
||||||
|
const toJsonText = (value: unknown) => (value === null ? 'null' : JSON.stringify(String(value)).slice(1, -1))
|
||||||
|
|
||||||
|
export const createLookupApiDataSource = (
|
||||||
listFormCode?: string,
|
listFormCode?: string,
|
||||||
lookupQuery?: string,
|
lookupQuery?: string,
|
||||||
filters?: any[],
|
filters?: any[] | null,
|
||||||
keyName?: string,
|
keyName?: string,
|
||||||
isSubForm?: boolean,
|
isSubForm?: boolean,
|
||||||
) =>
|
) =>
|
||||||
|
|
@ -99,7 +133,7 @@ const createLookupApiDataSource = (
|
||||||
// Gövdedeki @param0, @param1… yer tutucularını cascade filtreleriyle doldur.
|
// Gövdedeki @param0, @param1… yer tutucularını cascade filtreleriyle doldur.
|
||||||
let resolvedBody = bodyTemplate ?? ''
|
let resolvedBody = bodyTemplate ?? ''
|
||||||
filters?.forEach((filterValue, index) => {
|
filters?.forEach((filterValue, index) => {
|
||||||
resolvedBody = resolvedBody.replace(new RegExp(`@param${index}`, 'g'), String(filterValue))
|
resolvedBody = resolvedBody.replace(new RegExp(`@param${index}\\b`, 'g'), toJsonText(filterValue))
|
||||||
})
|
})
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -129,6 +163,10 @@ const createLookupApiDataSource = (
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup kolonunun veri kaynağı. Grid/Tree/Card (`useListFormColumns`) ve Form aynı kuralı
|
||||||
|
* kullanır; `rowData` cascade ebeveynlerinin okunduğu kayıttır.
|
||||||
|
*/
|
||||||
export const useLookupDataSource = ({
|
export const useLookupDataSource = ({
|
||||||
listFormCode,
|
listFormCode,
|
||||||
isSubForm,
|
isSubForm,
|
||||||
|
|
@ -139,24 +177,9 @@ export const useLookupDataSource = ({
|
||||||
const { translate, cultureName } = useLocalization()
|
const { translate, cultureName } = useLocalization()
|
||||||
|
|
||||||
const getLookupDataSource = useCallback(
|
const getLookupDataSource = useCallback(
|
||||||
(options: any, colData: any, data: any) => {
|
(colData: any, rowData: any) => {
|
||||||
const { lookupDto } = colData
|
const { lookupDto } = colData
|
||||||
const filters: any[] = []
|
const filters = buildCascadeFilters(lookupDto, rowData)
|
||||||
|
|
||||||
// Cascading alanlar: parent değeri yoksa null gönderilir, istek yine de yapılır.
|
|
||||||
if (lookupDto.cascadeParentFields) {
|
|
||||||
if (lookupDto.dataSourceType == UiLookupDataSourceTypeEnum.StaticData) {
|
|
||||||
filters.push([
|
|
||||||
lookupDto?.cascadeRelationField,
|
|
||||||
lookupDto?.cascadeFilterOperator,
|
|
||||||
options?.data?.[lookupDto?.cascadeParentField] ?? null,
|
|
||||||
])
|
|
||||||
} else {
|
|
||||||
for (const cascadeParentField of lookupDto.cascadeParentFields.split(',')) {
|
|
||||||
filters.push(data?.[cascadeParentField.trim()] ?? null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (lookupDto.dataSourceType) {
|
switch (lookupDto.dataSourceType) {
|
||||||
case UiLookupDataSourceTypeEnum.StaticData:
|
case UiLookupDataSourceTypeEnum.StaticData:
|
||||||
|
|
@ -166,8 +189,8 @@ export const useLookupDataSource = ({
|
||||||
...item,
|
...item,
|
||||||
name: typeof item.name === 'string' ? translate(`::${item.name}`) : item.name,
|
name: typeof item.name === 'string' ? translate(`::${item.name}`) : item.name,
|
||||||
})),
|
})),
|
||||||
filters.length ? filters : null,
|
filters,
|
||||||
`static:${cultureName}:${listFormCode}:${colData.fieldName}`,
|
`${cultureName}:${listFormCode}:${colData.fieldName}`,
|
||||||
)
|
)
|
||||||
case UiLookupDataSourceTypeEnum.Query:
|
case UiLookupDataSourceTypeEnum.Query:
|
||||||
return createLookupQueryDataSource(listFormCode, colData.fieldName, filters, isSubForm)
|
return createLookupQueryDataSource(listFormCode, colData.fieldName, filters, isSubForm)
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,8 @@ import {
|
||||||
UiLookupDataSourceTypeEnum,
|
UiLookupDataSourceTypeEnum,
|
||||||
} from '@/proxy/form/models'
|
} from '@/proxy/form/models'
|
||||||
import { addCss, getEditingFormFields } from './Utils'
|
import { addCss, getEditingFormFields } from './Utils'
|
||||||
import {
|
import { clearLookupCache, clearLookupCacheByPrefix } from '../shared/lookupCache'
|
||||||
cachedLookupLoad,
|
import { useLookupDataSource } from '../form/useLookupDataSource'
|
||||||
clearLookupCache,
|
|
||||||
clearLookupCacheByPrefix,
|
|
||||||
} from '../shared/lookupCache'
|
|
||||||
import {
|
import {
|
||||||
NO_IMAGE,
|
NO_IMAGE,
|
||||||
normalizeImageSize,
|
normalizeImageSize,
|
||||||
|
|
@ -169,7 +166,7 @@ const useListFormColumns = ({
|
||||||
onShowNote?: (rowData: Record<string, any>) => void
|
onShowNote?: (rowData: Record<string, any>) => void
|
||||||
}) => {
|
}) => {
|
||||||
const dialog: any = useDialogContext()
|
const dialog: any = useDialogContext()
|
||||||
const { translate, cultureName } = useLocalization()
|
const { translate } = useLocalization()
|
||||||
const { checkPermission } = usePermission()
|
const { checkPermission } = usePermission()
|
||||||
const isPwaMode = usePWA()
|
const isPwaMode = usePWA()
|
||||||
|
|
||||||
|
|
@ -178,55 +175,12 @@ const useListFormColumns = ({
|
||||||
clearLookupCache()
|
clearLookupCache()
|
||||||
}, [listFormCode])
|
}, [listFormCode])
|
||||||
|
|
||||||
|
const { getLookupDataSource } = useLookupDataSource({ listFormCode, isSubForm })
|
||||||
|
|
||||||
|
// DataGrid lookup'ı satırı `options.data` ile verir; görünen metin yüklemesi satırsız çağırır.
|
||||||
const lookupDataSource = useCallback(
|
const lookupDataSource = useCallback(
|
||||||
(options: any, colData: any, listFormCode: string) => {
|
(options: any, colData: any) => getLookupDataSource(colData, options?.data ?? options),
|
||||||
const { lookupDto } = colData
|
[getLookupDataSource],
|
||||||
const filters = []
|
|
||||||
if (lookupDto.cascadeParentFields) {
|
|
||||||
if (lookupDto.dataSourceType == UiLookupDataSourceTypeEnum.StaticData) {
|
|
||||||
filters.push([
|
|
||||||
lookupDto?.cascadeRelationField,
|
|
||||||
lookupDto?.cascadeFilterOperator,
|
|
||||||
options?.data[lookupDto?.cascadeParentField],
|
|
||||||
])
|
|
||||||
//TODO: Statik data test edilecek
|
|
||||||
} else {
|
|
||||||
const data = options?.data ?? options
|
|
||||||
for (const cascadeParentField of lookupDto.cascadeParentFields.split(',')) {
|
|
||||||
filters.push(data[cascadeParentField])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//UiLookupDataSourceTypeEnum :
|
|
||||||
// Data = 1 (Statik Data),
|
|
||||||
// Query = 2 (API'den geliyor fakat API query çalıştırıyor)
|
|
||||||
// WebService = 3 (API servisten geliyor)
|
|
||||||
if (lookupDto.dataSourceType == UiLookupDataSourceTypeEnum.StaticData) {
|
|
||||||
return createLookupStaticDataSource(
|
|
||||||
() =>
|
|
||||||
JSON.parse(lookupDto?.lookupQuery).map((item: any) => ({
|
|
||||||
...item,
|
|
||||||
name: typeof item.name === 'string' ? translate(`::${item.name}`) : item.name,
|
|
||||||
})),
|
|
||||||
filters.length ? filters : null,
|
|
||||||
`static:${cultureName}:${listFormCode}:${colData.fieldName}`, // cache key
|
|
||||||
)
|
|
||||||
} else if (lookupDto.dataSourceType == UiLookupDataSourceTypeEnum.Query) {
|
|
||||||
return createLookupQueryDataSource(listFormCode, colData.fieldName, filters)
|
|
||||||
} else if (lookupDto.dataSourceType == UiLookupDataSourceTypeEnum.WebService) {
|
|
||||||
return createLookupApiDataSource(
|
|
||||||
listFormCode,
|
|
||||||
lookupDto?.lookupQuery,
|
|
||||||
filters,
|
|
||||||
colData.lookupDto?.valueExpr?.toLowerCase(),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
store: [],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[listFormCode, translate, cultureName],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const loadLookupDisplayValues = useCallback(
|
const loadLookupDisplayValues = useCallback(
|
||||||
|
|
@ -241,7 +195,7 @@ const useListFormColumns = ({
|
||||||
)
|
)
|
||||||
.map(async (column) => {
|
.map(async (column) => {
|
||||||
const lookup = column.colData!.lookupDto
|
const lookup = column.colData!.lookupDto
|
||||||
const source = lookupDataSource({}, column.colData, listFormCode)
|
const source = lookupDataSource({}, column.colData)
|
||||||
const store =
|
const store =
|
||||||
source instanceof CustomStore
|
source instanceof CustomStore
|
||||||
? source
|
? source
|
||||||
|
|
@ -270,7 +224,7 @@ const useListFormColumns = ({
|
||||||
|
|
||||||
return Object.fromEntries(entries) as Record<string, Map<string, string>>
|
return Object.fromEntries(entries) as Record<string, Map<string, string>>
|
||||||
},
|
},
|
||||||
[listFormCode, lookupDataSource],
|
[lookupDataSource],
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -311,7 +265,7 @@ const useListFormColumns = ({
|
||||||
const prefix = getCachePrefix(colData)
|
const prefix = getCachePrefix(colData)
|
||||||
if (!prefix) return
|
if (!prefix) return
|
||||||
|
|
||||||
const source = lookupDataSource({}, colData, listFormCode)
|
const source = lookupDataSource({}, colData)
|
||||||
const store =
|
const store =
|
||||||
source instanceof CustomStore
|
source instanceof CustomStore
|
||||||
? source
|
? source
|
||||||
|
|
@ -347,115 +301,6 @@ const useListFormColumns = ({
|
||||||
[gridDto, listFormCode, lookupDataSource],
|
[gridDto, listFormCode, lookupDataSource],
|
||||||
)
|
)
|
||||||
|
|
||||||
const createLookupStaticDataSource = (
|
|
||||||
load: () => any,
|
|
||||||
filter: any = null,
|
|
||||||
key: any = 'static',
|
|
||||||
sort: any = 'name',
|
|
||||||
) => ({
|
|
||||||
store: new CustomStore({
|
|
||||||
key,
|
|
||||||
loadMode: 'raw',
|
|
||||||
load: async () => {
|
|
||||||
// load fonksiyonu sync sonuç döndürüyor olabilir, o yüzden Promise.resolve ile sar
|
|
||||||
return cachedLookupLoad(`static:${key}`, async () => {
|
|
||||||
const result = await Promise.resolve(load())
|
|
||||||
if (result === undefined || result === null) return []
|
|
||||||
return Array.isArray(result) ? result : [result]
|
|
||||||
})
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
sort,
|
|
||||||
filter,
|
|
||||||
})
|
|
||||||
|
|
||||||
const createLookupQueryDataSource = (
|
|
||||||
listFormCode?: string,
|
|
||||||
listFormFieldName?: string,
|
|
||||||
filters?: any[],
|
|
||||||
) => {
|
|
||||||
return new CustomStore({
|
|
||||||
loadMode: 'raw',
|
|
||||||
load: async () => {
|
|
||||||
if (!isSubForm && listFormCode && !window.location.pathname.includes(listFormCode)) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const cacheKey = `query:${listFormCode}:${listFormFieldName}:${JSON.stringify(filters ?? null)}`
|
|
||||||
return cachedLookupLoad(cacheKey, async () => {
|
|
||||||
const response = await dynamicFetch('list-form-select/lookup', 'POST', null, {
|
|
||||||
listFormCode,
|
|
||||||
listFormFieldName,
|
|
||||||
filters,
|
|
||||||
})
|
|
||||||
|
|
||||||
return (response.data ?? []).map((a: any) => ({
|
|
||||||
key: a.Key,
|
|
||||||
name: a.Name,
|
|
||||||
group: a.Group,
|
|
||||||
|
|
||||||
...a,
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Lookup query data could not be loaded:', error)
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const createLookupApiDataSource = (
|
|
||||||
listFormCode?: string,
|
|
||||||
lookupQuery?: string,
|
|
||||||
filters?: any[],
|
|
||||||
keyName?: string,
|
|
||||||
) => {
|
|
||||||
return new CustomStore({
|
|
||||||
key: keyName,
|
|
||||||
loadMode: 'raw',
|
|
||||||
load: async () => {
|
|
||||||
if (!isSubForm && listFormCode && !window.location.pathname.includes(listFormCode)) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
if (!lookupQuery) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
const [method, url, body, keySelector, nameSelector, groupSelector] = lookupQuery.split(';')
|
|
||||||
|
|
||||||
// body içindeki @paramN'leri filtrelerle değiştir
|
|
||||||
let resolvedBody = body
|
|
||||||
if (filters?.length) {
|
|
||||||
for (let i = 0; i < filters.length; i++) {
|
|
||||||
resolvedBody = resolvedBody.replace(new RegExp(`@param${i}`, 'g'), filters[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const cacheKey = `api:${lookupQuery}:${JSON.stringify(filters ?? null)}`
|
|
||||||
return cachedLookupLoad(cacheKey, async () => {
|
|
||||||
const response = await dynamicFetch(url, method, null, resolvedBody)
|
|
||||||
let { data } = response
|
|
||||||
if (!data) return []
|
|
||||||
if (!Array.isArray(data)) data = [data]
|
|
||||||
return data.map((a: any) => ({
|
|
||||||
key: eval(keySelector),
|
|
||||||
name: eval(nameSelector),
|
|
||||||
group: eval(groupSelector),
|
|
||||||
|
|
||||||
...a,
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Lookup API data could not be loaded:', error)
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const getCommandColumn = useCallback((): GridColumnData | undefined => {
|
const getCommandColumn = useCallback((): GridColumnData | undefined => {
|
||||||
if (!gridDto) {
|
if (!gridDto) {
|
||||||
return
|
return
|
||||||
|
|
@ -817,9 +662,8 @@ const useListFormColumns = ({
|
||||||
column.lookup = {
|
column.lookup = {
|
||||||
valueExpr: colData.lookupDto?.valueExpr?.toLowerCase(),
|
valueExpr: colData.lookupDto?.valueExpr?.toLowerCase(),
|
||||||
displayExpr: colData.lookupDto?.displayExpr?.toLowerCase(),
|
displayExpr: colData.lookupDto?.displayExpr?.toLowerCase(),
|
||||||
dataSource: (o) => lookupDataSource(o, colData, listFormCode),
|
dataSource: (o) => lookupDataSource(o, colData),
|
||||||
}
|
}
|
||||||
//column.lookup.dataSource = lookupDataSource(null, colData)
|
|
||||||
|
|
||||||
//cascadeEmptyFields verisi dolu ise bu kolon/field bir parent field dir
|
//cascadeEmptyFields verisi dolu ise bu kolon/field bir parent field dir
|
||||||
if (colData.lookupDto.cascadeEmptyFields) {
|
if (colData.lookupDto.cascadeEmptyFields) {
|
||||||
|
|
@ -891,7 +735,7 @@ const useListFormColumns = ({
|
||||||
|
|
||||||
return columns
|
return columns
|
||||||
},
|
},
|
||||||
[gridDto, lookupDataSource, translate, checkPermission, dialog, isPwaMode, listFormCode],
|
[gridDto, lookupDataSource, translate],
|
||||||
)
|
)
|
||||||
|
|
||||||
const getBandedColumns = useCallback(() => {
|
const getBandedColumns = useCallback(() => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue