# 任务进度与加载反馈

本页给出一个进度反馈面板示例，把 `Slider`、`SliderRange`、`Progress`、`Spin`、`Divider` 与按钮联动起来，适合文件处理、部署流水线、批量同步等任务界面。

> 重点：`Progress.Value` 是 `0` 到 `1` 的比例值，不是 `0` 到 `100` 的百分比整数。滑块通常用 `0` 到 `100`，再换算为 `progress.Value = slider.Value / 100`。

## 完整示例

```aardio
import win.ui;
import dotNet.AntdUI;
/*DSG{{*/
var winform = win.form(text="任务进度与加载反馈";right=900;bottom=560)
winform.add(
alertHost={cls="custom";left=34;top=425;right=560;bottom=486;db=1;dl=1;dr=1;frame=1;z=10};
btnPauseHost={cls="custom";text="暂停";left=696;top=425;right=760;bottom=461;dr=1;dt=1;frame=1;z=13};
btnResetHost={cls="custom";text="重置";left=772;top=425;right=836;bottom=461;dr=1;dt=1;frame=1;z=14};
btnStartHost={cls="custom";text="开始";left=620;top=425;right=684;bottom=461;dr=1;dt=1;frame=1;z=12};
divControlHost={cls="custom";text="交互控制";left=24;top=205;right=560;bottom=235;dl=1;dr=1;dt=1;z=7};
divLoadingHost={cls="custom";text="加载状态";left=610;top=18;right=850;bottom=48;dr=1;dt=1;z=2};
divProgressHost={cls="custom";text="进度展示";left=24;top=18;right=560;bottom=48;dl=1;dr=1;dt=1;z=1};
progressCircleHost={cls="custom";left=645;top=65;right=795;bottom=215;dr=1;dt=1;z=5};
progressMainHost={cls="custom";left=34;top=70;right=560;bottom=112;dl=1;dr=1;dt=1;z=3};
progressMiniHost={cls="custom";left=620;top=235;right=840;bottom=269;dr=1;dt=1;z=6};
progressStepsHost={cls="custom";left=34;top=130;right=560;bottom=176;dl=1;dr=1;dt=1;z=4};
rangeHost={cls="custom";left=34;top=325;right=560;bottom=377;dl=1;dr=1;dt=1;z=9};
sliderHost={cls="custom";left=34;top=252;right=560;bottom=304;dl=1;dr=1;dt=1;z=8};
spinHost={cls="custom";left=620;top=300;right=840;bottom=396;dr=1;dt=1;z=11}
)
/*}}*/

// 推荐模式：在设计器中放置 custom 宿主，再用 AntdUI 控件填充宿主。
// custom 宿主由 aardio 负责 DPI 缩放与锚定缩放，AntdUI 控件只负责自身外观与交互。
var divProgress = AntdUI.Divider(winform.divProgressHost);
var divLoading = AntdUI.Divider(winform.divLoadingHost);

var progressMain = AntdUI.Progress(winform.progressMainHost);
progressMain.Shape = AntdUI.TShapeProgress.Round;
progressMain.Text = "总体";
progressMain.TextUnit = "%";
progressMain.UseSystemText = true;
progressMain.Value = 0.35;

var progressSteps = AntdUI.Progress(winform.progressStepsHost);
progressSteps.Shape = AntdUI.TShapeProgress.Steps;
progressSteps.Steps = 10;
progressSteps.StepSize = 10;
progressSteps.StepGap = 4;
progressSteps.Value = 0.35;
progressSteps.Text = "分段";
progressSteps.TextUnit = "%";

var progressCircle = AntdUI.Progress(winform.progressCircleHost);
progressCircle.Shape = AntdUI.TShapeProgress.Circle;
progressCircle.UseTextCenter = true;
progressCircle.Value = 0.35;
progressCircle.Text = "35";
progressCircle.TextUnit = "%";

var progressMini = AntdUI.Progress(winform.progressMiniHost);
progressMini.Shape = AntdUI.TShapeProgress.Mini;
progressMini.Loading = false;
progressMini.Value = 0.35;

var divControl = AntdUI.Divider(winform.divControlHost);
var slider = AntdUI.Slider(winform.sliderHost);
slider.MinValue = 0;
slider.MaxValue = 100;
slider.Value = 35;
slider.ShowValue = true;
slider.Dots = true;

var range = AntdUI.SliderRange(winform.rangeHost);
range.MinValue = 0;
range.MaxValue = 100;
range.Value = 20;
range.Value2 = 80;
range.ShowValue = true;

var alert = AntdUI.Alert(winform.alertHost);
alert.TextTitle = "等待开始";
alert.Text = "拖动滑块可调整任务进度，范围滑块表示期望区间。";
alert.Icon = AntdUI.TType.Info;
alert.CloseIcon = false;
alert.BorderWidth = 1;
alert.Radius = 8;
alert.Loop = true;
alert.LoopPauseOnMouseEnter = true;

var spin = AntdUI.Spin(winform.spinHost);
spin.Text = "空闲";
spin.CirSize = 30;
spin.CirWidth = 4;

var btnStart = AntdUI.Button(winform.btnStartHost);
btnStart.Type = AntdUI.TTypeMini.Primary;
btnStart.Shape = AntdUI.TShape.Round;

var btnPause = AntdUI.Button(winform.btnPauseHost);
btnPause.Type = AntdUI.TTypeMini.Warn;
btnPause.Shape = AntdUI.TShape.Round;

var btnReset = AntdUI.Button(winform.btnResetHost);
btnReset.Type = AntdUI.TTypeMini.Default;
btnReset.Shape = AntdUI.TShape.Round;

var running = false;
var updating = false;

var applyProgress = function(){
    var pct = slider.Value;
    var ratio = pct / 100;

    progressMain.Value = ratio;
    progressSteps.Value = ratio;
    progressCircle.Value = ratio;
    progressCircle.Text = tostring(pct);
    progressMini.Value = ratio;

    if(pct >= 80){
        progressMain.State = AntdUI.TType.Success;
        progressSteps.State = AntdUI.TType.Success;
        progressCircle.State = AntdUI.TType.Success;
        alert.Icon = AntdUI.TType.Success;
        alert.TextTitle = "接近完成";
    }
    elseif(pct < range.Value){
        progressMain.State = AntdUI.TType.Warn;
        progressSteps.State = AntdUI.TType.Warn;
        progressCircle.State = AntdUI.TType.Warn;
        alert.Icon = AntdUI.TType.Warn;
        alert.TextTitle = "低于期望";
    }
    else{
        progressMain.State = AntdUI.TType.Info;
        progressSteps.State = AntdUI.TType.Info;
        progressCircle.State = AntdUI.TType.Info;
        alert.Icon = AntdUI.TType.Info;
        alert.TextTitle = running ? "任务运行中" : "任务已暂停";
    }

    alert.Text = string.concat("当前进度 ",pct,"% ，期望区间 ",range.Value,"% ~ ",range.Value2,"% 。");
}

slider.ValueChanged = function(sender,e){
    if(updating) return;
    applyProgress();
}

range.ValueChanged = function(sender,e){
    applyProgress();
}

range.Value2Changed = function(sender,e){
    applyProgress();
}

btnStart.Click = function(sender,e){
    running = true;
    spin.Text = "任务运行中...";
    progressMini.Loading = true;
    applyProgress();
}

btnPause.Click = function(sender,e){
    running = false;
    spin.Text = "已暂停";
    progressMini.Loading = false;
    applyProgress();
}

btnReset.Click = function(sender,e){
    running = false;
    updating = true;
    slider.Value = 0;
    updating = false;
    spin.Text = "已重置";
    progressMini.Loading = false;
    applyProgress();
}

winform.setInterval(
    function(){
        if(!running) return;
        var nextValue = slider.Value + 2;
        if(nextValue > 100){
            nextValue = 100;
            running = false;
            spin.Text = "任务完成";
            progressMini.Loading = false;
        }
        updating = true;
        slider.Value = nextValue;
        updating = false;
        applyProgress();
    },250
);

applyProgress();
winform.show();
win.loopMessage();
```

