feat(stock): GatePanel 자동 폼 + GlobalControls (TopN/ATR/RR + 3버튼)
This commit is contained in:
@@ -1,3 +1,41 @@
|
||||
export default function GatePanel({ meta, value, onChange }) {
|
||||
return <section className="screener-card"><h3>{meta?.label ?? '게이트'}</h3><p style={{fontSize: 12, color:'#9ca3af'}}>TODO: 게이트 파라미터 폼 (Task 4.5)</p></section>;
|
||||
if (!meta) return null;
|
||||
const props = meta.param_schema?.properties || {};
|
||||
return (
|
||||
<section className="screener-card">
|
||||
<h3>{meta.label}</h3>
|
||||
<p style={{ fontSize: 11, color: '#9ca3af', marginTop: 0 }}>
|
||||
통과 조건 — 통과한 종목만 점수 노드에 전달
|
||||
</p>
|
||||
{Object.entries(props).map(([key, prop]) => (
|
||||
<GateField key={key} paramKey={key} prop={prop}
|
||||
value={value?.[key] ?? meta.default_params?.[key]}
|
||||
onChange={(v) => onChange({ ...value, [key]: v })} />
|
||||
))}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function GateField({ paramKey, prop, value, onChange }) {
|
||||
if (prop.type === 'integer') {
|
||||
return (
|
||||
<div className="param-row">
|
||||
<label style={{ width: 160, fontSize: 12 }}>{paramKey}</label>
|
||||
<input type="number" value={value ?? ''}
|
||||
min={prop.minimum} onChange={(e) => onChange(parseInt(e.target.value, 10))}
|
||||
style={{ flex: 1 }} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (prop.type === 'boolean') {
|
||||
return (
|
||||
<div className="param-row">
|
||||
<label>
|
||||
<input type="checkbox" checked={!!value} onChange={(e) => onChange(e.target.checked)} />
|
||||
<span style={{ marginLeft: 6, fontSize: 12 }}>{paramKey}</span>
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user