原生html+css+ajax实现二级下拉选择的增删改及树形结构列出

 

<?php
$db_host = 'localhost';
$db_user = 'info_chalide';
$db_pass = 'j8c2rRr2RnA';
$db_name = 'info_chalide';
/*
数据库结构SQL
CREATE TABLE categories (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
parent_id INT DEFAULT 0
);
*/
try {
$pdo = new PDO("mysql:host=$db_host;dbname=$db_name;charset=utf8mb4", $db_name, $db_pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
die("连接失败: " . $e->getMessage());
}
// AJAX处理
if (!empty($_GET['act'])) {
header('Content-Type: application/json');
switch ($_GET['act']) {
case 'list':
// 获取所有类别
try {
$sql = "SELECT * FROM cat ORDER BY parent_id, id";
$stmt = $pdo->query($sql);
$categories = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 组织树形结构
$tree = [];
foreach ($categories as $cat) {
if ($cat['parent_id'] == 0) {
$cat['children'] = [];
$tree[$cat['id']] = $cat;
}
}
foreach ($categories as $cat) {
if ($cat['parent_id'] > 0 && isset($tree[$cat['parent_id']])) {
$tree[$cat['parent_id']]['children'][] = $cat;
}
}
echo json_encode(['status' => 'success', 'data' => array_values($tree)]);
} catch (PDOException $e) {
echo json_encode(['status' => 'error', 'message' => '获取类别失败:' . $e->getMessage()]);
}
break;
case 'add':
if (empty($_POST['name'])) {
echo json_encode(['status' => 'error', 'message' => '类别名称不能为空']);
exit;
}
try {
$name = trim($_POST['name']);
$parent_id = isset($_POST['parent_id']) ? intval($_POST['parent_id']) : 0;
$sql = "INSERT INTO cat (name, parent_id) VALUES (?, ?)";
$stmt = $pdo->prepare($sql);
$stmt->execute([$name, $parent_id]);
echo json_encode(['status' => 'success', 'message' => '添加成功']);
} catch (PDOException $e) {
echo json_encode(['status' => 'error', 'message' => '添加失败:' . $e->getMessage()]);
}
break;
case 'edit':
if (empty($_POST['name']) || empty($_POST['id'])) {
echo json_encode(['status' => 'error', 'message' => '参数错误']);
exit;
}
try {
$name = trim($_POST['name']);
$id = intval($_POST['id']);
$sql = "UPDATE cat SET name = ? WHERE id = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$name, $id]);
echo json_encode(['status' => 'success', 'message' => '修改成功']);
} catch (PDOException $e) {
echo json_encode(['status' => 'error', 'message' => '修改失败:' . $e->getMessage()]);
}
break;
case 'delete':
if (empty($_POST['id'])) {
echo json_encode(['status' => 'error', 'message' => '参数错误']);
exit;
}
try {
$id = intval($_POST['id']);
// 删除该类别及其子类别
$sql = "DELETE FROM cat WHERE id = ? OR parent_id = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$id, $id]);
echo json_encode(['status' => 'success', 'message' => '删除成功']);
} catch (PDOException $e) {
echo json_encode(['status' => 'error', 'message' => '删除失败:' . $e->getMessage()]);
}
break;
}
exit;
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>类别管理</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: Arial, sans-serif; padding: 20px; }
/* 树形结构样式 */
.tree-item { margin: 5px 0; }
.tree-item.child { margin-left: 30px; }
.category-name { display: inline-block; border: 1px solid #ddd; min-width: 150px; }
/* 按钮样式 */
button {
padding: 3px 5px;
margin: 0 2px;
cursor: pointer;
border: 1px solid #ddd;
background: #f8f8f8;
border-radius: 3px;
}
button:hover { background: #e8e8e8; }
/* 遮罩层样式 */
.overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
z-index: 1000;
}
.modal {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 20px;
border-radius: 5px;
min-width: 300px;
max-width: 90%;
max-height: 90vh;
display: flex;
flex-direction: column;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.modal-body {
overflow-y: auto;
margin-bottom: 20px;
}
.modal-footer {
border-top: 1px solid #eee;
padding-top: 15px;
text-align: right;
}
.close-btn {
cursor: pointer;
font-size: 20px;
}
/* 表单样式 */
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
}
.form-group input,
.form-group select {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 3px;
}
</style>
</head>
<body>
<h1>类别管理</h1>
<button onclick="showAddModal()">添加类别</button>
<div id="category-tree"></div>
<!-- 添加/修改类别的遮罩层 -->
<div id="categoryModal" class="overlay">
<div class="modal">
<div class="modal-header">
<h3 id="modalTitle">添加类别</h3>
<span class="close-btn" onclick="closeModal()">&times;</span>
</div>
<div class="modal-body">
<form id="categoryForm">
<input type="hidden" id="categoryId">
<div class="form-group">
<label for="categoryName">类别名称:</label>
<input type="text" id="categoryName" required>
</div>
<div class="form-group" id="parentSelectGroup">
<label for="parentCategory">上级类别:</label>
<select id="parentCategory">
<option value="0">无 (新增一级类别)</option>
</select>
</div>
</form>
</div>
<div class="modal-footer">
<button onclick="closeModal()">取消</button>
<button onclick="saveCategory()">保存</button>
</div>
</div>
</div>
<script>
// 加载类别列表
function loadCategories() {
fetch('?act=list')
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
renderCategoryTree(data.data);
updateParentSelect(data.data);
} else {
alert(data.message);
}
});
}
// 渲染类别树
function renderCategoryTree(categories) {
const tree = document.getElementById('category-tree');
tree.innerHTML = '';
categories.forEach(category => {
// 渲染一级类别
const item = document.createElement('div');
item.className = 'tree-item';
item.innerHTML = `
<span class="category-name">${category.name}</span>
<button onclick="showEditModal(${category.id}, '${category.name}')">修改</button>
<button onclick="deleteCategory(${category.id})">删除</button>
`;
tree.appendChild(item);
// 渲染二级类别
if (category.children && category.children.length > 0) {
category.children.forEach(child => {
const childItem = document.createElement('div');
childItem.className = 'tree-item child';
childItem.innerHTML = `
<span class="category-name">${child.name}</span>
<button onclick="showEditModal(${child.id}, '${child.name}')">修改</button>
<button onclick="deleteCategory(${child.id})">删除</button>
`;
tree.appendChild(childItem);
});
}
});
}
// 更新上级类别选择框
function updateParentSelect(categories) {
const select = document.getElementById('parentCategory');
select.innerHTML = '<option value="0">无 (新增一级类别)</option>';
categories.forEach(category => {
select.innerHTML += `<option value="${category.id}">${category.name}</option>`;
});
}
// 显示添加模态框
function showAddModal() {
document.getElementById('modalTitle').textContent = '添加类别';
document.getElementById('categoryId').value = '';
document.getElementById('categoryName').value = '';
document.getElementById('parentSelectGroup').style.display = 'block';
document.getElementById('categoryModal').style.display = 'block';
}
// 显示编辑模态框
function showEditModal(id, name) {
document.getElementById('modalTitle').textContent = '修改类别';
document.getElementById('categoryId').value = id;
document.getElementById('categoryName').value = name;
document.getElementById('parentSelectGroup').style.display = 'none';
document.getElementById('categoryModal').style.display = 'block';
}
// 关闭模态框
function closeModal() {
document.getElementById('categoryModal').style.display = 'none';
}
// 保存类别
function saveCategory() {
const id = document.getElementById('categoryId').value;
const name = document.getElementById('categoryName').value;
const parent_id = document.getElementById('parentCategory').value;
if (!name) {
alert('请输入类别名称');
return;
}
const formData = new FormData();
formData.append('name', name);
if (id) {
// 修改
formData.append('id', id);
fetch('?act=edit', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
closeModal();
loadCategories();
}
alert(data.message);
});
} else {
// 添加
formData.append('parent_id', parent_id);
fetch('?act=add', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
closeModal();
loadCategories();
}
alert(data.message);
});
}
}
// 删除类别
function deleteCategory(id) {
if (!confirm('确定要删除该类别吗?此操作无法恢复!')) {
return;
}
const formData = new FormData();
formData.append('id', id);
fetch('?act=delete', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
alert(data.message);
if (data.status === 'success') {
loadCategories();
}
});
}
// 页面加载完成后加载类别列表
window.onload = loadCategories;
</script>
</body>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/63155.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux操作系统--文件的重定向以及文件缓冲区

