修复: green_discount折扣率(折数)语义——前端/后端计算ecoAmt改为×折数/10,管理面板max=10默认值10,校验与文案全改

This commit is contained in:
ypsdf1
2026-07-08 00:18:47 +08:00
parent ac79628076
commit 28c7aa119e
5 changed files with 21 additions and 18 deletions
+2 -2
View File
@@ -408,7 +408,7 @@ async function loadShop(el) {
<div class="form-row"><label>塞背包折扣系数</label><input id="cfgBackpack" type="number" step="0.01" min="0.01" max="1" oninput="updateCartCfgHint()"></div>
<div class="form-row"><label>潜影盒加价系数</label><input id="cfgShulker" type="number" step="0.01" min="1" max="3" oninput="updateCartCfgHint()"></div>
<div class="form-row"><label>彩色潜影盒打包费</label><input id="cfgPackMoney" type="number" min="0" max="999" value="5"><span style="font-size:12px;color:var(--dim)">彩色潜影盒加收债券数(原色免费)</span></div>
<div class="form-row"><label>环保单减免(%)</label><input id="cfgGreen" type="number" min="0" max="9.99" step="0.01" value="2"><span style="font-size:12px;color:var(--dim)">0 = 不减免;玩家选「不打包」时按比例减免(命令 /sdf1_login shop setgreen 10 亦为不减免)</span></div>
<div class="form-row"><label>环保单折扣(折数)</label><input id="cfgGreen" type="number" min="0" max="10" step="0.1" value="10"><span style="font-size:12px;color:var(--dim)">折扣率(折数):10 = 不打折,9.9 = 9.9折(支付99%),9.8 = 9.8折(支付98%);玩家选「不打包」时按此折扣(命令 /sdf1_login shop setgreen 10 亦为不打折)</span></div>
<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap">
<button class="btn btn-green" onclick="saveCartConfig()">保存配置</button>
<span id="cartCfgHint" style="font-size:12px;color:var(--accent)"></span>
@@ -465,7 +465,7 @@ async function saveCartConfig() {
if (bp <= 0 || bp > 1) { toast('塞背包折扣系数应在 0.01 ~ 1.00 之间', 'err'); return; }
if (sh < 1 || sh > 3) { toast('潜影盒加价系数应在 1.00 ~ 3.00 之间', 'err'); return; }
if (isNaN(pm) || pm < 0 || pm > 999) { toast('打包费应在 0 ~ 999 之间', 'err'); return; }
if (gd < 0 || gd > 9.99) { toast('环保单减免应在 0 ~ 9.99 之间', 'err'); return; }
if (gd < 0 || gd > 10) { toast('环保单折扣(折数)应在 0 ~ 10 之间', 'err'); return; }
const r = await postApi('save_shop_config', { cart_backpack_rate: bp, cart_shulker_rate: sh, packmoney: pm, green_discount: gd });
toast(r.message || (r.success ? '已保存' : '保存失败'), r.success ? 'ok' : 'err');
if (r.success) updateCartCfgHint();
+2 -2
View File
@@ -329,11 +329,11 @@ function adminSaveShopConfig() {
$saved['packmoney'] = $pm;
}
// 环保单减免百分比(0=不减免;命令 setgreen 10 亦为不减免)
// 环保单折扣率(折数):10=不打折,9.9=9.9折;命令 setgreen 10 亦为不打折
$gd = getParam('green_discount');
if ($gd !== null) {
$gd = (float)$gd;
if ($gd < 0 || $gd > 9.99) error('环保单减免需介于 0 ~ 9.99 之间');
if ($gd < 0 || $gd > 10) error('环保单折扣(折数)需介于 0 ~ 10 之间');
$upsert->bindValue(':k', 'green_discount', SQLITE3_TEXT);
$upsert->bindValue(':v', number_format($gd, 2, '.', ''), SQLITE3_TEXT);
$upsert->execute();
+6 -5
View File
@@ -294,7 +294,7 @@ function cartConfig() {
'backpack_rate' => (float)($cfg['cart_backpack_rate'] ?? '0.98'),
'shulker_rate' => (float)($cfg['cart_shulker_rate'] ?? '1.00'),
'packmoney' => (float)($cfg['packmoney'] ?? '5'),
'green_discount' => (float)($cfg['green_discount'] ?? '2')
'green_discount' => (float)($cfg['green_discount'] ?? '10')
]);
}
@@ -390,8 +390,8 @@ function shopBuyCart($token) {
$modeName = '塞背包(环保单)';
$colorFee = 0;
$colorName = '';
// 环保单减免:不打包/塞背包时按配置比例减免(与游戏内"不打包"一致)
$ecoPct = (float)($cfg['green_discount'] ?? '2');
// 环保单折扣率(折数):10=不打折,9.9=9.9折(支付99%),与游戏内"不打包"一致
$ecoPct = (float)($cfg['green_discount'] ?? '10');
}
$db = getDB();
@@ -418,9 +418,10 @@ function shopBuyCart($token) {
}
unset($p);
// 先按费率计算,再叠加环保单减免(不打包/塞背包),最后加颜色打包费
// 先按费率计算,再叠加环保单折扣(不打包/塞背包,折扣率为折数),最后加颜色打包费
// green_discount 语义:10=不打折,9.9=9.9折(×0.99),9.8=9.8折(×0.98)
$baseAfterRate = (int)round($subtotal * $rate);
if ($ecoPct > 0) $baseAfterRate = (int)round($baseAfterRate * (100 - $ecoPct) / 100);
if ($ecoPct > 0) $baseAfterRate = (int)round($baseAfterRate * $ecoPct / 10);
$totalPrice = $baseAfterRate + $colorFee;
$saved = $subtotal - $totalPrice; // 折扣省下的(潜影盒加价+颜色费时为负)
+2 -2
View File
@@ -2819,7 +2819,7 @@ function getShopConfigSync() {
};
success([
'packmoney' => (float)$read('packmoney', '5'),
'green_discount' => (float)$read('green_discount', '2')
'green_discount' => (float)$read('green_discount', '10')
]);
}
@@ -2839,7 +2839,7 @@ function setShopConfigSync() {
if ($v < 0 || $v > 999) error('打包费需介于 0 ~ 999');
} else {
$v = (float)$value;
if ($v < 0 || $v > 9.99) error('环保单减免需介于 0 ~ 9.99');
if ($v < 0 || $v > 10) error('环保单折扣(折数)需介于 0 ~ 10');
}
$db = getDB();
+9 -7
View File
@@ -13,13 +13,13 @@ function cashierGetConfig() {
$db = getDB();
$stmt = $db->prepare("SELECT cfg_key, cfg_value FROM shop_config WHERE cfg_key IN ('packmoney','green_discount','cart_backpack_rate','cart_shulker_rate')");
$result = $stmt->execute();
$map = ['packmoney' => 5, 'green_discount' => 2, 'cart_backpack_rate' => '0.98', 'cart_shulker_rate' => '1.00']; // 默认值
$map = ['packmoney' => 5, 'green_discount' => 10, 'cart_backpack_rate' => '0.98', 'cart_shulker_rate' => '1.00']; // 默认值
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$map[$row['cfg_key']] = $row['cfg_value'];
}
return $map;
} catch (Exception $e) {
return ['packmoney' => 5, 'green_discount' => 2, 'cart_backpack_rate' => '0.98', 'cart_shulker_rate' => '1.00'];
return ['packmoney' => 5, 'green_discount' => 10, 'cart_backpack_rate' => '0.98', 'cart_shulker_rate' => '1.00'];
}
}
$cfg = cashierGetConfig();
@@ -581,14 +581,16 @@ async function recalc() {
});
const rate = RATES[settlement];
let afterRate = Math.round(subtotal * rate);
// ★ 环保单减免:用 ?? 代替 ||,避免 green_discount=0 被当 falsy 回退
const ecoPctVal = STATE.green_discount ?? 0;
// ★ 环保单折扣(折数):green_discount=10 不打折,9.9=9.9折(支付99%);用 ?? 避免=0 被当 falsy
const ecoPctVal = STATE.green_discount ?? 0; // 折数(如 9.9)
let ecoPct = 0;
let ecoAmt = 0;
if (settlement === 'backpack') ecoPct = ecoPctVal;
if (ecoPct > 0) {
ecoAmt = afterRate - Math.round(afterRate * (100 - ecoPct) / 100);
afterRate -= ecoAmt;
// 折扣率语义:折后 = 原价 × 折数/10(9.9折→×0.99)
const ecoDiscounted = Math.round(afterRate * ecoPct / 10);
ecoAmt = afterRate - ecoDiscounted;
afterRate = ecoDiscounted;
}
let colorFee = 0;
const sc = document.getElementById('shulkerColor').value;
@@ -608,7 +610,7 @@ async function recalc() {
document.getElementById('summary').innerHTML = `
<div class="summary-line"><span>商品小计</span><span>${subtotal} 债券</span></div>
<div class="summary-line"><span>${settlement==='shulker'?'潜影盒费率':'背包费率'} (${rate*100}%)</span><span>${colorFee?('+'+colorFee):''}</span></div>
${ecoPct>0?`<div class="summary-line"><span class="disc">环保单减免 ${ecoPct}%</span><span class="disc">-${ecoAmt} 债券</span></div>`:''}
${ecoPct>0?`<div class="summary-line"><span class="disc">环保单 ${ecoPct}折</span><span class="disc">-${ecoAmt} 债券</span></div>`:''}
<div class="summary-line"><span>应收原价</span><span>${total} 债券</span></div>
<div class="summary-line"><span class="disc">手动折扣 ${discount}%</span><span class="disc">-${discAmt} 债券</span></div>
${payMode === 'cash' ? '<div class="summary-line" style="border-color:var(--orange);color:var(--orange)"><span>💵 现金收款模式</span><span>仅记账,不扣债券</span></div>' : ''}