product_management/wwwroot/storefront/api/purchase_confirm.dspy

175 lines
7.4 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 购买确认页:算价预览 + 余额显示 + 参数输入 + 确认支付
from ahserver.serverenv import ServerEnv
product_id = params_kw.get('product_id', '')
userid = await get_user()
result = {'widgettype': 'Text', 'options': {'text': '加载中...'}}
if not product_id:
result = {'widgettype': 'Text', 'options': {'text': '缺少产品ID', 'color': '#e74c3c'}}
elif not userid:
result = {'widgettype': 'Text', 'options': {'text': '请先登录后购买', 'color': '#e74c3c'}}
else:
userorgid = await get_userorgid()
dbname = get_module_dbname('product_management')
try:
async with DBPools().sqlorContext(dbname) as sor:
recs = await sor.sqlExe(
"SELECT * FROM product WHERE id=${id}$ AND status='1'",
{'id': product_id})
if not recs:
raise Exception('产品不存在或已下架')
p = recs[0]
product_type = getattr(p, 'product_type', '') or ''
# 余额
balance = None
try:
env = ServerEnv()
acc_dbname = env.get_module_dbname('accounting')
async with DBPools().sqlorContext(acc_dbname) as asor:
balance = await env.getCustomerBalance(asor, userorgid)
except Exception:
pass
rows = []
def _row(label, value, color='#333', bold=False):
return {
'widgettype': 'HBox',
'options': {'padding': '8px 0', 'gap': '8px'},
'subwidgets': [
{'widgettype': 'Text', 'options': {
'text': label, 'width': '90px', 'fontSize': '13px',
'color': '#666', 'fontWeight': '600' if bold else '400'}},
{'widgettype': 'Text', 'options': {
'text': str(value), 'fontSize': '13px', 'color': color,
'fontWeight': '700' if bold else '400'}}
]
}
rows.append(_row('产品名称', getattr(p, 'product_name', ''), '#222', True))
# 参数输入区(存储需容量+月数;账号走默认月租)
param_widgets = []
if product_type == 'workspace_storage':
param_widgets.append({
'widgettype': 'HBox',
'options': {'padding': '8px 0', 'gap': '8px', 'alignItems': 'center'},
'subwidgets': [
{'widgettype': 'Text', 'options': {
'text': '购买容量(GB)', 'width': '90px', 'fontSize': '13px', 'color': '#666'}},
{'widgettype': 'InputNumber', 'id': 'buy_storage_gb',
'options': {'value': 100, 'min': 1, 'step': 10, 'width': '120px'}}
]
})
param_widgets.append({
'widgettype': 'HBox',
'options': {'padding': '8px 0', 'gap': '8px', 'alignItems': 'center'},
'subwidgets': [
{'widgettype': 'Text', 'options': {
'text': '购买月数', 'width': '90px', 'fontSize': '13px', 'color': '#666'}},
{'widgettype': 'InputNumber', 'id': 'buy_valid_months',
'options': {'value': 1, 'min': 1, 'max': 12, 'step': 1, 'width': '120px'}}
]
})
rows.append(_row('计费方式', '按容量直购(元/GB月)', '#666'))
elif product_type == 'account':
rows.append(_row('计费方式', '订阅制(月/年/试用)', '#666'))
else:
rows.append(_row('计费方式', '按量计费', '#666'))
# 余额展示
if balance is None:
balance_text = '未开户'
balance_color = '#e67e22'
else:
balance_text = '¥ %.2f' % balance
balance_color = '#27ae60' if balance > 0 else '#e74c3c'
rows.append(_row('账户余额', balance_text, balance_color, True))
# 确认支付按钮:script+fetch 提交,确保读取输入框当前值
is_storage = (product_type == 'workspace_storage')
pay_script = (
"var pid='" + product_id + "';"
"var params=new URLSearchParams();"
"params.append('product_id',pid);"
)
if is_storage:
pay_script += (
"var gb=bricks.getWidgetById('buy_storage_gb');"
"var mo=bricks.getWidgetById('buy_valid_months');"
"var gbv=gb?gb.value:100; var mov=mo?mo.value:1;"
"if(!gbv||gbv<=0){alert('请输入购买容量');return;}"
"params.append('storage_gb',gbv);"
"params.append('valid_months',mov);"
)
pay_script += (
"var btn=this; btn.disabled=true;"
"fetch('/product_management/storefront/api/purchase_realtime.dspy',"
"{method:'POST',body:params}).then(function(r){return r.json()})"
".then(function(msg){btn.disabled=false;"
"if(msg.widgettype){bricks.widgetBuild(msg).then(function(w){if(w)w.open()})}"
"else{alert(msg.message||'支付完成')}})"
".catch(function(e){btn.disabled=false;alert('支付请求失败: '+e)})"
)
pay_btn = {
'widgettype': 'Button',
'options': {
'label': '确认支付',
'bgcolor': '#e74c3c',
'color': '#fff',
'padding': '10px 36px',
'borderRadius': '6px',
'fontWeight': '600',
'marginTop': '16px'
},
'binds': [{
'wid': 'self',
'event': 'click',
'actiontype': 'script',
'target': 'self',
'script': pay_script
}]
}
cancel_btn = {
'widgettype': 'Button',
'options': {
'label': '取消',
'bgcolor': '#f0f0f0',
'color': '#666',
'padding': '10px 24px',
'borderRadius': '6px',
'marginTop': '16px'
},
'binds': [{
'wid': 'self', 'event': 'click', 'actiontype': 'script',
'target': 'self', 'script': 'if(window.closePopup) closePopup()'
}]
}
result = {
'widgettype': 'VBox',
'options': {'width': '100%', 'padding': '16px'},
'subwidgets': [
{'widgettype': 'Title4', 'options': {'text': '确认购买', 'fontWeight': '700', 'marginBottom': '12px'}},
{'widgettype': 'VBox', 'options': {'gap': '0', 'marginBottom': '8px'}, 'subwidgets': rows},
{'widgettype': 'VBox', 'options': {'gap': '0', 'marginBottom': '8px'}, 'subwidgets': param_widgets},
{
'widgettype': 'Text',
'options': {
'text': '支付将从账户余额实时扣款并完成记账,购买成功后权益立即生效。',
'fontSize': '12px', 'color': '#999', 'marginTop': '8px'}
},
{'widgettype': 'HBox', 'options': {'gap': '12px', 'marginTop': '8px'},
'subwidgets': [pay_btn, cancel_btn]}
]
}
except Exception as e:
debug(f'purchase_confirm error: {format_exc()}')
result = {'widgettype': 'Text', 'options': {'text': str(e), 'color': '#e74c3c'}}
return json.dumps(result, ensure_ascii=False)