首页 / 应用软件 / 详细教程,为WordPress网站集成电子签名与合同管理工具

详细教程,为WordPress网站集成电子签名与合同管理工具

详细教程:为WordPress网站集成电子签名与合同管理工具

引言:为什么WordPress网站需要电子签名功能

在数字化时代,电子签名已成为商业活动中不可或缺的一环。无论是自由职业者与客户签订服务协议,还是企业与员工签署劳动合同,电子签名都能显著提高效率、降低成本并确保法律合规性。对于WordPress网站所有者而言,集成电子签名与合同管理功能可以:

  1. 提升专业形象:为客户提供完整的在线签约体验
  2. 简化工作流程:自动化合同创建、发送、签署和存档过程
  3. 增强安全性:确保合同文件的完整性和不可否认性
  4. 节省成本:减少纸质合同打印、邮寄和存储费用
  5. 提高转化率:减少客户签约过程中的摩擦点

本教程将指导您通过WordPress代码二次开发,为您的网站集成完整的电子签名与合同管理系统,而无需依赖昂贵的第三方插件。

第一部分:准备工作与环境配置

1.1 系统要求与工具准备

在开始开发之前,请确保您的环境满足以下要求:

  • WordPress 5.0或更高版本
  • PHP 7.4或更高版本(推荐8.0+)
  • MySQL 5.6或更高版本
  • 文本编辑器(如VS Code、Sublime Text等)
  • FTP客户端或服务器文件管理器访问权限
  • 基本的PHP、JavaScript和WordPress开发知识

1.2 创建开发子主题

为了避免直接修改主题文件导致更新时丢失更改,我们首先创建一个子主题:

  1. wp-content/themes/目录下创建新文件夹my-esignature-theme
  2. 创建style.css文件,添加以下内容:

    /*
    Theme Name: My eSignature Theme
    Template: your-parent-theme-folder-name
    Version: 1.0.0
    Description: 子主题,用于集成电子签名功能
    */
  3. 创建functions.php文件,添加以下代码:

    <?php
    // 子主题functions.php
    add_action('wp_enqueue_scripts', 'my_esignature_theme_enqueue_styles');
    function my_esignature_theme_enqueue_styles() {
     wp_enqueue_style('parent-style', get_template_directory_uri() . '/style.css');
    }
    ?>
  4. 在WordPress后台激活此子主题

1.3 创建插件目录结构

我们将创建一个独立的插件来管理电子签名功能:

wp-content/plugins/my-esignature-system/
├── my-esignature-system.php
├── includes/
│   ├── class-database.php
│   ├── class-contract-manager.php
│   ├── class-signature-handler.php
│   └── class-pdf-generator.php
├── assets/
│   ├── css/
│   ├── js/
│   └── images/
├── templates/
│   ├── contract-form.php
│   ├── signature-pad.php
│   └── contract-view.php
└── vendor/ (第三方库)

第二部分:数据库设计与合同存储

2.1 创建数据库表

includes/class-database.php中,我们将创建必要的数据库表:

<?php
class ESIGN_Database {
    
    private static $instance = null;
    
    public static function get_instance() {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    private function __construct() {
        add_action('init', array($this, 'create_tables'));
    }
    
    public function create_tables() {
        global $wpdb;
        
        $charset_collate = $wpdb->get_charset_collate();
        $table_prefix = $wpdb->prefix . 'esign_';
        
        // 合同表
        $contracts_table = $table_prefix . 'contracts';
        $sql1 = "CREATE TABLE IF NOT EXISTS $contracts_table (
            id INT(11) NOT NULL AUTO_INCREMENT,
            contract_id VARCHAR(50) NOT NULL UNIQUE,
            title VARCHAR(255) NOT NULL,
            content LONGTEXT NOT NULL,
            status ENUM('draft', 'sent', 'signed', 'expired', 'cancelled') DEFAULT 'draft',
            created_by INT(11) NOT NULL,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            expires_at DATETIME,
            PRIMARY KEY (id),
            INDEX (contract_id),
            INDEX (status),
            INDEX (created_by)
        ) $charset_collate;";
        
        // 签署方表
        $parties_table = $table_prefix . 'parties';
        $sql2 = "CREATE TABLE IF NOT EXISTS $parties_table (
            id INT(11) NOT NULL AUTO_INCREMENT,
            contract_id VARCHAR(50) NOT NULL,
            user_id INT(11),
            email VARCHAR(255) NOT NULL,
            name VARCHAR(255) NOT NULL,
            role ENUM('sender', 'signer', 'witness', 'approver') DEFAULT 'signer',
            signing_order INT(3) DEFAULT 1,
            signature_data TEXT,
            signed_at DATETIME,
            ip_address VARCHAR(45),
            user_agent TEXT,
            PRIMARY KEY (id),
            INDEX (contract_id),
            INDEX (email),
            FOREIGN KEY (contract_id) REFERENCES $contracts_table(contract_id) ON DELETE CASCADE
        ) $charset_collate;";
        
