feat: 独立产品折扣设置页面(全量产品列表+行内upsert)

This commit is contained in:
Hermes Agent 2026-06-24 20:42:36 +08:00
parent b2691fe02a
commit 29578196a1
5 changed files with 214 additions and 2 deletions

View File

@ -32,8 +32,8 @@
"subtables": [
{
"field": "discountid",
"title": "折扣产品明细",
"subtable": "discount_detail_list"
"title": "设置产品折扣",
"subtable": "discount_setting"
}
]
}

View File

@ -0,0 +1,44 @@
# 获取用户机构的所有产品及其折扣信息
# 用于折扣明细设置页面
ns = params_kw.copy()
discountid = ns.get('discountid')
if not discountid:
return {"total": 0, "rows": []}
user_orgid = await get_userorgid()
if not user_orgid:
return {"total": 0, "rows": []}
if not ns.get('page'):
ns['page'] = 1
if not ns.get('sort'):
ns['sort'] = 'category_id, product_name'
# 查询用户机构的所有产品LEFT JOIN折扣明细
sql = '''
SELECT
p.id as productid,
p.product_name,
p.product_code,
p.category_id,
pc.name as category_name,
COALESCE(dd.id, '') as detail_id,
COALESCE(dd.discount, 0) as discount
FROM product p
LEFT JOIN product_category pc ON p.category_id = pc.id
LEFT JOIN discount_detail dd ON dd.productid = p.id AND dd.discountid = ${discountid}$
WHERE p.org_id = ${org_id}$ AND p.status = '1'
ORDER BY p.category_id, p.product_name
'''
ns['org_id'] = user_orgid
ns['discountid'] = discountid
db = DBPools()
dbname = get_module_dbname('discount')
async with db.sqlorContext(dbname) as sor:
r = await sor.sqlPaging(sql, ns)
debug(f'get_product_discount_list: {len(r.get("rows", []))} products')
return r

View File

@ -0,0 +1,43 @@
# 查询用户所在机构的所有产品及其折扣信息
# 参数: discountid (必需)
discountid = params_kw.get('discountid')
if not discountid:
return {"total": 0, "rows": []}
user_orgid = await get_userorgid()
if not user_orgid:
return {"total": 0, "rows": []}
ns = params_kw.copy()
if not ns.get('page'):
ns['page'] = 1
if not ns.get('sort'):
ns['sort'] = 'category_name, product_name'
sql = '''
SELECT
p.id as productid,
p.product_code,
p.product_name,
p.category_id,
pc.name as category_name,
dd.id as detail_id,
dd.discount,
dd.discountid
FROM product p
LEFT JOIN product_category pc ON p.category_id = pc.id
LEFT JOIN discount_detail dd ON dd.productid = p.id
AND dd.discountid = ${discountid}$
WHERE p.org_id = ${org_id}$ AND p.status = '1'
ORDER BY pc.name, p.product_name
'''
ns['org_id'] = user_orgid
db = DBPools()
dbname = get_module_dbname('discount')
async with db.sqlorContext(dbname) as sor:
r = await sor.sqlPaging(sql, ns)
debug(f'get_products_with_discount: {len(r.get("rows", []))} products for org {user_orgid}')
return r

View File

@ -0,0 +1,71 @@
{
"widgettype": "VBox",
"options": {"height": "100%", "width": "100%"},
"subwidgets": [
{
"id": "product_discount_tbl",
"widgettype": "Tabular",
"options": {
"width": "100%",
"height": "100%",
"title": "产品折扣设置",
"description": "选中产品后点击工具栏按钮设置折扣",
"css": "card",
"toolbar": {
"tools": [
{
"name": "set_discount",
"label": "设置折扣",
"selected_row": true,
"icon": "{{entire_url('/bricks/imgs/edit.svg')}}"
}
]
},
"data_url": "{{entire_url('./get_products_with_discount.dspy')}}",
"data_method": "GET",
"data_params": {},
"row_options": {
"idField": "productid",
"checkField": "checked",
"fields": [
{
"name": "category_name",
"title": "产品分类",
"type": "str",
"cwidth": 2
},
{
"name": "product_name",
"title": "产品名称",
"type": "str",
"cwidth": 4
},
{
"name": "product_code",
"title": "产品编码",
"type": "str",
"cwidth": 3
},
{
"name": "discount",
"title": "当前折扣",
"type": "float",
"cwidth": 2
}
]
},
"page_rows": 100,
"cache_limit": 5
},
"binds": [
{
"wid": "set_discount",
"event": "click",
"actiontype": "script",
"target": "self",
"script": "var dv = bricks.getWidgetById('product_discount_tbl', bricks.app.root); if (!dv || !dv.select_row || !dv.select_row.user_data) { alert('请先选中一个产品'); return; } var row = dv.select_row.user_data; var discountid = new URLSearchParams(window.location.search).get('discountid') || ''; var mf = new bricks.ModalForm({title: '设置折扣 - ' + row.product_name, width: '400px', auto_open: true, fields: [{name: 'discountid', uitype: 'hide', value: discountid}, {name: 'productid', uitype: 'hide', value: row.productid}, {name: 'category_id', uitype: 'hide', value: row.category_id}, {name: 'detail_id', uitype: 'hide', value: row.detail_id || ''}, {name: 'product_name', label: '产品', uitype: 'text', value: row.product_name}, {name: 'category_name', label: '分类', uitype: 'text', value: row.category_name}, {name: 'discount', label: '折扣(0-1)', uitype: 'float', value: row.discount || '', tip: '0到1之间如0.8表示8折留空或0表示清除折扣'}], submit_url: '{{entire_url(\"./save_discount.dspy\")}}'}); mf.bind('submited', async function(params) { await bricks.show_resp_message_or_error(params); await dv.render({}); });"
}
]
}
]
}

View File

@ -0,0 +1,54 @@
# Upsert折扣明细有detail_id则更新无则新增
# 参数: discountid, productid, category_id, discount, detail_id(可选)
result = {'widgettype': 'Message', 'options': {'title': 'Error', 'message': 'Invalid', 'type': 'error'}}
try:
discountid = params_kw.get('discountid')
productid = params_kw.get('productid')
category_id = params_kw.get('category_id')
discount_val = params_kw.get('discount')
detail_id = params_kw.get('detail_id')
if not discountid or not productid:
raise Exception('缺少必要参数: discountid, productid')
# discount为0或空时如果已有记录则删除
if not discount_val or float(discount_val) == 0:
if detail_id:
dbname = get_module_dbname('discount')
async with DBPools().sqlorContext(dbname) as sor:
await sor.D('discount_detail', {'id': detail_id})
result = {'widgettype': 'Message', 'options': {'title': 'Success', 'message': '折扣已清除', 'type': 'success'}}
else:
result = {'widgettype': 'Message', 'options': {'title': 'Success', 'message': 'ok', 'type': 'success'}}
return result
dbname = get_module_dbname('discount')
user_orgid = await get_userorgid()
async with DBPools().sqlorContext(dbname) as sor:
if detail_id:
# 更新
await sor.U('discount_detail', {
'id': detail_id,
'discount': float(discount_val)
})
else:
# 新增
await sor.C('discount_detail', {
'id': uuid(),
'discountid': discountid,
'resellerid': user_orgid,
'prodtypeid': category_id,
'productid': productid,
'discount': float(discount_val)
})
result = {'widgettype': 'Message', 'options': {'title': 'Success', 'message': '折扣保存成功', 'type': 'success'}}
except Exception as e:
debug(f'save_discount error: {e}')
result['options'] = {'title': 'Error', 'message': f'保存失败: {str(e)}', 'type': 'error'}
return result