目录 前言 一、文件描述符的分配规则 二、重定向 三、系统中的重定向接口 1、dup2()介绍 2、dup2()使用 1&#xff09;输出重定向和追加重定向 2&#xff09;输入重定向 四、文件缓冲区 1、定义 2、缓冲区刷新的条件 1&#xff09;文件缓冲区存在的意义 2&…

5G CPE核心器件-基带处理器(三)

5G CPE 核心器件 -5G基带芯片 基带芯片简介基带芯片组成与结构技术特点与发展趋势5G基带芯片是5G CPE中最核心的组件,负责接入5G网络,并进行上下行数据业务传输。移动通信从1G发展到5G,终端形态产生了极大的变化,在集成度、功耗、性能等方面都取得巨大的提升。 基带芯片简…

深入了解 Python 的 xarray 库:多维数据的高效处理工具

深入了解 Python 的 xarray 库&#xff1a;多维数据的高效处理工具 什么是 xarray&#xff1f; 在科学计算和数据分析领域&#xff0c;处理多维数据&#xff08;如时间序列、空间网格等&#xff09;是常见需求。虽然 NumPy 提供了高效的多维数组操作&#xff0c;但它缺乏对数…

mmdection配置-yolo转coco

基础配置看我的mmsegmentation。 也可以参考b站 &#xff1a;https://www.bilibili.com/video/BV1xA4m1c7H8/?vd_source701421543dabde010814d3f9ea6917f6#reply248829735200 这里面最大的坑就是配置coco数据集。我一般是用yolo&#xff0c;这个yolo转coco格式很难搞定&#…

