Files
coolcoth.com/app/Views/admin/product_form.php
T
2026-08-08 15:53:53 +08:00

200 lines
12 KiB
PHP
Raw 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 string $mode */
$v = function ($k, $d = '') use ($p) { return $p ? ($p[$k] ?? $d) : $d; };
$isEdit = !empty($p);
$mode = $mode ?? 'fixed';
$switchUrl = $isEdit ? site_url('admin/products/switchMode/' . (int)$p['id']) : '';
$coverVal = $v('cover');
$galleryArr = [];
$g = $v('gallery');
if ($g) { $d = @json_decode($g, true); if (is_array($d)) $galleryArr = $d; }
$desc = $v('description');
?>
<div class="page-head">
<div>
<h1><?php echo $isEdit ? '编辑产品' : '新增产品'; ?><span class="mode-badge mode-fixed">固定版面</span></h1>
<div class="desc">固定版面:填写资料并上传封面 / 图集,图片自适应展示<?php echo $isEdit ? ';可切换为可视化自由排版。' : '。'; ?></div>
</div>
<?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 else: ?>
<div class="mode-switch-sel">
<label for="modeSel">排版方式</label>
<select id="modeSel" class="mode-sel">
<option value="fixed" <?php echo $mode === 'fixed' ? 'selected' : ''; ?>>固定版面</option>
<option value="builder" <?php echo $mode === 'builder' ? 'selected' : ''; ?>>可视化编辑</option>
</select>
</div>
<?php endif; ?>
</div>
<div class="admin-card">
<form id="fxForm" method="post" action="<?php echo site_url($isEdit ? 'admin/products/update/' . $p['id'] : 'admin/products/store'); ?>" enctype="multipart/form-data">
<?php echo csrf_field(); ?>
<input type="hidden" name="mode" value="fixed">
<div class="form-grid">
<div class="field">
<label>所属分类 *</label>
<select name="category_id" required>
<?php foreach ($cats as $c): ?><option value="<?php echo e($c['id']); ?>" <?php echo $v('category_id') == $c['id'] ? 'selected' : ''; ?>><?php echo e($c['name']); ?></option><?php endforeach; ?>
</select>
</div>
<div class="field"><label>产品名称 *</label><input name="name" value="<?php echo e($v('name')); ?>" required></div>
<div class="field"><label>URL 标识(留空按序号生成,短而稳定)</label><input name="slug" value="<?php echo e($v('slug')); ?>" placeholder="留空则自动生成如 12"></div>
<div class="field"><label>价格(元,起)</label><input name="price" type="number" step="0.01" value="<?php echo e($v('price')); ?>"></div>
</div>
<div class="field"><label>一句话简介</label><input name="summary" value="<?php echo e($v('summary')); ?>"></div>
<div class="field">
<label>封面图(上传,建议 4:3,将作为列表/详情主图)</label>
<input type="file" name="cover" accept="image/*">
<?php if ($coverVal): ?>
<div class="img-prev"><img src="<?php echo e(site_url($coverVal)); ?>" alt=""><span class="img-prev-path"><?php echo e($coverVal); ?></span></div>
<p class="fx-hint">已上传封面;重新选择文件将替换,留空则保留。</p>
<?php endif; ?>
<input type="text" name="cover_url" value="<?php echo e($coverVal); ?>" placeholder="或填写图片地址/路径 assets/uploads/xxx.jpg 或 http(s)://" style="margin-top:8px">
</div>
<div class="field fx-fixed-only">
<label>图集(可一次选择多张,每张都会单独上传)</label>
<input type="file" name="gallery[]" accept="image/*" multiple>
<?php if (!empty($galleryArr)): ?>
<div class="gallery-prev">
<?php foreach ($galleryArr as $gp): ?><div class="gp-item"><img src="<?php echo e(site_url($gp)); ?>" alt=""><span><?php echo e($gp); ?></span></div><?php endforeach; ?>
</div>
<label class="chk-inline"><input type="checkbox" name="clear_gallery" value="1"> 清空现有图集(重新上传)</label>
<?php endif; ?>
</div>
<div class="field fx-fixed-only">
<label>详细描述(富文本,每个图片均可上传,前台自适应展示)</label>
<div class="fx-toolbar">
<button type="button" data-cmd="bold" title="加粗"><b>B</b></button>
<button type="button" data-cmd="italic" title="斜体"><i>I</i></button>
<button type="button" data-cmd="formatBlock" data-val="H2">H2</button>
<button type="button" data-cmd="formatBlock" data-val="H3">H3</button>
<button type="button" data-cmd="insertUnorderedList" title="无序列表">• 列表</button>
<button type="button" data-cmd="insertOrderedList" title="有序列表">1. 列表</button>
<button type="button" data-cmd="formatBlock" data-val="BLOCKQUOTE" title="引用">引用</button>
<button type="button" id="fxLink" title="插入链接">链接</button>
<button type="button" id="fxImg" title="插入图片">图片</button>
</div>
<div class="fx-editor" id="fxEditor" contenteditable="true"><?php echo $desc; ?></div>
<textarea name="description" id="fxContent" hidden><?php echo e($desc); ?></textarea>
<p class="fx-hint">直接排版正文即可;点击「图片」可从素材库选择或上传新图。保存后前台固定版式展示。</p>
</div>
<div class="field">
<label>规格参数(每行一项,格式:参数名|参数值)</label>
<textarea name="specs" placeholder="降温方式|水冷循环&#10;续航|6-8 小时"><?php echo e($specText ?? ''); ?></textarea>
</div>
<div class="form-grid">
<div class="field"><label>标签(逗号分隔)</label><input name="tags" value="<?php echo e($v('tags')); ?>"></div>
<div class="field"><label>排序(越小越靠前)</label><input name="sort_order" type="number" value="<?php echo e($v('sort_order', 0)); ?>"></div>
</div>
<div class="field" style="display:flex;align-items:center;gap:8px">
<input type="checkbox" name="status" value="1" <?php echo $v('status', 1) ? 'checked' : ''; ?> id="st"> <label for="st" style="margin:0">立即上线</label>
</div>
<div class="form-actions">
<button class="btn-primary" type="submit">保存</button>
<a class="btn-ghost" href="<?php echo site_url('admin/products'); ?>">取消</a>
</div>
</form>
</div>
<!-- 图片选择弹层 -->
<div class="fx-modal" id="fxModal" hidden>
<div class="fx-modal-box">
<div class="fx-modal-head"><span>选择图片</span><button type="button" id="fxModalClose">×</button></div>
<div class="fx-modal-body">
<label class="fx-upload"> 上传图片<input type="file" id="fxUp" accept="image/*" hidden></label>
<div class="fx-lib" id="fxLib"></div>
</div>
</div>
</div>
<style>
.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:8px 12px;font-size:14px;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:10px;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}
.img-prev{display:flex;align-items:center;gap:10px;margin-top:10px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:10px;padding:8px 10px}
.img-prev img{width:72px;height:54px;object-fit:cover;border-radius:8px;display:block}
.img-prev-path{font-size:12px;color:#94a3b8;word-break:break-all}
.gallery-prev{display:flex;flex-wrap:wrap;gap:10px;margin-top:10px}
.gallery-prev .gp-item{width:104px;border:1px solid #e2e8f0;border-radius:10px;overflow:hidden;background:#fff}
.gallery-prev .gp-item img{width:100%;height:74px;object-fit:cover;display:block}
.gallery-prev .gp-item span{display:block;font-size:11px;color:#94a3b8;padding:4px 6px;word-break:break-all;line-height:1.3}
.chk-inline{display:inline-flex;align-items:center;gap:6px;margin-top:10px;font-size:13px;color:#64748b;cursor:pointer}
.fx-toolbar{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px}
.fx-toolbar button{width:auto;min-width:38px;height:34px;padding:0 10px;border:1px solid #e2e8f0;background:#fff;border-radius:8px;cursor:pointer;font-size:14px;color:#334155}
.fx-toolbar button:hover{border-color:#0ea5e9;color:#0ea5e9}
.fx-editor{min-height:260px;border:1px solid #e2e8f0;border-radius:10px;padding:16px 18px;font-size:16px;line-height:1.9;outline:none;background:#fff;overflow:auto}
.fx-editor:focus{border-color:#0ea5e9;box-shadow:0 0 0 3px rgba(14,165,233,.12)}
.fx-editor h2{font-size:24px;margin:.6em 0 .4em}
.fx-editor h3{font-size:20px;margin:.6em 0 .4em}
.fx-editor blockquote{margin:.6em 0;padding:8px 14px;border-left:4px solid #0ea5e9;color:#475569;background:#f8fafc}
.fx-editor img{max-width:100%;height:auto;border-radius:8px;display:block;margin:8px 0}
.fx-editor a{color:#0ea5e9}
.fx-hint{font-size:12px;color:#94a3b8;margin:8px 2px 0}
.fx-modal{position:fixed;inset:0;background:rgba(15,23,42,.45);display:flex;align-items:center;justify-content:center;z-index:80}
.fx-modal[hidden]{display:none}
.fx-modal-box{background:#fff;border-radius:14px;width:420px;max-width:92vw;overflow:hidden}
.fx-modal-head{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;border-bottom:1px solid #e2e8f0;font-weight:700}
.fx-modal-head button{border:none;background:none;font-size:22px;cursor:pointer;color:#64748b;line-height:1}
.fx-modal-body{padding:16px;max-height:60vh;overflow:auto}
.fx-upload{display:block;text-align:center;background:#0ea5e9;color:#fff;border-radius:10px;padding:10px;cursor:pointer;font-weight:600;margin-bottom:12px}
.fx-lib{display:flex;flex-wrap:wrap;gap:8px}
.fx-lib img{width:72px;height:72px;object-fit:cover;border-radius:8px;cursor:pointer;border:2px solid transparent}
.fx-lib img:hover{border-color:#0ea5e9}
</style>
<script>
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(); ?>';
</script>
<script src="<?php echo asset('js/fixed-editor.js'); ?>"></script>
<script>
// 新增产品时按「排版方式」选择器联动:选可视化编辑则隐藏图集/详细描述,并提示保存后进入可视化编辑器
(function(){
var sel = document.getElementById('modeSel');
if(!sel) return;
var isCreate = <?php echo $isEdit ? 'false' : 'true'; ?>;
var modeField = document.querySelector('#fxForm input[name="mode"]');
var fixedOnly = document.querySelectorAll('.fx-fixed-only');
var note = document.createElement('p');
note.className = 'fx-hint fx-builder-note';
note.style.cssText = 'margin-top:10px;color:#6d28d9;background:#f5f3ff;border:1px solid #ddd6fe;border-radius:8px;padding:8px 12px;display:none';
note.textContent = '已选择「可视化编辑」:图集与详细描述无需填写,保存后将进入可视化编辑器排版产品详情。';
var firstFixed = fixedOnly[0];
if(firstFixed && firstFixed.parentNode){ firstFixed.parentNode.insertBefore(note, firstFixed); }
function apply(){
var m = sel.value;
if(modeField) modeField.value = m;
if(!isCreate) return; // 编辑页选择器仅用于切换页面,不在此隐藏字段
var isBuilder = (m === 'builder');
for(var i=0;i<fixedOnly.length;i++){ fixedOnly[i].style.display = isBuilder ? 'none' : ''; }
note.style.display = isBuilder ? 'block' : 'none';
}
sel.addEventListener('change', apply);
apply();
})();
</script>