        // 审计日志表
        $audit_table = $table_prefix . 'audit_log';
        $sql3 = "CREATE TABLE IF NOT EXISTS $audit_log_table (
            id INT(11) NOT NULL AUTO_INCREMENT,
            contract_id VARCHAR(50) NOT NULL,
            action VARCHAR(100) NOT NULL,
            details TEXT,
            performed_by INT(11),
            performed_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            ip_address VARCHAR(45),
            PRIMARY KEY (id),
            INDEX (contract_id),
            INDEX (performed_at)
        ) $charset_collate;";
        
        require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
        dbDelta($sql1);
        dbDelta($sql2);
        dbDelta($sql3);
    }
    
    // 生成唯一合同ID
    public function generate_contract_id() {
        return 'CONTRACT-' . date('Ymd') . '-' . strtoupper(wp_generate_password(8, false));
    }
}
?>

2.2 合同数据模型

includes/class-contract-manager.php中,创建合同管理类:

<?php
class ESIGN_Contract_Manager {
    
    private $db;
    
    public function __construct() {
        $this->db = ESIGN_Database::get_instance();
    }
    
    // 创建新合同
    public function create_contract($data) {
        global $wpdb;
        
        $contract_id = $this->db->generate_contract_id();
        $current_user_id = get_current_user_id();
        
        $contract_data = array(
            'contract_id' => $contract_id,
            'title' => sanitize_text_field($data['title']),
            'content' => wp_kses_post($data['content']),
            'created_by' => $current_user_id,
            'status' => 'draft',
            'expires_at' => !empty($data['expires_at']) ? $data['expires_at'] : null
        );
        
        $table_name = $wpdb->prefix . 'esign_contracts';
        $result = $wpdb->insert($table_name, $contract_data);
        
        if ($result) {
            // 添加签署方
            if (!empty($data['parties'])) {
                $this->add_parties($contract_id, $data['parties']);
            }
            
            // 记录审计日志
            $this->log_audit($contract_id, 'contract_created', '合同创建');
            
            return $contract_id;
        }
        
        return false;
    }
    
    // 添加签署方
    private function add_parties($contract_id, $parties) {
        global $wpdb;
        
        $table_name = $wpdb->prefix . 'esign_parties';
        
        foreach ($parties as $index => $party) {
            $party_data = array(
                'contract_id' => $contract_id,
                'email' => sanitize_email($party['email']),
                'name' => sanitize_text_field($party['name']),
                'role' => sanitize_text_field($party['role']),
                'signing_order' => $index + 1
            );
            
            $wpdb->insert($table_name, $party_data);
        }
    }
    
    // 获取合同详情
    public function get_contract($contract_id) {
        global $wpdb;
        
        $contracts_table = $wpdb->prefix . 'esign_contracts';
        $parties_table = $wpdb->prefix . 'esign_parties';
        
        $contract = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM $contracts_table WHERE contract_id = %s",
            $contract_id
        ));
        
        if ($contract) {
            $contract->parties = $wpdb->get_results($wpdb->prepare(
                "SELECT * FROM $parties_table WHERE contract_id = %s ORDER BY signing_order ASC",
                $contract_id
            ));
        }
        
        return $contract;
    }
    
    // 记录审计日志
    private function log_audit($contract_id, $action, $details = '') {
        global $wpdb;
        
        $table_name = $wpdb->prefix . 'esign_audit_log';
        
        $log_data = array(
            'contract_id' => $contract_id,
            'action' => $action,
            'details' => $details,
            'performed_by' => get_current_user_id(),
            'ip_address' => $this->get_client_ip()
        );
        
        $wpdb->insert($table_name, $log_data);
    }
    
    // 获取客户端IP
    private function get_client_ip() {
        $ipaddress = '';
        if (isset($_SERVER['HTTP_CLIENT_IP']))
            $ipaddress = $_SERVER['HTTP_CLIENT_IP'];
        else if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
            $ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
        else if(isset($_SERVER['HTTP_X_FORWARDED']))
            $ipaddress = $_SERVER['HTTP_X_FORWARDED'];
        else if(isset($_SERVER['HTTP_FORWARDED_FOR']))
            $ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
        else if(isset($_SERVER['HTTP_FORWARDED']))
            $ipaddress = $_SERVER['HTTP_FORWARDED'];
        else if(isset($_SERVER['REMOTE_ADDR']))
            $ipaddress = $_SERVER['REMOTE_ADDR'];
        else
            $ipaddress = 'UNKNOWN';
        return $ipaddress;
    }
}
?>

