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

972 lines
31 KiB
HTML
Raw Normal View History

<!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>