- 在OtherFees组件中添加Fragment包装和配置日志输出 - 将PackingSpec组件中的div标签替换为View组件以保持一致性 - 修复Step2Preview组件中各模块的key值设置问题 - 在ExpenseCostList组件中添加费用显示和可添加费用的过滤逻辑 - 根据是否有可添加费用控制添加按钮的显示 - 在DeliveryFormSection组件中添加costList属性并更新otherFees模块配置 - 更新费用项的映射关系和显示配置 - 修复API类型定义中多个ID字段的数据类型从string到number - 为CostVO类型添加isDefault字段 - 调整分页响应类型中的empty和notEmpty字段位置 - 为TreeLong类型调整字段顺序 - 更新APP版本号从v0.0.57到v0.0.58 - 优化HTML页面样式布局和容器样式
733 lines
15 KiB
HTML
733 lines
15 KiB
HTML
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>新发雷盛西瓜管理系统</title>
|
||
<style>
|
||
body {
|
||
margin: 0;
|
||
background: #f5f5f5;
|
||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||
width: 100vw;
|
||
height: 100vh;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.container {
|
||
background: white;
|
||
border-radius: 12px;
|
||
overflow: hidden;
|
||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.header h1 {
|
||
margin: 0 0 10px 0;
|
||
font-size: 24px;
|
||
}
|
||
|
||
.header p {
|
||
margin: 0;
|
||
opacity: 0.9;
|
||
}
|
||
|
||
.content-wrapper {
|
||
display: flex;
|
||
padding: 20px;
|
||
gap: 30px;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
/* 左侧设备选择器 */
|
||
.device-selector {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 10px;
|
||
padding: 15px;
|
||
background: #f8f9fa;
|
||
border-radius: 12px;
|
||
flex-shrink: 0;
|
||
width: 140px;
|
||
height: fit-content;
|
||
position: sticky;
|
||
top: 20px;
|
||
}
|
||
|
||
.device-selector-label {
|
||
font-weight: 600;
|
||
color: #495057;
|
||
font-size: 13px;
|
||
text-align: center;
|
||
padding-bottom: 8px;
|
||
border-bottom: 2px solid #dee2e6;
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.device-buttons {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
}
|
||
|
||
.device-btn {
|
||
padding: 10px 12px;
|
||
border: 2px solid #dee2e6;
|
||
background: white;
|
||
border-radius: 8px;
|
||
cursor: pointer;
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
color: #495057;
|
||
transition: all 0.2s;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 4px;
|
||
text-align: center;
|
||
}
|
||
|
||
.device-btn:hover {
|
||
border-color: #667eea;
|
||
color: #667eea;
|
||
transform: translateX(2px);
|
||
}
|
||
|
||
.device-btn.active {
|
||
background: #667eea;
|
||
border-color: #667eea;
|
||
color: white;
|
||
transform: translateX(4px);
|
||
}
|
||
|
||
.device-btn .device-icon {
|
||
font-size: 20px;
|
||
}
|
||
|
||
.device-btn span:last-child {
|
||
font-size: 12px;
|
||
}
|
||
|
||
/* 右侧内容区 */
|
||
.main-content {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 40px;
|
||
justify-content: center;
|
||
min-width: 0;
|
||
}
|
||
|
||
.frame-section {
|
||
flex: 1;
|
||
min-width: 400px;
|
||
max-width: 500px;
|
||
}
|
||
|
||
.qrcode-section {
|
||
flex: 1;
|
||
min-width: 300px;
|
||
max-width: 400px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
/* 通用设备框架样式 */
|
||
.frame-wrapper {
|
||
overflow: hidden;
|
||
position: relative;
|
||
background: white;
|
||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
|
||
margin: 0 auto;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
/* iPhone X */
|
||
.frame-wrapper.iphone-x {
|
||
width: 375px;
|
||
height: 812px;
|
||
border: 12px solid #333;
|
||
border-radius: 40px;
|
||
}
|
||
|
||
.frame-wrapper.iphone-x:before {
|
||
content: "";
|
||
position: absolute;
|
||
top: 0;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 60%;
|
||
height: 25px;
|
||
background: #333;
|
||
border-bottom-left-radius: 15px;
|
||
border-bottom-right-radius: 15px;
|
||
z-index: 10;
|
||
}
|
||
|
||
.frame-wrapper.iphone-x:after {
|
||
content: "";
|
||
position: absolute;
|
||
bottom: 8px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 134px;
|
||
height: 5px;
|
||
background: #333;
|
||
border-radius: 3px;
|
||
z-index: 10;
|
||
}
|
||
|
||
/* iPhone 14 Pro Max */
|
||
.frame-wrapper.iphone-14-pro {
|
||
width: 430px;
|
||
height: 932px;
|
||
border: 8px solid #1c1c1e;
|
||
border-radius: 55px;
|
||
}
|
||
|
||
.frame-wrapper.iphone-14-pro:before {
|
||
content: "";
|
||
position: absolute;
|
||
top: 12px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 140px;
|
||
height: 35px;
|
||
background: #1c1c1e;
|
||
border-radius: 20px;
|
||
z-index: 10;
|
||
}
|
||
|
||
.frame-wrapper.iphone-14-pro:after {
|
||
content: "";
|
||
position: absolute;
|
||
bottom: 8px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 134px;
|
||
height: 5px;
|
||
background: #333;
|
||
border-radius: 3px;
|
||
z-index: 10;
|
||
}
|
||
|
||
/* Samsung Galaxy S21 */
|
||
.frame-wrapper.galaxy-s21 {
|
||
width: 384px;
|
||
height: 854px;
|
||
border: 10px solid #1a1a1a;
|
||
border-radius: 32px;
|
||
}
|
||
|
||
.frame-wrapper.galaxy-s21:before {
|
||
content: "";
|
||
position: absolute;
|
||
top: 8px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 12px;
|
||
height: 12px;
|
||
background: #1a1a1a;
|
||
border-radius: 50%;
|
||
z-index: 10;
|
||
}
|
||
|
||
/* iPad */
|
||
.frame-wrapper.ipad {
|
||
width: 768px;
|
||
height: 1024px;
|
||
border: 18px solid #b4b4b4;
|
||
border-radius: 24px;
|
||
}
|
||
|
||
.frame-wrapper.ipad:before {
|
||
content: "";
|
||
position: absolute;
|
||
top: 18px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 12px;
|
||
height: 12px;
|
||
background: #333;
|
||
border-radius: 50%;
|
||
z-index: 10;
|
||
}
|
||
|
||
/* iPad Pro 11 */
|
||
.frame-wrapper.ipad-pro {
|
||
width: 834px;
|
||
height: 1194px;
|
||
border: 14px solid #b4b4b4;
|
||
border-radius: 18px;
|
||
}
|
||
|
||
/* Android 通用 */
|
||
.frame-wrapper.android {
|
||
width: 360px;
|
||
height: 760px;
|
||
border: 10px solid #2c2c2c;
|
||
border-radius: 24px;
|
||
}
|
||
|
||
.frame-wrapper.android:before {
|
||
content: "";
|
||
position: absolute;
|
||
top: 10px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 60px;
|
||
height: 8px;
|
||
background: #2c2c2c;
|
||
border-radius: 4px;
|
||
z-index: 10;
|
||
}
|
||
|
||
/* 屏幕容器 */
|
||
.frame-wrapper .screen-container {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
overflow: hidden;
|
||
z-index: 1;
|
||
}
|
||
|
||
.frame-wrapper.iphone-x .screen-container,
|
||
.frame-wrapper.iphone-14-pro .screen-container,
|
||
.frame-wrapper.galaxy-s21 .screen-container,
|
||
.frame-wrapper.android .screen-container {
|
||
border-radius: 28px;
|
||
}
|
||
|
||
.frame-wrapper.ipad .screen-container,
|
||
.frame-wrapper.ipad-pro .screen-container {
|
||
border-radius: 12px;
|
||
}
|
||
|
||
iframe {
|
||
width: 100%;
|
||
height: calc(100% - 84px); /* 减去TabBar高度 */
|
||
border: none;
|
||
}
|
||
|
||
/* 顶部TabBar */
|
||
.tabbar {
|
||
height: 50px;
|
||
background: rgba(248, 248, 248, 0.95);
|
||
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 0 16px;
|
||
z-index: 20;
|
||
}
|
||
|
||
.tabbar-time {
|
||
font-size: 15px;
|
||
font-weight: 600;
|
||
color: #000;
|
||
margin-right: auto;
|
||
}
|
||
|
||
.tabbar-icon svg {
|
||
width: 100%;
|
||
height: 100%;
|
||
fill: #000;
|
||
}
|
||
|
||
/* 底部安全区域占位 */
|
||
.safe-area-bottom {
|
||
height: 34px;
|
||
background: transparent;
|
||
z-index: 5;
|
||
}
|
||
|
||
.qrcode-container {
|
||
background: white;
|
||
padding: 25px;
|
||
border-radius: 16px;
|
||
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1);
|
||
text-align: center;
|
||
margin-bottom: 25px;
|
||
border: 1px solid #eee;
|
||
}
|
||
|
||
#qrcode {
|
||
width: 200px;
|
||
height: 200px;
|
||
margin: 15px auto;
|
||
padding: 10px;
|
||
background: white;
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.qrcode-title {
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.qrcode-desc {
|
||
color: #666;
|
||
font-size: 14px;
|
||
line-height: 1.5;
|
||
margin-bottom: 20px;
|
||
max-width: 300px;
|
||
}
|
||
|
||
.url-display {
|
||
background: #f8f9fa;
|
||
padding: 12px 15px;
|
||
border-radius: 8px;
|
||
font-size: 13px;
|
||
color: #555;
|
||
word-break: break-all;
|
||
margin-top: 15px;
|
||
border: 1px solid #e9ecef;
|
||
max-width: 300px;
|
||
}
|
||
|
||
.mobile-tips {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 10px;
|
||
margin-top: 15px;
|
||
color: #666;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.mobile-tips svg {
|
||
width: 20px;
|
||
height: 20px;
|
||
fill: #667eea;
|
||
}
|
||
|
||
.tips {
|
||
padding: 20px;
|
||
text-align: center;
|
||
color: #666;
|
||
font-size: 14px;
|
||
background: #f8f9fa;
|
||
border-top: 1px solid #eee;
|
||
}
|
||
|
||
@media (max-width: 1100px) {
|
||
.content-wrapper {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.device-selector {
|
||
width: 100%;
|
||
flex-direction: row;
|
||
flex-wrap: wrap;
|
||
justify-content: center;
|
||
position: static;
|
||
}
|
||
|
||
.device-buttons {
|
||
flex-direction: row;
|
||
flex-wrap: wrap;
|
||
justify-content: center;
|
||
}
|
||
|
||
.device-btn {
|
||
flex-direction: row;
|
||
padding: 8px 16px;
|
||
}
|
||
|
||
.device-btn:hover {
|
||
transform: translateY(-1px);
|
||
}
|
||
|
||
.device-btn.active {
|
||
transform: translateY(-1px);
|
||
}
|
||
|
||
.device-btn .device-icon {
|
||
font-size: 16px;
|
||
}
|
||
|
||
.device-btn span:last-child {
|
||
font-size: 14px;
|
||
}
|
||
|
||
.main-content {
|
||
flex-direction: column;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.frame-section, .qrcode-section {
|
||
min-width: 100%;
|
||
max-width: 100%;
|
||
}
|
||
|
||
.qrcode-section {
|
||
order: -1;
|
||
}
|
||
}
|
||
|
||
/* 设备信息提示 */
|
||
.device-info {
|
||
text-align: center;
|
||
padding: 10px;
|
||
color: #666;
|
||
font-size: 13px;
|
||
background: #f8f9fa;
|
||
border-radius: 6px;
|
||
margin-top: 15px;
|
||
}
|
||
|
||
.device-info .device-size {
|
||
font-weight: 600;
|
||
color: #495057;
|
||
}
|
||
</style>
|
||
<script src="qrcode.min.js"></script>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
|
||
<div class="content-wrapper">
|
||
<!-- 左侧设备选择器 -->
|
||
<div class="device-selector">
|
||
<span class="device-selector-label">📱 设备</span>
|
||
<div class="device-buttons">
|
||
<button class="device-btn active" data-device="iphone-x">
|
||
<span class="device-icon">📱</span>
|
||
<span>iPhone X</span>
|
||
</button>
|
||
<button class="device-btn" data-device="iphone-14-pro">
|
||
<span class="device-icon">📲</span>
|
||
<span>iPhone 14 Pro</span>
|
||
</button>
|
||
<button class="device-btn" data-device="galaxy-s21">
|
||
<span class="device-icon">🤖</span>
|
||
<span>Galaxy S21</span>
|
||
</button>
|
||
<button class="device-btn" data-device="android">
|
||
<span class="device-icon">📱</span>
|
||
<span>Android</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 右侧内容区 -->
|
||
<div class="main-content">
|
||
<div class="frame-section">
|
||
<div class="frame-wrapper iphone-x" id="device-frame">
|
||
<div class="screen-container">
|
||
<!-- 顶部TabBar -->
|
||
<div class="tabbar">
|
||
<div class="tabbar-time" id="current-time">9:41</div>
|
||
|
||
</div>
|
||
|
||
<!-- iframe内容区域 -->
|
||
<iframe id="mobile-frame" src="/"
|
||
title="移动端页面"></iframe>
|
||
|
||
<!-- 底部安全区域占位 -->
|
||
<div class="safe-area-bottom"></div>
|
||
</div>
|
||
</div>
|
||
<div class="device-info">
|
||
当前设备: <span class="device-size" id="device-name">iPhone X (375×812)</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="qrcode-section">
|
||
<div class="qrcode-container">
|
||
<div class="qrcode-title">手机扫码预览</div>
|
||
<div class="qrcode-desc">
|
||
使用手机扫描下方二维码,可直接在手机上访问此页面,获得真实的移动端体验
|
||
</div>
|
||
|
||
<div id="qrcode"></div>
|
||
|
||
<div class="url-display" id="current-url">
|
||
<!-- URL 将在这里显示 -->
|
||
</div>
|
||
|
||
<div class="mobile-tips">
|
||
<svg viewBox="0 0 24 24">
|
||
<path
|
||
d="M17 1.01L7 1c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99zM17 19H7V5h10v14z"/>
|
||
</svg>
|
||
<span>建议使用手机扫描体验最佳效果</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// 设备配置信息
|
||
const deviceConfigs = {
|
||
'iphone-x': {
|
||
name: 'iPhone X',
|
||
size: '375×812',
|
||
className: 'iphone-x'
|
||
},
|
||
'iphone-14-pro': {
|
||
name: 'iPhone 14 Pro Max',
|
||
size: '430×932',
|
||
className: 'iphone-14-pro'
|
||
},
|
||
'galaxy-s21': {
|
||
name: 'Samsung Galaxy S21',
|
||
size: '384×854',
|
||
className: 'galaxy-s21'
|
||
},
|
||
'android': {
|
||
name: 'Android (通用)',
|
||
size: '360×760',
|
||
className: 'android'
|
||
},
|
||
};
|
||
|
||
// 当前选择的设备
|
||
let currentDevice = 'iphone-x';
|
||
|
||
// 切换设备
|
||
function switchDevice(deviceId) {
|
||
const frame = document.getElementById('device-frame');
|
||
const deviceName = document.getElementById('device-name');
|
||
const config = deviceConfigs[deviceId];
|
||
|
||
// 移除所有设备类名
|
||
frame.className = 'frame-wrapper';
|
||
|
||
// 添加新设备类名
|
||
frame.classList.add(config.className);
|
||
|
||
// 更新设备信息显示
|
||
deviceName.textContent = `${config.name} (${config.size})`;
|
||
|
||
// 保存到localStorage
|
||
localStorage.setItem('previewDevice', deviceId);
|
||
|
||
// 更新按钮状态
|
||
document.querySelectorAll('.device-btn').forEach(btn => {
|
||
btn.classList.remove('active');
|
||
if (btn.dataset.device === deviceId) {
|
||
btn.classList.add('active');
|
||
}
|
||
});
|
||
|
||
currentDevice = deviceId;
|
||
}
|
||
|
||
// 初始化设备选择器
|
||
function initDeviceSelector() {
|
||
// 从localStorage读取上次选择的设备
|
||
const savedDevice = localStorage.getItem('previewDevice');
|
||
if (savedDevice && deviceConfigs[savedDevice]) {
|
||
switchDevice(savedDevice);
|
||
}
|
||
|
||
// 绑定按钮点击事件
|
||
document.querySelectorAll('.device-btn').forEach(btn => {
|
||
btn.addEventListener('click', function() {
|
||
const deviceId = this.dataset.device;
|
||
switchDevice(deviceId);
|
||
});
|
||
});
|
||
}
|
||
|
||
// 更新当前时间
|
||
function updateCurrentTime() {
|
||
const now = new Date();
|
||
const hours = now.getHours().toString().padStart(2, '0');
|
||
const minutes = now.getMinutes().toString().padStart(2, '0');
|
||
document.getElementById('current-time').textContent = `${hours}:${minutes}`;
|
||
}
|
||
|
||
// 获取当前页面URL
|
||
function getCurrentUrl() {
|
||
// 如果 $request_uri 是占位符,则使用实际URL
|
||
let iframeSrc = document.getElementById('mobile-frame').src;
|
||
if (iframeSrc.includes('$request_uri')) {
|
||
// 使用当前页面URL(去掉预览页面的路径)
|
||
let currentUrl = window.location.href;
|
||
// 移除预览页面的查询参数或路径
|
||
return currentUrl.split('?')[0].replace(/\/preview\/?$/, '');
|
||
}
|
||
return iframeSrc;
|
||
}
|
||
|
||
// 生成二维码
|
||
function generateQRCode() {
|
||
const url = getCurrentUrl();
|
||
const qrcodeElement = document.getElementById('qrcode');
|
||
const urlDisplay = document.getElementById('current-url');
|
||
|
||
// 显示URL
|
||
urlDisplay.textContent = url.length > 50 ? url.substring(0, 50) + '...' : url;
|
||
|
||
// 清空之前的二维码
|
||
qrcodeElement.innerHTML = '';
|
||
|
||
// 生成当前页面的二维码
|
||
new QRCode(document.getElementById('qrcode'), {
|
||
text: window.location.href,
|
||
width: 200,
|
||
height: 200,
|
||
margin: 1,
|
||
color: {
|
||
dark: '#333333',
|
||
light: '#ffffff'
|
||
}
|
||
});
|
||
}
|
||
|
||
// 处理iframe内部链接
|
||
var iframe = document.getElementById("mobile-frame");
|
||
iframe.onload = function () {
|
||
try {
|
||
var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
|
||
var links = iframeDoc.querySelectorAll("a");
|
||
links.forEach(function (link) {
|
||
link.onclick = function (e) {
|
||
e.preventDefault();
|
||
var href = this.getAttribute("href");
|
||
if (href && !href.match(/^(http|https|#|javascript:)/)) {
|
||
iframe.src = href;
|
||
// 更新二维码
|
||
setTimeout(generateQRCode, 100);
|
||
}
|
||
};
|
||
});
|
||
} catch (e) {
|
||
// 跨域限制
|
||
}
|
||
|
||
// 每次iframe加载后更新二维码
|
||
generateQRCode();
|
||
};
|
||
|
||
// 页面加载时初始化
|
||
document.addEventListener('DOMContentLoaded', function () {
|
||
// 初始化设备选择器
|
||
initDeviceSelector();
|
||
|
||
// 更新时间
|
||
updateCurrentTime();
|
||
setInterval(updateCurrentTime, 60000); // 每分钟更新一次
|
||
|
||
// 生成二维码
|
||
generateQRCode();
|
||
});
|
||
|
||
// 监听URL变化(如果使用History API)
|
||
window.addEventListener('popstate', generateQRCode);
|
||
</script>
|
||
</body>
|
||
</html>
|