feat: add admin + reset admin password toolbar for sub_distributors

- api/add_sub_distributor_admin.dspy: create org+user+reseller.admin role, show password
- api/reset_sub_distributor_admin_pwd.dspy: reset admin password, show new password
- sub_distributors_list: add toolbar buttons with popup binds
This commit is contained in:
yumoqing 2026-07-10 12:15:31 +08:00
parent efe45215f0
commit 916b501c67
3 changed files with 161 additions and 0 deletions

View File

@ -0,0 +1,76 @@
"""Create an admin user for the selected sub_distributor. Show the initial password."""
sub_distributor_id = params_kw.get('sub_distributor_id') or params_kw.get('id')
if not sub_distributor_id:
return {'widgettype': 'Error', 'options': {'title': 'Error', 'message': 'Missing sub_distributor_id', 'timeout': 3}}
userorgid = await get_userorgid()
if not userorgid:
return {'widgettype': 'Error', 'options': {'title': 'Auth Error', 'message': 'Please login', 'timeout': 3}}
dbname = get_module_dbname('supplychain')
async with DBPools().sqlorContext(dbname) as sor:
recs = await sor.sqlExe(
'SELECT id, sub_dist_name FROM sub_distributors WHERE id = ${sid}$',
{'sid': sub_distributor_id}
)
if not recs:
return {'widgettype': 'Error', 'options': {'title': 'Error', 'message': '二级分销商不存在', 'timeout': 3}}
sd = recs[0]
org_id = sd.id
admin_username = f'admin_{sub_distributor_id[:8]}'
async with DBPools().sqlorContext('sage') as sor_sage:
# Check/ensure org exists
org_recs = await sor_sage.sqlExe(
'SELECT id FROM organization WHERE id = ${oid}$', {'oid': org_id}
)
if not org_recs:
now = timestampstr()
await sor_sage.C('organization', {
'id': org_id, 'orgname': sd.sub_dist_name, 'create_at': now,
})
# Check if admin already exists
user_recs = await sor_sage.sqlExe(
'SELECT id FROM users WHERE username = ${un}$', {'un': admin_username}
)
if user_recs:
return {
'widgettype': 'Message',
'options': {
'title': '管理员已存在',
'message': f'管理员 {admin_username} 已存在,请用重置密码功能',
'type': 'warning', 'timeout': 5
}
}
# Generate password from uuid
pwd = getID().replace('-','')[:12]
now = timestampstr()
user_id = getID()
await sor_sage.C('users', {
'id': user_id, 'username': admin_username,
'password': password_encode(pwd),
'orgid': org_id, 'nick_name': sd.sub_dist_name + '管理员',
'user_status': '1', 'created_at': now,
})
# Assign reseller.admin role
role_recs = await sor_sage.sqlExe(
"SELECT id FROM role WHERE role = ${r}$", {'r': 'reseller.admin'}
)
if role_recs:
await sor_sage.C('userrole', {
'userid': user_id, 'roleid': role_recs[0].id,
})
return {
'widgettype': 'Message',
'options': {
'title': '管理员创建成功',
'message': f'用户名: {admin_username}\n初始密码: {pwd}\n请妥善保管登录后建议修改',
'type': 'success', 'timeout': 0
}
}

View File

@ -0,0 +1,35 @@
"""Reset the admin password for the selected sub_distributor."""
sub_distributor_id = params_kw.get('sub_distributor_id') or params_kw.get('id')
if not sub_distributor_id:
return {'widgettype': 'Error', 'options': {'title': 'Error', 'message': 'Missing sub_distributor_id', 'timeout': 3}}
admin_username = f'admin_{sub_distributor_id[:8]}'
new_pwd = getID().replace('-','')[:12]
async with DBPools().sqlorContext('sage') as sor:
recs = await sor.sqlExe(
'SELECT id FROM users WHERE username = ${un}$', {'un': admin_username}
)
if not recs:
return {
'widgettype': 'Message',
'options': {
'title': '管理员不存在',
'message': f'管理员 {admin_username} 不存在,请先创建',
'type': 'warning', 'timeout': 5
}
}
await sor.U('users', {
'id': recs[0].id,
'password': password_encode(new_pwd),
})
return {
'widgettype': 'Message',
'options': {
'title': '密码重置成功',
'message': f'用户名: {admin_username}\n新密码: {new_pwd}',
'type': 'success', 'timeout': 0
}
}

View File

@ -21,6 +21,18 @@
"name": "distribution_agreements",
"icon": "{{entire_url('/imgs/distribution_agreement_items.svg')}}",
"label": "分销协议"
},
{
"selected_row": true,
"name": "add_admin",
"icon": "{{entire_url('/imgs/userrole.svg')}}",
"label": "添加管理员"
},
{
"selected_row": true,
"name": "reset_admin_pwd",
"icon": "{{entire_url('/imgs/key.svg')}}",
"label": "重置管理员密码"
}
]
},
@ -336,6 +348,44 @@
"method": "POST",
"url": "{{entire_url('../api/ensure_distribution_agreement.dspy')}}"
}
},
{
"wid": "self",
"event": "add_admin",
"actiontype": "urlwidget",
"target": "PopupWindow",
"popup_options": {
"title": "添加管理员",
"height": "250px",
"width": "400px"
},
"params_mapping": {
"mapping": {"id": "sub_distributor_id"},
"need_other": false
},
"options": {
"method": "POST",
"url": "{{entire_url('../api/add_sub_distributor_admin.dspy')}}"
}
},
{
"wid": "self",
"event": "reset_admin_pwd",
"actiontype": "urlwidget",
"target": "PopupWindow",
"popup_options": {
"title": "重置管理员密码",
"height": "250px",
"width": "400px"
},
"params_mapping": {
"mapping": {"id": "sub_distributor_id"},
"need_other": false
},
"options": {
"method": "POST",
"url": "{{entire_url('../api/reset_sub_distributor_admin_pwd.dspy')}}"
}
}
]