第三部分:电子签名功能实现

3.1 签名画板实现

创建templates/signature-pad.php模板文件:

<div class="esignature-container">
    <div class="signature-pad-wrapper">
        <h3>请在下方签署您的名字</h3>
        
        <div class="signature-pad-container">
            <canvas id="signature-pad" width="600" height="200"></canvas>
        </div>
        
        <div class="signature-actions">
            <button type="button" id="clear-signature" class="button button-secondary">
                <span class="dashicons dashicons-trash"></span> 清除
            </button>
            <button type="button" id="undo-signature" class="button button-secondary">
                <span class="dashicons dashicons-undo"></span> 撤销
            </button>
            <button type="button" id="save-signature" class="button button-primary">
                <span class="dashicons dashicons-yes-alt"></span> 确认签名
            </button>
        </div>
        
        <div class="signature-preview" style="display:none;">
            <h4>签名预览:</h4>
            <img id="signature-preview" src="" alt="签名预览" />
        </div>
        
        <div class="signature-consent">
            <label>
                <input type="checkbox" id="signature-consent" required>
                我确认此电子签名具有法律约束力,并同意电子签名条款
            </label>
        </div>
    </div>
</div>

3.2 签名画板JavaScript实现

创建assets/js/signature-pad.js

(function($) {
    'use strict';
    
    class SignaturePad {
        constructor(canvasId) {
            this.canvas = document.getElementById(canvasId);
            this.ctx = this.canvas.getContext('2d');
            this.signatureData = null;
            this.isDrawing = false;
            this.lastX = 0;
            this.lastY = 0;
            
            this.init();
        }
        
        init() {
            // 设置画布样式
            this.ctx.strokeStyle = '#000';
            this.ctx.lineWidth = 2;
            this.ctx.lineCap = 'round';
            this.ctx.lineJoin = 'round';
            
            // 绑定事件
            this.bindEvents();
            
            // 清除画布
            this.clear();
        }
        
        bindEvents() {
            const canvas = this.canvas;
            
            // 鼠标事件
            canvas.addEventListener('mousedown', (e) => this.startDrawing(e));
            canvas.addEventListener('mousemove', (e) => this.draw(e));
            canvas.addEventListener('mouseup', () => this.stopDrawing());
            canvas.addEventListener('mouseout', () => this.stopDrawing());
            
            // 触摸事件(移动设备支持)
            canvas.addEventListener('touchstart', (e) => {
                e.preventDefault();
                const touch = e.touches[0];
                const mouseEvent = new MouseEvent('mousedown', {
                    clientX: touch.clientX,
                    clientY: touch.clientY
                });
                canvas.dispatchEvent(mouseEvent);
            });
            
            canvas.addEventListener('touchmove', (e) => {
                e.preventDefault();
                const touch = e.touches[0];
                const mouseEvent = new MouseEvent('mousemove', {
                    clientX: touch.clientX,
                    clientY: touch.clientY
                });
                canvas.dispatchEvent(mouseEvent);
            });
            
            canvas.addEventListener('touchend', (e) => {
                e.preventDefault();
                const mouseEvent = new MouseEvent('mouseup', {});
                canvas.dispatchEvent(mouseEvent);
            });
        }
        
        startDrawing(e) {
            this.isDrawing = true;
            const rect = this.canvas.getBoundingClientRect();
            this.lastX = e.clientX - rect.left;
            this.lastY = e.clientY - rect.top;
        }
        
        draw(e) {
            if (!this.isDrawing) return;
            
            const rect = this.canvas.getBoundingClientRect();
            const currentX = e.clientX - rect.left;
            const currentY = e.clientY - rect.top;
            
            this.ctx.beginPath();
            this.ctx.moveTo(this.lastX, this.lastY);
            this.ctx.lineTo(currentX, currentY);
            this.ctx.stroke();
            
            this.lastX = currentX;
            this.lastY = currentY;
        }
        
        stopDrawing() {
            this.isDrawing = false;
            this.saveSignature();
        }
        
        saveSignature() {
            this.signatureData = this.canvas.toDataURL('image/png');
        }
        
        clear() {
            this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
            this.ctx.fillStyle = '#f8f9fa';
            this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
            this.signatureData = null;
        }
        
        undo() {
            // 简单实现:清除整个画布
            this.clear();
        }
        
        getSignatureData() {
            return this.signatureData;
        }
        
        setSignatureData(data) {
            const img = new Image();
            img.onload = () => {
                this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
                this.ctx.drawImage(img, 0, 0);
                this.signatureData = data;
            };
            img.src = data;
        }
    }
    
    // 初始化签名板
    $(document).ready(function() {
        if ($('#signature-pad').length) {
            window.signaturePad = new SignaturePad('signature-pad');
            
            // 绑定按钮事件
            $('#clear-signature').on('click', function() {
                signaturePad.clear();
                $('#signature-preview').hide();
            });
            
            $('#undo-signature').on('click', function() {
                signaturePad.undo();
            });
            
            $('#save-signature').on('click', function() {
                const signatureData = signaturePad.getSignatureData();
                if (signatureData) {
                    $('#signature-preview').attr('src', signatureData).show();
                    $('#signature-data').val(signatureData);
                    
                    // 显示成功消息
                    $('.signature-preview').show();
                    alert('签名已保存!');
                } else {
                    alert('请先绘制您的签名');
                }
            });
            
            // 表单提交验证
            $('form.esignature-form').on('submit', function(e) {
                if (!$('#signature-consent').is(':checked')) {
                    e.preventDefault();
                    alert('请同意电子签名条款');
                    return false;
                }
                
                if (!signaturePad.getSignatureData()) {
                    e.preventDefault();
                    alert('请提供您的签名');
                    return false;
                }
            });
        }
    });
    
})(jQuery);

