Files
TakeoutSaaS.Prototypes/pages/ch-menu-sync.html

423 lines
20 KiB
HTML

<!-- 菜单同步页 -->
<style>
.cms-page { font-size: 13px; color: var(--g-text); }
/* ===== 统计条 ===== */
.cms-stats {
display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 16px;
}
.cms-stat-card {
background: #fff; border-radius: var(--g-radius); border: 1px solid var(--g-border);
padding: 16px 20px; display: flex; align-items: center; gap: 14px;
transition: box-shadow var(--g-transition);
}
.cms-stat-card:hover { box-shadow: var(--g-shadow-md); }
.cms-stat-icon {
width: 42px; height: 42px; border-radius: 10px; display: flex;
align-items: center; justify-content: center; flex-shrink: 0;
}
.cms-stat-icon.total { background: color-mix(in srgb, var(--primary) 10%, #fff); color: var(--primary); }
.cms-stat-icon.synced { background: #f6ffed; color: var(--g-success); }
.cms-stat-icon.pending { background: #fff7e6; color: var(--g-warning); }
.cms-stat-icon.failed { background: #fff1f0; color: var(--g-danger); }
.cms-stat-info { flex: 1; }
.cms-stat-label { font-size: 12px; color: var(--g-text-muted); margin-bottom: 4px; }
.cms-stat-value { font-size: 22px; font-weight: 700; color: var(--g-text); line-height: 1; }
.cms-stat-value.danger { color: var(--g-danger); }
/* ===== 工具栏 ===== */
.cms-toolbar {
background: #fff; border-radius: var(--g-radius); border: 1px solid var(--g-border);
padding: 14px 20px; display: flex; align-items: center; gap: 10px;
flex-wrap: wrap; margin-bottom: 14px;
}
.cms-select {
height: 34px; border-radius: var(--g-radius-sm); border: 1px solid #e5e7eb;
padding: 0 10px; font-size: 13px; outline: none; min-width: 140px;
cursor: pointer; transition: all var(--g-transition); color: var(--g-text-secondary);
}
.cms-select:focus { border-color: var(--primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 12%, transparent); }
.cms-search {
height: 34px; border-radius: var(--g-radius-sm); border: 1px solid #e5e7eb;
padding: 0 10px 0 32px; font-size: 13px; outline: none; width: 200px;
transition: all var(--g-transition); color: var(--g-text); background: #fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E") 9px center no-repeat;
}
.cms-search:focus { border-color: var(--primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 12%, transparent); }
.cms-spacer { flex: 1; }
/* ===== 表格卡片 ===== */
.cms-table-card {
background: #fff; border-radius: var(--g-radius); border: 1px solid var(--g-border);
overflow: hidden;
}
.cms-table-wrap { overflow-x: auto; }
/* 平台价格单元格 */
.cms-price-cell { display: flex; align-items: center; gap: 5px; }
.cms-price-ok { color: var(--g-success); width: 14px; height: 14px; flex-shrink: 0; }
.cms-price-warn { color: var(--g-warning); width: 14px; height: 14px; flex-shrink: 0; cursor: help; }
.cms-price-fail { color: var(--g-danger); width: 14px; height: 14px; flex-shrink: 0; }
.cms-price-na { color: var(--g-text-muted); }
/* 操作列 */
.cms-actions { display: flex; align-items: center; gap: 12px; }
/* ===== 抽屉内 ===== */
.cms-readonly {
height: 34px; line-height: 34px; padding: 0 11px; background: var(--g-bg-subtle);
border: 1px solid var(--g-border); border-radius: var(--g-radius-sm);
font-size: 13px; color: var(--g-text);
}
.cms-platform-row {
display: flex; align-items: center; gap: 12px; padding: 12px 0;
border-bottom: 1px solid #f5f5f5;
}
.cms-platform-row:last-child { border-bottom: none; }
.cms-platform-name {
width: 72px; flex-shrink: 0; font-size: 13px; font-weight: 500; color: var(--g-text);
display: flex; align-items: center; gap: 6px;
}
.cms-platform-name i { width: 16px; height: 16px; color: var(--g-text-muted); }
.cms-platform-price { flex: 1; }
.cms-platform-price .g-input { width: 100%; }
.cms-platform-price.disabled .g-input {
background: #f5f5f5; color: var(--g-text-muted); pointer-events: none;
}
.cms-follow-hint { font-size: 11px; color: var(--g-text-muted); margin-top: 4px; }
</style>
<div class="cms-page">
<!-- 统计条 -->
<div class="cms-stats">
<div class="cms-stat-card">
<div class="cms-stat-icon total"><i data-lucide="utensils-crossed" style="width:20px;height:20px"></i></div>
<div class="cms-stat-info">
<div class="cms-stat-label">本店菜品总数</div>
<div class="cms-stat-value">48</div>
</div>
</div>
<div class="cms-stat-card">
<div class="cms-stat-icon synced"><i data-lucide="check-circle-2" style="width:20px;height:20px"></i></div>
<div class="cms-stat-info">
<div class="cms-stat-label">已全平台同步</div>
<div class="cms-stat-value">42</div>
</div>
</div>
<div class="cms-stat-card">
<div class="cms-stat-icon pending"><i data-lucide="clock" style="width:20px;height:20px"></i></div>
<div class="cms-stat-info">
<div class="cms-stat-label">待同步</div>
<div class="cms-stat-value">4</div>
</div>
</div>
<div class="cms-stat-card">
<div class="cms-stat-icon failed"><i data-lucide="alert-circle" style="width:20px;height:20px"></i></div>
<div class="cms-stat-info">
<div class="cms-stat-label">同步失败</div>
<div class="cms-stat-value danger">2</div>
</div>
</div>
</div>
<!-- 工具栏 -->
<div class="cms-toolbar">
<select class="cms-select">
<option>全部分类</option>
<option>热销套餐</option>
<option>主食</option>
<option>小吃</option>
<option>饮品</option>
<option>甜品</option>
</select>
<select class="cms-select">
<option>全部状态</option>
<option>已同步</option>
<option>待同步</option>
<option>同步失败</option>
<option>部分同步</option>
</select>
<input class="cms-search" type="text" placeholder="搜索菜品名称">
<div class="cms-spacer"></div>
<button class="g-btn g-btn-primary" onclick="alert('已发起全量同步')">
<i data-lucide="refresh-cw" style="width:14px;height:14px"></i>
一键全量同步
</button>
</div>
<!-- 表格 -->
<div class="cms-table-card">
<div class="cms-table-wrap">
<table class="g-table">
<thead>
<tr>
<th style="min-width:160px">菜品名称</th>
<th style="min-width:80px">分类</th>
<th style="min-width:90px">本店价格</th>
<th style="min-width:110px">美团价格</th>
<th style="min-width:110px">饿了么价格</th>
<th style="min-width:110px">小程序价格</th>
<th style="min-width:90px">同步状态</th>
<th style="min-width:120px">操作</th>
</tr>
</thead>
<tbody>
<!-- 1. 宫保鸡丁套餐 - 已同步 -->
<tr>
<td style="font-weight:500">宫保鸡丁套餐</td>
<td><span class="g-tag g-tag-orange">热销套餐</span></td>
<td>&yen;32.00</td>
<td><span class="cms-price-cell">&yen;32.00 <i data-lucide="check" class="cms-price-ok"></i></span></td>
<td><span class="cms-price-cell">&yen;32.00 <i data-lucide="check" class="cms-price-ok"></i></span></td>
<td><span class="cms-price-cell">&yen;32.00 <i data-lucide="check" class="cms-price-ok"></i></span></td>
<td><span class="g-tag g-tag-green">已同步</span></td>
<td class="cms-actions">
<a class="g-action" onclick="alert('同步中...')">同步</a>
<a class="g-action" onclick="openDrawer('宫保鸡丁套餐','32.00','32.00','32.00','32.00')">编辑价格</a>
</td>
</tr>
<!-- 2. 麻辣香锅(中份) - 已同步 -->
<tr>
<td style="font-weight:500">麻辣香锅(中份)</td>
<td><span class="g-tag g-tag-blue">主食</span></td>
<td>&yen;48.00</td>
<td><span class="cms-price-cell">&yen;48.00 <i data-lucide="check" class="cms-price-ok"></i></span></td>
<td><span class="cms-price-cell">&yen;48.00 <i data-lucide="check" class="cms-price-ok"></i></span></td>
<td><span class="cms-price-cell">&yen;48.00 <i data-lucide="check" class="cms-price-ok"></i></span></td>
<td><span class="g-tag g-tag-green">已同步</span></td>
<td class="cms-actions">
<a class="g-action" onclick="alert('同步中...')">同步</a>
<a class="g-action" onclick="openDrawer('麻辣香锅(中份)','48.00','48.00','48.00','48.00')">编辑价格</a>
</td>
</tr>
<!-- 3. 牛肉面套餐 - 已同步 -->
<tr>
<td style="font-weight:500">牛肉面套餐</td>
<td><span class="g-tag g-tag-blue">主食</span></td>
<td>&yen;28.00</td>
<td><span class="cms-price-cell">&yen;28.00 <i data-lucide="check" class="cms-price-ok"></i></span></td>
<td><span class="cms-price-cell">&yen;28.00 <i data-lucide="check" class="cms-price-ok"></i></span></td>
<td><span class="cms-price-cell">&yen;28.00 <i data-lucide="check" class="cms-price-ok"></i></span></td>
<td><span class="g-tag g-tag-green">已同步</span></td>
<td class="cms-actions">
<a class="g-action" onclick="alert('同步中...')">同步</a>
<a class="g-action" onclick="openDrawer('牛肉面套餐','28.00','28.00','28.00','28.00')">编辑价格</a>
</td>
</tr>
<!-- 4. 小龙虾(2斤) - 部分同步,饿了么价格不一致 -->
<tr>
<td style="font-weight:500">小龙虾(2斤)</td>
<td><span class="g-tag g-tag-orange">热销套餐</span></td>
<td>&yen;128.00</td>
<td><span class="cms-price-cell">&yen;128.00 <i data-lucide="check" class="cms-price-ok"></i></span></td>
<td><span class="cms-price-cell">&yen;138.00 <i data-lucide="alert-triangle" class="cms-price-warn" title="与本店价格不一致"></i></span></td>
<td><span class="cms-price-cell">&yen;128.00 <i data-lucide="check" class="cms-price-ok"></i></span></td>
<td><span class="g-tag g-tag-blue">部分同步</span></td>
<td class="cms-actions">
<a class="g-action" onclick="alert('同步中...')">同步</a>
<a class="g-action" onclick="openDrawer('小龙虾(2斤)','128.00','128.00','138.00','128.00')">编辑价格</a>
</td>
</tr>
<!-- 5. 烤鱼套餐 - 已同步 -->
<tr>
<td style="font-weight:500">烤鱼套餐</td>
<td><span class="g-tag g-tag-blue">主食</span></td>
<td>&yen;68.00</td>
<td><span class="cms-price-cell">&yen;68.00 <i data-lucide="check" class="cms-price-ok"></i></span></td>
<td><span class="cms-price-cell">&yen;68.00 <i data-lucide="check" class="cms-price-ok"></i></span></td>
<td><span class="cms-price-cell">&yen;68.00 <i data-lucide="check" class="cms-price-ok"></i></span></td>
<td><span class="g-tag g-tag-green">已同步</span></td>
<td class="cms-actions">
<a class="g-action" onclick="alert('同步中...')">同步</a>
<a class="g-action" onclick="openDrawer('烤鱼套餐','68.00','68.00','68.00','68.00')">编辑价格</a>
</td>
</tr>
<!-- 6. 炸鸡翅(6只) - 待同步 -->
<tr>
<td style="font-weight:500">炸鸡翅(6只)</td>
<td><span class="g-tag g-tag-purple">小吃</span></td>
<td>&yen;22.00</td>
<td><span class="cms-price-cell cms-price-na">&mdash;</span></td>
<td><span class="cms-price-cell cms-price-na">&mdash;</span></td>
<td><span class="cms-price-cell cms-price-na">&mdash;</span></td>
<td><span class="g-tag g-tag-orange">待同步</span></td>
<td class="cms-actions">
<a class="g-action" onclick="alert('同步中...')">同步</a>
<a class="g-action" onclick="openDrawer('炸鸡翅(6只)','22.00','','','')">编辑价格</a>
</td>
</tr>
<!-- 7. 珍珠奶茶 - 待同步 -->
<tr>
<td style="font-weight:500">珍珠奶茶</td>
<td><span class="g-tag g-tag-gray">饮品</span></td>
<td>&yen;15.00</td>
<td><span class="cms-price-cell cms-price-na">&mdash;</span></td>
<td><span class="cms-price-cell cms-price-na">&mdash;</span></td>
<td><span class="cms-price-cell cms-price-na">&mdash;</span></td>
<td><span class="g-tag g-tag-orange">待同步</span></td>
<td class="cms-actions">
<a class="g-action" onclick="alert('同步中...')">同步</a>
<a class="g-action" onclick="openDrawer('珍珠奶茶','15.00','','','')">编辑价格</a>
</td>
</tr>
<!-- 8. 提拉米苏 - 同步失败 -->
<tr>
<td style="font-weight:500">提拉米苏</td>
<td><span class="g-tag g-tag-gray">甜品</span></td>
<td>&yen;28.00</td>
<td><span class="cms-price-cell">&yen;28.00 <i data-lucide="x" class="cms-price-fail"></i></span></td>
<td><span class="cms-price-cell">&yen;28.00 <i data-lucide="x" class="cms-price-fail"></i></span></td>
<td><span class="cms-price-cell">&yen;28.00 <i data-lucide="x" class="cms-price-fail"></i></span></td>
<td><span class="g-tag g-tag-red">同步失败</span></td>
<td class="cms-actions">
<a class="g-action" onclick="alert('重新同步中...')">同步</a>
<a class="g-action" onclick="openDrawer('提拉米苏','28.00','28.00','28.00','28.00')">编辑价格</a>
</td>
</tr>
<!-- 9. 美式咖啡 - 已同步 -->
<tr>
<td style="font-weight:500">美式咖啡</td>
<td><span class="g-tag g-tag-gray">饮品</span></td>
<td>&yen;18.00</td>
<td><span class="cms-price-cell">&yen;18.00 <i data-lucide="check" class="cms-price-ok"></i></span></td>
<td><span class="cms-price-cell">&yen;18.00 <i data-lucide="check" class="cms-price-ok"></i></span></td>
<td><span class="cms-price-cell">&yen;18.00 <i data-lucide="check" class="cms-price-ok"></i></span></td>
<td><span class="g-tag g-tag-green">已同步</span></td>
<td class="cms-actions">
<a class="g-action" onclick="alert('同步中...')">同步</a>
<a class="g-action" onclick="openDrawer('美式咖啡','18.00','18.00','18.00','18.00')">编辑价格</a>
</td>
</tr>
<!-- 10. 4人聚餐套餐 - 同步失败 -->
<tr>
<td style="font-weight:500">4人聚餐套餐</td>
<td><span class="g-tag g-tag-orange">热销套餐</span></td>
<td>&yen;168.00</td>
<td><span class="cms-price-cell">&yen;168.00 <i data-lucide="x" class="cms-price-fail"></i></span></td>
<td><span class="cms-price-cell">&yen;168.00 <i data-lucide="x" class="cms-price-fail"></i></span></td>
<td><span class="cms-price-cell">&yen;168.00 <i data-lucide="x" class="cms-price-fail"></i></span></td>
<td><span class="g-tag g-tag-red">同步失败</span></td>
<td class="cms-actions">
<a class="g-action" onclick="alert('重新同步中...')">同步</a>
<a class="g-action" onclick="openDrawer('4人聚餐套餐','168.00','168.00','168.00','168.00')">编辑价格</a>
</td>
</tr>
</tbody>
</table>
</div>
<!-- 分页 -->
<div style="padding: 12px 20px;">
<div class="g-pagination">
<span>共 48 条</span>
<button class="g-page-btn" disabled>&laquo;</button>
<button class="g-page-btn active">1</button>
<button class="g-page-btn">2</button>
<button class="g-page-btn">3</button>
<button class="g-page-btn">4</button>
<button class="g-page-btn">5</button>
<button class="g-page-btn">&raquo;</button>
</div>
</div>
</div>
</div>
<!-- 编辑价格抽屉 -->
<div class="g-drawer-mask" id="cmsDrawerMask" onclick="closeDrawer()"></div>
<div class="g-drawer" id="cmsDrawer" style="width:460px">
<div class="g-drawer-hd">
<div class="g-drawer-title">编辑价格</div>
<button class="g-drawer-close" onclick="closeDrawer()">&times;</button>
</div>
<div class="g-drawer-bd">
<!-- 菜品名称(只读) -->
<div class="g-form-group">
<label class="g-form-label">菜品名称</label>
<div class="cms-readonly" id="cmsName">宫保鸡丁套餐</div>
</div>
<!-- 本店价格 -->
<div class="g-form-group">
<label class="g-form-label required">本店价格</label>
<input class="g-input" id="cmsBasePrice" type="number" step="0.01" placeholder="请输入本店价格">
</div>
<div class="g-divider"></div>
<!-- 各平台价格 -->
<div class="g-form-group">
<label class="g-form-label" style="margin-bottom:12px; font-size:14px; font-weight:600;">各平台价格设置</label>
<div class="cms-follow-hint" style="margin-bottom:12px; margin-top:-8px;">关闭开关则该平台不上架此菜品,开启后默认跟随本店价格</div>
<!-- 美团 -->
<div class="cms-platform-row">
<div class="cms-platform-name">
<i data-lucide="shopping-bag"></i> 美团
</div>
<div class="g-toggle on" id="toggleMeituan" onclick="togglePlatform(event.currentTarget, 'priceMeituan')"></div>
<div class="cms-platform-price" id="priceMeituanWrap">
<input class="g-input" id="priceMeituan" type="number" step="0.01" placeholder="跟随本店价格">
</div>
</div>
<!-- 饿了么 -->
<div class="cms-platform-row">
<div class="cms-platform-name">
<i data-lucide="bike"></i> 饿了么
</div>
<div class="g-toggle on" id="toggleEleme" onclick="togglePlatform(event.currentTarget, 'priceEleme')"></div>
<div class="cms-platform-price" id="priceElemeWrap">
<input class="g-input" id="priceEleme" type="number" step="0.01" placeholder="跟随本店价格">
</div>
</div>
<!-- 小程序 -->
<div class="cms-platform-row">
<div class="cms-platform-name">
<i data-lucide="smartphone"></i> 小程序
</div>
<div class="g-toggle on" id="toggleMini" onclick="togglePlatform(event.currentTarget, 'priceMini')"></div>
<div class="cms-platform-price" id="priceMiniWrap">
<input class="g-input" id="priceMini" type="number" step="0.01" placeholder="跟随本店价格">
</div>
</div>
</div>
</div>
<div class="g-drawer-ft">
<button class="g-btn" onclick="closeDrawer()">取消</button>
<button class="g-btn g-btn-primary" onclick="closeDrawer()">保存并同步</button>
</div>
</div>
<script>
/* 抽屉开关 */
function openDrawer(name, base, mt, ele, mini) {
document.getElementById('cmsName').textContent = name;
document.getElementById('cmsBasePrice').value = base;
document.getElementById('priceMeituan').value = mt;
document.getElementById('priceEleme').value = ele;
document.getElementById('priceMini').value = mini;
document.getElementById('cmsDrawerMask').classList.add('open');
document.getElementById('cmsDrawer').classList.add('open');
}
function closeDrawer() {
document.getElementById('cmsDrawerMask').classList.remove('open');
document.getElementById('cmsDrawer').classList.remove('open');
}
/* 平台开关 */
function togglePlatform(el, inputId) {
el.classList.toggle('on');
var wrap = document.getElementById(inputId + 'Wrap');
if (el.classList.contains('on')) {
wrap.classList.remove('disabled');
} else {
wrap.classList.add('disabled');
}
}
/* 初始化图标 */
if (typeof lucide !== 'undefined') { lucide.createIcons(); }
</script>