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

Flutter中Firebase Firestore时间重复校验功能实现求助

解决Firestore时间存在性校验与数据写入问题

嘿,看起来你在做一个时间预约类的功能对吧?我帮你梳理下当前代码里的几个关键问题,一步步解决你的困扰:

1. 先搞定数据无法写入的核心问题

我第一眼就看到你else分支里的字段名有问题:'selected_time '后面多了个空格!这会导致Firestore存储的字段名带空格,不仅后续查询会匹配不上,甚至可能直接导致写入失败,先把这个空格去掉,改成'selected_time'。

另外,直接存DateTime到Firestore可能会有时区或者精度偏差的问题,建议转成Firestore官方支持的Timestamp类型,这样查询匹配会更准确:

// 写入时转成Timestamp
"event_date": Timestamp.fromDate(this._eventDate)

对应的查询也要改成用Timestamp匹配:

.where('event_date', isEqualTo: Timestamp.fromDate(this._eventDate))

2. 实现校验后的时间选择页面跳转

你现在已经能检测到重复时间并弹窗,但还没实现跳转回时间选择页的逻辑。可以在弹窗的确认按钮里添加导航代码:

void showAlertDialogue(BuildContext context) {
  showDialog(
    context: context,
    builder: (ctx) => AlertDialog(
      title: const Text('时间已被占用'),
      content: const Text('请选择其他可用时间'),
      actions: [
        TextButton(
          onPressed: () {
            Navigator.pop(ctx); // 先关闭弹窗
            // 跳转回你的时间选择页面,这里替换成实际的页面路由
            Navigator.pushReplacement(
              context,
              MaterialPageRoute(builder: (context) => const TimeSelectionPage()),
            );
          },
          child: const Text('确定'),
        )
      ],
    ),
  );
}

3. 完善状态与条件判断逻辑

  • 按钮点击时先把processing设为true,防止用户重复点击提交
  • 还要加上_time的非空判断,避免空值查询导致的异常
  • 写入操作加上异常捕获,能给用户更友好的错误提示

修复后的按钮逻辑代码:

onPressed: processing ? null : () async {
  setState(() {
    processing = true;
  });

  // 确保日期和时间都已选择
  if (_eventDate != null && _time != null && _time.isNotEmpty) {
    final QuerySnapshot result = await FirebaseFirestore
        .instance
        .collection('events')
        .where('event_date', isEqualTo: Timestamp.fromDate(this._eventDate))
        .where('selected_time', isEqualTo: this._time)
        .get();
    final List<DocumentSnapshot> documents = result.docs;

    if (documents.isNotEmpty) {
      // 时间已存在,弹窗提示并跳转
      showAlertDialogue(context);
    } else {
      final data = {
        // "title": _title.text,
        'selected_time': this._time,
        "event_date": Timestamp.fromDate(this._eventDate)
      };
      try {
        if (widget.note != null) {
          await eventDBS.updateData(widget.note.id, data);
        } else {
          await eventDBS.create(data);
        }
        // 写入成功后,这里可以选择返回上一页或者跳转回时间选择页
        Navigator.pop(context);
      } catch (e) {
        // 捕获写入错误,提示用户
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('数据保存失败: ${e.toString()}')),
        );
      }
    }
  } else {
    // 提示用户选择完整的日期和时间
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('请选择完整的日期和时间')),
    );
  }

  // 不管成功失败,都把processing设回false
  setState(() {
    processing = false;
  });
},

额外小建议

  • 给_time加上初始化:String _time = '';,避免空值问题
  • 在时间选择组件里确保_time被正确赋值,不然查询条件会缺失
  • 按钮可以根据processing状态禁用,比如上面代码里的onPressed: processing ? null : () async {...},防止重复提交

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 20:12:40