THREE.js 入门(一)xyz坐标系

一、坐标系概念 在 three.js 中&#xff0c;相机的默认朝向是沿着 Z 轴的负方向。也就是说&#xff0c;默认情况下&#xff0c;相机会沿着 Z 轴的负方向“看”到场景中的对象&#xff0c;而 X 轴和 Y 轴分别对应水平方向和垂直方向。换句话说&#xff0c;相机的默认位置是 (0,…

【Java从入门到放弃 之 Stream API】

Java Stream API Stream API行为参数化传递代码Lambda表达式Lambda 表达式的语法方法引用 Lambda 表达式的实际应用集合操作并发编程 Lambda 表达式的注意事项总结 Stream API Java8提供了一个全新的API - Stream。引入这个Stream的主要目的&#xff0c;一个是可以支持更好的并…

Java 单元测试模拟框架-Mockito 的介绍

Mockito 是什么 Mockito 是一个用于单元测试的模拟框架&#xff0c;基于它可以使用简洁易用的API编写出色的测试。 Mockito 允许开发人员创建和管理模拟对象&#xff08;mock objects&#xff09;&#xff0c;以便在测试过程中替换那些不容易构造或获取的对象。 Mockito的基本…

websocket通信

“WebSocket 允许客户端和服务器在连接建立后随时互相发送数据&#xff0c;而无需每次交互都重新建立连接。”我想请问&#xff0c;第一次前端往后端发送数据时&#xff0c;传递的数据应该满足接口的参数内容&#xff0c;在第一次建立连接后之后的数据传递还是要满足接口的参数…

C++Qt开机自启动

文章目录 方法一&#xff1a;注册表方法二&#xff1a;快捷方式到自启动目录 方法一&#xff1a;注册表 #include <QtCore/QCoreApplication> #include <QtCore/QSettings> #include <QtCore/QDebug> #include <QtCore/QProcess>int main(int argc, c…

NiFi-从部署到开发(图文详解)

NiFi简介 Apache NiFi 是一款强大的开源数据集成工具&#xff0c;旨在简化数据流的管理、传输和自动化。它提供了直观的用户界面和可视化工具&#xff0c;使用户能够轻松设计、控制和监控复杂的数据流程&#xff0c;NiFi 具备强大的扩展性和可靠性&#xff0c;可用于处理海量数…