3.3 签名处理类

创建includes/class-signature-handler.php

<?php
class ESIGN_Signature_Handler {
    
    public function __construct() {
        add_action('wp_ajax_submit_signature', array($this, 'handle_signature_submission'));

ature_submission'));

}

// 处理签名提交
public function handle_signature_submission() {
    // 验证nonce
    if (!wp_verify_nonce($_POST['nonce'], 'esignature_nonce')) {
        wp_die('安全验证失败');
    }
    
    $contract_id = sanitize_text_field($_POST['contract_id']);
    $signature_data = $_POST['signature_data'];
    $party_email = sanitize_email($_POST['party_email']);
    
    // 验证签名数据
    if (!$this->validate_signature_data($signature_data)) {
        wp_send_json_error('无效的签名数据');
    }
    
    // 保存签名
    $result = $this->save_signature($contract_id, $party_email, $signature_data);
    
    if ($result) {
        // 更新合同状态
        $this->update_contract_status($contract_id);
        
        // 发送通知邮件
        $this->send_notification_email($contract_id, $party_email);
        
        wp_send_json_success('签名提交成功');
    } else {
        wp_send_json_error('签名保存失败');
    }
}

// 验证签名数据
private function validate_signature_data($signature_data) {
    // 检查是否为有效的base64图像数据
    if (preg_match('/^data:image/(png|jpeg);base64,/', $signature_data)) {
        return true;
    }
    return false;
}

// 保存签名到数据库
private function save_signature($contract_id, $party_email, $signature_data) {
    global $wpdb;
    
    $table_name = $wpdb->prefix . 'esign_parties';
    
    $result = $wpdb->update(
        $table_name,
        array(
            'signature_data' => $signature_data,
            'signed_at' => current_time('mysql'),
            'ip_address' => $this->get_client_ip(),
            'user_agent' => $_SERVER['HTTP_USER_AGENT']
        ),
        array(
            'contract_id' => $contract_id,
            'email' => $party_email
        )
    );
    
    return $result !== false;
}

// 更新合同状态
private function update_contract_status($contract_id) {
    global $wpdb;
    
    $contracts_table = $wpdb->prefix . 'esign_contracts';
    $parties_table = $wpdb->prefix . 'esign_parties';
    
    // 检查是否所有签署方都已签名
    $unsigned_parties = $wpdb->get_var($wpdb->prepare(
        "SELECT COUNT(*) FROM $parties_table 
         WHERE contract_id = %s AND signature_data IS NULL",
        $contract_id
    ));
    
    $new_status = ($unsigned_parties == 0) ? 'signed' : 'sent';
    
    $wpdb->update(
        $contracts_table,
        array('status' => $new_status),
        array('contract_id' => $contract_id)
    );
}

// 发送通知邮件
private function send_notification_email($contract_id, $party_email) {
    $contract = ESIGN_Contract_Manager::get_instance()->get_contract($contract_id);
    
    $to = $party_email;
    $subject = '合同签署通知 - ' . $contract->title;
    
    $message = "
    <html>
    <body>
        <h2>合同签署通知</h2>
        <p>您好,</p>
        <p>您已成功签署合同:<strong>{$contract->title}</strong></p>
        <p>合同ID:{$contract_id}</p>
        <p>签署时间:" . date('Y-m-d H:i:s') . "</p>
        <p>您可以通过以下链接查看合同详情:</p>
        <p><a href='" . home_url("/contract-view/{$contract_id}") . "'>查看合同</a></p>
        <hr>
        <p>此邮件为系统自动发送,请勿回复。</p>
    </body>
    </html>
    ";
    
    $headers = array('Content-Type: text/html; charset=UTF-8');
    
    wp_mail($to, $subject, $message, $headers);
}

}
?>


