From 4abd5533024084f679be5ed5bca5ac837125d6fd Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Thu, 18 Jun 2026 14:15:28 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20failed=5Faccounting.ui=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E4=BC=98=E5=8C=96=20+=20dspy=E8=B7=A8=E5=BA=93JOIN=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=5Ftext=E5=AD=97=E6=AE=B5=20-=20failed=5Faccounting.ui?= =?UTF-8?q?:=20userid=E2=86=92username,=20userorgid=E2=86=92orgname,=20llm?= =?UTF-8?q?id=E2=86=92llm.name=20-=20=E7=A7=BB=E9=99=A4cost/use=5Fdate?= =?UTF-8?q?=E5=88=97,=20InlineForm=E7=B4=A7=E5=87=91=E5=B8=83=E5=B1=80=20-?= =?UTF-8?q?=20failed=5Faccounting=5Flist.dspy:=20=E8=B7=A8=E5=BA=93JOIN=20?= =?UTF-8?q?users/organization/llm=E8=8E=B7=E5=8F=96=E5=90=8D=E7=A7=B0=20-?= =?UTF-8?q?=20handled=E4=BF=9D=E6=8C=81=E5=8E=9F=E5=A7=8B=E5=80=BC,=20?= =?UTF-8?q?=E7=94=B1UI=E7=9A=84code=E6=8E=A7=E4=BB=B6=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wwwroot/api/failed_accounting_list.dspy | 139 ++++++++++++++---------- wwwroot/failed_accounting.ui | 65 ++++++++--- 2 files changed, 132 insertions(+), 72 deletions(-) diff --git a/wwwroot/api/failed_accounting_list.dspy b/wwwroot/api/failed_accounting_list.dspy index 2bc7703..11fbe81 100644 --- a/wwwroot/api/failed_accounting_list.dspy +++ b/wwwroot/api/failed_accounting_list.dspy @@ -1,72 +1,101 @@ result = {'success': False, 'rows': [], 'total': 0, 'page': 1, 'page_size': 50} try: - dbname = get_module_dbname('llmage') + llmage_db = get_module_dbname('llmage') + sage_db = get_module_dbname('sage') + db = DBPools() - filters = {} - if params_kw.get('userorgid'): - filters['userorgid'] = params_kw.get('userorgid') - if params_kw.get('llmid'): - filters['llmid'] = params_kw.get('llmid') - if params_kw.get('handled') is not None and params_kw.get('handled') != '': - filters['handled'] = params_kw.get('handled') - if params_kw.get('start_date'): - filters['start_date'] = params_kw.get('start_date') - if params_kw.get('end_date'): - filters['end_date'] = params_kw.get('end_date') + filters = {} + if params_kw.get('userorgid'): + filters['userorgid'] = params_kw.get('userorgid') + if params_kw.get('llmid'): + filters['llmid'] = params_kw.get('llmid') + if params_kw.get('handled') is not None and params_kw.get('handled') != '': + filters['handled'] = params_kw.get('handled') + if params_kw.get('start_date'): + filters['start_date'] = params_kw.get('start_date') + if params_kw.get('end_date'): + filters['end_date'] = params_kw.get('end_date') + if params_kw.get('filter_userid'): + filters['filter_userid'] = params_kw.get('filter_userid') + if params_kw.get('filter_llmid'): + filters['filter_llmid'] = params_kw.get('filter_llmid') - page = int(params_kw.get('page', 1)) - page_size = int(params_kw.get('page_size', 50)) + page = int(params_kw.get('page', 1)) + page_size = int(params_kw.get('page_size', 50)) - async with DBPools().sqlorContext(dbname) as sor: - conditions = [] - ns = {} + async with db.sqlorContext(llmage_db) as sor: + conditions = [] + ns = {} - if 'handled' not in filters: - conditions.append("handled='0'") + if filters.get('userorgid'): + conditions.append("f.userorgid=${userorgid}$") + ns['userorgid'] = filters['userorgid'] + if filters.get('llmid'): + conditions.append("f.llmid=${llmid}$") + ns['llmid'] = filters['llmid'] + if filters.get('handled') is not None: + conditions.append("f.handled=${handled}$") + ns['handled'] = filters['handled'] + if filters.get('start_date'): + conditions.append("f.use_date>=${start_date}$") + ns['start_date'] = filters['start_date'] + if filters.get('end_date'): + conditions.append("f.use_date<=${end_date}$") + ns['end_date'] = filters['end_date'] + if filters.get('filter_userid'): + conditions.append("f.userid LIKE ${filter_userid}$") + ns['filter_userid'] = '%' + filters['filter_userid'] + '%' + if filters.get('filter_llmid'): + conditions.append("(f.llmid LIKE ${filter_llmid}$ OR f.llmid_text LIKE ${filter_llmid}$)") + ns['filter_llmid'] = '%' + filters['filter_llmid'] + '%' - if filters.get('userorgid'): - conditions.append("userorgid=${userorgid}$") - ns['userorgid'] = filters['userorgid'] - if filters.get('llmid'): - conditions.append("llmid=${llmid}$") - ns['llmid'] = filters['llmid'] - if filters.get('handled') is not None: - conditions.append("handled=${handled}$") - ns['handled'] = filters['handled'] - if filters.get('start_date'): - conditions.append("use_date>=${start_date}$") - ns['start_date'] = filters['start_date'] - if filters.get('end_date'): - conditions.append("use_date<=${end_date}$") - ns['end_date'] = filters['end_date'] + where = "" + if conditions: + where = "WHERE " + " AND ".join(conditions) - where = "" - if conditions: - where = "where " + " and ".join(conditions) + # 跨库JOIN获取名称 + sql = f""" +SELECT f.*, + u.username as userid_text, + o.orgname as userorgid_text, + l.name as llmid_text +FROM llmusage_accounting_failed f +LEFT JOIN {sage_db}.users u ON f.userid = u.userid +LEFT JOIN {sage_db}.organization o ON f.userorgid = o.id +LEFT JOIN {llmage_db}.llm l ON f.llmid = l.id +{where} +ORDER BY f.failed_time DESC +""" - count_sql = f"select count(*) as cnt from llmusage_accounting_failed {where}" - count_recs = await sor.sqlExe(count_sql, ns) - total = count_recs[0].cnt if count_recs else 0 + count_sql = f""" +SELECT count(*) as cnt +FROM llmusage_accounting_failed f +LEFT JOIN {sage_db}.users u ON f.userid = u.userid +LEFT JOIN {sage_db}.organization o ON f.userorgid = o.id +LEFT JOIN {llmage_db}.llm l ON f.llmid = l.id +{where} +""" + count_recs = await sor.sqlExe(count_sql, ns) + total = count_recs[0].cnt if count_recs else 0 - offset = (page - 1) * page_size - query_sql = f"""select * from llmusage_accounting_failed {where} -order by failed_time desc limit {page_size} offset {offset}""" - recs = await sor.sqlExe(query_sql, ns) + offset = (page - 1) * page_size + query_sql = sql + f" LIMIT {page_size} OFFSET {offset}" + recs = await sor.sqlExe(query_sql, ns) - rows = [] - for r in (recs or []): - d = dict(r) - d['handled'] = '已处理' if d.get('handled') == '1' else '未处理' - rows.append(d) + rows = [] + for r in (recs or []): + d = dict(r) + rows.append(d) - result['rows'] = rows - result['total'] = total - result['page'] = page - result['page_size'] = page_size - result['success'] = True + result['rows'] = rows + result['total'] = total + result['page'] = page + result['page_size'] = page_size + result['success'] = True except Exception as e: - result['error'] = str(e) + result['error'] = str(e) + debug(f'failed_accounting_list error: {format_exc()}') return json.dumps(result, ensure_ascii=False, default=str) diff --git a/wwwroot/failed_accounting.ui b/wwwroot/failed_accounting.ui index 7d70b99..40608ea 100644 --- a/wwwroot/failed_accounting.ui +++ b/wwwroot/failed_accounting.ui @@ -3,22 +3,15 @@ "options": { "width": "100%", "height": "100%", - "padding": "16px", - "spacing": 12 + "padding": "8px", + "gap": "8px" }, "subwidgets": [ - { - "widgettype": "Title2", - "options": { - "text": "记账失败记录", - "halign": "left" - } - }, { "widgettype": "HBox", "options": { "width": "100%", - "spacing": 8, + "gap": "8px", "alignItems": "flex-end" }, "subwidgets": [ @@ -28,7 +21,6 @@ "options": { "css": "card", "padding": "8px", - "show_label": true, "submit_label": "查询", "submit_css": "primary", "fields": [ @@ -115,19 +107,58 @@ {"value": "0", "text": "未处理"}, {"value": "1", "text": "已处理"} ] + }, + "userid": { + "uitype": "code", + "valueField": "userid", + "textField": "userid_text", + "params": { + "dbname": "sage", + "table": "users", + "tblvalue": "userid", + "tbltext": "username", + "valueField": "userid", + "textField": "userid_text" + }, + "dataurl": "{{entire_url('/appbase/get_code.dspy')}}" + }, + "userorgid": { + "uitype": "code", + "valueField": "userorgid", + "textField": "userorgid_text", + "params": { + "dbname": "sage", + "table": "organization", + "tblvalue": "id", + "tbltext": "orgname", + "valueField": "userorgid", + "textField": "userorgid_text" + }, + "dataurl": "{{entire_url('/appbase/get_code.dspy')}}" + }, + "llmid": { + "uitype": "code", + "valueField": "llmid", + "textField": "llmid_text", + "params": { + "dbname": "llmage", + "table": "llm", + "tblvalue": "id", + "tbltext": "name", + "valueField": "llmid", + "textField": "llmid_text" + }, + "dataurl": "{{entire_url('/appbase/get_code.dspy')}}" } } }, "fields": [ - {"name": "id", "title": "ID", "type": "str", "length": 32, "uitype": "str", "label": "ID"}, {"name": "llmusageid", "title": "使用记录ID", "type": "str", "length": 32, "cwidth": 12, "uitype": "str", "label": "使用记录ID"}, - {"name": "llmid", "title": "模型ID", "type": "str", "length": 32, "cwidth": 12, "uitype": "str", "label": "模型ID"}, - {"name": "userid", "title": "用户ID", "type": "str", "length": 32, "cwidth": 10, "uitype": "str", "label": "用户ID"}, - {"name": "userorgid", "title": "机构ID", "type": "str", "length": 32, "cwidth": 10, "uitype": "str", "label": "机构ID"}, - {"name": "use_date", "title": "使用日期", "type": "date", "cwidth": 10, "uitype": "date", "label": "使用日期"}, + {"name": "llmid", "title": "模型", "type": "str", "length": 32, "cwidth": 12, "uitype": "str", "label": "模型"}, + {"name": "userid", "title": "用户", "type": "str", "length": 32, "cwidth": 10, "uitype": "str", "label": "用户"}, + {"name": "userorgid", "title": "机构", "type": "str", "length": 32, "cwidth": 10, "uitype": "str", "label": "机构"}, {"name": "use_time", "title": "使用时间", "type": "timestamp", "cwidth": 14, "uitype": "str", "label": "使用时间"}, {"name": "amount", "title": "金额", "type": "double", "length": 18, "dec": 5, "cwidth": 8, "uitype": "float", "label": "金额"}, - {"name": "cost", "title": "成本", "type": "double", "length": 18, "dec": 5, "cwidth": 8, "uitype": "float", "label": "成本"}, {"name": "failed_reason", "title": "失败原因", "type": "text", "cwidth": 20, "uitype": "text", "label": "失败原因"}, {"name": "failed_time", "title": "失败时间", "type": "timestamp", "cwidth": 14, "uitype": "str", "label": "失败时间"}, {"name": "retry_count", "title": "重试", "type": "int", "cwidth": 4, "uitype": "int", "label": "重试"},