dm-design/商家端APP/工作台/市场配置/移动端配送设置.html

972 lines
31 KiB
HTML
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.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<title>同城配送设置</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
background-color: #f5f5f5;
color: #333;
line-height: 1.6;
-webkit-font-smoothing: antialiased;
}
/* 头部 */
.header {
position: sticky;
top: 0;
z-index: 100;
display: flex;
align-items: center;
padding: 12px 16px;
background-color: #fff;
border-bottom: 1px solid #e5e5e5;
}
.back-btn {
font-size: 24px;
color: #333;
text-decoration: none;
padding: 4px 8px 4px 0;
cursor: pointer;
}
.header-title {
font-size: 18px;
font-weight: 500;
flex: 1;
text-align: center;
margin-right: 32px;
}
/* 区块容器 */
.section {
background-color: #fff;
margin-bottom: 10px;
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px;
border-bottom: 1px solid #f0f0f0;
}
.section-title {
font-size: 15px;
font-weight: 500;
color: #333;
}
.section-help {
color: #999;
font-size: 13px;
display: flex;
align-items: center;
cursor: pointer;
}
.section-help::after {
content: "?";
display: inline-block;
width: 16px;
height: 16px;
border: 1px solid #999;
border-radius: 50%;
text-align: center;
line-height: 14px;
margin-left: 4px;
font-size: 11px;
}
/* 表单项 */
.form-item {
display: flex;
align-items: center;
padding: 14px 16px;
border-bottom: 1px solid #f0f0f0;
min-height: 52px;
}
.form-item:last-child {
border-bottom: none;
}
.form-label {
flex: 0 0 auto;
font-size: 14px;
color: #333;
margin-right: 12px;
}
.form-label.required::before {
content: "*";
color: #ff4d4f;
margin-right: 4px;
}
.form-value {
flex: 1;
display: flex;
align-items: center;
justify-content: flex-end;
}
/* 输入框 */
.form-input {
width: 100px;
padding: 6px 10px;
border: 1px solid #d9d9d9;
border-radius: 4px;
font-size: 14px;
text-align: right;
}
.form-input:focus {
outline: none;
border-color: #40a9ff;
}
.form-unit {
margin-left: 8px;
color: #666;
font-size: 14px;
white-space: nowrap;
}
/* 开关 */
.switch {
position: relative;
display: inline-block;
width: 46px;
height: 26px;
margin-right: 10px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: .3s;
border-radius: 26px;
}
.slider:before {
position: absolute;
content: "";
height: 20px;
width: 20px;
left: 3px;
bottom: 3px;
background-color: white;
transition: .3s;
border-radius: 50%;
}
input:checked + .slider {
background-color: #52c41a;
}
input:checked + .slider:before {
transform: translateX(20px);
}
.switch-label {
color: #999;
font-size: 14px;
}
input:checked ~ .switch-label {
color: #333;
}
/* 自定义选择器 */
.custom-select {
position: relative;
min-width: 120px;
}
.select-trigger {
display: flex;
align-items: center;
justify-content: space-between;
padding: 6px 10px;
border: 1px solid #d9d9d9;
border-radius: 4px;
font-size: 14px;
background-color: #fff;
cursor: pointer;
user-select: none;
min-width: 120px;
}
.select-trigger::after {
content: "";
width: 0;
height: 0;
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 5px solid #999;
margin-left: 8px;
transition: transform 0.3s;
}
.select-trigger.active::after {
transform: rotate(180deg);
}
.select-trigger:active {
background-color: #f5f5f5;
}
.select-options {
position: absolute;
top: 100%;
right: 0;
left: 0;
background-color: #fff;
border: 1px solid #d9d9d9;
border-radius: 4px;
margin-top: 4px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
z-index: 1000;
display: none;
overflow: hidden;
}
.select-options.show {
display: block;
}
.select-option {
padding: 10px 12px;
font-size: 14px;
cursor: pointer;
transition: background-color 0.2s;
display: flex;
align-items: center;
justify-content: space-between;
}
.select-option:active {
background-color: #f5f5f5;
}
.select-option.selected {
color: #006d3e;
font-weight: 500;
}
.select-option.selected::after {
content: "✓";
font-size: 16px;
color: #006d3e;
}
/* 复合输入 */
.compound-input {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.compound-input .form-input {
width: 70px;
}
.compound-input .form-unit {
margin: 0;
}
/* 底部按钮 */
.footer {
background-color: #fff;
padding: 16px;
display: flex;
gap: 12px;
margin-top: 10px;
}
.btn {
flex: 1;
padding: 12px 20px;
font-size: 16px;
border: none;
border-radius: 6px;
cursor: pointer;
transition: all 0.3s;
font-weight: 500;
}
.btn-cancel {
background-color: #fff;
color: #333;
border: 1px solid #d9d9d9;
}
.btn-cancel:active {
background-color: #f5f5f5;
}
.btn-submit {
background-color: #006d3e;
color: #fff;
}
.btn-submit:active {
background-color: #00562f;
}
/* 触摸反馈 */
.form-item:active {
background-color: #f9f9f9;
}
/* 提示信息 */
.toast {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: rgba(0, 0, 0, 0.75);
color: #fff;
padding: 12px 20px;
border-radius: 6px;
font-size: 14px;
z-index: 9999;
display: none;
max-width: 80%;
text-align: center;
}
.toast.show {
display: block;
animation: fadeInOut 2s ease-in-out;
}
@keyframes fadeInOut {
0% { opacity: 0; }
10% { opacity: 1; }
90% { opacity: 1; }
100% { opacity: 0; }
}
/* 确认对话框 */
.dialog-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: none;
z-index: 9998;
}
.dialog-overlay.show {
display: flex;
align-items: center;
justify-content: center;
}
.dialog {
background-color: #fff;
border-radius: 12px;
width: 80%;
max-width: 300px;
overflow: hidden;
}
.dialog-content {
padding: 20px;
text-align: center;
font-size: 15px;
color: #333;
}
.dialog-actions {
display: flex;
border-top: 1px solid #e5e5e5;
}
.dialog-btn {
flex: 1;
padding: 14px;
border: none;
background: none;
font-size: 16px;
cursor: pointer;
}
.dialog-btn:first-child {
border-right: 1px solid #e5e5e5;
color: #666;
}
.dialog-btn:last-child {
color: #006d3e;
font-weight: 500;
}
.dialog-btn:active {
background-color: #f5f5f5;
}
/* 遮罩层 */
.mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: transparent;
z-index: 999;
display: none;
}
.mask.show {
display: block;
}
</style>
</head>
<body>
<!-- 头部 -->
<div class="header">
<a href="javascript:history.back()" class="back-btn"></a>
<h1 class="header-title">同城配送设置</h1>
</div>
<!-- 同城配送开关 -->
<div class="section">
<div class="section-header">
<div class="section-title">同城配送开关</div>
<div class="section-help" onclick="showHelp('同城配送开关')">字段说明</div>
</div>
<div class="form-item">
<label class="form-label">是否开启同城配送</label>
<div class="form-value">
<label class="switch">
<input type="checkbox" id="deliveryEnabled" checked>
<span class="slider"></span>
</label>
<span class="switch-label" id="switchLabel">已开启</span>
</div>
</div>
</div>
<!-- 基础配置 -->
<div class="section">
<div class="section-header">
<div class="section-title">基础配置</div>
<div class="section-help" onclick="showHelp('基础配置')">字段说明</div>
</div>
<div class="form-item">
<label class="form-label required">订单包装费</label>
<div class="form-value">
<input type="number" class="form-input" id="packagingFee" value="1" min="0" step="0.1">
<span class="form-unit">元/单</span>
</div>
</div>
<div class="form-item">
<label class="form-label required">订单起送价</label>
<div class="form-value">
<input type="number" class="form-input" id="minOrderAmount" value="1" min="0" step="0.1">
<span class="form-unit">元/单</span>
</div>
</div>
<div class="form-item">
<label class="form-label required">最大配送距离</label>
<div class="form-value">
<input type="number" class="form-input" id="maxDistance" value="5" min="0" step="0.1">
<span class="form-unit">公里</span>
</div>
</div>
<div class="form-item">
<label class="form-label required">承诺订单送达时间</label>
<div class="form-value">
<input type="number" class="form-input" id="deliveryTime" value="3" min="0" step="1">
<span class="form-unit">小时以内</span>
</div>
</div>
</div>
<!-- 运费收益方 -->
<div class="section">
<div class="section-header">
<div class="section-title">运费收益方</div>
<div class="section-help" onclick="showHelp('运费收益方')">字段说明</div>
</div>
<div class="form-item">
<label class="form-label required">运费收益方</label>
<div class="form-value">
<div class="custom-select" id="beneficiarySelect">
<div class="select-trigger" onclick="toggleSelect('beneficiarySelect')">
<span class="select-value">市场经营者</span>
</div>
<div class="select-options">
<div class="select-option selected" data-value="market" onclick="selectOption('beneficiarySelect', 'market', '市场经营者')">市场经营者</div>
<div class="select-option" data-value="courier" onclick="selectOption('beneficiarySelect', 'courier', '专员')">专员</div>
</div>
</div>
</div>
</div>
</div>
<!-- 运费计算 -->
<div class="section">
<div class="section-header">
<div class="section-title">运费计算</div>
<div class="section-help" onclick="showHelp('运费计算')">字段说明</div>
</div>
<div class="form-item">
<label class="form-label required">运费模式</label>
<div class="form-value">
<div class="custom-select" id="freightModeSelect">
<div class="select-trigger" onclick="toggleSelect('freightModeSelect')">
<span class="select-value">距离运费</span>
</div>
<div class="select-options">
<div class="select-option selected" data-value="distance" onclick="selectOption('freightModeSelect', 'distance', '距离运费')">距离运费</div>
<div class="select-option" data-value="fixed" onclick="selectOption('freightModeSelect', 'fixed', '固定费用')">固定费用</div>
</div>
</div>
</div>
</div>
<!-- 距离运费配置 -->
<div id="distanceFreightConfig">
<div class="form-item">
<label class="form-label required">配送起步价</label>
<div class="form-value">
<div class="compound-input">
<input type="number" class="form-input" id="startDistance" value="3" min="0" step="0.1">
<span class="form-unit">公里内</span>
<input type="number" class="form-input" id="startPrice" value="1" min="0" step="0.1">
<span class="form-unit"></span>
</div>
</div>
</div>
<div class="form-item">
<label class="form-label required">每+0.1公里加收</label>
<div class="form-value">
<input type="number" class="form-input" id="extraPrice" value="0" min="0" step="0.1">
<span class="form-unit"></span>
</div>
</div>
</div>
<!-- 固定费用配置 -->
<div id="fixedFreightConfig" style="display: none;">
<div class="form-item">
<label class="form-label required">配送费用</label>
<div class="form-value">
<input type="number" class="form-input" id="fixedPrice" value="5" min="0" step="0.1">
<span class="form-unit"></span>
</div>
</div>
</div>
</div>
<!-- 免运费条件 -->
<div class="section">
<div class="section-header">
<div class="section-title">免运费条件</div>
<div class="section-help" onclick="showHelp('免运费条件')">字段说明</div>
</div>
<div class="form-item">
<label class="form-label">订单满额免运费</label>
<div class="form-value">
<label class="switch">
<input type="checkbox" id="freeShippingEnabled">
<span class="slider"></span>
</label>
<span class="switch-label" id="freeShippingLabel">已关闭</span>
</div>
</div>
<div class="form-item" id="freeShippingAmountItem" style="display: none;">
<label class="form-label required">订单满</label>
<div class="form-value">
<input type="number" class="form-input" id="freeShippingAmount" value="50" min="0" step="0.1">
<span class="form-unit">元,免运费</span>
</div>
</div>
</div>
<!-- 底部按钮 -->
<div class="footer">
<button class="btn btn-cancel" onclick="handleCancel()">取消</button>
<button class="btn btn-submit" onclick="handleSubmit()">提交</button>
</div>
<!-- 提示信息 -->
<div class="toast" id="toast"></div>
<!-- 确认对话框 -->
<div class="dialog-overlay" id="dialogOverlay">
<div class="dialog">
<div class="dialog-content" id="dialogContent"></div>
<div class="dialog-actions">
<button class="dialog-btn" onclick="hideDialog()">取消</button>
<button class="dialog-btn" onclick="confirmDialog()">确定</button>
</div>
</div>
</div>
<!-- 遮罩层 -->
<div class="mask" id="mask" onclick="closeAllSelects()"></div>
<script>
// 选择器数据存储
const selectData = {
beneficiarySelect: {
value: 'market',
text: '市场经营者'
},
freightModeSelect: {
value: 'distance',
text: '距离运费'
}
};
// 切换选择器
function toggleSelect(selectId) {
const select = document.getElementById(selectId);
const trigger = select.querySelector('.select-trigger');
const options = select.querySelector('.select-options');
const mask = document.getElementById('mask');
// 关闭其他选择器
document.querySelectorAll('.select-options').forEach(opt => {
if (opt !== options) {
opt.classList.remove('show');
opt.parentElement.querySelector('.select-trigger').classList.remove('active');
}
});
// 切换当前选择器
const isShow = options.classList.toggle('show');
trigger.classList.toggle('active');
if (isShow) {
mask.classList.add('show');
} else {
mask.classList.remove('show');
}
}
// 选择选项
function selectOption(selectId, value, text) {
const select = document.getElementById(selectId);
const trigger = select.querySelector('.select-trigger');
const valueSpan = trigger.querySelector('.select-value');
const options = select.querySelector('.select-options');
const mask = document.getElementById('mask');
// 更新选中状态
select.querySelectorAll('.select-option').forEach(opt => {
opt.classList.remove('selected');
if (opt.getAttribute('data-value') === value) {
opt.classList.add('selected');
}
});
// 更新显示值
valueSpan.textContent = text;
// 保存数据
selectData[selectId] = { value, text };
// 关闭选择器
options.classList.remove('show');
trigger.classList.remove('active');
mask.classList.remove('show');
// 运费模式切换逻辑
if (selectId === 'freightModeSelect') {
const distanceConfig = document.getElementById('distanceFreightConfig');
const fixedConfig = document.getElementById('fixedFreightConfig');
if (value === 'distance') {
distanceConfig.style.display = 'block';
fixedConfig.style.display = 'none';
} else {
distanceConfig.style.display = 'none';
fixedConfig.style.display = 'block';
}
}
}
// 关闭所有选择器
function closeAllSelects() {
document.querySelectorAll('.select-options').forEach(opt => {
opt.classList.remove('show');
opt.parentElement.querySelector('.select-trigger').classList.remove('active');
});
document.getElementById('mask').classList.remove('show');
}
// Toast 提示
function showToast(message) {
const toast = document.getElementById('toast');
toast.textContent = message;
toast.classList.add('show');
setTimeout(() => {
toast.classList.remove('show');
}, 2000);
}
// 对话框
let dialogCallback = null;
function showDialog(message, callback) {
const overlay = document.getElementById('dialogOverlay');
const content = document.getElementById('dialogContent');
content.textContent = message;
overlay.classList.add('show');
dialogCallback = callback;
}
function hideDialog() {
document.getElementById('dialogOverlay').classList.remove('show');
dialogCallback = null;
}
function confirmDialog() {
hideDialog();
if (dialogCallback) {
dialogCallback();
}
}
// 字段说明
function showHelp(section) {
let message = '';
switch(section) {
case '同城配送开关':
message = '控制是否启用同城配送功能';
break;
case '基础配置':
message = '设置配送的基本参数,包括包装费、起送价、配送距离和送达时间';
break;
case '运费收益方':
message = '设置运费收入归属于市场经营者还是配送专员';
break;
case '运费计算':
message = '设置运费的计算方式,可以按距离计费或固定费用';
break;
case '免运费条件':
message = '设置订单满额免运费的条件';
break;
}
showToast(message);
}
// 同城配送开关
const deliveryEnabledSwitch = document.getElementById('deliveryEnabled');
const switchLabel = document.getElementById('switchLabel');
deliveryEnabledSwitch.addEventListener('change', function() {
if (this.checked) {
switchLabel.textContent = '已开启';
} else {
switchLabel.textContent = '已关闭';
}
});
// 免运费条件开关
const freeShippingEnabledSwitch = document.getElementById('freeShippingEnabled');
const freeShippingLabel = document.getElementById('freeShippingLabel');
const freeShippingAmountItem = document.getElementById('freeShippingAmountItem');
freeShippingEnabledSwitch.addEventListener('change', function() {
if (this.checked) {
freeShippingLabel.textContent = '已开启';
freeShippingAmountItem.style.display = 'flex';
} else {
freeShippingLabel.textContent = '已关闭';
freeShippingAmountItem.style.display = 'none';
}
});
// 取消按钮
function handleCancel() {
showDialog('确定要取消吗?未保存的更改将丢失。', () => {
history.back();
});
}
// 表单验证
function validateForm() {
const packagingFee = parseFloat(document.getElementById('packagingFee').value);
const minOrderAmount = parseFloat(document.getElementById('minOrderAmount').value);
const maxDistance = parseFloat(document.getElementById('maxDistance').value);
const deliveryTime = parseInt(document.getElementById('deliveryTime').value);
if (isNaN(packagingFee) || packagingFee < 0) {
showToast('请输入有效的订单包装费');
return false;
}
if (isNaN(minOrderAmount) || minOrderAmount < 0) {
showToast('请输入有效的订单起送价');
return false;
}
if (isNaN(maxDistance) || maxDistance <= 0) {
showToast('请输入有效的最大配送距离');
return false;
}
if (isNaN(deliveryTime) || deliveryTime <= 0) {
showToast('请输入有效的送达时间');
return false;
}
const mode = selectData.freightModeSelect.value;
if (mode === 'distance') {
const startDistance = parseFloat(document.getElementById('startDistance').value);
const startPrice = parseFloat(document.getElementById('startPrice').value);
const extraPrice = parseFloat(document.getElementById('extraPrice').value);
if (isNaN(startDistance) || startDistance <= 0) {
showToast('请输入有效的配送起步距离');
return false;
}
if (isNaN(startPrice) || startPrice < 0) {
showToast('请输入有效的配送起步价');
return false;
}
if (isNaN(extraPrice) || extraPrice < 0) {
showToast('请输入有效的加收费用');
return false;
}
} else {
const fixedPrice = parseFloat(document.getElementById('fixedPrice').value);
if (isNaN(fixedPrice) || fixedPrice < 0) {
showToast('请输入有效的配送费用');
return false;
}
}
if (freeShippingEnabledSwitch.checked) {
const freeShippingAmount = parseFloat(document.getElementById('freeShippingAmount').value);
if (isNaN(freeShippingAmount) || freeShippingAmount <= 0) {
showToast('请输入有效的免运费金额');
return false;
}
}
return true;
}
// 提交按钮
function handleSubmit() {
if (!validateForm()) {
return;
}
const deliveryEnabled = deliveryEnabledSwitch.checked;
const freeShippingEnabled = freeShippingEnabledSwitch.checked;
// 收集表单数据
const formData = {
同城配送开关: {
是否开启: deliveryEnabled
},
基础配置: {
订单包装费: parseFloat(document.getElementById('packagingFee').value),
订单起送价: parseFloat(document.getElementById('minOrderAmount').value),
最大配送距离: parseFloat(document.getElementById('maxDistance').value),
承诺订单送达时间: parseInt(document.getElementById('deliveryTime').value)
},
运费收益方: {
收益方: selectData.beneficiarySelect.text
},
运费计算: {
运费模式: selectData.freightModeSelect.text
},
免运费条件: {
是否启用: freeShippingEnabled
}
};
// 根据模式添加不同的配置
if (selectData.freightModeSelect.value === 'distance') {
formData.运费计算.配送起步距离 = parseFloat(document.getElementById('startDistance').value);
formData.运费计算.配送起步价 = parseFloat(document.getElementById('startPrice').value);
formData.运费计算.每01公里加收 = parseFloat(document.getElementById('extraPrice').value);
} else {
formData.运费计算.配送费用 = parseFloat(document.getElementById('fixedPrice').value);
}
// 添加免运费条件
if (freeShippingEnabled) {
formData.免运费条件.订单满额 = parseFloat(document.getElementById('freeShippingAmount').value);
}
console.log('提交的数据:', formData);
// TODO: 这里添加实际的提交逻辑
showToast('配置已保存!');
// 延迟返回
setTimeout(() => {
history.back();
}, 1500);
}
// 表单输入验证
document.querySelectorAll('.form-input').forEach(input => {
input.addEventListener('input', function(e) {
if (this.type === 'number' && this.value < 0) {
this.value = 0;
}
});
});
// 防止双击缩放
let lastTouchEnd = 0;
document.addEventListener('touchend', function (event) {
const now = Date.now();
if (now - lastTouchEnd <= 300) {
event.preventDefault();
}
lastTouchEnd = now;
}, false);
</script>
</body>
</html>