You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在 ASP.NET Core MVC 中用 select 下拉框动态更新 dbo.Assets.State

实现方式

核心是新增一个只更新资产状态的 POST 接口,下拉框变化时通过 fetch 调用该接口,不需要刷新整个页面。

当前视图还有一个问题:每行下拉框都使用相同的 id="assetStateDropdown",而内联脚本总是通过 getElementById 获取第一个元素。应改为使用 class 和 data-* 属性。

1. 新增请求模型

public class UpdateAssetStateRequest
{
    public AssetState State { get; set; }
}

2. 在 AssetsController 中添加更新操作

假设 DbContext 已经通过构造函数注入,变量名为 _context。

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> UpdateState(
    int id,
    [FromBody] UpdateAssetStateRequest request)
{
    if (request is null || !ModelState.IsValid)
    {
        return BadRequest();
    }

    // 阻止传入未定义的枚举值
    if (!Enum.IsDefined(typeof(AssetState), request.State))
    {
        return BadRequest();
    }

    // 删除状态应通过单独的删除操作处理
    if (request.State == AssetState.deleted)
    {
        return BadRequest();
    }

    var asset = await _context.Assets.FindAsync(id);

    if (asset is null)
    {
        return NotFound();
    }

    // 已删除资产不允许通过该接口恢复
    if (asset.State == AssetState.deleted)
    {
        return BadRequest();
    }

    asset.State = request.State;

    await _context.SaveChangesAsync();

    return Json(new
    {
        success = true,
        state = (int)asset.State
    });
}

EF Core 默认会把枚举映射为整数,因此这里会直接更新 dbo.Assets.State 列。

3. 修改视图

在表格前面添加防伪令牌:

@Html.AntiForgeryToken()

然后将原来的状态列替换为下面的内容:

<td>
    @if (asset.State != Models.AssetState.deleted)
    {
        <select class="dropdown asset-state-select"
                data-asset-id="@asset.Id"
                data-url="@Url.Action("UpdateState", "Assets", new { id = asset.Id })"
                data-current-state="@((int)asset.State)">

            <option value="@((int)Models.AssetState.functional)"
                    selected="@(asset.State == Models.AssetState.functional)">
                Functional
            </option>

            <option value="@((int)Models.AssetState.non_functional)"
                    selected="@(asset.State == Models.AssetState.non_functional)">
                Non-functional
            </option>

            <option value="@((int)Models.AssetState.under_maintenance)"
                    selected="@(asset.State == Models.AssetState.under_maintenance)">
                Under-Maintenance
            </option>
        </select>
    }
    else
    {
        <p>Deleted</p>
    }
</td>

这里不再输出重复的 id,也不需要每个下拉框后面跟一段内联脚本。

4. 添加 JavaScript 提交逻辑

把下面代码放到视图底部的 Scripts 区块中:

@section Scripts {
<script>
document.addEventListener('change', async function (e) {
    const select = e.target.closest('.asset-state-select');

    if (!select) {
        return;
    }

    const token = document.querySelector(
        'input[name="__RequestVerificationToken"]'
    )?.value;

    const originalValue = select.dataset.currentState;
    select.disabled = true;

    try {
        const response = await fetch(select.dataset.url, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'RequestVerificationToken': token
            },
            body: JSON.stringify({
                state: Number(select.value)
            })
        });

        if (!response.ok) {
            throw new Error('状态更新失败');
        }

        const data = await response.json();
        select.dataset.currentState = String(data.state);
    } catch {
        // 保存失败时恢复下拉框原来的值
        select.value = originalValue;
        alert('状态保存失败,请稍后重试。');
    } finally {
        select.disabled = false;
    }
});
</script>
}

如果布局页没有定义 Scripts 区块,直接把这段 <script> 放在表格后面即可。

最终答案

给每个下拉框添加 data-url 和 data-current-state,使用一个委托的 change 事件通过 fetch 发起 POST 请求;服务端验证枚举值和资产状态后,用 EF Core 修改 State 并调用 SaveChangesAsync。保存成功后更新当前值,失败时将下拉框恢复为原状态。

内容的提问来源于stack exchange,提问作者kesarling

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.22 06:54:03