## 静态 Spin.open 浮层

嵌入式 `Spin` 适合固定区域持续显示加载状态；需要遮罩式耗时任务提示时，可使用 `Spin.open`。owner 建议传 `AntdUI.BaseForm(winform.host)` 或已经验证可作为 owner 的 AntdUI/WinForms 对象。

```aardio
var baseForm = AntdUI.BaseForm(winform.host);
var cfg = AntdUI.Spin.Config("正在同步数据...");
cfg.SetCirSize(32).SetCirWidth(4);
AntdUI.Spin.open(baseForm,cfg,function(){
    thread.delay(800);
});
```

## 实践要点

- `Slider.Value` / `SliderRange.Value` 常用整数百分比；`Progress.Value` 用 `0~1` 比例。
- 在定时器或事件中反向修改滑块值时，可用 `updating` 标志避免递归处理。
- `Progress.Shape` 常用 `Round`、`Circle`、`Steps`、`Mini`；`Steps/StepSize/StepGap` 仅适合分段进度。
- `Progress.State` 与 `Alert.Icon` 可用同一组 `AntdUI.TType.Success/Info/Warn/Error` 统一状态语义。
- `Spin.open` 适合短耗时任务；更长的任务建议放入线程，避免阻塞界面线程。
- `Alert.LoopPauseOnMouseEnter = true` 可让滚动提示在鼠标悬停时暂停，长文本更易阅读。
