Добавлен выбор режима условия для table-полей в переходах: по значению или пользователь из колонки
This commit is contained in:
@@ -3761,7 +3761,20 @@ return function Layout({ ctx }) {
|
||||
// 3. Простой: assigneeUserId установлен, assigneeConditions = null
|
||||
const raw = transition.assigneeConditions as any;
|
||||
|
||||
let assigneeBlocks: { type: 'user' | 'role' | 'field_user' | 'table_column_user'; id: number; fieldCode?: string; columnIndex?: number; rules: { fieldCode: string; value: string; operator?: string }[] }[] = [];
|
||||
let assigneeBlocks: { type: 'user' | 'role' | 'field_user' | 'table_column_user'; id: number; fieldCode?: string; columnIndex?: number; rules: { fieldCode: string; value: string; operator?: string; tableMode?: 'value' | 'column_user' }[] }[] = [];
|
||||
|
||||
const resolveTableMode = (r: any, fieldCode?: string): 'value' | 'column_user' | undefined => {
|
||||
if (r.tableMode === 'value' || r.tableMode === 'column_user') return r.tableMode;
|
||||
// Обратная совместимость: раньше для table-поля в value хранился индекс колонки
|
||||
const field = fields.find((f: FormField) => f.code === (fieldCode || r.fieldCode));
|
||||
if (field?.type === 'table') {
|
||||
const tableId = (field.options as any)?.tableId as number | undefined;
|
||||
const cols = tablesData?.tables?.find((t: any) => t.id === tableId)?.columns || [];
|
||||
const idx = Number(r.value);
|
||||
if (!isNaN(idx) && idx >= 0 && idx < cols.length) return 'column_user';
|
||||
}
|
||||
return 'value';
|
||||
};
|
||||
|
||||
if (raw?.assignees && Array.isArray(raw.assignees)) {
|
||||
assigneeBlocks = raw.assignees.map((a: any) => ({
|
||||
@@ -3769,15 +3782,20 @@ return function Layout({ ctx }) {
|
||||
id: a.id ?? 0,
|
||||
fieldCode: a.fieldCode,
|
||||
columnIndex: a.columnIndex,
|
||||
rules: (a.rules || []).map((r: any) => ({ fieldCode: r.fieldCode || '', value: r.value || '', operator: r.operator || 'contains' })),
|
||||
rules: (a.rules || []).map((r: any) => ({
|
||||
fieldCode: r.fieldCode || '',
|
||||
value: r.value || '',
|
||||
operator: r.operator || 'contains',
|
||||
tableMode: resolveTableMode(r, a.fieldCode),
|
||||
})),
|
||||
}));
|
||||
} else if (raw?.rules && Array.isArray(raw.rules)) {
|
||||
const merged = new Map<string, { type: 'user' | 'role' | 'field_user' | 'table_column_user'; id: number; fieldCode?: string; columnIndex?: number; rules: { fieldCode: string; value: string; operator?: string }[] }>();
|
||||
const merged = new Map<string, { type: 'user' | 'role' | 'field_user' | 'table_column_user'; id: number; fieldCode?: string; columnIndex?: number; rules: { fieldCode: string; value: string; operator?: string; tableMode?: 'value' | 'column_user' }[] }>();
|
||||
for (const r of raw.rules) {
|
||||
if (r.tableUserColumnIndex !== undefined && !r.tableId && r.fieldCode) {
|
||||
const key = `table_column_user:${r.fieldCode}:${r.tableUserColumnIndex}`;
|
||||
if (!merged.has(key)) merged.set(key, { type: 'table_column_user', id: 0, fieldCode: r.fieldCode, columnIndex: r.tableUserColumnIndex, rules: [] });
|
||||
if (r.fieldCode) merged.get(key)!.rules.push({ fieldCode: r.fieldCode, value: r.value || '', operator: r.operator || 'contains' });
|
||||
if (r.fieldCode) merged.get(key)!.rules.push({ fieldCode: r.fieldCode, value: r.value || '', operator: r.operator || 'contains', tableMode: 'column_user' });
|
||||
continue;
|
||||
}
|
||||
if (r.tableId !== undefined && r.tableUserColumnIndex !== undefined) {
|
||||
@@ -3788,7 +3806,7 @@ return function Layout({ ctx }) {
|
||||
if (!id) continue;
|
||||
const key = `${type}:${id}`;
|
||||
if (!merged.has(key)) merged.set(key, { type, id, rules: [] });
|
||||
if (r.fieldCode) merged.get(key)!.rules.push({ fieldCode: r.fieldCode, value: r.value || '', operator: r.operator || 'contains' });
|
||||
if (r.fieldCode) merged.get(key)!.rules.push({ fieldCode: r.fieldCode, value: r.value || '', operator: r.operator || 'contains', tableMode: resolveTableMode(r) });
|
||||
}
|
||||
assigneeBlocks = Array.from(merged.values());
|
||||
}
|
||||
@@ -3810,7 +3828,7 @@ return function Layout({ ctx }) {
|
||||
id: (b.type === 'user' || b.type === 'role') ? b.id : undefined,
|
||||
fieldCode: (b.type === 'field_user' || b.type === 'table_column_user') ? b.fieldCode : undefined,
|
||||
columnIndex: b.type === 'table_column_user' ? b.columnIndex : undefined,
|
||||
rules: b.rules.map(r => ({ fieldCode: r.fieldCode, value: r.value, operator: r.operator || 'contains' })),
|
||||
rules: b.rules.map(r => ({ fieldCode: r.fieldCode, value: r.value, operator: r.operator || 'contains', tableMode: r.tableMode })),
|
||||
})) }
|
||||
: null;
|
||||
|
||||
@@ -3822,7 +3840,7 @@ return function Layout({ ctx }) {
|
||||
updateTransition(index, { assigneeConditions: payload, assigneeUserId });
|
||||
};
|
||||
|
||||
const emptyRule = { fieldCode: '', value: '', operator: 'contains' };
|
||||
const emptyRule = { fieldCode: '', value: '', operator: 'contains', tableMode: undefined as 'value' | 'column_user' | undefined };
|
||||
const addRule = (bi: number) => {
|
||||
const blocks = [...assigneeBlocks];
|
||||
blocks[bi] = { ...blocks[bi], rules: [...blocks[bi].rules, { ...emptyRule }] };
|
||||
@@ -3833,7 +3851,7 @@ return function Layout({ ctx }) {
|
||||
blocks[bi] = { ...blocks[bi], rules: blocks[bi].rules.filter((_, i) => i !== ri) };
|
||||
saveAssigneeBlocks(blocks);
|
||||
};
|
||||
const updateRule = (bi: number, ri: number, patch: Partial<{ fieldCode: string; value: string; operator?: string }>) => {
|
||||
const updateRule = (bi: number, ri: number, patch: Partial<{ fieldCode: string; value: string; operator?: string; tableMode?: 'value' | 'column_user' }>) => {
|
||||
const blocks = [...assigneeBlocks];
|
||||
blocks[bi] = { ...blocks[bi], rules: blocks[bi].rules.map((r, i) => i === ri ? { ...r, ...patch } : r) };
|
||||
saveAssigneeBlocks(blocks);
|
||||
@@ -3855,7 +3873,7 @@ return function Layout({ ctx }) {
|
||||
id: b.id,
|
||||
fieldCode: b.fieldCode,
|
||||
columnIndex: b.columnIndex,
|
||||
rules: b.rules.map(r => ({ fieldCode: r.fieldCode, value: r.value })),
|
||||
rules: b.rules.map(r => ({ fieldCode: r.fieldCode, value: r.value, operator: r.operator, tableMode: r.tableMode })),
|
||||
})),
|
||||
},
|
||||
assigneeUserId: undefined,
|
||||
@@ -3965,21 +3983,66 @@ return function Layout({ ctx }) {
|
||||
|
||||
{isTableField ? (
|
||||
<>
|
||||
<span className="text-muted-foreground shrink-0">→ пользователь из колонки</span>
|
||||
<Select
|
||||
value={rule.value || 'none'}
|
||||
onValueChange={(v) => updateRule(bi, ri, { value: v === 'none' ? '' : v })}
|
||||
value={rule.tableMode || 'value'}
|
||||
onValueChange={(v) => {
|
||||
const nextMode = v as 'value' | 'column_user';
|
||||
updateRule(bi, ri, {
|
||||
tableMode: nextMode,
|
||||
value: nextMode === 'column_user' ? '' : '',
|
||||
operator: 'contains',
|
||||
});
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="h-6 text-xs w-36">
|
||||
<SelectValue placeholder="колонка..." />
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="none">— выбрать —</SelectItem>
|
||||
{fieldTableCols.map((col: any, ci: number) => (
|
||||
<SelectItem key={ci} value={ci.toString()}>{col.name} ({col.type})</SelectItem>
|
||||
))}
|
||||
<SelectItem value="value">содержит значение</SelectItem>
|
||||
<SelectItem value="column_user">пользователь из колонки</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
{rule.tableMode === 'column_user' ? (
|
||||
<Select
|
||||
value={rule.value || 'none'}
|
||||
onValueChange={(v) => updateRule(bi, ri, { value: v === 'none' ? '' : v })}
|
||||
>
|
||||
<SelectTrigger className="h-6 text-xs w-36">
|
||||
<SelectValue placeholder="колонка..." />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="none">— выбрать —</SelectItem>
|
||||
{fieldTableCols.map((col: any, ci: number) => (
|
||||
<SelectItem key={ci} value={ci.toString()}>{col.name} ({col.type})</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
) : (
|
||||
<>
|
||||
<Select
|
||||
value={rule.operator || 'contains'}
|
||||
onValueChange={(v) => updateRule(bi, ri, { operator: v })}
|
||||
>
|
||||
<SelectTrigger className="h-6 text-xs w-28">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="contains">содержит</SelectItem>
|
||||
<SelectItem value="empty">не заполнено</SelectItem>
|
||||
<SelectItem value="filled">заполнено</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{rule.operator !== 'empty' && (
|
||||
<Input
|
||||
className="h-6 text-xs w-28 px-1.5"
|
||||
placeholder="значение"
|
||||
value={rule.value || ''}
|
||||
onChange={(e) => updateRule(bi, ri, { value: e.target.value })}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
|
||||
@@ -292,7 +292,7 @@ export function buildSystemFieldValuesForConditions(
|
||||
* Проверяет, соответствуют ли значения полей заданным правилам.
|
||||
*/
|
||||
export function fieldConditionsMatch(
|
||||
rules: { fieldCode?: string; value?: string; operator?: "contains" | "empty" | "filled" }[],
|
||||
rules: { fieldCode?: string; value?: string; operator?: "contains" | "empty" | "filled"; tableMode?: "value" | "column_user" }[],
|
||||
fieldValues: Array<{ fieldId: number; value: unknown }>,
|
||||
fields: Array<{
|
||||
id: number;
|
||||
@@ -311,6 +311,10 @@ export function fieldConditionsMatch(
|
||||
const field = fields.find((f) => f.code === rule.fieldCode);
|
||||
if (!field) return false;
|
||||
|
||||
// Режим "пользователь из колонки" — это конфигурация выборки согласующего,
|
||||
// а не условие на значение поля. Пропускаем, чтобы не ломать проверку.
|
||||
if (rule.tableMode === "column_user") continue;
|
||||
|
||||
const fv = fieldValues.find((fv) => fv.fieldId === field.id);
|
||||
const operator = rule.operator || "contains";
|
||||
|
||||
@@ -364,6 +368,7 @@ export interface FieldRule {
|
||||
fieldCode: string;
|
||||
operator?: "contains" | "empty" | "filled";
|
||||
value?: string;
|
||||
tableMode?: "value" | "column_user";
|
||||
}>;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user