Welcome to HACMS

HACMS网页版是基于PHP+(MySQL/SQLite)开发的开源程序,采用CodeIgniter框架、Adminlte后台模板,以会员核心系统为中心,以自身需求为出发点,采用模块分离的方式快速建立站群,具有速度快、效率高、功能强大、操作体验佳等特点,支持文章页面生成HTML静态页面、URL Rewrite、支持多数据库、多表操作与管理,包括网页版进销存、文章、MD文档等等。

HACMS桌面版是以C#、Python为开发语言,选择PostgreSQL、MySQL、SQLite为数据库,还是以自身需求为出发点,现已形成以网页源码采集器、进销存系统、键盘鼠标自动化工具、软件多开助手、单表自定义设置管理、EPUB电子书阅读器等小工具。

PostgreSQL表名

CREATE TABLE IF NOT EXISTS demo_test (
    tid SERIAL PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    notes TEXT NOT NULL,
    dateline BIGINT NOT NULL DEFAULT 0
);

PHP操作PostgreSQL

<?php
/**
 * demo_test 数据表管理程序 (PostgreSQL 版)
 * 功能:列表分页、新增、编辑、删除、查看详情(双击行)
 * 数据库表:demo_test (tid, title, notes, dateline)
 * 使用技术:PHP + PDO (PostgreSQL) + Bootstrap 5 + jQuery + Font Awesome
 */

// ======================= 配置区域 =======================
define('DB_HOST', 'localhost');
define('DB_PORT', '5432');           // PostgreSQL 默认端口
define('DB_NAME', 'your_database');
define('DB_USER', 'postgres');
define('DB_PASS', 'your_password');
define('TABLE_NAME', 'demo_test');   // 表名,可随时修改
define('PAGE_SIZE', 10);             // 每页显示记录数
// =======================================================

// 创建 PDO 连接 (PostgreSQL)
$dsn = "pgsql:host=" . DB_HOST . ";port=" . DB_PORT . ";dbname=" . DB_NAME . ";options='--client_encoding=UTF8'";
try {
    $pdo = new PDO($dsn, DB_USER, DB_PASS);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    // 设置时区(可选,让时间戳处理与 PHP 一致)
    $pdo->exec("SET TIME ZONE 'UTC'");
} catch (PDOException $e) {
    die("数据库连接失败: " . $e->getMessage());
}

// 处理 AJAX 请求(增、删、改、获取单条记录)
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_SERVER['HTTP_X_REQUESTED_WITH'])
    && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {

    $action = $_POST['action'] ?? '';
    $response = ['success' => false, 'message' => ''];

    switch ($action) {
        case 'add':
            $title = trim($_POST['title'] ?? '');
            $notes = trim($_POST['notes'] ?? '');
            $date = trim($_POST['date'] ?? '');
            if (empty($title) || empty($notes) || empty($date)) {
                $response['message'] = '所有字段都不能为空';
                break;
            }
            $timestamp = strtotime($date);
            if ($timestamp === false) {
                $response['message'] = '日期格式无效,请使用 YYYY-MM-DD';
                break;
            }
            $sql = "INSERT INTO " . TABLE_NAME . " (title, notes, dateline) VALUES (?, ?, ?)";
            $stmt = $pdo->prepare($sql);
            try {
                $stmt->execute([$title, $notes, $timestamp]);
                $newId = $pdo->lastInsertId('demo_test_tid_seq'); // PostgreSQL 自增序列名(默认 表名_列名_seq)
                $response['success'] = true;
                $response['message'] = '添加成功';
                $response['new_id'] = $newId;
            } catch (PDOException $e) {
                $response['message'] = '添加失败: ' . $e->getMessage();
            }
            break;

        case 'edit':
            $tid = intval($_POST['tid'] ?? 0);
            $title = trim($_POST['title'] ?? '');
            $notes = trim($_POST['notes'] ?? '');
            $date = trim($_POST['date'] ?? '');
            if ($tid <= 0 || empty($title) || empty($notes) || empty($date)) {
                $response['message'] = '参数错误或字段为空';
                break;
            }
            $timestamp = strtotime($date);
            if ($timestamp === false) {
                $response['message'] = '日期格式无效';
                break;
            }
            $sql = "UPDATE " . TABLE_NAME . " SET title=?, notes=?, dateline=? WHERE tid=?";
            $stmt = $pdo->prepare($sql);
            try {
                $stmt->execute([$title, $notes, $timestamp, $tid]);
                $response['success'] = true;
                $response['message'] = '更新成功';
            } catch (PDOException $e) {
                $response['message'] = '更新失败: ' . $e->getMessage();
            }
            break;

        case 'delete':
            $tid = intval($_POST['tid'] ?? 0);
            if ($tid <= 0) {
                $response['message'] = '无效的序号';
                break;
            }
            $sql = "DELETE FROM " . TABLE_NAME . " WHERE tid=?";
            $stmt = $pdo->prepare($sql);
            try {
                $stmt->execute([$tid]);
                $response['success'] = true;
                $response['message'] = '删除成功';
            } catch (PDOException $e) {
                $response['message'] = '删除失败: ' . $e->getMessage();
            }
            break;

        case 'get_record':
            $tid = intval($_POST['tid'] ?? 0);
            if ($tid <= 0) {
                $response['message'] = '无效的序号';
                break;
            }
            $sql = "SELECT tid, title, notes, dateline FROM " . TABLE_NAME . " WHERE tid=?";
            $stmt = $pdo->prepare($sql);
            $stmt->execute([$tid]);
            $row = $stmt->fetch(PDO::FETCH_ASSOC);
            if ($row) {
                $row['dateline_formatted'] = $row['dateline'] ? date('Y-m-d', $row['dateline']) : '';
                $response['success'] = true;
                $response['data'] = $row;
            } else {
                $response['message'] = '记录不存在';
            }
            break;

        default:
            $response['message'] = '未知操作';
    }

    header('Content-Type: application/json');
    echo json_encode($response);
    exit;
}