## 第四部分:PDF生成与合同管理

### 4.1 集成TCPDF库生成PDF

创建`includes/class-pdf-generator.php`:

<?php
require_once(plugin_dir_path(__FILE__) . '../vendor/tcpdf/tcpdf.php');

class ESIGN_PDF_Generator extends TCPDF {


private $contract_data;

public function __construct($contract_data) {
    parent::__construct(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
    $this->contract_data = $contract_data;
    $this->init_pdf();
}

private function init_pdf() {
    // 设置文档信息
    $this->SetCreator('WordPress eSignature System');
    $this->SetAuthor(get_bloginfo('name'));
    $this->SetTitle($this->contract_data->title);
    $this->SetSubject('电子合同');
    
    // 设置默认字体
    $this->SetFont('stsongstdlight', '', 12);
    
    // 设置边距
    $this->SetMargins(15, 15, 15);
    $this->SetHeaderMargin(5);
    $this->SetFooterMargin(10);
    
    // 自动分页
    $this->SetAutoPageBreak(TRUE, 15);
    
    // 设置图像比例因子
    $this->setImageScale(PDF_IMAGE_SCALE_RATIO);
}

// 生成合同PDF
public function generate_contract_pdf() {
    $this->AddPage();
    
    // 添加合同标题
    $this->SetFont('stsongstdlight', 'B', 16);
    $this->Cell(0, 10, $this->contract_data->title, 0, 1, 'C');
    $this->Ln(10);
    
    // 添加合同信息
    $this->SetFont('stsongstdlight', '', 10);
    $this->Cell(0, 6, '合同编号:' . $this->contract_data->contract_id, 0, 1);
    $this->Cell(0, 6, '创建日期:' . $this->contract_data->created_at, 0, 1);
    $this->Cell(0, 6, '状态:' . $this->get_status_text($this->contract_data->status), 0, 1);
    $this->Ln(10);
    
    // 添加合同内容
    $this->SetFont('stsongstdlight', '', 12);
    $this->writeHTML($this->contract_data->content, true, false, true, false, '');
    $this->Ln(20);
    
    // 添加签署方信息
    $this->add_signature_section();
    
    // 添加审计信息
    $this->add_audit_info();
    
    return $this;
}

// 添加签署方部分
private function add_signature_section() {
    $this->SetFont('stsongstdlight', 'B', 14);
    $this->Cell(0, 10, '签署方信息', 0, 1);
    $this->Ln(5);
    
    $this->SetFont('stsongstdlight', '', 11);
    
    foreach ($this->contract_data->parties as $index => $party) {
        $this->Cell(0, 6, '签署方 ' . ($index + 1) . ':', 0, 1);
        $this->Cell(40, 6, '姓名:', 0, 0);
        $this->Cell(0, 6, $party->name, 0, 1);
        $this->Cell(40, 6, '邮箱:', 0, 0);
        $this->Cell(0, 6, $party->email, 0, 1);
        $this->Cell(40, 6, '角色:', 0, 0);
        $this->Cell(0, 6, $this->get_role_text($party->role), 0, 1);
        
        if ($party->signature_data) {
            $this->Cell(40, 6, '签署时间:', 0, 0);
            $this->Cell(0, 6, $party->signed_at, 0, 1);
            
            // 添加签名图像
            $signature_data = $party->signature_data;
            $temp_file = $this->save_signature_image($signature_data);
            
            if ($temp_file) {
                $this->Image($temp_file, 50, $this->GetY(), 40, 20);
                $this->Ln(25);
                unlink($temp_file); // 删除临时文件
            }
        }
        
        $this->Ln(10);
    }
}

// 保存签名图像到临时文件
private function save_signature_image($signature_data) {
    $upload_dir = wp_upload_dir();
    $temp_dir = $upload_dir['basedir'] . '/esignature_temp/';
    
    if (!file_exists($temp_dir)) {
        wp_mkdir_p($temp_dir);
    }
    
    $temp_file = $temp_dir . uniqid('sig_') . '.png';
    
    // 移除base64前缀
    $signature_data = preg_replace('/^data:image/w+;base64,/', '', $signature_data);
    $signature_data = base64_decode($signature_data);
    
    if (file_put_contents($temp_file, $signature_data)) {
        return $temp_file;
    }
    
    return false;
}

// 添加审计信息
private function add_audit_info() {
    global $wpdb;
    
    $audit_table = $wpdb->prefix . 'esign_audit_log';
    $audit_logs = $wpdb->get_results($wpdb->prepare(
        "SELECT * FROM $audit_table 
         WHERE contract_id = %s 
         ORDER BY performed_at DESC 
         LIMIT 10",
        $this->contract_data->contract_id
    ));
    
    if ($audit_logs) {
        $this->SetFont('stsongstdlight', 'B', 12);
        $this->Cell(0, 10, '操作记录', 0, 1);
        $this->Ln(5);
        
        $this->SetFont('stsongstdlight', '', 9);
        
        foreach ($audit_logs as $log) {
            $user = get_userdata($log->performed_by);
            $username = $user ? $user->display_name : '系统';
            
            $this->Cell(0, 5, date('Y-m-d H:i:s', strtotime($log->performed_at)) . 
                ' - ' . $username . ' - ' . $log->action . 
                ' - ' . $log->details, 0, 1);
        }
    }
}

// 获取状态文本
private function get_status_text($status) {
    $status_map = array(
        'draft' => '草稿',
        'sent' => '已发送',
        'signed' => '已签署',
        'expired' => '已过期',
        'cancelled' => '已取消'
    );
    
    return isset($status_map[$status]) ? $status_map[$status] : $status;
}

// 获取角色文本
private function get_role_text($role) {
    $role_map = array(
        'sender' => '发起方',
        'signer' => '签署方',
        'witness' => '见证方',
        'approver' => '审批方'
    );
    
    return isset($role_map[$role]) ? $role_map[$role] : $role;
}

// 输出PDF到浏览器
public function output_pdf($filename = 'contract.pdf') {
    $this->Output($filename, 'I');
}

// 保存PDF到服务器
public function save_pdf($filename) {
    $this->Output($filename, 'F');
    return file_exists($filename);
}

}
?>


### 4.2 合同管理界面

创建`templates/contract-manager.php`:

<?php
/**

  • 合同管理界面模板
    */

if (!defined('ABSPATH')) {

exit;

}

global $wpdb;
$current_user_id = get_current_user_id();

// 获取用户相关的合同
$contracts_table = $wpdb->prefix . 'esign_contracts';
$parties_table = $wpdb->prefix . 'esign_parties';

$contracts = $wpdb->get_results($wpdb->prepare(

"SELECT c.* FROM $contracts_table c
 LEFT JOIN $parties_table p ON c.contract_id = p.contract_id
 WHERE c.created_by = %d OR p.email = %s
 GROUP BY c.id
 ORDER BY c.created_at DESC",
$current_user_id,
wp_get_current_user()->user_email

));
?>

<div class="esignature-manager-container">

<div class="esignature-header">
    <h1>合同管理</h1>
    <button id="create-new-contract" class="button button-primary">
        <span class="dashicons dashicons-plus"></span> 创建新合同
    </button>
</div>

<!-- 合同筛选 -->
<div class="contract-filters">
    <select id="status-filter">
        <option value="">所有状态</option>
        <option value="draft">草稿</option>
        <option value="sent">已发送</option>
        <option value="signed">已签署</option>
        <option value="expired">已过期</option>
    </select>
    
