ns = params_kw.copy() env = request._run_ns userorgid = await env.get_userorgid() # Per-org metering: documents.file_size by org_id (auto-decreases on delete) used = 0 limit = 104857600 docs = 0 async with get_sor_context(env, 'rag') as sor: rec = await sor.sqlExe( "SELECT COALESCE(SUM(d.file_size),0) AS used, COUNT(*) AS docs " "FROM documents d JOIN knowledge_bases k ON d.kb_id=k.id " "WHERE k.org_id=${org_id}$", {"org_id": userorgid}) if rec: used = int(rec[0].used) docs = int(rec[0].docs) lim = await sor.sqlExe("SELECT limit_bytes FROM org_storage_limits WHERE org_id=${org_id}$", {"org_id": userorgid}) if lim: limit = int(lim[0].limit_bytes) def fmt(sz): if sz < 1024: return str(sz) + 'B' elif sz < 1024*1024: return str(round(sz/1024,1)) + 'KB' else: return str(round(sz/(1024*1024),1)) + 'MB' pct = min(round(used / max(limit, 1) * 100, 1), 100) if used > 0 else 0 bar_color = "#f56c6c" if pct >= 90 else ("#e6a23c" if pct >= 70 else "#4a90d9") return json.dumps({ "widgettype": "VBox", "options": {"width": "100%", "bgcolor": "#f8f9fa", "padding": "16px", "css": "card", "spacing": "4px"}, "subwidgets": [ {"widgettype": "HBox", "options": {"width": "100%", "justifyContent": "space-between"}, "subwidgets": [ {"widgettype": "Text", "options": {"text": "💾 存储容量(本机构)", "cfontsize": 14, "fontWeight": "bold", "color": "#333"}}, {"widgettype": "Text", "options": {"text": "已用 " + fmt(used) + " / 限额 " + fmt(limit) + " | " + str(docs) + " 文档", "cfontsize": 12, "color": "#888"}} ]}, {"widgettype": "VBox", "options": {"width": "100%", "cheight": 0.5, "bgcolor": "#e0e0e0"}, "subwidgets": [ {"widgettype": "VBox", "options": {"cwidth": pct, "cheight": 0.5, "bgcolor": bar_color}} ]} ] }, ensure_ascii=False, default=str)