338 lines
14 KiB
HTML
338 lines
14 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}编辑应用{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4>编辑应用</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<form method="post">
|
|
<div class="mb-3">
|
|
<label class="form-label">标题</label>
|
|
<input type="text" name="title" class="form-control" value="{{ app.title }}" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">URL</label>
|
|
<input type="url" name="url" class="form-control" value="{{ app.url }}" required>
|
|
</div>
|
|
<!-- 在图标选择部分修改 -->
|
|
<div class="mb-3">
|
|
<label class="form-label">图标</label>
|
|
<input type="hidden" name="icon" id="selectedIcon" value="" required>
|
|
<div class="d-flex align-items-center mb-3">
|
|
<div class="icon-preview me-3">
|
|
<i id="iconPreview" class="fas fa-question-circle fa-2x"></i>
|
|
<img id="iconImagePreview" src="" style="display: none; max-width: 32px; max-height: 32px;">
|
|
</div>
|
|
<button type="button" class="btn btn-outline-primary me-2" data-bs-toggle="modal" data-bs-target="#iconModal">
|
|
<i class="fas fa-icons me-2"></i>选择图标
|
|
</button>
|
|
<button type="button" class="btn btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#iconImageModal">
|
|
<i class="fas fa-image me-2"></i>选择图片
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 添加图标图片选择模态框 -->
|
|
<div class="modal fade" id="iconImageModal" tabindex="-1" aria-labelledby="iconImageModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog modal-xl">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="iconImageModalLabel">选择图标图片</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="container-fluid">
|
|
<div class="input-group mb-3">
|
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
|
<input type="text" id="iconImageSearch" class="form-control" placeholder="搜索图标图片...">
|
|
</div>
|
|
<div class="row row-cols-3 row-cols-sm-4 row-cols-md-5 row-cols-lg-6 row-cols-xl-8 g-3" id="iconImageGrid">
|
|
{% for attachment in attachments if attachment.type == 'icon' %}
|
|
<div class="col">
|
|
<div class="icon-image-item p-3 text-center rounded" data-filename="{{ attachment.filename }}" title="{{ attachment.filename }}">
|
|
<img src="{{ url_for('uploaded_icon', filename=attachment.filename) }}" style="max-width: 50px; max-height: 50px;" class="img-thumbnail mb-2">
|
|
<div class="small text-truncate">{{ attachment.filename }}</div>
|
|
</div>
|
|
</div>
|
|
{% else %}
|
|
<div class="col-12 text-center py-3">
|
|
<p>暂无图标图片</p>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<div class="me-auto">
|
|
<span id="selectedIconImageName">未选择图片</span>
|
|
</div>
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
|
<button type="button" class="btn btn-primary" id="confirmIconImage">确认选择</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">主分类</label>
|
|
<select name="main_category" id="main_category" class="form-select" required>
|
|
<option value="">请选择</option>
|
|
{% for main_id, cat in categories.items() %}
|
|
<option value="{{ main_id }}" {% if app.category.main == main_id %}selected{% endif %}>{{ cat.name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">子分类</label>
|
|
<select name="sub_category" id="sub_category" class="form-select" required>
|
|
{% if app.category.main in categories %}
|
|
{% for sub_id, subData in categories[app.category.main].sub.items() %}
|
|
<option value="{{ sub_id }}" {% if app.category.sub == sub_id %}selected{% endif %}>{{ subData.name }}</option>
|
|
{% endfor %}
|
|
{% else %}
|
|
<option value="">请先选择主分类</option>
|
|
{% endif %}
|
|
</select>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">描述</label>
|
|
<textarea name="description" class="form-control" rows="3">{{ app.description if app.description else '' }}</textarea>
|
|
</div>
|
|
<div class="mb-3 form-check">
|
|
<input type="checkbox" name="private" class="form-check-input" id="privateCheck" {% if app.private %}checked{% endif %}>
|
|
<label class="form-check-label" for="privateCheck">私有应用(仅登录后可见)</label>
|
|
</div>
|
|
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
|
|
<button type="submit" class="btn btn-success me-md-2">
|
|
<i class="fas fa-save me-2"></i>保存修改
|
|
</button>
|
|
<a href="{{ url_for('index') }}" class="btn btn-secondary">
|
|
<i class="fas fa-arrow-left me-2"></i>返回
|
|
</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 图标选择模态框 -->
|
|
<div class="modal fade" id="iconModal" tabindex="-1" aria-labelledby="iconModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog modal-xl">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="iconModalLabel">选择图标</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="container-fluid">
|
|
<div class="input-group mb-3">
|
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
|
<input type="text" id="iconSearch" class="form-control" placeholder="搜索图标...">
|
|
</div>
|
|
<div class="row row-cols-3 row-cols-sm-4 row-cols-md-5 row-cols-lg-6 row-cols-xl-8 g-3" id="iconGrid">
|
|
{% for icon, name in icons.items() %}
|
|
<div class="col">
|
|
<div class="icon-item p-3 text-center rounded {% if app.icon == icon %}selected{% endif %}"
|
|
data-icon="{{ icon }}" title="{{ name }}">
|
|
<i class="{{ icon }} fa-2x mb-2"></i>
|
|
<div class="small text-truncate">{{ name }}</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<div class="me-auto">
|
|
<span id="selectedIconName">
|
|
{% if app.icon %}
|
|
{{ icons[app.icon] if app.icon in icons else '自定义图标' }}
|
|
{% else %}
|
|
未选择图标
|
|
{% endif %}
|
|
</span>
|
|
</div>
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
|
<button type="button" class="btn btn-primary" id="confirmIcon">确认选择</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
let selectedIcon = '{{ app.icon if app.icon else "" }}';
|
|
let selectedIconName = '{% if app.icon %}{{ icons[app.icon] if app.icon in icons else "自定义图标" }}{% else %}未选择图标{% endif %}';
|
|
|
|
// 图标搜索功能
|
|
document.getElementById('iconSearch').addEventListener('input', function() {
|
|
const searchTerm = this.value.toLowerCase();
|
|
const iconItems = document.querySelectorAll('.icon-item');
|
|
|
|
iconItems.forEach(item => {
|
|
const iconName = item.getAttribute('title').toLowerCase();
|
|
const iconCode = item.dataset.icon.toLowerCase();
|
|
if (iconName.includes(searchTerm) || iconCode.includes(searchTerm)) {
|
|
item.closest('.col').style.display = 'block';
|
|
} else {
|
|
item.closest('.col').style.display = 'none';
|
|
}
|
|
});
|
|
});
|
|
|
|
// 图标点击选择
|
|
document.querySelectorAll('.icon-item').forEach(item => {
|
|
item.addEventListener('click', function() {
|
|
// 移除所有选中状态
|
|
document.querySelectorAll('.icon-item').forEach(i => {
|
|
i.classList.remove('selected');
|
|
});
|
|
|
|
// 添加选中状态
|
|
this.classList.add('selected');
|
|
selectedIcon = this.dataset.icon;
|
|
selectedIconName = this.getAttribute('title');
|
|
|
|
// 更新底部显示
|
|
document.getElementById('selectedIconName').textContent = selectedIconName;
|
|
});
|
|
});
|
|
|
|
// 确认选择
|
|
document.getElementById('confirmIcon').addEventListener('click', function() {
|
|
if (selectedIcon) {
|
|
document.getElementById('selectedIcon').value = selectedIcon;
|
|
document.getElementById('iconPreview').className = selectedIcon + ' fa-2x';
|
|
bootstrap.Modal.getInstance(document.getElementById('iconModal')).hide();
|
|
} else {
|
|
alert('请先选择一个图标');
|
|
}
|
|
});
|
|
|
|
// 主分类变化时加载子分类
|
|
document.getElementById('main_category').addEventListener('change', function() {
|
|
const mainId = this.value;
|
|
if (!mainId) return;
|
|
|
|
fetch('/get_subcategories/' + mainId)
|
|
.then(res => res.json())
|
|
.then(data => {
|
|
const subSelect = document.getElementById('sub_category');
|
|
subSelect.innerHTML = '<option value="">请选择</option>';
|
|
|
|
for (const [id, subData] of Object.entries(data)) {
|
|
const option = document.createElement('option');
|
|
option.value = id;
|
|
option.textContent = subData.name;
|
|
subSelect.appendChild(option);
|
|
}
|
|
|
|
// 尝试保留原来的子分类选择
|
|
if ('{{ app.category.sub }}' && data['{{ app.category.sub }}']) {
|
|
subSelect.value = '{{ app.category.sub }}';
|
|
}
|
|
});
|
|
});
|
|
|
|
// 初始化时高亮已选图标
|
|
if (selectedIcon) {
|
|
const selectedItem = document.querySelector(`.icon-item[data-icon="${selectedIcon}"]`);
|
|
if (selectedItem) {
|
|
selectedItem.classList.add('selected');
|
|
}
|
|
}
|
|
});
|
|
// 图标图片选择功能
|
|
let selectedIconImage = '';
|
|
let selectedIconImageName = '';
|
|
|
|
// 图标图片搜索功能
|
|
document.getElementById('iconImageSearch').addEventListener('input', function() {
|
|
const searchTerm = this.value.toLowerCase();
|
|
const iconImageItems = document.querySelectorAll('.icon-image-item');
|
|
|
|
iconImageItems.forEach(item => {
|
|
const filename = item.dataset.filename.toLowerCase();
|
|
if (filename.includes(searchTerm)) {
|
|
item.closest('.col').style.display = 'block';
|
|
} else {
|
|
item.closest('.col').style.display = 'none';
|
|
}
|
|
});
|
|
});
|
|
|
|
// 图标图片点击选择
|
|
document.querySelectorAll('.icon-image-item').forEach(item => {
|
|
item.addEventListener('click', function() {
|
|
// 移除所有选中状态
|
|
document.querySelectorAll('.icon-image-item').forEach(i => {
|
|
i.classList.remove('selected');
|
|
});
|
|
|
|
// 添加选中状态
|
|
this.classList.add('selected');
|
|
selectedIconImage = this.dataset.filename;
|
|
selectedIconImageName = this.getAttribute('title');
|
|
|
|
// 更新底部显示
|
|
document.getElementById('selectedIconImageName').textContent = selectedIconImageName;
|
|
});
|
|
});
|
|
|
|
// 确认选择图标图片
|
|
document.getElementById('confirmIconImage').addEventListener('click', function() {
|
|
if (selectedIconImage) {
|
|
document.getElementById('selectedIcon').value = '/upload/icon/' + selectedIconImage;
|
|
document.getElementById('iconPreview').style.display = 'none';
|
|
const iconImagePreview = document.getElementById('iconImagePreview');
|
|
iconImagePreview.src = '/upload/icon/' + selectedIconImage;
|
|
iconImagePreview.style.display = 'inline';
|
|
bootstrap.Modal.getInstance(document.getElementById('iconImageModal')).hide();
|
|
} else {
|
|
alert('请先选择一张图片');
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<style>
|
|
.icon-preview {
|
|
width: 60px;
|
|
height: 60px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background-color: #f8f9fa;
|
|
border-radius: 5px;
|
|
}
|
|
|
|
.icon-item {
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
border: 1px solid transparent;
|
|
}
|
|
|
|
.icon-item:hover {
|
|
background-color: #f8f9fa;
|
|
border-color: #dee2e6;
|
|
}
|
|
|
|
.icon-item.selected {
|
|
background-color: #e7f1ff;
|
|
border-color: #86b7fe;
|
|
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
|
|
}
|
|
|
|
#iconGrid {
|
|
max-height: 60vh;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
#selectedIconName {
|
|
font-weight: bold;
|
|
color: #0d6efd;
|
|
}
|
|
</style>
|
|
{% endblock %} |