    <input type="text" id="search-contracts" placeholder="搜索合同标题或ID...">
    
    <button id="apply-filters" class="button">筛选</button>
    <button id="reset-filters" class="button button-secondary">重置</button>
</div>

<!-- 合同列表 -->
<div class="contracts-list">
    <table class="wp-list-table widefat fixed striped">
        <thead>
            <tr>
                <th>合同标题</th>
                <th>合同ID</th>
                <th>状态</th>
                <th>创建时间</th>
                <th>过期时间</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            <?php if ($contracts): ?>
                <?php foreach ($contracts as $contract): ?>
                    <?php 
                    $parties = $wpdb->get_results($wpdb->prepare(
                        "SELECT * FROM $parties_table WHERE contract_id = %s",
                        $contract->contract_id
                    ));
                    ?>
                    <tr data-contract-id="<?php echo esc_attr($contract->contract_id); ?>">
                        <td>
                            <strong><?php echo esc_html($contract->title); ?></strong>
                            <div class="row-actions">
                                <span class="view">
                                    <a href="#" class="view-contract" data-id="<?php echo esc_attr($contract->contract_id); ?>">查看</a> |
                                </span>
                                <span class="edit">
                                    <a href="#" class="edit-contract" data-id="<?php echo esc_attr($contract->contract_id); ?>">编辑</a> |
                                </span>
                                <span class="delete">
                                    <a href="#" class="delete-contract" data-id="<?php echo esc_attr($contract->contract_id); ?>">删除</a>
                                </span>
                            </div>
                        </td>
                        <td><?php echo esc_html($contract->contract_id); ?></td>
                        <td>
                            <span class="contract-status status-<?php echo esc_attr($contract->status); ?>">
                                <?php echo $this->get_status_badge($contract->status); ?>
                            </span>
                        </td>
                        <td><?php echo date('Y-m-d H:i', strtotime($contract->created_at)); ?></td>
                        <td>
                            <?php echo $contract->expires_at ? date('Y-m-d H:i', strtotime($contract->expires_at)) : '无'; ?>
                        </td>
                        <td>
                            <div class="contract-actions">
                                <?php if ($contract->status == 'draft'): ?>
                                    <button class="button button-small send-contract" 
                                            data-id="<?php echo esc_attr($contract->contract_id); ?>">
                                        发送签署
                                    </button>
                                <?php endif; ?>
                                
