文件还在测试中
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
/** @var array $p */
|
||||
/** @var array $layout */
|
||||
/** @var string $mode */
|
||||
$v = function ($k, $d = '') use ($p) { return $p ? ($p[$k] ?? $d) : $d; };
|
||||
$isEdit = !empty($p);
|
||||
$switchUrl = $isEdit ? site_url('admin/pages/switchMode/' . (int)$p['id']) : '';
|
||||
$initial = json_encode($layout ?: []);
|
||||
?>
|
||||
<div class="pb-root">
|
||||
<div class="pb-topbar">
|
||||
<div class="pb-top-left">
|
||||
<a class="btn-ghost" href="<?php echo site_url('admin/pages'); ?>">← 返回</a>
|
||||
<span class="pb-t">可视化编辑:<?php echo e($p['title']); ?></span>
|
||||
<span class="mode-badge mode-builder">可视化编辑</span>
|
||||
<?php if ($isEdit): ?>
|
||||
<div class="mode-switch-sel">
|
||||
<label for="modeSel">切换模式</label>
|
||||
<select id="modeSel" class="mode-sel" onchange="location.href='<?php echo $switchUrl; ?>?mode='+this.value">
|
||||
<option value="fixed" <?php echo $mode === 'fixed' ? 'selected' : ''; ?>>固定版面</option>
|
||||
<option value="builder" <?php echo $mode === 'builder' ? 'selected' : ''; ?>>可视化编辑</option>
|
||||
</select>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<form id="pbForm" method="post" action="<?php echo site_url('admin/pages/update/' . $p['id']); ?>" class="pb-top-form">
|
||||
<?php echo csrf_field(); ?>
|
||||
<input type="hidden" name="layout" id="pbLayout">
|
||||
<input class="pb-title" name="title" value="<?php echo e($p['title']); ?>" placeholder="页面标题">
|
||||
<button class="btn-primary" type="submit">保存页面</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="pb-workspace">
|
||||
<!-- 左侧:素材 + 添加 -->
|
||||
<aside class="pb-left">
|
||||
<div class="pb-box">
|
||||
<h4>素材库</h4>
|
||||
<label class="pb-upload">+ 上传图片
|
||||
<input type="file" id="pbFile" accept="image/*" hidden>
|
||||
</label>
|
||||
<div class="pb-lib" id="pbLib"></div>
|
||||
</div>
|
||||
<div class="pb-box">
|
||||
<h4>添加元素</h4>
|
||||
<button class="pb-add" id="pbAddText" type="button">+ 文字</button>
|
||||
<button class="pb-add" id="pbAddImg" type="button">+ 图片(从素材库)</button>
|
||||
</div>
|
||||
<p class="pb-hint">· 拖动元素移动位置<br>· 拖动右下角缩放<br>· 双击文字可直接编辑<br>· 选中后在右侧改样式</p>
|
||||
</aside>
|
||||
|
||||
<!-- 中间:画布 -->
|
||||
<main class="pb-canvas-wrap">
|
||||
<div class="pb-stage" id="pbStage"></div>
|
||||
</main>
|
||||
|
||||
<!-- 右侧:属性 -->
|
||||
<aside class="pb-right">
|
||||
<div class="pb-box">
|
||||
<h4>属性</h4>
|
||||
<div id="pbPropsBody" class="pb-empty">在画布中选择一个元素以编辑属性</div>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.pb-root{display:flex;flex-direction:column}
|
||||
.pb-topbar{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:14px 18px;background:#fff;border-bottom:1px solid var(--admin-border,#e2e8f0);position:sticky;top:0;z-index:30}
|
||||
.pb-top-left{display:flex;align-items:center;gap:12px}
|
||||
.pb-t{font-weight:700;color:#0f172a}
|
||||
.mode-switch-sel{display:inline-flex;align-items:center;gap:8px}
|
||||
.mode-switch-sel label{font-size:13px;color:#64748b}
|
||||
.mode-sel{border:1px solid #e2e8f0;border-radius:10px;padding:6px 12px;font-size:13px;background:#fff;color:#334155;cursor:pointer;min-width:140px}
|
||||
.mode-sel:focus{border-color:#0ea5e9;box-shadow:0 0 0 3px rgba(14,165,233,.12)}
|
||||
.mode-badge{display:inline-block;margin-left:6px;padding:2px 10px;border-radius:999px;font-size:12px;font-weight:600;vertical-align:middle;line-height:1.7}
|
||||
.mode-badge.mode-fixed{background:#e0f2fe;color:#0369a1}
|
||||
.mode-badge.mode-builder{background:#ede9fe;color:#6d28d9}
|
||||
.pb-top-form{display:flex;align-items:center;gap:10px}
|
||||
.pb-title{border:1px solid #e2e8f0;border-radius:10px;padding:8px 12px;font-size:14px;min-width:200px}
|
||||
.pb-workspace{display:flex;gap:0;min-height:72vh}
|
||||
.pb-left,.pb-right{width:248px;flex:0 0 248px;background:#f8fafc;border-left:1px solid #e2e8f0;border-right:1px solid #e2e8f0;padding:14px;overflow:auto}
|
||||
.pb-right{border-left:1px solid #e2e8f0}
|
||||
.pb-box{margin-bottom:18px}
|
||||
.pb-box h4{margin:0 0 10px;font-size:13px;color:#475569;letter-spacing:.04em;text-transform:uppercase}
|
||||
.pb-upload{display:block;text-align:center;background:#0ea5e9;color:#fff;border-radius:10px;padding:10px;cursor:pointer;font-size:14px;font-weight:600;margin-bottom:10px}
|
||||
.pb-upload:hover{background:#0284c7}
|
||||
.pb-lib{display:flex;flex-wrap:wrap;gap:8px}
|
||||
.pb-lib img{width:64px;height:64px;object-fit:cover;border-radius:8px;border:2px solid transparent;cursor:pointer}
|
||||
.pb-lib img:hover{border-color:#0ea5e9}
|
||||
.pb-add{display:block;width:100%;margin-bottom:8px;background:#fff;border:1px dashed #94a3b8;color:#334155;border-radius:10px;padding:10px;cursor:pointer;font-size:14px}
|
||||
.pb-add:hover{border-color:#0ea5e9;color:#0ea5e9}
|
||||
.pb-hint{font-size:12px;color:#94a3b8;line-height:1.8}
|
||||
.pb-canvas-wrap{flex:1;overflow:auto;background:#eef2f7;background-image:radial-gradient(#dbe3ec 1px,transparent 1px);background-size:18px 18px;padding:26px;display:flex;justify-content:center;align-items:flex-start}
|
||||
.pb-stage{position:relative;width:720px;min-height:480px;background:#fff;box-shadow:0 10px 40px rgba(15,23,42,.12);border-radius:6px}
|
||||
.pb-el{position:absolute;box-sizing:border-box;cursor:move;user-select:none}
|
||||
.pb-text{width:100%;min-height:1.4em;white-space:pre-wrap;word-break:break-word;padding:2px 4px}
|
||||
.pb-img{width:100%;display:block;object-fit:cover;border-radius:4px}
|
||||
.pb-text[contenteditable=true]{user-select:text;cursor:text;outline:none}
|
||||
.pb-el.sel{outline:2px dashed #0ea5e9;outline-offset:2px}
|
||||
.pb-handle{position:absolute;right:-7px;bottom:-7px;width:14px;height:14px;background:#0ea5e9;border:2px solid #fff;border-radius:50%;cursor:nwse-resize;display:none}
|
||||
.pb-el.sel .pb-handle{display:block}
|
||||
.pb-empty{font-size:13px;color:#94a3b8}
|
||||
#pbPropsBody label{display:block;font-size:12px;color:#64748b;margin:10px 0 4px}
|
||||
#pbPropsBody input[type=text],#pbPropsBody input[type=number],#pbPropsBody textarea,#pbPropsBody select{width:100%;border:1px solid #e2e8f0;border-radius:8px;padding:7px 9px;font-size:13px;font-family:inherit}
|
||||
#pbPropsBody textarea{min-height:64px;resize:vertical}
|
||||
.pb-del{margin-top:14px;width:100%;background:#fef2f2;color:#dc2626;border:1px solid #fecaca;border-radius:8px;padding:8px;cursor:pointer;font-size:13px}
|
||||
.pb-del:hover{background:#fee2e2}
|
||||
@media(max-width:980px){.pb-left,.pb-right{width:180px;flex-basis:180px}}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
window.__PB_INIT__ = <?php echo $initial; ?>;
|
||||
window.__PB_MEDIA__ = '<?php echo site_url('admin/media'); ?>';
|
||||
window.__PB_UPLOAD__ = '<?php echo site_url('admin/media/upload'); ?>';
|
||||
window.__PB_CSRF__ = '<?php echo csrf_token(); ?>';
|
||||
window.__PB_MODULE__ = 'page';
|
||||
window.__PB_DELETE__ = '<?php echo site_url('admin/media/delete/'); ?>';
|
||||
</script>
|
||||
<script src="<?php echo asset('js/page-builder.js'); ?>"></script>
|
||||
Reference in New Issue
Block a user