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

使用Javascript和Firestore填充KDS订单卡片时的内容错位问题

问题:所有订单项都集中显示在第一个订单卡片中

我正在开发基于Javascript和Firestore的KDS厨房显示系统,用卡片展示订单,但所有订单项都被塞进了第一个订单卡片里。

每个订单是Firestore中的一个文档,每个订单下有一个名为Order Items的子集合,专门用来存储该订单的订单项。

我的代码:

const openOrdersQuery = query
                                (
                                    collection(db, "Orders"),
                                    where("orderStatus", "==", "New"),
                                    orderBy("timeStamp")
                                );
        
const querySnapshot = onSnapshot(openOrdersQuery, (querySnapshot) => 
{
    container.innerHTML = "";
    ordersArray = [];
    querySnapshot.forEach((doc) => 
    {
        const orderObject = doc.data();
        ordersArray.push
        (
            [
                orderObject.orderNumber, 
                orderObject.guestRmNum, 
                orderObject.server, 
                orderObject.orderStatus, 
                orderObject.server, 
                orderObject.table, 
                orderObject.timeStamp,
                orderObject.dateCreated.toDate().toLocaleTimeString()
            ]
        );

        createOrderCard(orderObject);
    });

    async function createOrderCard(order) 
    {
        const card = document.createElement('div');
        card.classList = 'card-body';
        
        const orderContent = `
                            <div class="card">
                                <h1 id="orderNumberH1">Order: ${order.orderNumber}</h1>
                                <h2 id="orderInfoH2">Room: ${order.guestRmNum}</h1>
                                <h2 id="orderInfoH2">Table: ${order.table}</h2>
                                <h2 id="orderInfoH2">Server: ${order.server}</h2>
                                <h2 id="orderInfoH2">Time: ${order.dateCreated.toDate().toLocaleTimeString()}</h2>
                                <hr></hr>
                                <ul id="orderItemsList"></ul>
                                <hr></hr>
                                <button id="completeBtn" onclick="markCompleted('${order.orderNumber}')">Mark As Completed</button>
                            </div>
                        `
        ;
        container.innerHTML += orderContent;
        
        var orderItemsArray = new Array();
        const orderItemsDocSnap = await getDocs(collection(db, "Orders/" + order.orderNumber + "/Order Items"));
        orderItemsDocSnap.forEach((doc) => 
        {
            const orderItemsObject = doc.data();
            orderItemsArray.push
            (
                [
                    orderItemsObject.item, 
                    orderItemsObject.quantity, 
                    orderItemsObject.modifiers, 
                    orderItemsObject.guestRequests
                ]
            );

            let orderItemsList = document.getElementById("orderItemsList");
                
            let li = document.createElement('li');
            li.innerText = orderItemsObject.quantity + "x " + orderItemsObject.item;
            orderItemsList.appendChild(li);
        });
    }
});

问题原因:

所有订单卡片里的列表都用了同一个ID orderItemsList,document.getElementById只会返回页面中第一个匹配该ID的元素,所以不管哪个订单的订单项,都会被加到第一个卡片的列表里。

另外还有两个小问题:

  1. 多个h2用了同一个ID orderInfoH2,ID在页面中必须唯一,会导致后续DOM操作出错
  2. createOrderCard是异步函数,在forEach里直接调用会导致卡片创建顺序混乱,可能出现订单项和卡片不匹配的情况

修复后的代码:

const openOrdersQuery = query(
  collection(db, "Orders"),
  where("orderStatus", "==", "New"),
  orderBy("timeStamp")
);

const querySnapshot = onSnapshot(openOrdersQuery, async (querySnapshot) => {
  container.innerHTML = "";
  ordersArray = [];
  
  // 用for...of循环确保异步操作按顺序执行
  for (const doc of querySnapshot.docs) {
    const orderObject = doc.data();
    ordersArray.push([
      orderObject.orderNumber,
      orderObject.guestRmNum,
      orderObject.server,
      orderObject.orderStatus,
      orderObject.server,
      orderObject.table,
      orderObject.timeStamp,
      orderObject.dateCreated.toDate().toLocaleTimeString()
    ]);

    await createOrderCard(orderObject);
  }

  async function createOrderCard(order) {
    // 给每个订单的列表生成唯一ID
    const uniqueListId = `orderItemsList-${order.orderNumber}`;
    
    const orderContent = `
      <div class="card">
        <h1 class="orderNumberH1">Order: ${order.orderNumber}</h1>
        <h2 class="orderInfoH2">Room: ${order.guestRmNum}</h2>
        <h2 class="orderInfoH2">Table: ${order.table}</h2>
        <h2 class="orderInfoH2">Server: ${order.server}</h2>
        <h2 class="orderInfoH2">Time: ${order.dateCreated.toDate().toLocaleTimeString()}</h2>
        <hr>
        <ul id="${uniqueListId}"></ul>
        <hr>
        <button class="completeBtn" onclick="markCompleted('${order.orderNumber}')">Mark As Completed</button>
      </div>
    `;
    container.innerHTML += orderContent;

    // 获取当前订单对应的唯一列表元素
    const orderItemsList = document.getElementById(uniqueListId);
    const orderItemsDocSnap = await getDocs(collection(db, `Orders/${order.orderNumber}/Order Items`));
    
    orderItemsDocSnap.forEach((doc) => {
      const orderItemsObject = doc.data();
      const li = document.createElement('li');
      li.innerText = `${orderItemsObject.quantity}x ${orderItemsObject.item}`;
      orderItemsList.appendChild(li);
    });
  }
});

优化说明:

  1. 用订单号拼接生成唯一的列表ID,确保每个订单的订单项都加到自己的列表里
  2. 把重复的ID改成class,符合HTML规范
  3. 用for...of循环替代forEach,确保异步的订单项查询按订单顺序执行
  4. 简化了Firestore路径的拼接,用模板字符串更清晰
  5. 去掉了没用的orderItemsArray数组(如果后续不需要用可以删掉)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 07:02:35