799 lines
30 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.

{include file="public/header" /}
<div class="config-container">
<div class="config-header" style="display:flex;justify-content: space-between;">
<div>
<span>编辑资源</span>
</div>
<div>
<button type="button" class="layui-btn layui-btn-primary layui-btn-sm" onclick="goBack()">
<i class="layui-icon layui-icon-return"></i>返回
</button>
</div>
</div>
<form class="layui-form" action="" method="post">
<input type="hidden" name="id" value="{$resource.id|default=''}">
<div class="layui-form-item">
<label class="layui-form-label">资源名称</label>
<div class="layui-input-block">
<input type="text" name="title" required lay-verify="required" placeholder="请输入资源名称" autocomplete="off"
class="layui-input" value="{$resource.title|default=''}" lay-affix="clear">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">分类</label>
<div class="layui-input-block">
<select name="cate" lay-verify="required" lay-filter="cate">
<option value="">请选择分类</option>
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">资源编号</label>
<div class="layui-input-block">
<input type="text" name="number" required lay-verify="required" placeholder="请输入分类编号" autocomplete="off"
class="layui-input" value="{$resource.number|default=''}" lay-affix="clear" disabled>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">描述</label>
<div class="layui-input-block">
<textarea name="desc" placeholder="请输入资源描述" class="layui-textarea"
lay-affix="clear">{$resource.desc|default=''}</textarea>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">上传者</label>
<div class="layui-input-block">
<input type="text" name="uploader" required lay-verify="required" placeholder="请输入上传者"
autocomplete="off" class="layui-input" value="{$resource.uploader|default=''}" lay-affix="clear">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">资源图标</label>
<div class="layui-input-block">
<button type="button" class="layui-btn" id="upload-btn">
<i class="layui-icon layui-icon-upload"></i> 图标上传
</button>
<div style="width: 120px;">
<div class="layui-upload-list">
<img class="layui-upload-img" id="upload-img"
style="width: 118px; height: 118px;object-fit: cover;">
<div id="upload-text"></div>
</div>
<div class="layui-progress layui-progress-big" lay-showPercent="yes" lay-filter="icon-progress">
<div class="layui-progress-bar" lay-percent=""></div>
</div>
<input type="hidden" name="icon" id="icon" value="">
</div>
<div class="layui-form-mid layui-word-aux">建议尺寸128px * 128px</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">资源文件</label>
<div class="layui-input-block">
<input type="text" name="fileurl" required placeholder="本地资源地址" autocomplete="off" class="layui-input"
value="{$resource.fileurl|default=''}" style="margin-bottom: 10px;" lay-affix="clear">
<div class="layui-upload-drag" style="display: block;" id="ID-upload-demo-drag">
<i class="layui-icon layui-icon-upload"></i>
<div>点击上传,或将文件拖拽到此处</div>
<div class="layui-hide" id="ID-upload-demo-preview">
<hr>
<div class="file-info">
<i class="layui-icon layui-icon-file"></i>
<span class="file-name"></span>
<span class="file-size"></span>
</div>
</div>
</div>
<div class="layui-progress layui-progress-big" lay-showPercent="yes" lay-filter="file-progress"
style="margin-top: 10px;">
<div class="layui-progress-bar" lay-percent=""></div>
</div>
<input type="hidden" name="file" id="file" value="">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">资源链接</label>
<div class="layui-input-block">
<input type="text" name="url" required placeholder="百度网盘、115网盘、蓝奏云等" autocomplete="off"
class="layui-input" value="{$resource.url|default=''}" lay-affix="clear">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">图片上传</label>
<div class="layui-input-block">
<div class="image-upload-container">
<button type="button" class="btn btn-primary" id="imageUpload">
<i class="fas fa-upload"></i> 多图片上传
</button>
<div class="image-preview-container" id="imagePreview">
{if condition="isset($resource.images) && !empty($resource.images)"}
{if condition="strpos($resource.images, ',') !== false"}
{volist name="resource.images|explode=',',true" id="image"}
<div class="image-preview-item" data-src="{$image}">
<img src="{$image}" alt="已上传图片">
<div class="image-preview-overlay">
<button type="button" class="delete-image">
<i class="fas fa-trash"></i>
</button>
</div>
<p class="image-filename">{$image|basename}</p>
</div>
{/volist}
{else}
<div class="image-preview-item" data-src="{$resource.images}">
<img src="{$resource.images}" alt="已上传图片">
<div class="image-preview-overlay">
<button type="button" class="delete-image">
<i class="fas fa-trash"></i>
</button>
</div>
<p class="image-filename">{$resource.images|basename}</p>
</div>
{/if}
{/if}
</div>
<div class="upload-progress" id="imageProgress" style="display: none;">
<div class="progress-bar" role="progressbar" style="width: 0%"></div>
</div>
<input type="hidden" name="images" id="images" value="{$resource.images|default=''}">
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">分享码</label>
<div class="layui-input-block">
<input type="text" name="code" required placeholder="请输入分享码" autocomplete="off" class="layui-input"
value="{$resource.code|default=''}" lay-affix="clear">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">解压密码</label>
<div class="layui-input-block">
<input type="text" name="zipcode" required placeholder="请输入解压密码" autocomplete="off" class="layui-input"
value="{$resource.zipcode|default=''}" lay-affix="clear">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">排序</label>
<div class="layui-input-block">
<input type="number" name="sort" value="{$resource.sort|default='0'}" class="layui-input"
placeholder="数字越大越靠前" lay-affix="clear">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">内容</label>
<div class="layui-input-block">
<div id="editor—wrapper" id="content" name="content" style="border: 1px solid #ccc;">
<div id="toolbar-container" style="border-bottom: 1px solid #ccc;"><!-- 工具栏 --></div>
<div id="editor-container" style="height: 800px;"><!-- 编辑器 --></div>
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="formSubmit">立即提交</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
</div>
<script src="/static/js/wangeditor.js"></script>
<script>
layui.use(['form', 'layer'], function () {
var form = layui.form;
var layer = layui.layer;
var $ = layui.$;
var upload = layui.upload;
var element = layui.element;
// 获取资源详情
var resourceId = $('input[name="id"]').val();
var resourceData = null;
if (resourceId) {
$.get('{:url("resources/get")}', { id: resourceId }, function (res) {
if (res.code == 0) {
resourceData = res.data;
console.log('Resource data:', resourceData); // 调试输出
// 设置表单值
$('input[name="title"]').val(resourceData.title || '');
$('select[name="cate"]').val(resourceData.cate || '');
form.render('select'); // 重新渲染select以显示选中值
$('textarea[name="desc"]').val(resourceData.desc || '');
$('input[name="uploader"]').val(resourceData.uploader || '');
$('input[name="url"]').val(resourceData.url || '');
$('input[name="code"]').val(resourceData.code || '');
$('input[name="sort"]').val(resourceData.sort || '0');
$('input[name="icon"]').val(resourceData.icon || '');
$('input[name="file"]').val(resourceData.file || '');
// 设置图标预览
if (resourceData.icon) {
$('#upload-img').attr('src', resourceData.icon);
}
// 设置文件预览
if (resourceData.file) {
$('#ID-upload-demo-preview').show();
$('.file-name').text(resourceData.file_name || '已上传文件');
}
}
});
}
// 图标上传
var iconUpload = upload.render({
elem: '#upload-btn',
url: '{:url("index/upload_img")}',
before: function (obj) {
obj.preview(function (index, file, result) {
$('#upload-img').attr('src', result);
});
element.progress('icon-progress', '0%');
layer.msg('图标上传中', { icon: 16, time: 0 });
},
done: function (res) {
if (res.code > 0) {
return layer.msg('图标上传失败');
}
$('#icon').val(res.data);
$('#upload-text').html('');
layer.msg('图标上传成功', { icon: 1 });
},
error: function () {
var demoText = $('#upload-text');
demoText.html('<span style="color: #FF5722;">上传失败</span> <a class="layui-btn layui-btn-xs demo-reload">重试</a>');
demoText.find('.demo-reload').on('click', function () {
iconUpload.upload();
});
},
progress: function (n, elem, e) {
element.progress('icon-progress', n + '%');
if (n == 100) {
layer.msg('图标上传完毕', { icon: 1 });
}
}
});
// 多图片上传
var uploadInst = upload.render({
elem: '#imageUpload',
url: '{:url("index/upload_img")}',
multiple: true,
accept: 'images',
before: function (obj) {
obj.preview(function (index, file, result) {
$('#imagePreview').append('<div class="layui-upload-img-item" data-src="' + result + '"><img src="' + result + '" alt="' + file.name + '" style="width: 100px; height: 100px; object-fit: cover;"><p>' + file.name + '</p><button type="button" class="layui-btn layui-btn-xs layui-btn-danger delete-image" style="position: absolute; top: 0; right: 0;">删除</button></div>');
});
element.progress('image-progress', '0%');
layer.msg('图片上传中', { icon: 16, time: 0 });
},
done: function (res) {
if (res.code > 0) {
return layer.msg('图片上传失败');
}
var images = $('#images').val().split(',');
if (res.data) {
images.push(res.data);
}
$('#images').val(images.filter(Boolean).join(','));
layer.msg('图片上传成功', { icon: 1 });
},
error: function () {
var demoText = $('#imagePreview');
demoText.append('<span style="color: #FF5722;">上传失败</span> <a class="layui-btn layui-btn-xs demo-reload">重试</a>');
demoText.find('.demo-reload').on('click', function () {
uploadInst.upload();
});
},
progress: function (n, elem, e) {
element.progress('image-progress', n + '%');
if (n == 100) {
layer.msg('图片上传完毕', { icon: 1 });
}
}
});
// 删除图片功能
$('#imagePreview').on('click', '.delete-image', function () {
var $item = $(this).closest('.layui-upload-img-item');
var imageSrc = $item.data('src');
var images = $('#images').val().split(',');
var index = images.indexOf(imageSrc);
if (index > -1) {
images.splice(index, 1);
}
$('#images').val(images.join(','));
$item.remove();
});
// 文件上传
var fileUpload = upload.render({
elem: '#ID-upload-demo-drag',
url: '{:url("index/upload_file")}',
accept: 'file',
exts: 'doc|docx|xls|xlsx|ppt|pptx|pdf|txt|zip|rar|7z',
before: function (obj) {
obj.preview(function (index, file, result) {
$('#ID-upload-demo-preview').show();
$('.file-name').text(file.name);
$('.file-size').text(formatFileSize(file.size));
});
element.progress('file-progress', '0%');
layer.msg('文件上传中', { icon: 16, time: 0 });
},
done: function (res) {
if (res.code > 0) {
return layer.msg('文件上传失败');
}
$('#file').val(res.data.src);
$('input[name="fileurl"]').val(res.data.src);
layer.msg('文件上传成功', { icon: 1 });
},
uploadError: function () {
layer.msg('文件上传失败', { icon: 2 });
},
progress: function (n, elem, e) {
element.progress('file-progress', n + '%');
if (n == 100) {
layer.msg('文件上传完毕', { icon: 1 });
}
}
});
// 格式化文件大小
function formatFileSize(bytes) {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
// 获取分类列表
$.get('{:url("resources/getcate")}', function (res) {
if (res.code == 0) {
// 存储分类数据供后续使用
window.categoryData = res.data;
var html = '<option value="">请选择分类</option>';
res.data.forEach(function (item) {
html += '<option value="' + item.id + '">' + item.name + '</option>';
if (item.children && item.children.length > 0) {
item.children.forEach(function (child) {
html += '<option value="' + child.id + '">├─ ' + child.name + '</option>';
});
}
});
$('select[name="cate"]').html(html);
// 如果有资源数据,设置分类值
if (resourceData && resourceData.cate) {
console.log('Setting cate value:', resourceData.cate); // 调试输出
setTimeout(function () {
$('select[name="cate"]').val(resourceData.cate);
form.render('select');
}, 100);
}
} else {
layer.msg(res.msg, { icon: 2 });
}
});
// 监听分类选择变化
form.on('select(cate)', function (data) {
var selectedId = data.value;
if (!selectedId) {
$('input[name="number"]').val('');
return;
}
// 查找选中的分类信息
var parentCategory = null;
var childCategory = null;
window.categoryData.forEach(function (parent) {
if (parent.children) {
parent.children.forEach(function (child) {
if (child.id == selectedId) {
parentCategory = parent;
childCategory = child;
}
});
}
});
if (parentCategory && childCategory) {
// 生成资源编号
var total = childCategory.total || 0;
// 判断是否是初始化时的分类
var isInitialCategory = resourceData && resourceData.cate == selectedId;
var nextNumber = isInitialCategory ? total : total + 1;
var numberStr = nextNumber.toString().padStart(5, '0');
var resourceNumber = parentCategory.number + childCategory.number + numberStr;
// 设置资源编号
$('input[name="number"]').val(resourceNumber);
}
});
// 表单提交
form.on('submit(formSubmit)', function (data) {
// 获取编辑器内容
var content = editor.getHtml();
var loadIndex = layer.load(2);
data.field.content = content;
$.ajax({
url: '{:url("resources/edit")}',
type: 'POST',
data: data.field,
success: function (res) {
layer.close(loadIndex);
if (res.code == 0) {
layer.msg(res.msg, { icon: 1 });
setTimeout(function () {
window.location.href = '{:url("resources/lists")}';
}, 1000);
} else {
layer.msg(res.msg, { icon: 2 });
}
}
});
return false;
});
// 重置按钮点击事件
$('button[type="reset"]').on('click', function () {
// 重新加载分类列表
$.get('{:url("resources/getcate")}', function (res) {
if (res.code == 0) {
var html = '<option value="">请选择分类</option>';
res.data.forEach(function (item) {
html += '<option value="' + item.id + '">' + item.name + '</option>';
if (item.children && item.children.length > 0) {
item.children.forEach(function (child) {
html += '<option value="' + child.id + '">├─ ' + child.name + '</option>';
});
}
});
$('select[name="cate"]').html(html);
// 如果有资源数据,设置分类值
if (resourceData && resourceData.cate) {
setTimeout(function () {
$('select[name="cate"]').val(resourceData.cate);
form.render('select');
}, 100);
} else {
form.render('select');
}
} else {
layer.msg(res.msg, { icon: 2 });
}
});
});
});
</script>
<!-- wangeditor编辑器脚本 -->
<script>
const { createEditor, createToolbar } = window.wangEditor
const editorConfig = {
MENU_CONF: {},
placeholder: '请输入内容...',
onChange(editor) {
const html = editor.getHtml()
},
}
// 配置图片上传
editorConfig.MENU_CONF['uploadImage'] = {
server: '{:url("index/upload_img")}',
fieldName: 'file',
maxFileSize: 50 * 1024 * 1024, // 50M
maxNumberOfFiles: 10,
allowedFileTypes: ['image/*'],
meta: {
token: 'xxx'
},
metaWithUrl: true,
headers: {
Accept: 'text/x-json'
},
timeout: 30 * 1000, // 30s
onBeforeUpload(file) {
console.log('准备上传图片', file)
return file
},
onProgress(progress) {
console.log('上传进度', progress)
},
onSuccess(file, res) {
console.log('上传成功', file, res)
},
onFailed(file, res) {
layer.msg('上传失败:' + res.msg, { icon: 2 })
console.log('上传失败', file, res)
},
onError(file, err, res) {
layer.msg('上传出错:' + err.message, { icon: 2 })
console.error('上传出错', file, err, res)
},
customInsert(res, insertFn) {
// 只使用返回的url字段并确保使用完整的URL
if (res.code === 0 && res.url) {
// 如果URL不是以http开头添加https://
let imageUrl = res.url;
if (!imageUrl.startsWith('http')) {
imageUrl = 'https://' + imageUrl;
}
// 移除可能存在的重复域名和路径
imageUrl = imageUrl.replace(/^https?:\/\/[^\/]+\/admin\/resources\//, 'https://www.yunzer.cn/');
insertFn(imageUrl);
} else {
layer.msg('图片上传失败:' + (res.msg || '未知错误'), { icon: 2 });
}
}
}
const editor = createEditor({
selector: '#editor-container',
html: `{$resource.content|raw|default=''}`,
config: editorConfig,
mode: 'default', // or 'simple'
})
const toolbarConfig = {}
const toolbar = createToolbar({
editor,
selector: '#toolbar-container',
config: toolbarConfig,
mode: 'default', // or 'simple'
})
</script>
<script>
//返回资源列表
function goBack() {
window.location.href = '{:url("resources/lists")}';
}
</script>
<script>
document.addEventListener('DOMContentLoaded', function () {
const imageUpload = document.getElementById('imageUpload');
const imagePreview = document.getElementById('imagePreview');
const imageProgress = document.getElementById('imageProgress');
const progressBar = imageProgress.querySelector('.progress-bar');
const imagesInput = document.getElementById('images');
// 处理图片上传
imageUpload.addEventListener('click', function () {
const input = document.createElement('input');
input.type = 'file';
input.multiple = true;
input.accept = 'image/*';
input.onchange = function (e) {
const files = e.target.files;
if (files.length === 0) return;
imageProgress.style.display = 'block';
let uploadedCount = 0;
Array.from(files).forEach(file => {
const formData = new FormData();
formData.append('file', file);
fetch('{:url("index/upload_img")}', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(res => {
if (res.code === 0) {
addImagePreview(res.data);
updateImagesInput();
} else {
alert('上传失败:' + res.msg);
}
})
.catch(error => {
console.error('上传错误:', error);
alert('上传出错');
})
.finally(() => {
uploadedCount++;
const progress = (uploadedCount / files.length) * 100;
progressBar.style.width = progress + '%';
if (uploadedCount === files.length) {
setTimeout(() => {
imageProgress.style.display = 'none';
progressBar.style.width = '0%';
}, 500);
}
});
});
};
input.click();
});
// 添加图片预览
function addImagePreview(imageUrl) {
const div = document.createElement('div');
div.className = 'image-preview-item';
div.dataset.src = imageUrl;
div.innerHTML = `
<img src="${imageUrl}" alt="已上传图片">
<div class="image-preview-overlay">
<button type="button" class="btn btn-danger btn-sm delete-image">
<i class="fas fa-trash"></i>
</button>
</div>
<p class="image-filename">${imageUrl.split('/').pop()}</p>
`;
imagePreview.appendChild(div);
}
// 更新隐藏输入框的值
function updateImagesInput() {
const images = Array.from(imagePreview.querySelectorAll('.image-preview-item'))
.map(item => item.dataset.src);
imagesInput.value = images.join(',');
}
// 删除图片
imagePreview.addEventListener('click', function (e) {
if (e.target.closest('.delete-image')) {
const item = e.target.closest('.image-preview-item');
item.remove();
updateImagesInput();
}
});
});
</script>
<style>
.image-upload-container {
margin: 20px 0;
}
.image-preview-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 15px;
margin-top: 15px;
}
.image-preview-item {
position: relative;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.image-preview-item img {
width: 100%;
height: 150px;
object-fit: cover;
display: block;
}
.image-preview-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
transition: opacity 0.3s;
z-index: 1;
/* 添加 z-index */
}
.image-preview-item:hover .image-preview-overlay {
opacity: 1;
}
.image-filename {
margin: 5px 0;
font-size: 0.9em;
text-align: center;
word-break: break-all;
}
.upload-progress {
margin-top: 10px;
height: 4px;
background: #f0f0f0;
border-radius: 2px;
overflow: hidden;
}
.progress-bar {
height: 100%;
background: #007bff;
transition: width 0.3s ease;
}
.btn {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: all 0.3s;
}
.btn-primary {
background: #007bff;
color: white;
}
.btn-primary:hover {
background: #0056b3;
}
.btn-danger {
background: #dc3545;
color: white;
}
.btn-danger:hover {
background: #c82333;
}
.btn-sm {
padding: 4px 8px;
font-size: 12px;
}
.delete-image {
background: #dc3545;
color: white;
border: none;
border-radius: 4px;
padding: 8px 12px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background-color 0.3s;
z-index: 2;
/* 确保按钮在悬停层之上 */
}
.delete-image i {
font-size: 14px;
margin-right: 4px;
/* 添加图标右边距 */
}
</style>