"""Bounded conversational pagination over the server-validated customer scope.""" import re import sqlite3 from .db import connect def page_command(message): text=re.sub(r'[\s,,。.!!??]','',message) match=re.fullmatch(r'(?:请)?(?:订单)?第(\d{1,5})页',text) if match:return int(match.group(1)) if re.fullmatch(r'(?:请|继续)?(?:下一页|下页|继续显示|接着显示(?:剩下的)?订单)',text):return 'next' if re.fullmatch(r'(?:请)?(?:上一页|上页)',text):return 'previous' return None def answer_list(message,tenants,conv_id=None): from .order_data import is_lookup_help,parse_count_query,tenant_filter,STATUS_LABELS from .customer_service import order_login_response command=page_command(message) initial=(not is_lookup_help(message) and re.search(r'订单|运单|\borders?\b|\bshipments?\b',message,re.I) and re.search(r'列出|列表|全部|所有|\blist\b',message,re.I)) if command is None and not initial:return None if not tenants:return order_login_response() page=1;status=None if command is None: intent=parse_count_query(re.sub(r'列出|列表|全部|所有|\blist\b','多少',message,flags=re.I)) if intent is None or intent['unsupported']: return {'t':'暂不支持按这个条件列出订单。可查看全部订单或按履约中、已完成等业务状态查询。'} status=intent['status'] scope=tenant_filter(tenant_ids=tenants) if scope is None:return order_login_response() connection=None try: connection=connect() if command is not None: if not conv_id:return {'t':'请先在当前对话中发送“列出我的订单”,再翻页查看。'} prior=connection.execute("SELECT content FROM messages WHERE conv_id=? AND role='assistant' ORDER BY id DESC LIMIT 1",(conv_id,)).fetchone() header=prior[0].split('\n',1)[0] if prior else '' match=re.fullmatch(r'您当前的订单列表(.*第(\d+)页;业务状态:([^)]+)):',header) if not match:return {'t':'请先在当前对话中发送“列出我的订单”,再翻页查看。'} labels={label:code for code,label in STATUS_LABELS.items()} status=labels.get(match[2]) if match[2]!='全部' and status is None:return {'t':'请重新指定需要查看的订单状态。'} page=int(command) if isinstance(command,int) else max(1,int(match[1])+(1 if command=='next' else -1)) if not 1<=page<=10000:return {'t':'请提供1至10000之间的有效页码。'} where=' WHERE 1=1'+scope[0];values=scope[1] if status:where+=' AND status=?';values=values+[status] # Both reads see one current snapshot and apply exactly the same scope/filter. connection.execute('BEGIN') total=connection.execute('SELECT COUNT(*) FROM order_test_data'+where,values).fetchone()[0] page=min(page,max(1,(total+19)//20)) rows=connection.execute('SELECT order_no,inbound_code,status,warehouse_code FROM order_test_data'+where+ ' ORDER BY id DESC LIMIT 20 OFFSET ?',values+[(page-1)*20]).fetchall() if not rows:return {'t':'当前账号下没有符合条件的订单。','_customer_data':True} label=STATUS_LABELS[status] if status else '全部' first='先列出20票;' if page==1 and total>20 else '' lines=[f'您当前的订单列表({first}第{page}页;业务状态:{label}):',f'共{total}票,当前显示第{(page-1)*20+1}至{(page-1)*20+len(rows)}票。'] for number,inbound,business_status,warehouse in rows: lines.append(f'- 入仓码:{inbound or "未登记"};订单号:{number};业务状态:{STATUS_LABELS.get(business_status,business_status)};目的仓:{warehouse or "未登记"}') lines.append('回复“下一页”查看后续订单。' if page*20