From 144b3afbc8f1b722ca3959a1af232f73eb03878f Mon Sep 17 00:00:00 2001 From: ping <1017253325@qq.com> Date: Tue, 21 Jul 2026 11:19:09 +0800 Subject: [PATCH 01/15] update --- b/cntoai/get_user_balance.dspy | 2 ++ 1 file changed, 2 insertions(+) diff --git a/b/cntoai/get_user_balance.dspy b/b/cntoai/get_user_balance.dspy index 53c6ce8..1a646d8 100644 --- a/b/cntoai/get_user_balance.dspy +++ b/b/cntoai/get_user_balance.dspy @@ -35,6 +35,8 @@ async def get_user_balance(ns={}): } orgid = await sor.R('organization', {'id': user[0]['orgid']}) balance = await getCustomerBalance(sor, orgid[0]['id']) + ns['balance'] = balance + debug(ns) return { 'status': 'ok', 'balance': balance -- 2.34.1 From d7e2875375bc9f273f841979e1eec7bd060111e5 Mon Sep 17 00:00:00 2001 From: ping <1017253325@qq.com> Date: Tue, 21 Jul 2026 15:23:56 +0800 Subject: [PATCH 02/15] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BE=9B=E5=BA=94?= =?UTF-8?q?=E5=95=86=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- b/provider/providerAdd.dspy | 41 +++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/b/provider/providerAdd.dspy b/b/provider/providerAdd.dspy index b522eaa..ae3d96e 100644 --- a/b/provider/providerAdd.dspy +++ b/b/provider/providerAdd.dspy @@ -82,14 +82,6 @@ async def providerAdd(ns={}): 'status': False, 'msg': 'provider add failed, orgcode is empty' } - # filter by orgcode - res = await sor.R('organization', {}) - orgcodes = [orgc.get('orgcode') for orgc in res] - if org_code in orgcodes: - return { - 'status': False, - 'msg': 'provider add failed, orgcode has already exist' - } if not ns.get('orgid'): orgid_li = await sor.R('users', {'id': await get_user()}) orgid = orgid_li[0].get('orgid') if orgid_li else '' @@ -101,8 +93,33 @@ async def providerAdd(ns={}): else: orgid = ns.get('orgid') + # filter by orgcode; existing provider returns ids for idempotent callers + exist_org_li = await sor.R('organization', {'orgcode': org_code, 'del_flg': '0'}) + if len(exist_org_li) >= 1: + exist_org = exist_org_li[0] + exist_provider_li = await sor.R('provider', {'orgid': exist_org.get('id'), 'del_flg': '0'}) + if not exist_provider_li: + return { + 'status': False, + 'msg': 'provider add failed, orgcode has already exist but provider not found' + } + exist_protocol_li = await sor.R('saleprotocol', {'offer_orgid': exist_org.get('id'), 'bid_orgid': orgid, 'del_flg': '0'}) + if not exist_protocol_li: + exist_protocol_li = await sor.R('saleprotocol', {'offer_orgid': exist_org.get('id'), 'del_flg': '0'}) + return { + 'status': True, + 'msg': 'provider already exist', + 'data': { + 'orgid': exist_org.get('id'), + 'provider_orgid': exist_org.get('id'), + 'provider_id': exist_provider_li[0].get('id'), + 'protocolid': exist_protocol_li[0].get('id') if exist_protocol_li else None + } + } + # 供应商parentid 和 运营机构id相同 ns_org['parentid'] = orgid + ns_sale_mode['bid_orgid'] = orgid if not ns_provider.get('start_date'): ns_provider['start_date'] = time.strftime('%Y-%m-%d %H:%M:%S') @@ -115,7 +132,13 @@ async def providerAdd(ns={}): await openProviderAccounts(sor, orgid, ns_org['id']) return { "status": True, - "msg": "provider add success" + "msg": "provider add success", + "data": { + "orgid": ns_org['id'], + "provider_orgid": ns_org['id'], + "provider_id": ns_provider['id'], + "protocolid": ns_sale_mode['id'] + } } except Exception as e: raise e -- 2.34.1 From 35d7fa08eadcb77ef8bc98e0e431d81a0ad6a9f4 Mon Sep 17 00:00:00 2001 From: ping <1017253325@qq.com> Date: Tue, 21 Jul 2026 16:06:04 +0800 Subject: [PATCH 03/15] =?UTF-8?q?llm=E8=A1=A8=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- b/llm.sql | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 b/llm.sql diff --git a/b/llm.sql b/b/llm.sql new file mode 100644 index 0000000..7bd517c --- /dev/null +++ b/b/llm.sql @@ -0,0 +1,145 @@ +# 创建表格命令 +CREATE TABLE llm ( + id VARCHAR(64) NOT NULL COMMENT '唯一标识', + name VARCHAR(50) NOT NULL COMMENT '模型名称', + model VARCHAR(50) NOT NULL COMMENT '模型代号', + description TEXT COMMENT '模型描述', + iconid VARCHAR(50) COMMENT '图标标识', + upappid VARCHAR(50) COMMENT '上层应用ID', + providerid VARCHAR(64) COMMENT '供应商ID', + ownerid VARCHAR(20) DEFAULT '0' COMMENT '所有者ID', + enabled_date DATE COMMENT '启用日期', + expired_date DATE COMMENT '过期日期', + min_balance INT DEFAULT 0 COMMENT '最低余额要求(元)', + status VARCHAR(20) COMMENT '状态(如published)', + catelogname VARCHAR(50) COMMENT '目录名称(如文生视频)', + catelog_id VARCHAR(20) COMMENT '目录ID', + apiname VARCHAR(50) COMMENT 'API名称', + query_apiname VARCHAR(50) COMMENT '查询API名称', + query_period INT COMMENT '查询周期(秒)', + ppid VARCHAR(64) COMMENT '定价计划ID', + provider_name VARCHAR(100) COMMENT '供应商名称', + pricing_display TEXT COMMENT '定价显示文本', + provider_iconurl VARCHAR(255) COMMENT '供应商图标URL', + PRIMARY KEY (id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='LLM模型信息表'; + + +# 厂商返回的部分数据示例 +[ + { + "catelogid": "2i2v", + "catelogname": "首尾帧生视频", + "llms": [ + { + "id": "r0ill7L0s6PtBS8mkmg-7", + "name": "viduq3-pro", + "model": "viduq3-pro", + "description": "vidu文生视频,viduq3-pro模型", + "iconid": "vidu", + "upappid": "vidu", + "providerid": "Bu3Z6OXANehbkD6OK5NJb", + "ownerid": "0", + "enabled_date": "2026-01-01", + "expired_date": "9999-12-31", + "min_balance": 10, + "status": "published", + "catelogname": "首尾帧生视频", + "catelog_id": "2i2v", + "apiname": "2i2v", + "query_apiname": "taskStatus", + "query_period": 30, + "ppid": "sF2gcl7UeANKtnZv8hfvL", + "provider_name": "北京生数科技有限公司", + "pricing_display": " - duration: 0.56 元/秒 ", + "provider_iconurl": "https://token.opencomputing.cn/appbase/show_icon.dspy?id=vidu" + } + ] + }, + { + "catelogid": "asr", + "catelogname": "语音识别", + "llms": [ + { + "id": "9glv3S-JSzxholxAblU14", + "name": "qwen3-asr-flash", + "model": "qwen3-asr-flash", + "description": "通义千问系列的录音文件识", + "iconid": "qwen", + "upappid": "tongyi-wan", + "providerid": "6fadgewjraOyvxC_EkHou", + "ownerid": "0", + "enabled_date": "2025-12-01", + "expired_date": "9999-12-31", + "min_balance": 10, + "status": "published", + "catelogname": "语音识别", + "catelog_id": "asr", + "apiname": "short_asr", + "query_apiname": null, + "query_period": null, + "ppid": "16pwEsQeHiOrxC0O6A2j6", + "provider_name": "阿里云", + "provider_iconurl": "https://token.opencomputing.cn/appbase/show_icon.dspy?id=qwen" + } + ] + }, + { + "catelogid": "digital_human", + "catelogname": "数字人", + "llms": [ + { + "id": "KOsAo6YjTdU0KG7_sKUJF", + "name": "wan2.2-s2v", + "model": "wan2.2-s2v", + "description": "模型:wan2.2-s2v,输入音频和照片,用照片中的人生成数字人", + "iconid": "qwen", + "upappid": "tongyi-wan", + "providerid": "6fadgewjraOyvxC_EkHou", + "ownerid": "0", + "enabled_date": "2025-12-19", + "expired_date": "9999-12-31", + "min_balance": 10, + "status": "published", + "catelogname": "数字人", + "catelog_id": "digital_human", + "apiname": "avator", + "query_apiname": "avatorstatus", + "query_period": 10, + "ppid": "0B6aldoAej1PpZ4ydtrEZ", + "provider_name": "阿里云", + "pricing_display": " - duration: 0.5 元/秒 [分辨率=480P]\n - duration: 0.9 元/秒 [分辨率=720P]", + "provider_iconurl": "https://token.opencomputing.cn/appbase/show_icon.dspy?id=qwen" + } + ] + }, + { + "catelogid": "i2v", + "catelogname": "图生视频", + "llms": [ + { + "id": "7y7kfYM0Xasizyi37WvAZ", + "name": "happyhorse-1.0-i2v", + "model": "happyhorse-1.0-i2v", + "description": "HappyHorse图生视频模型,以首帧图片为基础,支持通过文本描述进行引导,生成物理真实、运动流畅的视频。", + "iconid": "qwen", + "upappid": "tongyi-wan", + "providerid": "6fadgewjraOyvxC_EkHou", + "ownerid": "0", + "enabled_date": "2026-04-28", + "expired_date": "9999-12-31", + "min_balance": 10, + "status": "published", + "catelogname": "图生视频", + "catelog_id": "i2v", + "apiname": "i2v-happyhorse", + "query_apiname": "t2vstatus", + "query_period": 10, + "ppid": "knEwDP35DEz5oMAXyvwN3", + "provider_name": "阿里云", + "pricing_display": " - duration: 0.9 元/秒 [SR=720]\n - duration: 1.6 元/秒 [SR=1080]", + "provider_iconurl": "https://token.opencomputing.cn/appbase/show_icon.dspy?id=qwen" + }, + ] + } +] \ No newline at end of file -- 2.34.1 From 4af3ff5000e0dd37f2ee5cad49c8581eac2f6447 Mon Sep 17 00:00:00 2001 From: ping <1017253325@qq.com> Date: Tue, 21 Jul 2026 16:13:44 +0800 Subject: [PATCH 04/15] update --- b/cntoai/sync_model_to_llm.dspy | 79 +++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 3 deletions(-) diff --git a/b/cntoai/sync_model_to_llm.dspy b/b/cntoai/sync_model_to_llm.dspy index ac187af..278d721 100644 --- a/b/cntoai/sync_model_to_llm.dspy +++ b/b/cntoai/sync_model_to_llm.dspy @@ -1,5 +1,11 @@ async def sync_model_to_llm(ns={}): import aiohttp + + async def get_sync_orgid(sor): + if ns.get('orgid'): + return ns.get('orgid') + user_li = await sor.R('users', {'id': await get_user()}) + return user_li[0].get('orgid') if user_li else '' # 从数据库读取domain和Bearer token db = DBPools() @@ -13,6 +19,12 @@ async def sync_model_to_llm(ns={}): } domain = domain_li[0]['pvalue'] bearer_token = user_key[0]['pvalue'] + sync_orgid = await get_sync_orgid(sor) + if not sync_orgid: + return { + 'status': False, + 'msg': '未找到当前用户所属机构' + } url = f"{domain}/llmage/list_llms" header = { @@ -33,9 +45,70 @@ async def sync_model_to_llm(ns={}): db = DBPools() async with db.sqlorContext('kboss') as sor: new_llms_count = 0 + sync_products_count = 0 new_llms_list = [] for category_list in result: for item in category_list.get('llms', []): + provider_orgcode = item.get('providerid') + provider_name = item.get('provider_name') or item.get('providerid') or '模型供应商' + if not provider_orgcode: + continue + + provider_ns = { + 'orgid': sync_orgid, + 'orgcode': provider_orgcode, + 'orgname': provider_name, + 'name': provider_name, + 'description': provider_name, + 'appid': item.get('upappid') or '', + 'providerkey': provider_orgcode, + 'state': '1', + 'start_date': item.get('enabled_date'), + 'end_date': item.get('expired_date') or '9999-12-31', + 'salemode': ns.get('salemode') or '0', + 'settle_mode': ns.get('settle_mode') or '0', + 'settle_datep': ns.get('settle_datep') + } + provider_res = await path_call('../provider/providerAdd.dspy', provider_ns) + if not provider_res.get('status'): + return { + 'status': False, + 'msg': '供应商同步失败, %s, %s' % (provider_name, provider_res.get('msg')) + } + provider_data = provider_res.get('data') or {} + provider_orgid = provider_data.get('provider_orgid') or provider_data.get('orgid') + protocolid = provider_data.get('protocolid') + if not provider_orgid or not protocolid: + return { + 'status': False, + 'msg': '供应商同步失败, 未返回provider_orgid或protocolid, %s' % provider_name + } + + product_ns = { + 'providerid': provider_orgid, + 'providerpid': item.get('id'), + 'protocolid': protocolid, + 'name': item.get('name'), + 'description': item.get('description'), + 'ptype': item.get('catelogname') or category_list.get('catelogname') or '', + 'state': '1', + 'product_code': item.get('model'), + 'reseller_orgid': sync_orgid, + 'salemode': ns.get('salemode') or '0', + 'productgroup': item.get('catelog_id') or item.get('catelogid') or category_list.get('catelogid'), + 'label': item.get('catelogname') or category_list.get('catelogname'), + 'unit': ns.get('unit'), + 'discount': ns.get('discount'), + 'floorprice': ns.get('floorprice') + } + product_res = await path_call('../product/productAdd.dspy', product_ns) + if not product_res.get('status'): + return { + 'status': False, + 'msg': '产品同步失败, %s, %s' % (item.get('name'), product_res.get('msg')) + } + sync_products_count += 1 + # 查找数据库中是否已经存在,不存在就插入 exist_llm = await sor.R('llm', {'model': item.get('model')}) if exist_llm: @@ -49,13 +122,13 @@ async def sync_model_to_llm(ns={}): 'iconid': item.get('iconid'), 'upappid': item.get('upappid'), 'apiname': item.get('apiname'), - 'providerid': item.get('providerid'), + 'providerid': provider_orgid, 'ownerid': item.get('ownerid') or '0', 'enabled_date': item.get('enabled_date'), 'expired_date': item.get('expired_date'), 'query_apiname': item.get('query_apiname') or '', 'query_period': item.get('query_period'), - 'ppid': item.get('ppid'), + 'ppid': protocolid, } new_llms_count += 1 new_llms_list.append(new_llms.get('model')) @@ -63,7 +136,7 @@ async def sync_model_to_llm(ns={}): return { 'status': True, - 'msg': f"sync_llm_list同步模型成功,共插入{new_llms_count}个模型,模型列表: {new_llms_list}" + 'msg': f"sync_llm_list同步模型成功,共同步{sync_products_count}个产品,共插入{new_llms_count}个模型,模型列表: {new_llms_list}" } except Exception as e: -- 2.34.1 From f2b432df51adf44a931408c41da8a55ff34e04c5 Mon Sep 17 00:00:00 2001 From: ping <1017253325@qq.com> Date: Tue, 21 Jul 2026 17:15:53 +0800 Subject: [PATCH 05/15] updte --- b/cntoai/sync_model_to_llm.dspy | 54 +++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/b/cntoai/sync_model_to_llm.dspy b/b/cntoai/sync_model_to_llm.dspy index 278d721..c119057 100644 --- a/b/cntoai/sync_model_to_llm.dspy +++ b/b/cntoai/sync_model_to_llm.dspy @@ -19,7 +19,8 @@ async def sync_model_to_llm(ns={}): } domain = domain_li[0]['pvalue'] bearer_token = user_key[0]['pvalue'] - sync_orgid = await get_sync_orgid(sor) + # sync_orgid = await get_sync_orgid(sor) + sync_orgid = "mIWUHBeeDM8mwAFPIQ8pS" # 固定写 if not sync_orgid: return { 'status': False, @@ -63,11 +64,17 @@ async def sync_model_to_llm(ns={}): 'appid': item.get('upappid') or '', 'providerkey': provider_orgcode, 'state': '1', - 'start_date': item.get('enabled_date'), - 'end_date': item.get('expired_date') or '9999-12-31', - 'salemode': ns.get('salemode') or '0', - 'settle_mode': ns.get('settle_mode') or '0', - 'settle_datep': ns.get('settle_datep') + 'start_date': '2026-07-01', + 'end_date': '9999-12-31', + 'settle_flowid': '0', + 'salemode': '0', + 'settle_mode': '3', + 'settle_datep': 'M00', + 'contactor': '连战', + 'contactor_phone': '13800138000', + 'emailaddress': 'lianzhan@cntoai.com', + 'address': '北京市海淀区', + 'org_type': '4' } provider_res = await path_call('../provider/providerAdd.dspy', provider_ns) if not provider_res.get('status'): @@ -89,17 +96,14 @@ async def sync_model_to_llm(ns={}): 'providerpid': item.get('id'), 'protocolid': protocolid, 'name': item.get('name'), - 'description': item.get('description'), - 'ptype': item.get('catelogname') or category_list.get('catelogname') or '', - 'state': '1', 'product_code': item.get('model'), 'reseller_orgid': sync_orgid, - 'salemode': ns.get('salemode') or '0', - 'productgroup': item.get('catelog_id') or item.get('catelogid') or category_list.get('catelogid'), 'label': item.get('catelogname') or category_list.get('catelogname'), - 'unit': ns.get('unit'), - 'discount': ns.get('discount'), - 'floorprice': ns.get('floorprice') + 'classify': 'A', + 'ptype': '21', + 'unit': 'hour', + 'discount': '1', + 'product_area': '北京' } product_res = await path_call('../product/productAdd.dspy', product_ns) if not product_res.get('status'): @@ -112,23 +116,33 @@ async def sync_model_to_llm(ns={}): # 查找数据库中是否已经存在,不存在就插入 exist_llm = await sor.R('llm', {'model': item.get('model')}) if exist_llm: + # 更新 + exits_id = exist_llm[0].get('id') + await sor.U('llm', {'id': exits_id}, item) continue + new_llms = { 'id': item.get('id'), 'name': item.get('name'), 'model': item.get('model'), 'description': item.get('description'), - 'llmcatelogid': item.get('catelog_id') or item.get('catelogid'), 'iconid': item.get('iconid'), 'upappid': item.get('upappid'), - 'apiname': item.get('apiname'), - 'providerid': provider_orgid, - 'ownerid': item.get('ownerid') or '0', + 'providerid': item.get('providerid'), + 'ownerid': item.get('ownerid'), 'enabled_date': item.get('enabled_date'), 'expired_date': item.get('expired_date'), - 'query_apiname': item.get('query_apiname') or '', + 'min_balance': item.get('min_balance'), + 'status': item.get('status'), + 'catelogname': item.get('catelogname'), + 'catelog_id': item.get('catelog_id'), + 'apiname': item.get('apiname'), + 'query_apiname': item.get('query_apiname'), 'query_period': item.get('query_period'), - 'ppid': protocolid, + 'ppid': item.get('ppid'), + 'provider_name': item.get('provider_name'), + 'pricing_display': item.get('pricing_display'), + 'provider_iconurl': item.get('provider_iconurl') } new_llms_count += 1 new_llms_list.append(new_llms.get('model')) -- 2.34.1 From 52568b33520c4b479a499883117d276d955959fe Mon Sep 17 00:00:00 2001 From: ping <1017253325@qq.com> Date: Wed, 22 Jul 2026 10:11:18 +0800 Subject: [PATCH 06/15] update --- b/user/get_user_and_role.dspy | 83 +++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 b/user/get_user_and_role.dspy diff --git a/b/user/get_user_and_role.dspy b/b/user/get_user_and_role.dspy new file mode 100644 index 0000000..6c555a2 --- /dev/null +++ b/b/user/get_user_and_role.dspy @@ -0,0 +1,83 @@ +def _parse_page(ns, default_page=1, default_size=20, max_size=200): + try: + current_page = int(ns.get('current_page') or ns.get('page') or default_page) + except (TypeError, ValueError): + current_page = default_page + try: + page_size = int(ns.get('page_size') or default_size) + except (TypeError, ValueError): + page_size = default_size + current_page = max(1, current_page) + page_size = max(1, min(page_size, max_size)) + return current_page, page_size, (current_page - 1) * page_size + + +async def get_user_and_role(ns={}): + """获取机构下所有用户及用户对应的所有角色""" + orgid = ns.get('orgid') + if not orgid: + return {'status': False, 'msg': '缺少 orgid'} + + current_page, page_size, offset = _parse_page(ns) + db = DBPools() + async with db.sqlorContext('kboss') as sor: + try: + where_sql = """ + u.del_flg='0' + AND ( + u.orgid=${orgid}$ + OR o.parentid=${orgid}$ + ) + """ + if ns.get('username'): + where_sql += " AND u.username LIKE '%%%%%s%%%%'" % ns.get('username') + if ns.get('mobile'): + where_sql += " AND u.mobile LIKE '%%%%%s%%%%'" % ns.get('mobile') + count_rows = await sor.sqlExe( + """ + SELECT COUNT(*) AS total_count + FROM users u + LEFT JOIN organization o ON u.orgid = o.id AND o.del_flg='0' + WHERE %s + """ % where_sql, + {'orgid': orgid}, + ) + total_count = count_rows[0]['total_count'] if count_rows else 0 + sql = """ + SELECT u.* + FROM users u + LEFT JOIN organization o ON u.orgid = o.id AND o.del_flg='0' + WHERE %s + ORDER BY u.create_at DESC + LIMIT %d OFFSET %d + """ % (where_sql, page_size, offset) + users = await sor.sqlExe(sql, {'orgid': orgid}) + for user in users: + user['roles'] = [] + userroles = await sor.R('userrole', {'userid': user['id']}) + for userrole in userroles: + if userrole.get('del_flg') == '1' or not userrole.get('roleid'): + continue + roles = await sor.R('role', {'id': userrole['roleid']}) + if len(roles) >= 1 and roles[0].get('del_flg') != '1': + user['roles'].append({ + 'id': roles[0].get('id'), + 'name': roles[0].get('role'), + }) + + return { + 'status': True, + 'msg': 'ok', + 'data': { + 'total_count': total_count, + 'current_page': current_page, + 'page_size': page_size, + 'rows': users, + }, + } + except Exception as e: + return {'status': False, 'msg': '获取用户角色失败, %s' % str(e)} + + +ret = await get_user_and_role(params_kw) +return ret -- 2.34.1 From faedbb8edfb1a22bd3beb4b566ce69bb5fa26842 Mon Sep 17 00:00:00 2001 From: ping <1017253325@qq.com> Date: Wed, 22 Jul 2026 10:18:48 +0800 Subject: [PATCH 07/15] update --- b/user/get_user_and_role.dspy | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/b/user/get_user_and_role.dspy b/b/user/get_user_and_role.dspy index 6c555a2..f209a11 100644 --- a/b/user/get_user_and_role.dspy +++ b/b/user/get_user_and_role.dspy @@ -47,14 +47,21 @@ async def get_user_and_role(ns={}): SELECT u.* FROM users u LEFT JOIN organization o ON u.orgid = o.id AND o.del_flg='0' + LEFT JOIN ( + SELECT userid, MAX(create_at) AS userrole_create_at + FROM userrole + WHERE del_flg='0' + GROUP BY userid + ) ur_sort ON u.id = ur_sort.userid WHERE %s - ORDER BY u.create_at DESC + ORDER BY ur_sort.userrole_create_at DESC, u.create_at DESC LIMIT %d OFFSET %d """ % (where_sql, page_size, offset) users = await sor.sqlExe(sql, {'orgid': orgid}) for user in users: user['roles'] = [] userroles = await sor.R('userrole', {'userid': user['id']}) + userroles = sorted(userroles, key=lambda item: item.get('create_at') or '', reverse=True) for userrole in userroles: if userrole.get('del_flg') == '1' or not userrole.get('roleid'): continue -- 2.34.1 From cbf68a3d5e9b089e1e54c1759a8e6662cfd2ff25 Mon Sep 17 00:00:00 2001 From: ping <1017253325@qq.com> Date: Wed, 22 Jul 2026 11:30:05 +0800 Subject: [PATCH 08/15] update --- b/user/add_user_role.dspy | 55 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 b/user/add_user_role.dspy diff --git a/b/user/add_user_role.dspy b/b/user/add_user_role.dspy new file mode 100644 index 0000000..06988e3 --- /dev/null +++ b/b/user/add_user_role.dspy @@ -0,0 +1,55 @@ +import json + + +def _parse_roleids(roleid): + if roleid is None: + return [] + if isinstance(roleid, list): + return [i for i in roleid if i] + if isinstance(roleid, str): + roleid = roleid.strip() + if not roleid: + return [] + try: + roleids = json.loads(roleid) + except Exception: + roleids = [roleid] + if isinstance(roleids, list): + return [i for i in roleids if i] + return [roleids] if roleids else [] + return [roleid] + + +async def add_user_role(ns): + """ + 用户分配角色 + :param userid: 用户id + :param roleid: 角色id列表 + :return: + """ + if not ns or not ns.get('userid') or 'roleid' not in ns: + return {'status': False, 'msg': '参数不正确'} + + userid = ns.get('userid') + roleids = _parse_roleids(ns.get('roleid')) + db = DBPools() + async with db.sqlorContext('kboss') as sor: + userroles = await sor.R('userrole', {'userid': userid}) + for userrole in userroles: + if userrole.get('roleid') not in roleids: + await sor.U('userrole', {'del_flg': '1', 'id': userrole['id']}) + + for roleid in roleids: + roles = {'userid': userid, 'roleid': roleid} + reacs = await sor.R('userrole', roles) + if len(reacs) >= 1: + await sor.U('userrole', {'id': reacs[0]['id'], 'del_flg': '0'}) + continue + await sor.C('userrole', {'id': uuid(), 'userid': userid, 'roleid': roleid}) + return {'status': True, 'msg': '添加成功'} + + return {'status': False, 'msg': '添加失败'} + + +ret = await add_user_role(params_kw) +return ret -- 2.34.1 From 2faa82f4bef54c6693f946754f0ac81cd6edef1f Mon Sep 17 00:00:00 2001 From: hrx <18603305412@163.com> Date: Wed, 22 Jul 2026 11:34:07 +0800 Subject: [PATCH 09/15] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- f/web-kboss/src/api/roleManagement.js | 33 + f/web-kboss/src/router/index.js | 7 + f/web-kboss/src/store/modules/permission.js | 35 + .../src/views/LoginDialog/LoginDialog.vue | 5 + .../homePage/components/topBox/index.vue | 1 + .../homePage/news/ArticleEditorDialog.vue | 2 +- .../src/views/modelManagement/ApiDocument.vue | 338 ++++++---- .../roleManagement/index.vue | 619 ++++++++++++++++++ 8 files changed, 910 insertions(+), 130 deletions(-) create mode 100644 f/web-kboss/src/api/roleManagement.js create mode 100644 f/web-kboss/src/views/superAdministrator/roleManagement/index.vue diff --git a/f/web-kboss/src/api/roleManagement.js b/f/web-kboss/src/api/roleManagement.js new file mode 100644 index 0000000..cca6343 --- /dev/null +++ b/f/web-kboss/src/api/roleManagement.js @@ -0,0 +1,33 @@ +import request from '@/utils/request' +// 获取角色 +export function getRoleAPI(data) { + return request({ + url: `/role/getRole.dspy`, + method: 'get', + params: data + }) +} +// 添加角色 +export function addRoleAPI(data) { + return request({ + url: `/reseller/reseller_add_user.dspy`, + method: 'post', + data: data + }) +} +// 列表 +export function getListAPI(data) { + return request({ + url: `/user/get_user_and_role.dspy`, + method: 'get', + params: data + }) +} +// 分配角色 参数为userid roleid +export function assignRoleAPI(data) { + return request({ + url: `/user/add_user_role.dspy`, + method: 'post', + data: data + }) +} \ No newline at end of file diff --git a/f/web-kboss/src/router/index.js b/f/web-kboss/src/router/index.js index 81298f0..1dca6fa 100644 --- a/f/web-kboss/src/router/index.js +++ b/f/web-kboss/src/router/index.js @@ -2305,6 +2305,13 @@ export const asyncRoutes = [ path: "/superAdministrator", component: Layout, redirect: "/superAdministrator/index", meta: { title: "超级管理员", icon: "el-icon-user-solid", noCache: true, fullPath: "/superAdministrator", }, children: [{ + path: "roleManagement", + component: () => import("@/views/superAdministrator/roleManagement"), + name: "RoleManagement", + meta: { + title: "角色管理", fullPath: "/superAdministrator/roleManagement", + }, + }, { path: "addAdmin", component: () => import("@/views/superAdministrator/addAdmin"), name: "addAdmin", meta: { title: "添加业主机构管理员", fullPath: "/superAdministrator/addAdmin", }, diff --git a/f/web-kboss/src/store/modules/permission.js b/f/web-kboss/src/store/modules/permission.js index d773d45..08d5880 100644 --- a/f/web-kboss/src/store/modules/permission.js +++ b/f/web-kboss/src/store/modules/permission.js @@ -7,6 +7,7 @@ const MOBILE_UA_REGEXP = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Ope const CUSTOMER_ROLE = '客户'; const OPERATION_ROLE = '运营'; const FINANCE_ROLE = '财务'; +const ADMINISTRATOR_ROLE = '管理员'; // 这个用户能看到订单管理里的特殊子菜单,比如历史订单和订单详情。 const SPECIAL_ORDER_USER = 'ZhipuHZ'; @@ -23,6 +24,8 @@ const OPERATION_EXTRA_ROUTE_PATHS = ['/modelManagement', '/modelInfoConfig', '/o // 财务角色需要额外补出来的菜单。 const FINANCE_EXTRA_ROUTE_PATHS = ['/financialOverview']; +const ADMINISTRATOR_ROUTE_FULL_PATH = '/superAdministrator/roleManagement'; + // 普通客户账号默认要补出来的基础菜单。 const BASE_USER_ROUTE_PATHS = ['/orderManagement', '/resourceManagement']; @@ -350,6 +353,30 @@ function addFinanceRoutes(accessedRoutes, routes, userRoles = [], deviceType = ' return appendMissingRoutes(accessedRoutes, getRoutesByPath(routes, FINANCE_EXTRA_ROUTE_PATHS)); } +function getAdministratorRoutes(routes, deviceType = 'pc') { + if (deviceType !== 'pc') { + return []; + } + + const superAdminRoute = findRouteByPath(routes, SUPER_ADMIN_ROUTE_PATH); + if (!superAdminRoute) { + return []; + } + + const clonedRoute = cloneRoute(superAdminRoute); + clonedRoute.redirect = ADMINISTRATOR_ROUTE_FULL_PATH; + clonedRoute.children = (clonedRoute.children || []).filter(child => child.meta?.fullPath === ADMINISTRATOR_ROUTE_FULL_PATH); + return clonedRoute.children.length ? [clonedRoute] : []; +} + +function addAdministratorRoutes(accessedRoutes, routes, userRoles = [], deviceType = 'pc') { + if (!userRoles.includes(ADMINISTRATOR_ROLE)) { + return accessedRoutes; + } + + return appendMissingRoutes(accessedRoutes, getAdministratorRoutes(routes, deviceType)); +} + // token市集是公共菜单,所有登录用户都要能看到。 function addCommonRoutes(accessedRoutes, routes, deviceType = 'pc') { const commonRoutes = getRoutesByPath(routes, COMMON_ROUTE_PATHS) @@ -495,6 +522,13 @@ const actions = { console.log("用户类型:", userType, "orgType:", orgType, "设备类型:", deviceType); console.log("ACTION generateRoutes - auths:", auths); + if (!isSuperAdmin && userRoles.includes(ADMINISTRATOR_ROLE)) { + const administratorRoutes = getAdministratorRoutes(asyncRoutes, deviceType); + commit("SET_ROUTES", administratorRoutes); + resolve(administratorRoutes); + return; + } + // 3. 先生成第一版菜单:超级管理员只拿超管菜单,普通用户按后端 auths 过滤。 let accessedRoutes = isSuperAdmin ? getSuperAdminRoutes(deviceType) @@ -502,6 +536,7 @@ const actions = { // 4. token市集是公共入口,所有登录用户都补上。 accessedRoutes = addCommonRoutes(accessedRoutes, asyncRoutes, deviceType); + accessedRoutes = addAdministratorRoutes(accessedRoutes, asyncRoutes, userRoles, deviceType); if (!isSuperAdmin) { // 5. 普通用户再补一些固定入口,比如订单、资源、客户专属菜单。 diff --git a/f/web-kboss/src/views/LoginDialog/LoginDialog.vue b/f/web-kboss/src/views/LoginDialog/LoginDialog.vue index 263a61f..298bfc8 100644 --- a/f/web-kboss/src/views/LoginDialog/LoginDialog.vue +++ b/f/web-kboss/src/views/LoginDialog/LoginDialog.vue @@ -382,6 +382,11 @@ export default { }) }, redirectAfterLogin(res) { + if (res.roles && res.roles.includes('管理员')) { + sessionStorage.removeItem('loginRedirectPath') + this.$router.push('/superAdministrator/roleManagement').catch(() => {}) + return + } const redirectPath = sessionStorage.getItem('loginRedirectPath') if (redirectPath && redirectPath.startsWith('/') && !redirectPath.includes('/login')) { sessionStorage.removeItem('loginRedirectPath') diff --git a/f/web-kboss/src/views/homePage/components/topBox/index.vue b/f/web-kboss/src/views/homePage/components/topBox/index.vue index 91f25ee..24c8b71 100644 --- a/f/web-kboss/src/views/homePage/components/topBox/index.vue +++ b/f/web-kboss/src/views/homePage/components/topBox/index.vue @@ -544,6 +544,7 @@ export default Vue.extend({ else if (role.includes('运维')) this.$router.push('/operationAndMaintenance/workOrderProcessing') else if (role.includes('销售')) this.$router.push('/sales/distributorManagement') else if (role.includes('财务')) this.$router.push('/finance/supplierSettlementStatistics') + else if (role.includes('管理员')) this.$router.push('/superAdministrator/roleManagement') else if (role.includes('admin')) this.$router.push('/superAdministrator/addAdmin') }, async logout() { diff --git a/f/web-kboss/src/views/homePage/news/ArticleEditorDialog.vue b/f/web-kboss/src/views/homePage/news/ArticleEditorDialog.vue index 4f04029..792d8a1 100644 --- a/f/web-kboss/src/views/homePage/news/ArticleEditorDialog.vue +++ b/f/web-kboss/src/views/homePage/news/ArticleEditorDialog.vue @@ -243,7 +243,7 @@ export default { this.stopObserveEditorFullscreen() this.editorFullscreen = false }, - methods: { + methods: { createEmptyForm() { // 创建新增文章时使用的默认表单结构。 return { diff --git a/f/web-kboss/src/views/modelManagement/ApiDocument.vue b/f/web-kboss/src/views/modelManagement/ApiDocument.vue index 61c629c..8ed6cc9 100644 --- a/f/web-kboss/src/views/modelManagement/ApiDocument.vue +++ b/f/web-kboss/src/views/modelManagement/ApiDocument.vue @@ -5,7 +5,7 @@ 返回 - API文档 + 元境 API 文档
@@ -19,40 +19,12 @@ >
-