draggable插件——实现元素的拖动排序——拖动和不可拖动的两种情况处理

最近在写后台管理系统的时候&#xff0c;遇到一个需求&#xff0c;就是关于拖动排序的功能。 我之前是写过一个关于拖动表格的功能&#xff0c;此功能可以实现表格中的每一行数据上下拖动实现排序的效果。 vue——实现表格的拖拽排序功能——技能提升 但是目前我这边的需求是…

Delphi Web前端开发教程(9):基于TMS WEB Core框架

3、REST Servers服务端(后端)框架 REST服务端特点&#xff1a; – 为远程资源提供一个REST API接口。也可以为其他网络内容提供服务&#xff1b; – 包括在Delphi Enterprise & Architect企业版和架构师版中的RAD服务器、DataSnap、WebBroker&#xff1b; – 开源框架&a…

MySQL 函数创建中的 Err 1418:原因解析与解决指南20241203

&#x1f6a8; MySQL 函数创建中的 Err 1418&#xff1a;原因解析与解决指南 &#x1f4d6; 引言 在使用 MySQL 创建函数时&#xff0c;许多开发者会偶然遇到如下报错&#xff1a; [Err] 1418 - This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its…

前端首屏加载优化

1.首屏加载慢的原因 网络延迟资源太大服务器响应慢 1.网络延迟 首屏优化中网络延迟是一个重要的考虑因素&#xff0c;它直接影响到页面资源的加载速度和用户体验。 影响原因 后端服务器性能原因&#xff0c;导致响应速度慢&#xff0c;从而影响了首屏加载速度。网络传输速度…

利用空闲主机进行Nmap隐匿扫描:IP伪造与空闲扫描技术

IP伪造与空闲扫描技术 在网络安全领域&#xff0c;扫描和识别目标主机的开放端口是攻击者获取目标信息的重要手段。传统的扫描方法可能会暴露扫描者的真实IP地址&#xff0c;从而引起目标主机的警觉。然而&#xff0c;IP地址伪造是一种巧妙的方式&#xff0c;可以帮助攻击者在…

学习视频超分辨率扩散模型中的空间适应和时间相干性(原文翻译)

文章目录 摘要1. Introduction2. Related Work3. Our Approach3.1. Video Upscaler3.2. Spatial Feature Adaptation Module3.3. Temporal Feature Alignment Module3.4. Video Refiner3.5. Training Strategy 4. Experiments4.1. Experimental Settings4.2. Comparisons with …

JavaScript 键盘控制移动

如果你想通过 JavaScript 实现键盘控制对象&#xff08;比如一个方块&#xff09;的移动&#xff0c;下面是一个简单的示例&#xff0c;展示如何监听键盘事件并根据按下的键来移动一个元素。 HTML 和 CSS&#xff1a; <!DOCTYPE html> <html lang"en">…

SpringMVC其他扩展

一、全局异常处理机制: 1.异常处理两种方式: 开发过程中是不可避免地会出现各种异常情况的&#xff0c;例如网络连接异常、数据格式异常、空指针异常等等。异常的出现可能导致程序的运行出现问题&#xff0c;甚至直接导致程序崩溃。因此&#xff0c;在开发过程中&#xff0c;…

AWS S3 权限配置与文件上传下载指南

本文介绍如何配置 AWS S3 存储桶的访问权限,实现 EC2 实例上传文件和本地用户下载文件的功能。 权限配置 © ivwdcwso (ID: u012172506) 1. EC2 角色上传权限 创建 IAM 角色并附加以下策略,允许 EC2 实例上传文件到 S3: {"Version": "2012-10-17&qu…

Flink随笔 20241203 Flink重点内容

Flink 是一个强大的流处理框架&#xff0c;它的设计理念是高吞吐量、低延迟的流式计算。你提到的这些重点是 Flink 的核心组成部分&#xff0c;下面我将详细解析每一个方面。 1. 窗口&#xff08;Window&#xff09; 窗口是 Flink 流处理中一个非常重要的概念&#xff0c;主要…