feat(credit): redesign credit limit UI with dashboard, overview and management views
- Add hub.ui as main entry with stat cards (total/used/available/usage%) - Add credit_overview.ui for user's own credit visualization with progress bars - Add credit_manage.ui for distributor sales to manage customer credits - Add set_credit_form.ui and set_customer_credit.dspy for credit adjustment - Add credit_summary.dspy API for stats data - Enhance creditlimit.py with get_credit_stats, get_my_credit_list, get_all_customer_credits - Register new functions in init.py with ServerEnv
This commit is contained in:
parent
195a7bfb46
commit
78ff190789
@ -1,6 +1,103 @@
|
|||||||
from appPublic.log import debug, exception
|
from appPublic.log import debug, exception
|
||||||
|
from appPublic.uniqueID import getID
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
|
async def get_credit_stats(sor, orgid):
|
||||||
|
"""
|
||||||
|
Get credit summary statistics for an organization.
|
||||||
|
Returns total_credit, total_used, total_available, usage_pct, customer_count.
|
||||||
|
"""
|
||||||
|
sql = """
|
||||||
|
SELECT
|
||||||
|
COALESCE(SUM(credit_limit), 0) as total_credit,
|
||||||
|
COALESCE(SUM(used_credit), 0) as total_used,
|
||||||
|
COALESCE(SUM(available_credit), 0) as total_available,
|
||||||
|
COUNT(*) as customer_count,
|
||||||
|
COUNT(CASE WHEN status = 'active' THEN 1 END) as active_count,
|
||||||
|
COUNT(CASE WHEN status = 'expired' THEN 1 END) as expired_count
|
||||||
|
FROM credit_limit
|
||||||
|
WHERE orgid = ${orgid}$
|
||||||
|
"""
|
||||||
|
recs = await sor.sqlExe(sql, {'orgid': orgid})
|
||||||
|
if recs and len(recs) > 0:
|
||||||
|
r = recs[0]
|
||||||
|
total_credit = float(r.total_credit or 0)
|
||||||
|
total_used = float(r.total_used or 0)
|
||||||
|
total_available = float(r.total_available or 0)
|
||||||
|
usage_pct = round((total_used / total_credit * 100), 1) if total_credit > 0 else 0
|
||||||
|
return {
|
||||||
|
'total_credit': total_credit,
|
||||||
|
'total_used': total_used,
|
||||||
|
'total_available': total_available,
|
||||||
|
'usage_pct': usage_pct,
|
||||||
|
'customer_count': int(r.customer_count or 0),
|
||||||
|
'active_count': int(r.active_count or 0),
|
||||||
|
'expired_count': int(r.expired_count or 0)
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
'total_credit': 0, 'total_used': 0, 'total_available': 0,
|
||||||
|
'usage_pct': 0, 'customer_count': 0, 'active_count': 0, 'expired_count': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def get_my_credit_list(sor, orgid):
|
||||||
|
"""
|
||||||
|
Get all credit limit records for the current user's organization,
|
||||||
|
with organization name and account info for display.
|
||||||
|
"""
|
||||||
|
sql = """
|
||||||
|
SELECT
|
||||||
|
cl.*,
|
||||||
|
org.orgname as orgname_text,
|
||||||
|
sub.name as subject_name,
|
||||||
|
CASE
|
||||||
|
WHEN cl.credit_limit > 0 THEN ROUND(cl.used_credit / cl.credit_limit * 100, 1)
|
||||||
|
ELSE 0
|
||||||
|
END as usage_pct
|
||||||
|
FROM credit_limit cl
|
||||||
|
LEFT JOIN organization org ON cl.orgid = org.id
|
||||||
|
LEFT JOIN account acc ON cl.accountid = acc.id
|
||||||
|
LEFT JOIN subject sub ON acc.subjectid = sub.id
|
||||||
|
WHERE cl.orgid = ${orgid}$
|
||||||
|
ORDER BY cl.created_at DESC
|
||||||
|
"""
|
||||||
|
recs = await sor.sqlExe(sql, {'orgid': orgid})
|
||||||
|
return recs
|
||||||
|
|
||||||
|
|
||||||
|
async def get_all_customer_credits(sor, orgid, status_filter=None):
|
||||||
|
"""
|
||||||
|
Get all customer credit limits for management view.
|
||||||
|
For distributor sales to see all their customers' credit status.
|
||||||
|
"""
|
||||||
|
where_clause = "WHERE cl.orgid = ${orgid}$"
|
||||||
|
params = {'orgid': orgid}
|
||||||
|
if status_filter and status_filter != 'all':
|
||||||
|
where_clause += " AND cl.status = ${status}$"
|
||||||
|
params['status'] = status_filter
|
||||||
|
|
||||||
|
sql = f"""
|
||||||
|
SELECT
|
||||||
|
cl.*,
|
||||||
|
org.orgname as orgname_text,
|
||||||
|
sub.name as subject_name,
|
||||||
|
acc.balance as account_balance,
|
||||||
|
CASE
|
||||||
|
WHEN cl.credit_limit > 0 THEN ROUND(cl.used_credit / cl.credit_limit * 100, 1)
|
||||||
|
ELSE 0
|
||||||
|
END as usage_pct
|
||||||
|
FROM credit_limit cl
|
||||||
|
LEFT JOIN organization org ON cl.orgid = org.id
|
||||||
|
LEFT JOIN account acc ON cl.accountid = acc.id
|
||||||
|
LEFT JOIN subject sub ON acc.subjectid = sub.id
|
||||||
|
{where_clause}
|
||||||
|
ORDER BY cl.updated_at DESC
|
||||||
|
"""
|
||||||
|
recs = await sor.sqlExe(sql, params)
|
||||||
|
return recs
|
||||||
|
|
||||||
|
|
||||||
async def get_credit_limit_for_account(sor, accid):
|
async def get_credit_limit_for_account(sor, accid):
|
||||||
"""
|
"""
|
||||||
Get active credit limit for an account.
|
Get active credit limit for an account.
|
||||||
@ -52,8 +149,6 @@ async def set_credit_limit(sor, accountid, orgid, credit_limit_amount,
|
|||||||
Set or update credit limit for an account.
|
Set or update credit limit for an account.
|
||||||
If a credit limit already exists, update it; otherwise create new.
|
If a credit limit already exists, update it; otherwise create new.
|
||||||
"""
|
"""
|
||||||
from appPublic.uniqueID import getID
|
|
||||||
|
|
||||||
# Check if credit limit exists
|
# Check if credit limit exists
|
||||||
existing = await get_credit_limit_for_account(sor, accountid)
|
existing = await get_credit_limit_for_account(sor, accountid)
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ from .getaccount import getAccountBalance, getCustomerBalance, getAccountByName,
|
|||||||
from .stats import get_accounting_stats
|
from .stats import get_accounting_stats
|
||||||
from .recharge import RechargeBiz, recharge_accounting
|
from .recharge import RechargeBiz, recharge_accounting
|
||||||
from .consume import consume_accounting
|
from .consume import consume_accounting
|
||||||
from .creditlimit import get_credit_limit_for_account, update_used_credit, set_credit_limit
|
from .creditlimit import get_credit_limit_for_account, update_used_credit, set_credit_limit, get_credit_stats, get_my_credit_list, get_all_customer_credits
|
||||||
|
|
||||||
async def all_my_accounts(request):
|
async def all_my_accounts(request):
|
||||||
env = request._run_ns
|
env = request._run_ns
|
||||||
@ -77,3 +77,34 @@ def load_accounting():
|
|||||||
g.get_credit_limit_for_account = get_credit_limit_for_account
|
g.get_credit_limit_for_account = get_credit_limit_for_account
|
||||||
g.update_used_credit = update_used_credit
|
g.update_used_credit = update_used_credit
|
||||||
g.set_credit_limit = set_credit_limit
|
g.set_credit_limit = set_credit_limit
|
||||||
|
g.get_credit_stats = get_credit_stats
|
||||||
|
g.get_my_credit_list = get_my_credit_list
|
||||||
|
g.get_all_customer_credits = get_all_customer_credits
|
||||||
|
g.get_credit_stats_web = get_credit_stats_web
|
||||||
|
g.get_my_credits_web = get_my_credits_web
|
||||||
|
g.get_all_credits_web = get_all_credits_web
|
||||||
|
|
||||||
|
|
||||||
|
async def get_credit_stats_web(request):
|
||||||
|
"""Web wrapper for get_credit_stats - used in Jinja2 .ui templates"""
|
||||||
|
env = request._run_ns
|
||||||
|
userorgid = await env.get_userorgid()
|
||||||
|
async with get_sor_context(env, 'accounting') as sor:
|
||||||
|
return await get_credit_stats(sor, userorgid)
|
||||||
|
|
||||||
|
|
||||||
|
async def get_my_credits_web(request):
|
||||||
|
"""Web wrapper for get_my_credit_list - used in Jinja2 .ui templates"""
|
||||||
|
env = request._run_ns
|
||||||
|
userorgid = await env.get_userorgid()
|
||||||
|
async with get_sor_context(env, 'accounting') as sor:
|
||||||
|
return await get_my_credit_list(sor, userorgid)
|
||||||
|
|
||||||
|
|
||||||
|
async def get_all_credits_web(request):
|
||||||
|
"""Web wrapper for get_all_customer_credits - used in Jinja2 .ui templates"""
|
||||||
|
env = request._run_ns
|
||||||
|
userorgid = await env.get_userorgid()
|
||||||
|
status_filter = getattr(request, '_params_kw', {}).get('status', None) if hasattr(request, '_params_kw') else None
|
||||||
|
async with get_sor_context(env, 'accounting') as sor:
|
||||||
|
return await get_all_customer_credits(sor, userorgid, status_filter)
|
||||||
|
|||||||
43
wwwroot/credit_limit/api/credit_summary.dspy
Normal file
43
wwwroot/credit_limit/api/credit_summary.dspy
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
|
||||||
|
orgid = await get_userorgid()
|
||||||
|
|
||||||
|
db = DBPools()
|
||||||
|
dbname = get_module_dbname('accounting')
|
||||||
|
async with db.sqlorContext(dbname) as sor:
|
||||||
|
sql = """
|
||||||
|
SELECT
|
||||||
|
COALESCE(SUM(credit_limit), 0) as total_credit,
|
||||||
|
COALESCE(SUM(used_credit), 0) as total_used,
|
||||||
|
COALESCE(SUM(available_credit), 0) as total_available,
|
||||||
|
COUNT(*) as customer_count,
|
||||||
|
COUNT(CASE WHEN status = 'active' THEN 1 END) as active_count,
|
||||||
|
COUNT(CASE WHEN status = 'expired' THEN 1 END) as expired_count
|
||||||
|
FROM credit_limit
|
||||||
|
WHERE orgid = ${orgid}$
|
||||||
|
"""
|
||||||
|
recs = await sor.sqlExe(sql, {'orgid': orgid})
|
||||||
|
if recs and len(recs) > 0:
|
||||||
|
r = recs[0]
|
||||||
|
total_credit = float(r.total_credit or 0)
|
||||||
|
total_used = float(r.total_used or 0)
|
||||||
|
total_available = float(r.total_available or 0)
|
||||||
|
usage_pct = round((total_used / total_credit * 100), 1) if total_credit > 0 else 0
|
||||||
|
return json.dumps({
|
||||||
|
"status": "ok",
|
||||||
|
"data": {
|
||||||
|
"total_credit": total_credit,
|
||||||
|
"total_used": total_used,
|
||||||
|
"total_available": total_available,
|
||||||
|
"usage_pct": usage_pct,
|
||||||
|
"customer_count": int(r.customer_count or 0),
|
||||||
|
"active_count": int(r.active_count or 0),
|
||||||
|
"expired_count": int(r.expired_count or 0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return json.dumps({
|
||||||
|
"status": "ok",
|
||||||
|
"data": {
|
||||||
|
"total_credit": 0, "total_used": 0, "total_available": 0,
|
||||||
|
"usage_pct": 0, "customer_count": 0, "active_count": 0, "expired_count": 0
|
||||||
|
}
|
||||||
|
})
|
||||||
63
wwwroot/credit_limit/api/set_credit_form.ui
Normal file
63
wwwroot/credit_limit/api/set_credit_form.ui
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"widgettype": "Form",
|
||||||
|
"options": {
|
||||||
|
"width": "100%",
|
||||||
|
"padding": "16px",
|
||||||
|
"url": "{{entire_url('/accounting/credit_limit/api/set_customer_credit.dspy')}}",
|
||||||
|
"method": "POST",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"label": "id",
|
||||||
|
"uitype": "hidden",
|
||||||
|
"value": "{{params_kw.get('id', '')}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "accountid",
|
||||||
|
"label": "账户ID",
|
||||||
|
"uitype": "str",
|
||||||
|
"required": true,
|
||||||
|
"value": "{{params_kw.get('accountid', '')}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "credit_limit",
|
||||||
|
"label": "授信额度",
|
||||||
|
"uitype": "float",
|
||||||
|
"required": true,
|
||||||
|
"value": "{{params_kw.get('credit_limit', '0')}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "valid_from",
|
||||||
|
"label": "生效日期",
|
||||||
|
"uitype": "date",
|
||||||
|
"value": "{{params_kw.get('valid_from', '')}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "valid_to",
|
||||||
|
"label": "失效日期",
|
||||||
|
"uitype": "date",
|
||||||
|
"value": "{{params_kw.get('valid_to', '')}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "remark",
|
||||||
|
"label": "备注",
|
||||||
|
"uitype": "str",
|
||||||
|
"value": "{{params_kw.get('remark', '')}}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"buttons": [
|
||||||
|
{
|
||||||
|
"label": "保存",
|
||||||
|
"actiontype": "submit",
|
||||||
|
"bgcolor": "#3B82F6",
|
||||||
|
"color": "#FFFFFF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "取消",
|
||||||
|
"actiontype": "close",
|
||||||
|
"bgcolor": "#475569",
|
||||||
|
"color": "#FFFFFF"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
105
wwwroot/credit_limit/api/set_customer_credit.dspy
Normal file
105
wwwroot/credit_limit/api/set_customer_credit.dspy
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
|
||||||
|
ns = params_kw.copy()
|
||||||
|
for k, v in ns.items():
|
||||||
|
if v == 'NaN' or v == 'null' or v == '':
|
||||||
|
ns[k] = None
|
||||||
|
|
||||||
|
accountid = ns.get('accountid')
|
||||||
|
if not accountid:
|
||||||
|
return {
|
||||||
|
"widgettype": "Error",
|
||||||
|
"options": {
|
||||||
|
"title": "参数错误",
|
||||||
|
"cwidth": 16,
|
||||||
|
"cheight": 9,
|
||||||
|
"timeout": 3,
|
||||||
|
"message": "账户ID不能为空"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
credit_limit_amount = float(ns.get('credit_limit', 0) or 0)
|
||||||
|
if credit_limit_amount <= 0:
|
||||||
|
return {
|
||||||
|
"widgettype": "Error",
|
||||||
|
"options": {
|
||||||
|
"title": "参数错误",
|
||||||
|
"cwidth": 16,
|
||||||
|
"cheight": 9,
|
||||||
|
"timeout": 3,
|
||||||
|
"message": "授信额度必须大于0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
valid_from = ns.get('valid_from')
|
||||||
|
valid_to = ns.get('valid_to')
|
||||||
|
remark = ns.get('remark')
|
||||||
|
record_id = ns.get('id')
|
||||||
|
|
||||||
|
user_id = await get_user()
|
||||||
|
orgid = await get_userorgid()
|
||||||
|
|
||||||
|
db = DBPools()
|
||||||
|
dbname = get_module_dbname('accounting')
|
||||||
|
async with db.sqlorContext(dbname) as sor:
|
||||||
|
if record_id:
|
||||||
|
sql = """
|
||||||
|
UPDATE credit_limit
|
||||||
|
SET credit_limit = ${credit_limit}$,
|
||||||
|
available_credit = ${credit_limit}$ - used_credit,
|
||||||
|
valid_from = ${valid_from}$,
|
||||||
|
valid_to = ${valid_to}$,
|
||||||
|
remark = ${remark}$,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ${id}$ AND orgid = ${orgid}$
|
||||||
|
"""
|
||||||
|
await sor.sqlExe(sql, {
|
||||||
|
'credit_limit': credit_limit_amount,
|
||||||
|
'valid_from': valid_from,
|
||||||
|
'valid_to': valid_to,
|
||||||
|
'remark': remark,
|
||||||
|
'id': record_id,
|
||||||
|
'orgid': orgid
|
||||||
|
})
|
||||||
|
debug(f'Updated credit limit {record_id} to {credit_limit_amount}')
|
||||||
|
else:
|
||||||
|
new_id = uuid()
|
||||||
|
now = datetime.now()
|
||||||
|
data = {
|
||||||
|
'id': new_id,
|
||||||
|
'accountid': accountid,
|
||||||
|
'orgid': orgid,
|
||||||
|
'credit_limit': credit_limit_amount,
|
||||||
|
'used_credit': 0,
|
||||||
|
'available_credit': credit_limit_amount,
|
||||||
|
'valid_from': valid_from,
|
||||||
|
'valid_to': valid_to,
|
||||||
|
'status': 'active',
|
||||||
|
'created_at': now,
|
||||||
|
'updated_at': now,
|
||||||
|
'created_by': user_id,
|
||||||
|
'remark': remark
|
||||||
|
}
|
||||||
|
await sor.C('credit_limit', data)
|
||||||
|
debug(f'Created credit limit for {accountid}: {credit_limit_amount}')
|
||||||
|
|
||||||
|
return {
|
||||||
|
"widgettype": "Message",
|
||||||
|
"options": {
|
||||||
|
"cwidth": 16,
|
||||||
|
"cheight": 9,
|
||||||
|
"title": "授信额度设置成功",
|
||||||
|
"timeout": 3,
|
||||||
|
"message": "ok"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
"widgettype": "Error",
|
||||||
|
"options": {
|
||||||
|
"title": "设置失败",
|
||||||
|
"cwidth": 16,
|
||||||
|
"cheight": 9,
|
||||||
|
"timeout": 3,
|
||||||
|
"message": "failed"
|
||||||
|
}
|
||||||
|
}
|
||||||
276
wwwroot/credit_limit/credit_manage.ui
Normal file
276
wwwroot/credit_limit/credit_manage.ui
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
{% set credits = get_all_credits_web(request) %}
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {
|
||||||
|
"width": "100%",
|
||||||
|
"gap": "12px",
|
||||||
|
"padding": "4px"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {
|
||||||
|
"alignItems": "center",
|
||||||
|
"justifyContent": "space-between"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "客户额度管理 (共{{credits|length}}条)",
|
||||||
|
"fontSize": "16px",
|
||||||
|
"fontWeight": "600",
|
||||||
|
"color": "#F1F5F9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Button",
|
||||||
|
"options": {
|
||||||
|
"label": "新增授信",
|
||||||
|
"bgcolor": "#3B82F6",
|
||||||
|
"color": "#FFFFFF",
|
||||||
|
"borderRadius": "6px",
|
||||||
|
"padding": "6px 14px"
|
||||||
|
},
|
||||||
|
"binds": [{
|
||||||
|
"wid": "self",
|
||||||
|
"event": "click",
|
||||||
|
"actiontype": "urlwidget",
|
||||||
|
"target": "PopupWindow",
|
||||||
|
"popup_options": {
|
||||||
|
"title": "新增客户授信",
|
||||||
|
"width": "480px",
|
||||||
|
"height": "520px"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"url": "{{entire_url('/accounting/credit_limit/api/set_credit_form.ui')}}"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {
|
||||||
|
"bgcolor": "#1E293B",
|
||||||
|
"borderRadius": "10px",
|
||||||
|
"border": "1px solid #334155",
|
||||||
|
"width": "100%"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {
|
||||||
|
"bgcolor": "#0F172A",
|
||||||
|
"padding": "10px 16px",
|
||||||
|
"borderRadius": "10px 10px 0 0",
|
||||||
|
"alignItems": "center"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": "客户名称", "fontSize": "12px", "fontWeight": "600", "color": "#94A3B8", "cwidth": 10}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": "授信额度", "fontSize": "12px", "fontWeight": "600", "color": "#94A3B8", "cwidth": 8}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": "已用/剩余", "fontSize": "12px", "fontWeight": "600", "color": "#94A3B8", "cwidth": 10}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": "使用率", "fontSize": "12px", "fontWeight": "600", "color": "#94A3B8", "cwidth": 6}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": "状态", "fontSize": "12px", "fontWeight": "600", "color": "#94A3B8", "cwidth": 4}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": "操作", "fontSize": "12px", "fontWeight": "600", "color": "#94A3B8", "cwidth": 6}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{% if credits|length == 0 %}
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {
|
||||||
|
"padding": "30px",
|
||||||
|
"alignItems": "center"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "暂无客户授信记录",
|
||||||
|
"fontSize": "14px",
|
||||||
|
"color": "#64748B"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{% else %}
|
||||||
|
{% for c in credits %}
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {
|
||||||
|
"padding": "12px 16px",
|
||||||
|
"alignItems": "center",
|
||||||
|
"border": "0 0 1px 0",
|
||||||
|
"borderColor": "#334155"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {"cwidth": 10, "gap": "2px"},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "{{c.orgname_text or c.accountid}}",
|
||||||
|
"fontSize": "13px",
|
||||||
|
"fontWeight": "500",
|
||||||
|
"color": "#F1F5F9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "{{c.subject_name or ''}}",
|
||||||
|
"fontSize": "11px",
|
||||||
|
"color": "#64748B"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "¥{{'%.2f' % c.credit_limit}}",
|
||||||
|
"fontSize": "13px",
|
||||||
|
"fontWeight": "600",
|
||||||
|
"color": "#3B82F6",
|
||||||
|
"cwidth": 8
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {"cwidth": 10, "gap": "2px"},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "已用 ¥{{'%.2f' % c.used_credit}}",
|
||||||
|
"fontSize": "12px",
|
||||||
|
"color": "#F59E0B"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "剩余 ¥{{'%.2f' % c.available_credit}}",
|
||||||
|
"fontSize": "12px",
|
||||||
|
"color": "#22C55E"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {"cwidth": 6, "alignItems": "center", "gap": "4px"},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {
|
||||||
|
"bgcolor": "#334155",
|
||||||
|
"borderRadius": "3px",
|
||||||
|
"height": "6px",
|
||||||
|
"width": "50px"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {
|
||||||
|
"bgcolor": "{{'#22C55E' if c.usage_pct < 60 else ('#F59E0B' if c.usage_pct < 85 else '#EF4444')}}",
|
||||||
|
"borderRadius": "3px",
|
||||||
|
"height": "6px",
|
||||||
|
"width": "{{c.usage_pct}}%"
|
||||||
|
},
|
||||||
|
"subwidgets": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "{{c.usage_pct}}%",
|
||||||
|
"fontSize": "11px",
|
||||||
|
"color": "{{'#22C55E' if c.usage_pct < 60 else ('#F59E0B' if c.usage_pct < 85 else '#EF4444')}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {"cwidth": 4},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "{{'生效' if c.status == 'active' else ('停用' if c.status == 'inactive' else '过期')}}",
|
||||||
|
"fontSize": "11px",
|
||||||
|
"fontWeight": "600",
|
||||||
|
"color": "{{'#22C55E' if c.status == 'active' else '#EF4444'}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {"cwidth": 6, "gap": "4px"},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Button",
|
||||||
|
"options": {
|
||||||
|
"label": "调整",
|
||||||
|
"bgcolor": "#475569",
|
||||||
|
"color": "#FFFFFF",
|
||||||
|
"borderRadius": "4px",
|
||||||
|
"padding": "4px 8px",
|
||||||
|
"fontSize": "11px"
|
||||||
|
},
|
||||||
|
"binds": [{
|
||||||
|
"wid": "self",
|
||||||
|
"event": "click",
|
||||||
|
"actiontype": "urlwidget",
|
||||||
|
"target": "PopupWindow",
|
||||||
|
"popup_options": {
|
||||||
|
"title": "调整授信额度",
|
||||||
|
"width": "480px",
|
||||||
|
"height": "520px"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"url": "{{entire_url('/accounting/credit_limit/api/set_credit_form.ui')}}",
|
||||||
|
"params_kw": {
|
||||||
|
"id": "{{c.id}}",
|
||||||
|
"accountid": "{{c.accountid}}",
|
||||||
|
"credit_limit": "{{c.credit_limit}}",
|
||||||
|
"valid_from": "{{c.valid_from or ''}}",
|
||||||
|
"valid_to": "{{c.valid_to or ''}}",
|
||||||
|
"remark": "{{c.remark or ''}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}{% if not loop.last %},{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
289
wwwroot/credit_limit/credit_overview.ui
Normal file
289
wwwroot/credit_limit/credit_overview.ui
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
{% set credits = get_my_credits_web(request) %}
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {
|
||||||
|
"width": "100%",
|
||||||
|
"gap": "12px",
|
||||||
|
"padding": "4px"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{% if credits|length == 0 %}
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {
|
||||||
|
"bgcolor": "#1E293B",
|
||||||
|
"padding": "40px",
|
||||||
|
"borderRadius": "10px",
|
||||||
|
"border": "1px solid #334155",
|
||||||
|
"alignItems": "center"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "暂无信用额度记录",
|
||||||
|
"fontSize": "16px",
|
||||||
|
"color": "#94A3B8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "请联系您的分销商销售人员为您设置信用额度",
|
||||||
|
"fontSize": "13px",
|
||||||
|
"color": "#64748B",
|
||||||
|
"marginTop": "8px"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{% else %}
|
||||||
|
{% for c in credits %}
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {
|
||||||
|
"bgcolor": "#1E293B",
|
||||||
|
"padding": "16px",
|
||||||
|
"borderRadius": "10px",
|
||||||
|
"border": "1px solid #334155",
|
||||||
|
"gap": "12px"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {
|
||||||
|
"alignItems": "center",
|
||||||
|
"justifyContent": "space-between"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {"gap": "2px"},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "{{c.orgname_text or '未知客户'}}",
|
||||||
|
"fontSize": "16px",
|
||||||
|
"fontWeight": "600",
|
||||||
|
"color": "#F1F5F9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "{{c.subject_name or ''}} | 账户: {{c.accountid}}",
|
||||||
|
"fontSize": "12px",
|
||||||
|
"color": "#64748B"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {
|
||||||
|
"bgcolor": "{{'#16A34A22' if c.status == 'active' else '#EF444422'}}",
|
||||||
|
"padding": "4px 12px",
|
||||||
|
"borderRadius": "12px"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "{{'生效' if c.status == 'active' else ('停用' if c.status == 'inactive' else '已过期')}}",
|
||||||
|
"fontSize": "12px",
|
||||||
|
"fontWeight": "600",
|
||||||
|
"color": "{{'#22C55E' if c.status == 'active' else '#EF4444'}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {
|
||||||
|
"gap": "12px",
|
||||||
|
"alignItems": "center"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {"flex": "1", "gap": "4px"},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {"justifyContent": "space-between"},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "额度使用",
|
||||||
|
"fontSize": "12px",
|
||||||
|
"color": "#94A3B8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "{{c.usage_pct}}%",
|
||||||
|
"fontSize": "12px",
|
||||||
|
"fontWeight": "600",
|
||||||
|
"color": "{{'#22C55E' if c.usage_pct < 60 else ('#F59E0B' if c.usage_pct < 85 else '#EF4444')}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {
|
||||||
|
"bgcolor": "#334155",
|
||||||
|
"borderRadius": "4px",
|
||||||
|
"height": "8px",
|
||||||
|
"width": "100%"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {
|
||||||
|
"bgcolor": "{{'#22C55E' if c.usage_pct < 60 else ('#F59E0B' if c.usage_pct < 85 else '#EF4444')}}",
|
||||||
|
"borderRadius": "4px",
|
||||||
|
"height": "8px",
|
||||||
|
"width": "{{c.usage_pct}}%"
|
||||||
|
},
|
||||||
|
"subwidgets": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {
|
||||||
|
"gap": "8px"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {
|
||||||
|
"flex": "1",
|
||||||
|
"bgcolor": "#0F172A",
|
||||||
|
"padding": "10px",
|
||||||
|
"borderRadius": "6px",
|
||||||
|
"alignItems": "center"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "¥{{'%.2f' % c.credit_limit}}",
|
||||||
|
"fontSize": "16px",
|
||||||
|
"fontWeight": "700",
|
||||||
|
"color": "#3B82F6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "授信额度",
|
||||||
|
"fontSize": "11px",
|
||||||
|
"color": "#64748B",
|
||||||
|
"marginTop": "2px"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {
|
||||||
|
"flex": "1",
|
||||||
|
"bgcolor": "#0F172A",
|
||||||
|
"padding": "10px",
|
||||||
|
"borderRadius": "6px",
|
||||||
|
"alignItems": "center"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "¥{{'%.2f' % c.used_credit}}",
|
||||||
|
"fontSize": "16px",
|
||||||
|
"fontWeight": "700",
|
||||||
|
"color": "#F59E0B"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "已用额度",
|
||||||
|
"fontSize": "11px",
|
||||||
|
"color": "#64748B",
|
||||||
|
"marginTop": "2px"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {
|
||||||
|
"flex": "1",
|
||||||
|
"bgcolor": "#0F172A",
|
||||||
|
"padding": "10px",
|
||||||
|
"borderRadius": "6px",
|
||||||
|
"alignItems": "center"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "¥{{'%.2f' % c.available_credit}}",
|
||||||
|
"fontSize": "16px",
|
||||||
|
"fontWeight": "700",
|
||||||
|
"color": "#22C55E"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "剩余额度",
|
||||||
|
"fontSize": "11px",
|
||||||
|
"color": "#64748B",
|
||||||
|
"marginTop": "2px"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {
|
||||||
|
"justifyContent": "space-between"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "有效期: {{c.valid_from or '不限'}} ~ {{c.valid_to or '不限'}}",
|
||||||
|
"fontSize": "11px",
|
||||||
|
"color": "#64748B"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "更新于 {{c.updated_at}}",
|
||||||
|
"fontSize": "11px",
|
||||||
|
"color": "#475569"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}{% if not loop.last %},{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
]
|
||||||
|
}
|
||||||
301
wwwroot/credit_limit/hub.ui
Normal file
301
wwwroot/credit_limit/hub.ui
Normal file
@ -0,0 +1,301 @@
|
|||||||
|
{% set cstats = get_credit_stats_web(request) %}
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {
|
||||||
|
"width": "100%",
|
||||||
|
"height": "100%",
|
||||||
|
"padding": "16px",
|
||||||
|
"gap": "16px"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "信用额度管理",
|
||||||
|
"fontSize": "22px",
|
||||||
|
"fontWeight": "700",
|
||||||
|
"color": "#F1F5F9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "ResponsableBox",
|
||||||
|
"options": {
|
||||||
|
"gap": "12px",
|
||||||
|
"minWidth": "200px"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {
|
||||||
|
"bgcolor": "#1E293B",
|
||||||
|
"padding": "16px",
|
||||||
|
"borderRadius": "10px",
|
||||||
|
"border": "1px solid #334155",
|
||||||
|
"flex": "1",
|
||||||
|
"minHeight": "100px"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {
|
||||||
|
"alignItems": "center",
|
||||||
|
"marginBottom": "8px"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Svg",
|
||||||
|
"options": {
|
||||||
|
"svg": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#3B82F6\" stroke-width=\"2\"><path d=\"M12 2v20M17 5H9.5a3.5 3.5 0 000 7h5a3.5 3.5 0 010 7H6\"/></svg>",
|
||||||
|
"width": "20px",
|
||||||
|
"height": "20px"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{"widgettype": "Filler"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "¥{{'%.2f' % cstats.total_credit}}",
|
||||||
|
"fontSize": "26px",
|
||||||
|
"fontWeight": "700",
|
||||||
|
"color": "#3B82F6",
|
||||||
|
"lineHeight": "1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "授信总额度",
|
||||||
|
"fontSize": "13px",
|
||||||
|
"color": "#94A3B8",
|
||||||
|
"marginTop": "4px"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {
|
||||||
|
"bgcolor": "#1E293B",
|
||||||
|
"padding": "16px",
|
||||||
|
"borderRadius": "10px",
|
||||||
|
"border": "1px solid #334155",
|
||||||
|
"flex": "1",
|
||||||
|
"minHeight": "100px"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {
|
||||||
|
"alignItems": "center",
|
||||||
|
"marginBottom": "8px"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Svg",
|
||||||
|
"options": {
|
||||||
|
"svg": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#F59E0B\" stroke-width=\"2\"><path d=\"M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"/><path d=\"M9 12l2 2 4-4\"/></svg>",
|
||||||
|
"width": "20px",
|
||||||
|
"height": "20px"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{"widgettype": "Filler"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "¥{{'%.2f' % cstats.total_used}}",
|
||||||
|
"fontSize": "26px",
|
||||||
|
"fontWeight": "700",
|
||||||
|
"color": "#F59E0B",
|
||||||
|
"lineHeight": "1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "已用额度",
|
||||||
|
"fontSize": "13px",
|
||||||
|
"color": "#94A3B8",
|
||||||
|
"marginTop": "4px"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {
|
||||||
|
"bgcolor": "#1E293B",
|
||||||
|
"padding": "16px",
|
||||||
|
"borderRadius": "10px",
|
||||||
|
"border": "1px solid #334155",
|
||||||
|
"flex": "1",
|
||||||
|
"minHeight": "100px"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {
|
||||||
|
"alignItems": "center",
|
||||||
|
"marginBottom": "8px"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Svg",
|
||||||
|
"options": {
|
||||||
|
"svg": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#22C55E\" stroke-width=\"2\"><path d=\"M2.25 18.75a60.07 60.07 0 0115.797 2.101c.727.198 1.453-.342 1.453-1.096V18.75M3.75 4.5v.75A.75.75 0 013 6h-.75m0 0v-.375c0-.621.504-1.125 1.125-1.125H20.25c.621 0 1.125.504 1.125 1.125v8.25c0 .621-.504 1.125-1.125 1.125H3.375a.75.75 0 01-.75-.75V4.5\"/></svg>",
|
||||||
|
"width": "20px",
|
||||||
|
"height": "20px"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{"widgettype": "Filler"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "¥{{'%.2f' % cstats.total_available}}",
|
||||||
|
"fontSize": "26px",
|
||||||
|
"fontWeight": "700",
|
||||||
|
"color": "#22C55E",
|
||||||
|
"lineHeight": "1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "剩余额度",
|
||||||
|
"fontSize": "13px",
|
||||||
|
"color": "#94A3B8",
|
||||||
|
"marginTop": "4px"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {
|
||||||
|
"bgcolor": "#1E293B",
|
||||||
|
"padding": "16px",
|
||||||
|
"borderRadius": "10px",
|
||||||
|
"border": "1px solid #334155",
|
||||||
|
"flex": "1",
|
||||||
|
"minHeight": "100px"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {
|
||||||
|
"alignItems": "center",
|
||||||
|
"marginBottom": "8px"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Svg",
|
||||||
|
"options": {
|
||||||
|
"svg": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#A78BFA\" stroke-width=\"2\"><path d=\"M3 3v18h18\"/><path d=\"M18.7 8l-5.1 5.2-2.8-2.7L7 14.3\"/></svg>",
|
||||||
|
"width": "20px",
|
||||||
|
"height": "20px"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{"widgettype": "Filler"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "{{cstats.usage_pct}}%",
|
||||||
|
"fontSize": "26px",
|
||||||
|
"fontWeight": "700",
|
||||||
|
"color": "#A78BFA",
|
||||||
|
"lineHeight": "1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {
|
||||||
|
"text": "额度使用率 ({{cstats.active_count}}/{{cstats.customer_count}}户)",
|
||||||
|
"fontSize": "13px",
|
||||||
|
"color": "#94A3B8",
|
||||||
|
"marginTop": "4px"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {
|
||||||
|
"gap": "8px",
|
||||||
|
"alignItems": "center"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Button",
|
||||||
|
"options": {
|
||||||
|
"label": "我的额度",
|
||||||
|
"bgcolor": "#3B82F6",
|
||||||
|
"color": "#FFFFFF",
|
||||||
|
"borderRadius": "6px",
|
||||||
|
"padding": "8px 16px"
|
||||||
|
},
|
||||||
|
"binds": [{
|
||||||
|
"wid": "self",
|
||||||
|
"event": "click",
|
||||||
|
"actiontype": "urlwidget",
|
||||||
|
"target": "app.credit_content",
|
||||||
|
"options": {"url": "{{entire_url('/accounting/credit_limit/credit_overview.ui')}}"},
|
||||||
|
"mode": "replace"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Button",
|
||||||
|
"options": {
|
||||||
|
"label": "客户额度管理",
|
||||||
|
"bgcolor": "#475569",
|
||||||
|
"color": "#FFFFFF",
|
||||||
|
"borderRadius": "6px",
|
||||||
|
"padding": "8px 16px"
|
||||||
|
},
|
||||||
|
"binds": [{
|
||||||
|
"wid": "self",
|
||||||
|
"event": "click",
|
||||||
|
"actiontype": "urlwidget",
|
||||||
|
"target": "app.credit_content",
|
||||||
|
"options": {"url": "{{entire_url('/accounting/credit_limit/credit_manage.ui')}}"},
|
||||||
|
"mode": "replace"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Button",
|
||||||
|
"options": {
|
||||||
|
"label": "全部客户查询",
|
||||||
|
"bgcolor": "#475569",
|
||||||
|
"color": "#FFFFFF",
|
||||||
|
"borderRadius": "6px",
|
||||||
|
"padding": "8px 16px"
|
||||||
|
},
|
||||||
|
"binds": [{
|
||||||
|
"wid": "self",
|
||||||
|
"event": "click",
|
||||||
|
"actiontype": "urlwidget",
|
||||||
|
"target": "app.credit_content",
|
||||||
|
"options": {"url": "{{entire_url('/accounting/credit_limit/index.ui')}}"},
|
||||||
|
"mode": "replace"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"id": "credit_content",
|
||||||
|
"options": {
|
||||||
|
"width": "100%",
|
||||||
|
"flex": "1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user