{{ apiDoc.model_name }} API 文档

-

{{ heroDescription }}

- +

元境 API 文档

+

统一展示大模型、视频、图像、音频、任务查询等接口说明。

-
-

1. 接口地址

-

统一使用 HTTPS 请求,所有接口都需要携带平台签发的 API Key。

-
{{ apiUrlText }}
-
- - - - - -
-

2. 请求示例

-
{{ apiDoc.curl_code || requestExample }}
-
- -
-

3. Python 示例

-
{{ apiDoc.python_code || pythonExample }}
-
- -
-

4. 错误码

- - - - - +
+
@@ -61,124 +33,137 @@ + + -- 2.34.1 From 0baf4fb9ad1ed3def78a225f1455941b15dd70c0 Mon Sep 17 00:00:00 2001 From: ping <1017253325@qq.com> Date: Wed, 22 Jul 2026 15:12:11 +0800 Subject: [PATCH 10/15] update --- b/reseller/reseller_add_user.dspy | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/b/reseller/reseller_add_user.dspy b/b/reseller/reseller_add_user.dspy index 53736dc..2d77f31 100644 --- a/b/reseller/reseller_add_user.dspy +++ b/b/reseller/reseller_add_user.dspy @@ -27,15 +27,16 @@ async def reseller_add_user(ns): try: ns['id'] = uuid() ns['password'] = password_encode(ns['password']) - tenant_orgid = await get_reseller_user_tenant_orgid(sor, ns.get('orgid')) + # tenant_orgid = await get_reseller_user_tenant_orgid(sor, ns.get('orgid')) + tenant_orgid = ns.get('orgid') if not tenant_orgid: return {'status': False, 'msg': '未找到用户所属租户'} user_sql = """select id from users where username = '%s' and tenant_orgid = '%s' and del_flg = '0' limit 1;""" % (ns['username'], tenant_orgid) user = await sor.sqlExe(user_sql, {}) if len(user) >= 1: return {'status': False, 'msg': '用户名重复'} - rolereacs = await sor.R('role', {'role': '管理员', 'del_flg': '0', 'org_type': '1'}) - ns['user_reseller'] = '1' + rolereacs = await sor.R('role', {'role': '管理员', 'del_flg': '0', 'org_type': ns.get('org_type')}) + ns['user_reseller'] = ns.get('org_type') ns['tenant_orgid'] = tenant_orgid await sor.C('users', ns) await sor.C('userrole', {'userid': ns['id'], 'roleid': rolereacs[0]['id'], 'id': uuid()}) -- 2.34.1 From cbbdac9adc91b400fc7fa3932eb6a1be167835c1 Mon Sep 17 00:00:00 2001 From: ping <1017253325@qq.com> Date: Wed, 22 Jul 2026 15:37:50 +0800 Subject: [PATCH 11/15] update --- b/cntoai/sync_model_to_llm.dspy | 344 +++++++++++++++++++++++--------- 1 file changed, 248 insertions(+), 96 deletions(-) diff --git a/b/cntoai/sync_model_to_llm.dspy b/b/cntoai/sync_model_to_llm.dspy index c119057..ee87c1d 100644 --- a/b/cntoai/sync_model_to_llm.dspy +++ b/b/cntoai/sync_model_to_llm.dspy @@ -6,6 +6,177 @@ async def sync_model_to_llm(ns={}): return ns.get('orgid') user_li = await sor.R('users', {'id': await get_user()}) return user_li[0].get('orgid') if user_li else '' + + def build_llm_data(item): + return { + 'id': item.get('id') or uuid(), + 'name': item.get('name'), + 'model': item.get('model'), + 'description': item.get('description'), + 'iconid': item.get('iconid'), + 'upappid': item.get('upappid'), + 'providerid': item.get('providerid'), + 'ownerid': item.get('ownerid') or '0', + 'enabled_date': item.get('enabled_date'), + 'expired_date': item.get('expired_date'), + 'min_balance': item.get('min_balance'), + 'status': item.get('status') or 'published', + 'catelogname': item.get('catelogname'), + 'catelog_id': item.get('catelog_id') or item.get('catelogid'), + 'llmcatelogid': item.get('catelog_id') or item.get('catelogid'), + 'apiname': item.get('apiname'), + 'query_apiname': item.get('query_apiname'), + 'query_period': item.get('query_period'), + 'ppid': item.get('ppid'), + 'provider_name': item.get('provider_name'), + 'pricing_display': item.get('pricing_display'), + 'provider_iconurl': item.get('provider_iconurl') + } + + async def ensure_provider(sor, provider_orgcode, provider_name, sync_orgid, item): + exist_org_li = await sor.R('organization', {'orgcode': provider_orgcode, 'del_flg': '0'}) + if exist_org_li: + provider_orgid = exist_org_li[0].get('id') + await sor.U('organization', {'id': provider_orgid}, { + 'id': provider_orgid, + 'orgname': provider_name, + 'orgcode': provider_orgcode, + 'parentid': sync_orgid, + 'org_type': '4' + }) + else: + provider_orgid = uuid() + await sor.C('organization', { + 'id': provider_orgid, + 'orgname': provider_name, + 'contactor': '连战', + 'contactor_phone': '13800138000', + 'address': '北京市海淀区', + 'main_business': provider_name, + 'orgcode': provider_orgcode, + 'emailaddress': 'lianzhan@cntoai.com', + 'org_type': '4', + 'parentid': sync_orgid + }) + await openProviderAccounts(sor, sync_orgid, provider_orgid) + + provider_li = await sor.R('provider', {'orgid': provider_orgid, 'del_flg': '0'}) + provider_data = { + 'name': provider_name, + 'description': provider_name, + 'appid': item.get('upappid') or '', + 'providerkey': provider_orgcode, + 'state': '1', + 'start_date': '2026-07-01', + 'end_date': '9999-12-31', + 'settle_mode': '3', + 'settle_flowid': '0', + 'settle_datep': 'M00', + 'discount_mode': 1, + 'orgid': provider_orgid + } + if provider_li: + provider_id = provider_li[0].get('id') + provider_data['id'] = provider_id + await sor.U('provider', {'id': provider_id}, provider_data) + else: + provider_id = uuid() + provider_data['id'] = provider_id + await sor.C('provider', provider_data) + + protocol_li = await sor.R('saleprotocol', {'offer_orgid': provider_orgid, 'bid_orgid': sync_orgid, 'del_flg': '0'}) + if protocol_li: + protocolid = protocol_li[0].get('id') + await sor.U('saleprotocol', {'id': protocolid}, { + 'id': protocolid, + 'offer_orgid': provider_orgid, + 'bid_orgid': sync_orgid, + 'salemode': '0', + 'settle_mode': '3', + 'settle_dp': 'M00', + 'start_date': '2026-07-01', + 'end_date': '9999-12-31' + }) + else: + protocolid = uuid() + await sor.C('saleprotocol', { + 'id': protocolid, + 'offer_orgid': provider_orgid, + 'bid_orgid': sync_orgid, + 'salemode': '0', + 'settle_mode': '3', + 'settle_dp': 'M00', + 'start_date': '2026-07-01', + 'end_date': '9999-12-31' + }) + + return { + 'provider_orgid': provider_orgid, + 'provider_id': provider_id, + 'protocolid': protocolid + } + + async def sync_product(sor, item, category_list, provider_orgid, protocolid, sync_orgid): + product_data = { + 'providerid': provider_orgid, + 'providerpid': item.get('id'), + 'name': item.get('name'), + 'description': item.get('description') or '', + 'ptype': '21', + 'state': '1', + 'salemode': '0', + 'product_code': item.get('model'), + 'reseller_orgid': sync_orgid, + 'classify': 'A', + 'label': item.get('catelogname') or category_list.get('catelogname'), + 'productgroup': item.get('catelog_id') or item.get('catelogid') or category_list.get('catelogid'), + 'product_area': '北京', + 'effect_date': '2026-07-01', + 'expire_date': '9999-12-31' + } + product_li = await sor.R('product', {'providerid': provider_orgid, 'product_code': item.get('model'), 'del_flg': '0'}) + if product_li: + product_id = product_li[0].get('id') + product_data['id'] = product_id + await sor.U('product', {'id': product_id}, product_data) + product_action = 'update' + else: + product_id = uuid() + product_data['id'] = product_id + await sor.C('product', product_data) + product_action = 'insert' + + salemode_data = { + 'protocolid': protocolid, + 'providerid': provider_orgid, + 'productid': product_id, + 'discount': 1, + 'unit': 'hour' + } + product_salemode_li = await sor.R('product_salemode', { + 'protocolid': protocolid, + 'providerid': provider_orgid, + 'productid': product_id, + 'del_flg': '0' + }) + if product_salemode_li: + salemode_data['id'] = product_salemode_li[0].get('id') + await sor.U('product_salemode', {'id': salemode_data['id']}, salemode_data) + else: + salemode_data['id'] = uuid() + await sor.C('product_salemode', salemode_data) + + return product_action + + async def upsert_llm(sor, item): + llm_data = build_llm_data(item) + exist_llm = await sor.R('llm', {'model': item.get('model')}) + if exist_llm: + llm_data['id'] = exist_llm[0].get('id') + await sor.U('llm', {'id': llm_data['id']}, llm_data) + return 'update' + await sor.C('llm', llm_data) + return 'insert' # 从数据库读取domain和Bearer token db = DBPools() @@ -45,112 +216,93 @@ async def sync_model_to_llm(ns={}): # 插入数据库 db = DBPools() async with db.sqlorContext('kboss') as sor: - new_llms_count = 0 - sync_products_count = 0 - new_llms_list = [] + provider_groups = {} + current_model_set = set() for category_list in result: for item in category_list.get('llms', []): provider_orgcode = item.get('providerid') - provider_name = item.get('provider_name') or item.get('providerid') or '模型供应商' - if not provider_orgcode: + model = item.get('model') + if not provider_orgcode or not model: continue - - provider_ns = { - 'orgid': sync_orgid, - 'orgcode': provider_orgcode, - 'orgname': provider_name, - 'name': provider_name, - 'description': provider_name, - 'appid': item.get('upappid') or '', - 'providerkey': provider_orgcode, - 'state': '1', - 'start_date': '2026-07-01', - 'end_date': '9999-12-31', - 'settle_flowid': '0', - 'salemode': '0', - 'settle_mode': '3', - 'settle_datep': 'M00', - 'contactor': '连战', - 'contactor_phone': '13800138000', - 'emailaddress': 'lianzhan@cntoai.com', - 'address': '北京市海淀区', - 'org_type': '4' - } - provider_res = await path_call('../provider/providerAdd.dspy', provider_ns) - if not provider_res.get('status'): - return { - 'status': False, - 'msg': '供应商同步失败, %s, %s' % (provider_name, provider_res.get('msg')) - } - provider_data = provider_res.get('data') or {} - provider_orgid = provider_data.get('provider_orgid') or provider_data.get('orgid') - protocolid = provider_data.get('protocolid') - if not provider_orgid or not protocolid: - return { - 'status': False, - 'msg': '供应商同步失败, 未返回provider_orgid或protocolid, %s' % provider_name + item['catelogname'] = item.get('catelogname') or category_list.get('catelogname') + item['catelog_id'] = item.get('catelog_id') or item.get('catelogid') or category_list.get('catelogid') + current_model_set.add(model) + if provider_orgcode not in provider_groups: + provider_groups[provider_orgcode] = { + 'provider_name': item.get('provider_name') or provider_orgcode or '模型供应商', + 'items': [] } + elif item.get('provider_name'): + provider_groups[provider_orgcode]['provider_name'] = item.get('provider_name') + provider_groups[provider_orgcode]['items'].append({ + 'item': item, + 'category': category_list + }) - product_ns = { - 'providerid': provider_orgid, - 'providerpid': item.get('id'), - 'protocolid': protocolid, - 'name': item.get('name'), - 'product_code': item.get('model'), - 'reseller_orgid': sync_orgid, - 'label': item.get('catelogname') or category_list.get('catelogname'), - 'classify': 'A', - 'ptype': '21', - 'unit': 'hour', - 'discount': '1', - 'product_area': '北京' - } - product_res = await path_call('../product/productAdd.dspy', product_ns) - if not product_res.get('status'): - return { - 'status': False, - 'msg': '产品同步失败, %s, %s' % (item.get('name'), product_res.get('msg')) - } - sync_products_count += 1 + provider_count = 0 + product_insert_count = 0 + product_update_count = 0 + llm_insert_count = 0 + llm_update_count = 0 + synced_llms_list = [] - # 查找数据库中是否已经存在,不存在就插入 - exist_llm = await sor.R('llm', {'model': item.get('model')}) - if exist_llm: - # 更新 - exits_id = exist_llm[0].get('id') - await sor.U('llm', {'id': exits_id}, item) - continue - - new_llms = { - 'id': item.get('id'), - 'name': item.get('name'), - 'model': item.get('model'), - 'description': item.get('description'), - 'iconid': item.get('iconid'), - 'upappid': item.get('upappid'), - 'providerid': item.get('providerid'), - 'ownerid': item.get('ownerid'), - 'enabled_date': item.get('enabled_date'), - 'expired_date': item.get('expired_date'), - 'min_balance': item.get('min_balance'), - 'status': item.get('status'), - 'catelogname': item.get('catelogname'), - 'catelog_id': item.get('catelog_id'), - 'apiname': item.get('apiname'), - 'query_apiname': item.get('query_apiname'), - 'query_period': item.get('query_period'), - 'ppid': item.get('ppid'), - 'provider_name': item.get('provider_name'), - 'pricing_display': item.get('pricing_display'), - 'provider_iconurl': item.get('provider_iconurl') - } - new_llms_count += 1 - new_llms_list.append(new_llms.get('model')) - await sor.C('llm', new_llms) + for provider_orgcode, provider_group in provider_groups.items(): + provider_name = provider_group.get('provider_name') or provider_orgcode or '模型供应商' + provider_data = await ensure_provider( + sor, + provider_orgcode, + provider_name, + sync_orgid, + provider_group['items'][0]['item'] + ) + provider_count += 1 + + for model_info in provider_group['items']: + item = model_info['item'] + category_list = model_info['category'] + product_action = await sync_product( + sor, + item, + category_list, + provider_data['provider_orgid'], + provider_data['protocolid'], + sync_orgid + ) + if product_action == 'insert': + product_insert_count += 1 + else: + product_update_count += 1 + + llm_action = await upsert_llm(sor, item) + if llm_action == 'insert': + llm_insert_count += 1 + else: + llm_update_count += 1 + synced_llms_list.append(item.get('model')) + + llm_unpublished_count = 0 + exist_llm_li = await sor.R('llm', {}) + for exist_llm in exist_llm_li: + exist_model = exist_llm.get('model') + if exist_model and exist_model not in current_model_set and exist_llm.get('status') != 'unpublished': + await sor.U('llm', {'id': exist_llm.get('id')}, { + 'id': exist_llm.get('id'), + 'status': 'unpublished' + }) + llm_unpublished_count += 1 return { 'status': True, - 'msg': f"sync_llm_list同步模型成功,共同步{sync_products_count}个产品,共插入{new_llms_count}个模型,模型列表: {new_llms_list}" + 'msg': 'sync_llm_list同步模型成功', + 'data': { + 'provider_count': provider_count, + 'product_insert_count': product_insert_count, + 'product_update_count': product_update_count, + 'llm_insert_count': llm_insert_count, + 'llm_update_count': llm_update_count, + 'llm_unpublished_count': llm_unpublished_count, + 'model_list': synced_llms_list + } } except Exception as e: -- 2.34.1 From f0f32b9239fb299d60c54c0523fa53060d0b2b4b Mon Sep 17 00:00:00 2001 From: ping <1017253325@qq.com> Date: Wed, 22 Jul 2026 16:20:06 +0800 Subject: [PATCH 12/15] update --- b/cntoai/sync_model_to_llm.dspy | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/b/cntoai/sync_model_to_llm.dspy b/b/cntoai/sync_model_to_llm.dspy index ee87c1d..917f0cf 100644 --- a/b/cntoai/sync_model_to_llm.dspy +++ b/b/cntoai/sync_model_to_llm.dspy @@ -37,7 +37,7 @@ async def sync_model_to_llm(ns={}): exist_org_li = await sor.R('organization', {'orgcode': provider_orgcode, 'del_flg': '0'}) if exist_org_li: provider_orgid = exist_org_li[0].get('id') - await sor.U('organization', {'id': provider_orgid}, { + await sor.U('organization', { 'id': provider_orgid, 'orgname': provider_name, 'orgcode': provider_orgcode, @@ -78,7 +78,7 @@ async def sync_model_to_llm(ns={}): if provider_li: provider_id = provider_li[0].get('id') provider_data['id'] = provider_id - await sor.U('provider', {'id': provider_id}, provider_data) + await sor.U('provider', provider_data) else: provider_id = uuid() provider_data['id'] = provider_id @@ -87,7 +87,7 @@ async def sync_model_to_llm(ns={}): protocol_li = await sor.R('saleprotocol', {'offer_orgid': provider_orgid, 'bid_orgid': sync_orgid, 'del_flg': '0'}) if protocol_li: protocolid = protocol_li[0].get('id') - await sor.U('saleprotocol', {'id': protocolid}, { + await sor.U('saleprotocol', { 'id': protocolid, 'offer_orgid': provider_orgid, 'bid_orgid': sync_orgid, @@ -121,7 +121,7 @@ async def sync_model_to_llm(ns={}): 'providerid': provider_orgid, 'providerpid': item.get('id'), 'name': item.get('name'), - 'description': item.get('description') or '', + # 'description': item.get('description') or '', 'ptype': '21', 'state': '1', 'salemode': '0', @@ -129,7 +129,7 @@ async def sync_model_to_llm(ns={}): 'reseller_orgid': sync_orgid, 'classify': 'A', 'label': item.get('catelogname') or category_list.get('catelogname'), - 'productgroup': item.get('catelog_id') or item.get('catelogid') or category_list.get('catelogid'), + # 'productgroup': item.get('catelog_id') or item.get('catelogid') or category_list.get('catelogid'), 'product_area': '北京', 'effect_date': '2026-07-01', 'expire_date': '9999-12-31' @@ -138,7 +138,7 @@ async def sync_model_to_llm(ns={}): if product_li: product_id = product_li[0].get('id') product_data['id'] = product_id - await sor.U('product', {'id': product_id}, product_data) + await sor.U('product', product_data) product_action = 'update' else: product_id = uuid() @@ -161,7 +161,7 @@ async def sync_model_to_llm(ns={}): }) if product_salemode_li: salemode_data['id'] = product_salemode_li[0].get('id') - await sor.U('product_salemode', {'id': salemode_data['id']}, salemode_data) + await sor.U('product_salemode', salemode_data) else: salemode_data['id'] = uuid() await sor.C('product_salemode', salemode_data) @@ -173,7 +173,7 @@ async def sync_model_to_llm(ns={}): exist_llm = await sor.R('llm', {'model': item.get('model')}) if exist_llm: llm_data['id'] = exist_llm[0].get('id') - await sor.U('llm', {'id': llm_data['id']}, llm_data) + await sor.U('llm', llm_data) return 'update' await sor.C('llm', llm_data) return 'insert' @@ -285,7 +285,7 @@ async def sync_model_to_llm(ns={}): for exist_llm in exist_llm_li: exist_model = exist_llm.get('model') if exist_model and exist_model not in current_model_set and exist_llm.get('status') != 'unpublished': - await sor.U('llm', {'id': exist_llm.get('id')}, { + await sor.U('llm', { 'id': exist_llm.get('id'), 'status': 'unpublished' }) -- 2.34.1 From 9465a005baf48bad0672ac6b5bc3321322b8c871 Mon Sep 17 00:00:00 2001 From: hrx <18603305412@163.com> Date: Wed, 22 Jul 2026 17:20:34 +0800 Subject: [PATCH 13/15] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- f/web-kboss/src/App.vue | 23 +++- f/web-kboss/src/utils/request.js | 12 +- .../src/views/product/allProduct/index.vue | 112 +++++++++++++----- 3 files changed, 106 insertions(+), 41 deletions(-) diff --git a/f/web-kboss/src/App.vue b/f/web-kboss/src/App.vue index 6e799fe..d1ac44a 100644 --- a/f/web-kboss/src/App.vue +++ b/f/web-kboss/src/App.vue @@ -4,6 +4,10 @@ +
@@ -38,6 +42,7 @@