Files
2026-08-08 17:19:44 +08:00

121 lines
6.7 KiB
PHP
Raw Permalink 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.
<?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>