                                <?php if ($contract->status == 'sent'): ?>
                                    <?php 
                                    $user_can_sign = false;
                                    foreach ($parties as $party) {
                                        if ($party->email == wp_get_current_user()->user_email && !$party->signature_data) {
                                            $user_can_sign = true;
                                            break;
                                        }
                                    }
                                    ?>
                                    <?php if ($user_can_sign): ?>
                                        <a href="<?php echo home_url("/sign-contract/{$contract->contract_id}"); ?>" 
                                           class="button button-small button-primary">
                                            签署合同
                                        </a>
                                    <?php endif; ?>
                                <?php endif; ?>
                                
                                <button class="button button-small download-pdf" 
                                        data-id="<?php echo esc_attr($contract->contract_id); ?>">
                                    下载PDF
                                </button>
                                
                                <button class="button button-small view-audit" 
                                        data-id="<?php echo esc_attr($contract->contract_id); ?>">
                                    查看记录
                                </button>
                            </div>
                        </td>
                    </tr>
                <?php endforeach; ?>
            <?php else: ?>
                <tr>
                    <td colspan="6" class="no-contracts">
                        暂无合同记录。点击"创建新合同"按钮开始创建。
                    </td>
                </tr>
            <?php endif; ?>
        </tbody>
    </table>
</div>

<!-- 分页 -->
<div class="tablenav bottom">
    <
本文来自网络,不代表柔性供应链服务中心立场,转载请注明出处:https://mall.org.cn/5106.html

EXCHANGES®作者

上一篇
下一篇

为您推荐

发表回复

联系我们

联系我们

18559313275

在线咨询: QQ交谈

邮箱: vip@exchanges.center

工作时间:周一至周五,9:00-17:30,节假日休息
返回顶部