// ======================= 非 AJAX 请求:显示页面 =======================

// 获取当前页码
$page = isset($_GET['page']) ? max(1, intval($_GET['page'])) : 1;
$offset = ($page - 1) * PAGE_SIZE;

// 获取总记录数
$total_sql = "SELECT COUNT(*) as total FROM " . TABLE_NAME;
$total_stmt = $pdo->query($total_sql);
$total_row = $total_stmt->fetch(PDO::FETCH_ASSOC);
$total_records = $total_row['total'];
$total_pages = ceil($total_records / PAGE_SIZE);

// 获取当前页数据
$sql = "SELECT tid, title, notes, dateline FROM " . TABLE_NAME . " ORDER BY tid DESC LIMIT ? OFFSET ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([PAGE_SIZE, $offset]);
$records = [];
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    $row['dateline_show'] = $row['dateline'] ? date('Y-m-d', $row['dateline']) : '';
    $records[] = $row;
}

// 关闭连接(页面输出后自动关闭,无需显式调用)
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Demo_Test 数据管理 (PostgreSQL)</title>
    <!-- Bootstrap 5 CSS + 图标库 -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <style>
        .clickable-row { cursor: pointer; transition: background-color 0.2s; }
        .clickable-row:hover { background-color: #f8f9fa; }
        .table-actions .btn { margin-right: 5px; }
        .pagination { justify-content: center; }
    </style>
</head>
<body>
<div class="container mt-4">
    <h2 class="mb-3"><i class="fas fa-database"></i> Demo_Test 数据管理 (PostgreSQL)</h2>
    <div class="mb-3">
        <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#editModal" onclick="openAddModal()">
            <i class="fas fa-plus"></i> 新增
        </button>
    </div>

    <div class="table-responsive">
        <table class="table table-bordered table-hover">
            <thead class="table-dark">
                <tr><th>序号</th><th>标题</th><th>内容</th><th>日期</th><th>操作</th></tr>
            </thead>
            <tbody>
                <?php if (empty($records)): ?>
                    <tr><td colspan="5" class="text-center">暂无数据</td></tr>
                <?php else: ?>
                    <?php foreach ($records as $r): ?>
                    <tr class="clickable-row" data-tid="<?= $r['tid'] ?>">
                        <td><?= htmlspecialchars($r['tid']) ?></td>
                        <td><?= htmlspecialchars($r['title']) ?></td>
                        <td><?= htmlspecialchars(mb_substr($r['notes'], 0, 50)) . (mb_strlen($r['notes']) > 50 ? '...' : '') ?></td>
                        <td><?= htmlspecialchars($r['dateline_show']) ?></td>
                        <td class="table-actions">
                            <button class="btn btn-sm btn-info" onclick="viewRecord(<?= $r['tid'] ?>)"><i class="fas fa-eye"></i> 查看</button>
                            <button class="btn btn-sm btn-warning" onclick="editRecord(<?= $r['tid'] ?>)"><i class="fas fa-edit"></i> 编辑</button>
                            <button class="btn btn-sm btn-danger" onclick="deleteRecord(<?= $r['tid'] ?>)"><i class="fas fa-trash"></i> 删除</button>
                        </td>
                    </tr>
                    <?php endforeach; ?>
                <?php endif; ?>
            </tbody>
        </table>
    </div>

    <?php if ($total_pages > 1): ?>
    <nav>
        <ul class="pagination">
            <li class="page-item <?= ($page <= 1) ? 'disabled' : '' ?>"><a class="page-link" href="?page=1">首页</a></li>
            <li class="page-item <?= ($page <= 1) ? 'disabled' : '' ?>"><a class="page-link" href="?page=<?= $page-1 ?>">上一页</a></li>
            <?php
            $start = max(1, $page - 2);
            $end = min($total_pages, $page + 2);
            for ($i = $start; $i <= $end; $i++):
            ?>
                <li class="page-item <?= ($i == $page) ? 'active' : '' ?>"><a class="page-link" href="?page=<?= $i ?>"><?= $i ?></a></li>
            <?php endfor; ?>
            <li class="page-item <?= ($page >= $total_pages) ? 'disabled' : '' ?>"><a class="page-link" href="?page=<?= $page+1 ?>">下一页</a></li>
            <li class="page-item <?= ($page >= $total_pages) ? 'disabled' : '' ?>"><a class="page-link" href="?page=<?= $total_pages ?>">末页</a></li>
        </ul>
    </nav>
    <?php endif; ?>
</div>

<!-- 新增/编辑模态框 -->
<div class="modal fade" id="editModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="editModalLabel">新增记录</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
            </div>
            <div class="modal-body">
                <form id="dataForm">
                    <input type="hidden" id="edit_tid" name="tid" value="0">
                    <div class="mb-3"><label class="form-label">标题 <span class="text-danger">*</span></label><input type="text" class="form-control" id="title" required></div>
                    <div class="mb-3"><label class="form-label">内容 <span class="text-danger">*</span></label><textarea class="form-control" id="notes" rows="5" required></textarea></div>
                    <div class="mb-3"><label class="form-label">日期 <span class="text-danger">*</span></label><input type="date" class="form-control" id="date" required></div>
                </form>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
                <button type="button" class="btn btn-primary" id="saveBtn">保存</button>
            </div>
        </div>
    </div>
</div>

<!-- 查看详情模态框 -->
<div class="modal fade" id="viewModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header"><h5 class="modal-title">查看记录</h5><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div>
            <div class="modal-body">
                <p><strong>序号:</strong> <span id="view_tid"></span></p>
                <p><strong>标题:</strong> <span id="view_title"></span></p>
                <p><strong>日期:</strong> <span id="view_date"></span></p>
                <p><strong>内容:</strong></p>
                <div id="view_notes" style="white-space: pre-wrap; border:1px solid #ddd; padding:8px; border-radius:5px;"></div>
            </div>
            <div class="modal-footer"><button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button></div>
        </div>
    </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
<script>
let editModal = new bootstrap.Modal(document.getElementById('editModal'));
let viewModal = new bootstrap.Modal(document.getElementById('viewModal'));

function ajaxRequest(action, data, successCallback) {
    data.action = action;
    $.post(window.location.href, data, function(response) {
        if (response.success) {
            if (successCallback) successCallback(response);
            else { alert(response.message); location.reload(); }
        } else alert("操作失败:" + response.message);
    }, 'json').fail(() => alert("网络错误"));
}

function openAddModal() {
    document.getElementById('editModalLabel').innerText = '新增记录';
    document.getElementById('edit_tid').value = '0';
    document.getElementById('title').value = '';
    document.getElementById('notes').value = '';
    document.getElementById('date').value = new Date().toISOString().slice(0,10);
    editModal.show();
}

function editRecord(tid) {
    ajaxRequest('get_record', {tid: tid}, function(resp) {
        let d = resp.data;
        document.getElementById('editModalLabel').innerText = '编辑记录';
        document.getElementById('edit_tid').value = d.tid;
        document.getElementById('title').value = d.title;
        document.getElementById('notes').value = d.notes;
        document.getElementById('date').value = d.dateline_formatted;
        editModal.show();
    });
}

function viewRecord(tid) {
    ajaxRequest('get_record', {tid: tid}, function(resp) {
        let d = resp.data;
        document.getElementById('view_tid').innerText = d.tid;
        document.getElementById('view_title').innerText = d.title;
        document.getElementById('view_date').innerText = d.dateline_formatted;
        document.getElementById('view_notes').innerText = d.notes;
        viewModal.show();
    });
}

function deleteRecord(tid) {
    if (confirm('确定删除吗?')) ajaxRequest('delete', {tid: tid}, () => { alert('删除成功'); location.reload(); });
}

document.getElementById('saveBtn').onclick = function() {
    let tid = document.getElementById('edit_tid').value;
    let title = document.getElementById('title').value.trim();
    let notes = document.getElementById('notes').value.trim();
    let date = document.getElementById('date').value;
    if (!title || !notes || !date) return alert('请完整填写所有字段');
    ajaxRequest(tid === '0' ? 'add' : 'edit', {tid, title, notes, date}, () => { alert('保存成功'); location.reload(); });
};

document.querySelectorAll('.clickable-row').forEach(row => {
    row.addEventListener('dblclick', function(e) {
        if (e.target.tagName === 'BUTTON') return;
        let tid = this.getAttribute('data-tid');
        if (tid) viewRecord(tid);
    });
});
</script>
</body>
</html>

帮助中心

HACMS进销存管理系统V1.0(桌面版)

HACMS进销存管理系统V1.0(桌面版)采用的是Python+MySQL开发,开发初衷仅为自己所用,主要包括采购管理、采购退货管理、销售管理、销售退货管理、库存预警、库存报表、报盈管理、报损管理、流水导出等功能 ...

使用手册

PHP

PHP is a popular general-purpose scripting language that is especially suited to web development. Fast, flexible and pragmatic, PHP powers everything from your blog to the most popular websites in the world.

PHP 手册

CodeIgniter

CodeIgniter is a powerful PHP framework with a very small footprint, built for developers who need a simple and elegant toolkit to create full-featured web applications.

CodeIgniter4用户指南