352352 min-width : 0 ;
353353 }
354354
355- .margin-policy-stack {
356- display : grid;
357- gap : 14px ;
358- min-width : 0 ;
359- }
360-
361355 .reserve-policy-stack .policy-stack-muted {
362356 opacity : 0.58 ;
363357 }
628622 margin : 0 ;
629623 padding : 8px 16px ;
630624 display : grid;
625+ gap : 0 ;
631626 }
632627
633628 .summary-row {
650645 background : color-mix (in srgb, var (--platform-color , var (--accent )) 6% , # ffffff );
651646 }
652647
653- .summary-row dt {
648+ .summary-label {
654649 color : var (--muted );
655650 font-size : 12px ;
656651 line-height : 1.4 ;
657652 font-weight : 760 ;
658653 }
659654
660- .summary-row dd {
655+ .summary-value {
661656 margin : 0 ;
662657 min-width : 0 ;
663658 color : var (--ink );
667662 overflow-wrap : anywhere;
668663 }
669664
670- .summary-row .pending dd {
665+ .summary-row .pending . summary-value {
671666 color : var (--platform-color , var (--accent ));
672667 font-weight : 800 ;
673668 }
11361131 border-bottom-color : rgba (229 , 236 , 242 , 0.96 );
11371132 }
11381133
1139- .summary-row dt {
1134+ .summary-label {
11401135 color : # 66758a ;
11411136 font-size : 12px ;
11421137 font-weight : 790 ;
11431138 }
11441139
1145- .summary-row dd {
1140+ .summary-value {
11461141 color : # 263244 ;
11471142 font-size : 13px ;
11481143 font-weight : 700 ;
@@ -1409,19 +1404,11 @@ <h3 class="execution-cash-policy-heading" data-i18n="executionCashPolicyTitle">
14091404 < p class ="execution-cash-policy-note " id ="execution-cash-policy-note " data-i18n ="executionCashPolicyNote "> 允许融资与预留现金覆盖不能同时生效。</ p >
14101405 < p class ="execution-cash-policy-note qmt-platform-cash-note " id ="qmt-platform-cash-note " hidden data-i18n ="qmtPlatformCashNote "> A 股 QMT 不使用 margin / 平台预留现金;现金约束在策略参数 execution_cash_reserve_ratio 内配置。</ p >
14111406 < div class ="execution-cash-policy-grid " id ="execution-cash-policy-grid ">
1412- < div class ="margin-policy-stack " id ="margin-policy-stack ">
1413- < label class ="control-block cash-only-mode-block policy-block " id ="cash-only-policy-block ">
1414- < span data-i18n ="cashOnlyExecutionMode "> 允许融资</ span >
1415- < select id ="cash-only-execution-mode-select "> </ select >
1416- < span class ="selection-meta " id ="cash-only-execution-mode-meta "> </ span >
1417- </ label >
1418-
1419- < label class ="control-block reserve-ratio-block policy-block " id ="reserve-ratio-block ">
1420- < span data-i18n ="reservedCashRatio "> 预留现金比例</ span >
1421- < input id ="reserved-cash-ratio-input " type ="number " inputmode ="decimal " min ="0 " max ="1 " step ="0.01 ">
1422- < span class ="selection-meta " data-i18n ="reservedCashRatioMeta "> 例如 0.03 表示 3%。</ span >
1423- </ label >
1424- </ div >
1407+ < label class ="control-block cash-only-mode-block policy-block " id ="cash-only-policy-block ">
1408+ < span data-i18n ="cashOnlyExecutionMode "> 允许融资</ span >
1409+ < select id ="cash-only-execution-mode-select "> </ select >
1410+ < span class ="selection-meta " id ="cash-only-execution-mode-meta "> </ span >
1411+ </ label >
14251412
14261413 < div class ="reserve-policy-stack " id ="reserve-policy-stack ">
14271414 < label class ="control-block reserve-policy-block policy-block " id ="reserve-policy-block ">
@@ -1435,6 +1422,12 @@ <h3 class="execution-cash-policy-heading" data-i18n="executionCashPolicyTitle">
14351422 < input id ="min-reserved-cash-input " type ="number " inputmode ="decimal " min ="0 " step ="1 ">
14361423 < span class ="selection-meta " data-i18n ="reservedCashMeta "> 固定金额下限,可单独设置或与比例取较大值。</ span >
14371424 </ label >
1425+
1426+ < label class ="control-block reserve-ratio-block policy-block " id ="reserve-ratio-block ">
1427+ < span data-i18n ="reservedCashRatio "> 预留现金比例</ span >
1428+ < input id ="reserved-cash-ratio-input " type ="number " inputmode ="decimal " min ="0 " max ="1 " step ="0.01 ">
1429+ < span class ="selection-meta " data-i18n ="reservedCashRatioMeta "> 例如 0.03 表示 3%。</ span >
1430+ </ label >
14381431 </ div >
14391432 </ div >
14401433 </ div >
@@ -1466,9 +1459,9 @@ <h3 class="execution-cash-policy-heading" data-i18n="executionCashPolicyTitle">
14661459 < h2 data-i18n ="summary "> 切换摘要</ h2 >
14671460 < span class ="pill " id ="mode-pill "> live</ span >
14681461 </ div >
1469- < dl class ="summary-list " id ="summary-list "> </ dl >
1462+ < div class ="summary-list " id ="summary-list " role =" list " > </ div >
14701463 < div class ="summary-actions ">
1471- < button class ="btn " id ="copy-button " type ="button " data-i18n ="copySummary "> 复制摘要 </ button >
1464+ < button class ="btn " id ="copy-button " type ="button " data-i18n ="copySummary "> 复制状态 </ button >
14721465 </ div >
14731466 </ aside >
14741467 </ section >
@@ -1736,7 +1729,6 @@ <h2 data-i18n="summary">切换摘要</h2>
17361729 loadingConfigNote : "正在读取账号配置和当前状态。" ,
17371730 missingConfigNote : "账号配置未加载,暂时不能执行。" ,
17381731 readyNote : "点击后会触发工作流,并同步目标平台服务。" ,
1739- noChangesNote : "当前选择与已读取配置一致。" ,
17401732 invalidStrategyNote : "当前账号没有可执行策略,暂时不能切换。" ,
17411733 invalidReservePolicyNote : "请为当前预留现金策略填写有效金额或比例。" ,
17421734 invalidIncomeLayerNote : "请填写有效的收入层起始金额和最高比例。" ,
@@ -1902,7 +1894,6 @@ <h2 data-i18n="summary">切换摘要</h2>
19021894 loadingConfigNote : "Reading account config and current state." ,
19031895 missingConfigNote : "Account config is not loaded, so switching is disabled." ,
19041896 readyNote : "This dispatches the workflow and syncs the target platform service." ,
1905- noChangesNote : "The current selection matches the readable config." ,
19061897 invalidStrategyNote : "This account has no runnable strategy, so switching is disabled." ,
19071898 invalidReservePolicyNote : "Enter a valid amount or ratio for the selected reserved-cash policy." ,
19081899 invalidIncomeLayerNote : "Enter a valid income layer start amount and max ratio." ,
@@ -2550,6 +2541,31 @@ <h2 data-i18n="summary">切换摘要</h2>
25502541 } ;
25512542 }
25522543
2544+ function incomeLayerFieldsConfigured ( entry ) {
2545+ const current = incomeLayerFromEntry ( entry ) ;
2546+ return current . enabled !== null || Boolean ( current . startUsd || current . maxRatio ) ;
2547+ }
2548+
2549+ function effectiveIncomeLayerForAccount ( platform , account , profile = state . forms [ platform ] ?. strategy ) {
2550+ const defaults = incomeLayerDefaultForStrategy ( profile ) ;
2551+ if ( ! defaults ) return null ;
2552+ const entry = currentEntryForAccount ( platform , account ) ;
2553+ if ( ! entry ) return null ;
2554+ const current = incomeLayerFromEntry ( entry ) ;
2555+ if ( ! incomeLayerFieldsConfigured ( entry ) ) {
2556+ return {
2557+ enabled : true ,
2558+ startUsd : String ( defaults . startUsd ) ,
2559+ maxRatio : defaults . maxRatio ,
2560+ } ;
2561+ }
2562+ return {
2563+ enabled : current . enabled ?? true ,
2564+ startUsd : current . startUsd || String ( defaults . startUsd ) ,
2565+ maxRatio : current . maxRatio || defaults . maxRatio ,
2566+ } ;
2567+ }
2568+
25532569 function currentDcaForAccount ( platform , account , profile = state . forms [ platform ] ?. strategy ) {
25542570 const defaults = dcaConfigForStrategy ( profile ) ;
25552571 if ( ! defaults ) return { supported : false , mode : "" , baseInvestmentUsd : "" } ;
@@ -3131,15 +3147,17 @@ <h2 data-i18n="summary">切换摘要</h2>
31313147 function currentIncomeLayerText ( platform = state . selected , account = selectedAccount ( platform ) , profile = state . forms [ platform ] ?. strategy ) {
31323148 const defaults = incomeLayerDefaultForStrategy ( profile ) ;
31333149 if ( ! defaults ) return t ( "incomeLayerNotSupported" ) ;
3134- const current = currentIncomeLayerForAccount ( platform , account ) ;
3135- const enabled = current . enabled ?? true ;
3136- const startUsd = current . startUsd || String ( defaults . startUsd ) ;
3137- const ratio = current . maxRatio || defaults . maxRatio ;
3138- if ( ! current . startUsd && ! current . maxRatio && current . enabled === null ) {
3150+ const entry = currentEntryForAccount ( platform , account ) ;
3151+ if ( ! entry ) return t ( "notRead" ) ;
3152+ const current = incomeLayerFromEntry ( entry ) ;
3153+ if ( ! incomeLayerFieldsConfigured ( entry ) ) {
31393154 return t ( "incomeLayerDefault" )
31403155 . replace ( "{start}" , formatUsd ( defaults . startUsd ) )
31413156 . replace ( "{ratio}" , formatRatioPercent ( defaults . maxRatio ) ) ;
31423157 }
3158+ const enabled = current . enabled ?? true ;
3159+ const startUsd = current . startUsd || String ( defaults . startUsd ) ;
3160+ const ratio = current . maxRatio || defaults . maxRatio ;
31433161 return enabled
31443162 ? t ( "incomeLayerOn" )
31453163 . replace ( "{start}" , formatUsd ( startUsd ) )
@@ -3243,25 +3261,38 @@ <h2 data-i18n="summary">切换摘要</h2>
32433261 const defaults = incomeLayerDefaultForStrategy ( profile ) ;
32443262 if ( ! defaults ) return { supported : false , changed : false , inputs : { } } ;
32453263 const mode = normalizeIncomeLayerMode ( inputs . income_layer_mode ) ;
3246- const current = currentIncomeLayerForAccount ( platform , account ) ;
3247- const currentEnabled = current . enabled ?? true ;
3248- const currentStartUsd = current . startUsd || String ( defaults . startUsd ) ;
3249- const currentRatio = current . maxRatio || defaults . maxRatio ;
3264+ const entry = currentEntryForAccount ( platform , account ) ;
3265+ const rawCurrent = currentIncomeLayerForAccount ( platform , account ) ;
3266+ const effective = effectiveIncomeLayerForAccount ( platform , account , profile ) ;
3267+ const currentEnabled = effective ?. enabled ?? true ;
3268+ const currentStartUsd = effective ?. startUsd ?? String ( defaults . startUsd ) ;
3269+ const currentRatio = effective ?. maxRatio ?? defaults . maxRatio ;
32503270 if ( mode === "current" ) {
32513271 return {
32523272 supported : true ,
32533273 changed : false ,
32543274 inputs : {
3255- income_layer_enabled : currentEnabled ,
3256- income_layer_start_usd : currentStartUsd ,
3257- income_layer_max_ratio : currentRatio ,
3275+ income_layer_enabled : rawCurrent . enabled ,
3276+ income_layer_start_usd : rawCurrent . startUsd ,
3277+ income_layer_max_ratio : rawCurrent . maxRatio ,
32583278 } ,
32593279 } ;
32603280 }
32613281 if ( mode === "disabled" ) {
3282+ if ( ! entry ) {
3283+ return {
3284+ supported : true ,
3285+ changed : false ,
3286+ inputs : {
3287+ income_layer_enabled : false ,
3288+ income_layer_start_usd : "" ,
3289+ income_layer_max_ratio : "" ,
3290+ } ,
3291+ } ;
3292+ }
32623293 return {
32633294 supported : true ,
3264- changed : currentEnabled !== false || Boolean ( current . startUsd || current . maxRatio ) ,
3295+ changed : currentEnabled !== false || Boolean ( rawCurrent . startUsd || rawCurrent . maxRatio ) ,
32653296 inputs : {
32663297 income_layer_enabled : false ,
32673298 income_layer_start_usd : "" ,
@@ -3273,7 +3304,7 @@ <h2 data-i18n="summary">切换摘要</h2>
32733304 const nextRatio = cleanDisplayRatio ( inputs . income_layer_max_ratio || defaults . maxRatio ) ;
32743305 return {
32753306 supported : true ,
3276- changed : Boolean ( currentEnabled !== true || nextStartUsd !== currentStartUsd || nextRatio !== currentRatio ) ,
3307+ changed : ! entry || Boolean ( currentEnabled !== true || nextStartUsd !== currentStartUsd || nextRatio !== currentRatio ) ,
32773308 inputs : {
32783309 income_layer_enabled : true ,
32793310 income_layer_start_usd : nextStartUsd ,
@@ -3852,10 +3883,13 @@ <h2 data-i18n="summary">切换摘要</h2>
38523883 for ( const [ label , value , rowClass , valueTone ] of summaryRows ( inputs ) ) {
38533884 const row = document . createElement ( "div" ) ;
38543885 row . className = "summary-row" ;
3886+ row . setAttribute ( "role" , "listitem" ) ;
38553887 if ( rowClass ) row . classList . add ( rowClass ) ;
3856- const labelNode = document . createElement ( "dt" ) ;
3888+ const labelNode = document . createElement ( "div" ) ;
3889+ labelNode . className = "summary-label" ;
38573890 labelNode . textContent = label ;
3858- const valueNode = document . createElement ( "dd" ) ;
3891+ const valueNode = document . createElement ( "div" ) ;
3892+ valueNode . className = "summary-value" ;
38593893 if ( valueTone ) {
38603894 const badge = document . createElement ( "span" ) ;
38613895 badge . className = `summary-status ${ valueTone } ` ;
@@ -4046,6 +4080,9 @@ <h2 data-i18n="summary">切换摘要</h2>
40464080 variable_scope : item . variable_scope ? String ( item . variable_scope ) : "" ,
40474081 plugin_mode : item . plugin_mode ? String ( item . plugin_mode ) : "" ,
40484082 option_overlay_mode : item . option_overlay_mode ? normalizeOptionOverlayMode ( item . option_overlay_mode ) : "" ,
4083+ cash_only_execution_mode : item . cash_only_execution_mode
4084+ ? normalizeCashOnlyExecutionMode ( item . cash_only_execution_mode )
4085+ : "" ,
40494086 dca_mode : item . dca_mode ? normalizeDcaMode ( item . dca_mode ) : "" ,
40504087 dca_base_investment_usd : cleanDisplayPositiveNumber ( item . dca_base_investment_usd ) ,
40514088 ibit_zscore_exit_mode : cleanIbitZscoreExitMode ( item . ibit_zscore_exit_mode ) ,
0 commit comments