diff --git a/discount/init.py b/discount/init.py index e13f9fd..65bf13d 100644 --- a/discount/init.py +++ b/discount/init.py @@ -730,3 +730,44 @@ def load_discount(): env.bind_customer = bind_customer env.get_customer_bind = get_customer_bind env.assign_customer_to_sale = assign_customer_to_sale + # Discount setting products list + env.get_discount_setting_products = get_discount_setting_products + + +async def get_discount_setting_products(request): + """Get products with their discount details for discount_setting page. + Used in Jinja2 template: {% set products = get_discount_setting_products(request) %} + """ + env = request._run_ns + discountid = (getattr(request, '_params_kw', {}) or {}).get('discountid', '') + user_orgid = await env.get_userorgid() + + if not discountid or not user_orgid: + return [] + + dbname = env.get_module_dbname('discount') + db = DBPools() + config = getConfig() + db.databases = config.databases + + 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 + """ + + async with db.sqlorContext(dbname) as sor: + recs = await sor.sqlExe(sql, {'discountid': discountid, 'org_id': user_orgid}) + return recs if recs else [] diff --git a/scripts/load_path.py b/scripts/load_path.py index cd1eb40..5f0a8a7 100644 --- a/scripts/load_path.py +++ b/scripts/load_path.py @@ -95,7 +95,6 @@ for d in crud_defs: PATHS_ANY = [ f"/{MOD}/menu.ui", f"/{MOD}/discount_setting", - f"/{MOD}/discount_inline_edit.js", ] # 每个 CRUD 定义 → any 别名目录 + logined 页面和脚本 diff --git a/wwwroot/discount_inline_edit.js b/wwwroot/discount_inline_edit.js deleted file mode 100644 index d25b4c2..0000000 --- a/wwwroot/discount_inline_edit.js +++ /dev/null @@ -1,116 +0,0 @@ -/** - * Discount inline editor for discount_setting Tabular. - * Scans discount cells after render and enables click-to-edit. - */ -(function() { - var PROCESSED_CELLS = new WeakSet(); - var SETUP_INTERVAL = 300; - - function findTabular() { - if (typeof bricks === 'undefined') return null; - try { - return bricks.getWidgetById('product_discount_tbl', bricks.app.root); - } catch(e) { - return null; - } - } - - function setupCell(cell) { - if (PROCESSED_CELLS.has(cell)) return; - var text = cell.textContent.trim(); - if (text === '' || isNaN(parseFloat(text))) return; - PROCESSED_CELLS.add(cell); - - cell.style.cursor = 'pointer'; - cell.title = '点击编辑折扣'; - - cell.addEventListener('click', function(e) { - e.stopPropagation(); - if (cell.querySelector('input')) return; - - var oldVal = cell.textContent.trim(); - var inp = document.createElement('input'); - inp.type = 'number'; - inp.step = '0.01'; - inp.min = '0'; - inp.max = '1'; - inp.value = oldVal; - inp.style.cssText = 'width:100%;box-sizing:border-box;text-align:center;background:#1E293B;color:#F1F5F9;border:1px solid #3B82F6;border-radius:4px;padding:2px 4px;font-size:12px;'; - - cell.textContent = ''; - cell.appendChild(inp); - inp.focus(); - inp.select(); - - var saved = false; - var saveFn = async function() { - if (saved) return; - saved = true; - var newVal = inp.value.trim(); - inp.disabled = true; - - if (newVal === oldVal) { - cell.textContent = oldVal; - return; - } - - try { - var url = new URL(window.location.href); - var discountid = url.searchParams.get('discountid') || ''; - var rowEl = cell.closest('.tabular-row'); - var productId = ''; - var detailId = ''; - var dv = findTabular(); - if (dv && dv.scrollpanel) { - for (var i = 0; i < dv.scrollpanel.children.length; i++) { - var r = dv.scrollpanel.children[i]; - if (r.dom_element === rowEl && r.user_data) { - productId = r.user_data.productid || ''; - detailId = r.user_data.detail_id || ''; - break; - } - } - } - - var resp = await fetch( - url.origin + url.pathname.replace(/\/[^\/]*$/, '/save_discount.dspy'), - { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({ - discountid: discountid, - productid: productId, - detail_id: detailId, - discount: newVal - }) - } - ); - - if (resp.ok) { - cell.textContent = parseFloat(newVal).toString(); - } else { - cell.textContent = oldVal; - } - } catch(ex) { - cell.textContent = oldVal; - } - }; - - inp.addEventListener('blur', saveFn); - inp.addEventListener('keydown', function(ev) { - if (ev.key === 'Enter') { ev.preventDefault(); inp.blur(); } - if (ev.key === 'Escape') { cell.textContent = oldVal; } - }); - }); - } - - function scan() { - var dv = findTabular(); - if (!dv || !dv.scrollpanel || !dv.scrollpanel.dom_element) return; - var cells = dv.scrollpanel.dom_element.querySelectorAll('.tabular-cell'); - cells.forEach(setupCell); - } - - // Keep scanning for new cells after each render - setInterval(scan, SETUP_INTERVAL); -})(); diff --git a/wwwroot/discount_setting/index.ui b/wwwroot/discount_setting/index.ui index e40b0cb..b785584 100644 --- a/wwwroot/discount_setting/index.ui +++ b/wwwroot/discount_setting/index.ui @@ -1,67 +1,88 @@ +{% set products = get_discount_setting_products(request) %} { - "id": "product_discount_tbl", - "widgettype": "Tabular", + "widgettype": "VBox", "options": { "width": "100%", "height": "100%", - "title": "产品折扣设置", - "description": "选中行后点击「设置折扣」编辑,折扣值留空或填0可清除折扣", - "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_params": { - "discountid": "{{params_kw.discountid}}" - }, - "data_method": "GET", - "row_options": { - "idField": "productid", - "checkField": "checked", - "fields": [ - { - "name": "category_name", - "title": "产品分类", - "type": "str", - "cwidth": 3 - }, - { - "name": "product_name", - "title": "产品名称", - "type": "str", - "cwidth": 5 - }, - { - "name": "product_code", - "title": "产品编码", - "type": "str", - "cwidth": 3 - }, - { - "name": "discount", - "title": "当前折扣", - "type": "float", - "cwidth": 3 - } - ] - }, - "page_rows": 100, - "cache_limit": 5 + "css": "filler" }, - "binds": [ + "subwidgets": [ { - "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({}); });" + "widgettype": "Text", + "options": { + "text": "产品折扣设置", + "fontSize": "16px", + "fontWeight": "600", + "color": "#F1F5F9", + "padding": "8px 12px" + } + }, + { + "widgettype": "HBox", + "options": { + "bgcolor": "#0F172A", + "padding": "8px 12px", + "borderRadius": "6px 6px 0 0", + "alignItems": "center" + }, + "subwidgets": [ + {"widgettype": "Text", "options": {"text": "产品分类", "cwidth": 3, "fontSize": "12px", "fontWeight": "600", "color": "#94A3B8"}}, + {"widgettype": "Text", "options": {"text": "产品名称", "cwidth": 5, "fontSize": "12px", "fontWeight": "600", "color": "#94A3B8"}}, + {"widgettype": "Text", "options": {"text": "产品编码", "cwidth": 3, "fontSize": "12px", "fontWeight": "600", "color": "#94A3B8"}}, + {"widgettype": "Text", "options": {"text": "折扣(可编辑)", "cwidth": 3, "fontSize": "12px", "fontWeight": "600", "color": "#94A3B8"}} + ] + }, + { + "widgettype": "VBox", + "id": "discount_rows", + "options": { + "width": "100%", + "css": "childrensize" + }, + "subwidgets": [ +{% for p in products %} + { + "widgettype": "HBox", + "options": { + "padding": "6px 12px", + "border": "0 0 1px 0", + "borderColor": "#334155", + "alignItems": "center", + "width": "100%" + }, + "subwidgets": [ + {"widgettype": "Text", "options": {"text": "{{p.category_name or ''}}", "cwidth": 3, "fontSize": "12px", "color": "#E2E8F0"}}, + {"widgettype": "Text", "options": {"text": "{{p.product_name or ''}}", "cwidth": 5, "fontSize": "12px", "color": "#F1F5F9"}}, + {"widgettype": "Text", "options": {"text": "{{p.product_code or ''}}", "cwidth": 3, "fontSize": "12px", "color": "#E2E8F0"}}, + { + "widgettype": "Form", + "id": "discount_form_{{loop.index}}", + "options": { + "cwidth": 3, + "show_label": false, + "css": "childrensize", + "submit_url": "{{entire_url('./save_discount.dspy')}}", + "fields": [ + {"name": "discountid", "uitype": "hide", "value": "{{params_kw.discountid}}"}, + {"name": "productid", "uitype": "hide", "value": "{{p.productid}}"}, + {"name": "detail_id", "uitype": "hide", "value": "{{p.detail_id or ''}}"}, + {"name": "discount", "uitype": "float", "value": "{{p.discount or ''}}", "placeholder": "0~1", "dec_len": 2} + ] + }, + "binds": [ + { + "wid": "self", + "event": "changed", + "actiontype": "script", + "target": "self", + "script": "var form = this.target; var d = form.getValue(); var old = form._last_val; if (d.discount === old) return; form._last_val = d.discount; fetch(form.options.submit_url, {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify(d)}).then(function(r){ return r.json(); }).then(function(resp){ if (resp.widgettype === 'Error') bricks.show_error(resp.options); else console.log('discount saved'); }).catch(function(e){ console.error(e); });" + } + ] + } + ] + }{% if not loop.last %},{% endif %} +{% endfor %} + ] } ] }