diff --git a/backend/app/routers/information.py b/backend/app/routers/information.py index e2be6b1..cbee18b 100644 --- a/backend/app/routers/information.py +++ b/backend/app/routers/information.py @@ -452,19 +452,57 @@ def create_information( db: Session = Depends(get_db) ): """发布资讯""" - # 生成行情编号:日期 + 5位自然数(从00001开始) + # 验证并矫正冠字号:必须是J0开头 + 8位数字 = 共10位 + if data.title: + import re + # 提取冠字号(J0开头后面跟数字) + match = re.search(r'J0(\d+)', data.title) + if match: + num = match.group(1) + # 必须是8位数字 + if len(num) > 8: + # 多于8位:取前8位 + num = num[:8] + elif len(num) < 8: + # 少于8位:前面补0 + num = num.zfill(8) + # 重新构建title,确保是J0开头 + original = match.group(0) + data.title = data.title.replace(original, 'J0' + num, 1) + else: + # 如果不是J0开头,尝试转换 + other_match = re.search(r'J([1-9]\d{0,8})', data.title) + if other_match: + # 非J0开头的,尝试补0变成J0开头 + num = other_match.group(1).zfill(8)[:8] + original = other_match.group(0) + data.title = data.title.replace(original, 'J0' + num, 1) + # 生成行情编号:年份后两位+月+日+当日序号(如260414001) + # 序号在当天最大序号基础上+1 deal_no = None if data.info_type == 'deal': - today = datetime.now().strftime('%Y%m%d') - # 查询当天已有行情数量 from app.models.models import Information - count_today = db.query(Information).filter( + today = datetime.now().strftime('%y%m%d') # 如260414 + # 查询当天最大的deal_no + max_deal = db.query(Information.deal_no).filter( Information.info_type == 'deal', - Information.deal_no.like(f'DJ{today}%') - ).count() - # 编号 = 日期 + 5位自然数(如 DJ2026041100001) - seq = count_today + 1 - deal_no = f'DJ{today}{seq:05d}' + Information.deal_no.isnot(None), + Information.deal_no != '', + Information.deal_no.like(f'{today}%') + ).order_by(Information.deal_no.desc()).first() + + if max_deal and max_deal[0] and max_deal[0].startswith(today): + # 当天已有编号,提取序号并+1 + try: + current_seq = int(max_deal[0][6:]) # 取最后3位序号 + new_seq = current_seq + 1 + except: + new_seq = 1 + else: + # 新的一天,从001开始 + new_seq = 1 + + deal_no = f'{today}{new_seq:03d}' info = Information( user_id=current_user.f99_90_id, @@ -511,6 +549,12 @@ def create_information( view_count=info.view_count, contact_count=info.contact_count, created_at=info.created_at, + packaging=info.packaging, + is_graded=info.is_graded, + grading_company=info.grading_company, + grading_score=info.grading_score, + category=info.category, + deal_no=info.deal_no, user_name=current_user.f01_01_name, user_avatar=current_user.avatar, collection_name=None, @@ -1277,7 +1321,45 @@ async def batch_parse_deals(text: str = Body(..., embed=True)): # 尝试直接解析 data = json.loads(content.strip()) - return {"success": True, "data": data} + # 对AI返回的数据进行冠字号矫正 - 确保J0开头+8位数字 + def normalize_serial_ai(num_str): + """矫正冠字号:J0开头,8位数字,共10位""" + if not num_str.startswith('J0'): + return None + num = num_str[2:] # 去掉J0 + diff = 8 - len(num) + # 位数正好8位,不需要矫正 + if diff == 0: + return num_str + elif diff == -1: + # 多1位:取前4位+最后4位 + if len(num) >= 4: + result = num[:4] + num[-4:] + if len(result) == 8: + return 'J0' + result + elif diff == 1: + # 少1位:J0 + 0 + 数字 + return 'J0' + '0' + num + elif diff == -2: + # 多2位:取前4位+最后4位 + if len(num) >= 4: + result = num[:4] + num[-4:] + if len(result) == 8: + return 'J0' + result + elif diff == 2: + # 少2位:J0 + 00 + 数字 + return 'J0' + '00' + num + return None + + # 矫正每条记录的冠字号 + corrected_data = [] + for item in data: + if 'serial' in item: + normalized = normalize_serial_ai(item['serial']) + if normalized: + item['serial'] = normalized + corrected_data.append(item) + return {"success": True, "data": corrected_data} except json.JSONDecodeError: # 尝试用正则提取 match = re.search(r'\[.*\]', content, re.DOTALL) @@ -1330,24 +1412,59 @@ def parse_deals_locally(text: str, default_packaging: str = '', default_date: st default_date = datetime.now().strftime('%Y-%m-%d') deal_date = extracted_date or default_date + # 冠字号矫正函数 - 确保是J0开头+8位数字 + def normalize_serial(num_str, needs_j0=False): + """矫正冠字号:J0开头,8位数字,共10位""" + num = num_str + # 如果是单独的7-9位数字(无J0前缀),取后8位 + if needs_j0 and len(num) > 8: + num = num[-8:] + + diff = 8 - len(num) + + # 位数正好8位,不需要矫正 + if diff == 0: + return 'J0' + num + # 少1位(7位数字)→ J0 + 0 + 数字 + elif diff == 1: + return 'J0' + '0' + num + # 多1位(9位数字)→ J0 + 取前4位+后4位 = 8位数字 + elif diff == -1: + if len(num) >= 8: + result = num[:4] + num[-4:] + return 'J0' + result + return None # 无法矫正 + lines = text.strip().split('\n') for line in lines: line = line.strip() - if not line or 'J0' not in line: + if not line: continue - # 提取冠字号 J0 + 8-9位数字 - serial_match = re.search(r'J0(\d{8,9})', line) + # 提取冠字号:J0 + 至少7位数字(可能到10位),或者单独的7~9位数字 + # 优先匹配 J0开头,否则匹配单独的7-9位数字 + serial_num = None + serial_match = re.search(r'J0(\d{7,11})', line) if not serial_match: - continue + # 尝试匹配单独的7-9位数字(前面是空格或行首) + serial_match = re.search(r'(?:^|\s)(\d{7,9})(?:\s|$|\n)', line) + if serial_match: + # 单独的7-9位数字需要加上J0前缀 + num = serial_match.group(1) + serial_num = num + serial = normalize_serial(num, needs_j0=True) + else: + continue + else: + # J0开头的7-9位数字 + serial_num = serial_match.group(1) + serial = normalize_serial(serial_num, needs_j0=False) - serial_num = serial_match.group(1) - if len(serial_num) == 9: - serial_num = serial_num[:8] - serial = 'J0' + serial_num + if not serial: + continue # 跳过无法矫正的数据 - # 提取价格 ¥xxx,xxx 或 xxx,xxx(必须在J0之后) + # 提取价格:在冠字号之后提取价格 serial_pos = line.find(serial) after_serial = line[serial_pos + len(serial):] price_match = re.search(r'[¥¥]?\s*([1-9][\d,]{2,})', after_serial) @@ -1356,13 +1473,13 @@ def parse_deals_locally(text: str, default_packaging: str = '', default_date: st price = int(price_match.group(1).replace(',', '')) # 提取卖家(价格后面的中文字符) - after_price_pos = after_serial.find(price_match.group(0)) + len(price_match.group(0)) - after_price = after_serial[after_price_pos:] + after_price_pos = line.find(price_match.group(0)) + len(price_match.group(0)) + after_price = line[after_price_pos:] seller_match = re.search(r'([^\d\s¥¥]+?)(?:\s*$|\s*\n)', after_price) seller = seller_match.group(1).strip() if seller_match else '' - # 分类判断 - digits = serial_num + # 分类判断(使用矫正后的冠字号去掉J0前缀的8位数字) + digits = serial[2:] # 去掉J0前缀 d = digits category = '通货' if not any(c in d for c in ['1','2','3','4','5','7']): category = '圆圆号'