首页 / 应用软件 / 详细指南,在WordPress中开发内嵌式项目管理与甘特图工具

详细指南,在WordPress中开发内嵌式项目管理与甘特图工具

详细指南:在WordPress中开发内嵌式项目管理与甘特图工具

摘要

本文提供了一份完整的指南,介绍如何在WordPress平台中通过代码二次开发,实现内嵌式项目管理与甘特图工具。我们将从需求分析开始,逐步讲解数据库设计、功能模块开发、甘特图集成、用户界面设计以及性能优化等关键环节,帮助开发者将常用互联网小工具功能无缝集成到WordPress系统中。


目录

  1. 项目概述与需求分析
  2. WordPress开发环境搭建
  3. 数据库设计与数据模型
  4. 项目管理核心功能开发
  5. 甘特图集成与可视化
  6. 用户权限与团队协作
  7. 前端界面与用户体验优化
  8. 数据安全与性能优化
  9. 测试与部署指南
  10. 扩展与维护建议

1. 项目概述与需求分析

1.1 项目背景

随着远程工作和团队协作的普及,项目管理工具成为企业日常运营的重要组成部分。许多中小型企业使用WordPress作为其官方网站或内容管理系统,但缺乏集成的项目管理功能。通过开发内嵌式项目管理与甘特图工具,用户可以在熟悉的WordPress环境中管理项目,无需切换多个平台,提高工作效率。

1.2 功能需求

  • 项目管理:创建、编辑、删除项目,设置项目基本信息
  • 任务管理:任务创建、分配、优先级设置、状态跟踪
  • 甘特图可视化:直观展示项目时间线、任务依赖关系
  • 团队协作:用户角色分配、任务评论、文件附件
  • 进度跟踪:完成百分比、里程碑标记、时间跟踪
  • 报告与分析:项目进度报告、团队绩效统计

1.3 技术选型

  • 核心框架:WordPress插件架构
  • 前端技术:React/Vue.js(可选)、jQuery、HTML5、CSS3
  • 图表库:DHTMLX Gantt、Frappe Gantt或自定义SVG实现
  • 数据库:WordPress默认MySQL数据库
  • 通信方式:REST API + AJAX

2. WordPress开发环境搭建

2.1 本地开发环境配置

# 使用Local by Flywheel或Docker配置WordPress环境
# 安装必要工具
npm install -g @wordpress/env
wp-env start

# 或使用传统方法
# 1. 安装XAMPP/MAMP/WAMP
# 2. 下载最新WordPress
# 3. 配置数据库

2.2 插件基础结构

创建插件主文件 project-management-gantt.php

<?php
/**
 * Plugin Name: 项目管理与甘特图工具
 * Plugin URI:  https://yourwebsite.com/
 * Description: 在WordPress中集成项目管理与甘特图功能
 * Version:     1.0.0
 * Author:      开发者名称
 * License:     GPL v2 or later
 */

// 防止直接访问
if (!defined('ABSPATH')) {
    exit;
}

// 定义插件常量
define('PMG_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('PMG_PLUGIN_URL', plugin_dir_url(__FILE__));
define('PMG_VERSION', '1.0.0');

// 初始化插件
require_once PMG_PLUGIN_DIR . 'includes/class-pmg-init.php';
PMG_Init::register();

2.3 插件目录结构

project-management-gantt/
├── project-management-gantt.php      # 主插件文件
├── includes/                         # 核心类文件
│   ├── class-pmg-init.php           # 初始化类
│   ├── class-pmg-database.php       # 数据库处理
│   ├── class-pmg-projects.php       # 项目管理类
│   ├── class-pmg-tasks.php          # 任务管理类
│   └── class-pmg-gantt.php          # 甘特图处理类
├── admin/                           # 后台管理文件
│   ├── css/                         # 管理端CSS
│   ├── js/                          # 管理端JavaScript
│   └── views/                       # 管理端视图
├── public/                          # 前端文件
│   ├── css/                         # 前端CSS
│   ├── js/                          # 前端JavaScript
│   └── views/                       # 前端视图
├── assets/                          # 静态资源
│   ├── lib/                         # 第三方库
│   └── images/                      # 图片资源
└── templates/                       # 模板文件

3. 数据库设计与数据模型

3.1 自定义数据表设计

为了避免与WordPress核心表冲突,我们创建独立的数据表:

// includes/class-pmg-database.php
class PMG_Database {
    
    public static function create_tables() {
        global $wpdb;
        
        $charset_collate = $wpdb->get_charset_collate();
        
        // 项目表
        $projects_table = $wpdb->prefix . 'pmg_projects';
        $projects_sql = "CREATE TABLE IF NOT EXISTS $projects_table (
            id mediumint(9) NOT NULL AUTO_INCREMENT,
            name varchar(255) NOT NULL,
            description text,
            status varchar(50) DEFAULT 'active',
            start_date date,
            end_date date,
            progress tinyint(3) DEFAULT 0,
            created_by bigint(20) NOT NULL,
            created_at datetime DEFAULT CURRENT_TIMESTAMP,
            updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            PRIMARY KEY (id)
        ) $charset_collate;";
        
        // 任务表
        $tasks_table = $wpdb->prefix . 'pmg_tasks';
        $tasks_sql = "CREATE TABLE IF NOT EXISTS $tasks_table (
            id mediumint(9) NOT NULL AUTO_INCREMENT,
            project_id mediumint(9) NOT NULL,
            parent_id mediumint(9) DEFAULT 0,
            title varchar(255) NOT NULL,
            description text,
            start_date date,
            end_date date,
            duration int(11) DEFAULT 1,
            progress tinyint(3) DEFAULT 0,
            priority varchar(20) DEFAULT 'medium',
            status varchar(50) DEFAULT 'pending',
            assigned_to bigint(20),
            sort_order int(11) DEFAULT 0,
            dependencies text,
            created_by bigint(20) NOT NULL,
            created_at datetime DEFAULT CURRENT_TIMESTAMP,
            updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            PRIMARY KEY (id),
            KEY project_id (project_id)
        ) $charset_collate;";
        
        // 项目成员表
        $members_table = $wpdb->prefix . 'pmg_project_members';
        $members_sql = "CREATE TABLE IF NOT EXISTS $members_table (
            id mediumint(9) NOT NULL AUTO_INCREMENT,
            project_id mediumint(9) NOT NULL,
            user_id bigint(20) NOT NULL,
            role varchar(50) DEFAULT 'member',
            joined_at datetime DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY (id),
            UNIQUE KEY project_user (project_id, user_id)
        ) $charset_collate;";
        
        require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
        dbDelta($projects_sql);
        dbDelta($tasks_sql);
        dbDelta($members_sql);
    }
}

3.2 数据关系模型

  • 一个项目包含多个任务
  • 一个任务可以有子任务(通过parent_id实现层级结构)
  • 一个项目可以有多个成员
  • 一个用户可以参与多个项目

3.3 数据表优化考虑

  • 添加适当的索引以提高查询性能
  • 考虑大数据量下的分表策略
  • 定期清理历史数据

4. 项目管理核心功能开发

4.1 项目CRUD操作

// includes/class-pmg-projects.php
class PMG_Projects {
    
    // 创建新项目
    public static function create_project($data) {
        global $wpdb;
        $table = $wpdb->prefix . 'pmg_projects';
        
        $defaults = array(
            'name' => '',
            'description' => '',
            'status' => 'active',
            'start_date' => current_time('mysql'),
            'end_date' => null,
            'progress' => 0,
            'created_by' => get_current_user_id()
        );
        
        $data = wp_parse_args($data, $defaults);
        
        $wpdb->insert($table, $data);
        
        return $wpdb->insert_id;
    }
    
    // 获取项目列表
    public static function get_projects($args = array()) {
        global $wpdb;
        $table = $wpdb->prefix . 'pmg_projects';
        
        $defaults = array(
            'status' => 'active',
            'user_id' => 0,
            'per_page' => 10,
            'page' => 1
        );
        
        $args = wp_parse_args($args, $defaults);
        
        $where = "WHERE status = '" . esc_sql($args['status']) . "'";
        
        if ($args['user_id'] > 0) {
            $members_table = $wpdb->prefix . 'pmg_project_members';
            $where .= " AND id IN (SELECT project_id FROM $members_table WHERE user_id = " . intval($args['user_id']) . ")";
        }
        
        $offset = ($args['page'] - 1) * $args['per_page'];
        
        $query = "SELECT * FROM $table $where ORDER BY created_at DESC LIMIT %d OFFSET %d";
        
        return $wpdb->get_results($wpdb->prepare($query, $args['per_page'], $offset));
    }
    
    // 更新项目
    public static function update_project($project_id, $data) {
        global $wpdb;
        $table = $wpdb->prefix . 'pmg_projects';
        
        return $wpdb->update($table, $data, array('id' => $project_id));
    }
    
    // 删除项目
    public static function delete_project($project_id) {
        global $wpdb;
        $table = $wpdb->prefix . 'pmg_projects';
        
        // 同时删除相关任务和成员
        $tasks_table = $wpdb->prefix . 'pmg_tasks';
        $members_table = $wpdb->prefix . 'pmg_project_members';
        
        $wpdb->delete($tasks_table, array('project_id' => $project_id));
        $wpdb->delete($members_table, array('project_id' => $project_id));
        
        return $wpdb->delete($table, array('id' => $project_id));
    }
}

4.2 任务管理功能

// includes/class-pmg-tasks.php
class PMG_Tasks {
    
    // 创建任务
    public static function create_task($data) {
        global $wpdb;
        $table = $wpdb->prefix . 'pmg_tasks';
        
        $defaults = array(
            'project_id' => 0,
            'parent_id' => 0,
            'title' => '',
            'description' => '',
            'start_date' => current_time('mysql'),
            'end_date' => null,
            'duration' => 1,
            'progress' => 0,
            'priority' => 'medium',
            'status' => 'pending',
            'assigned_to' => null,
            'sort_order' => 0,
            'dependencies' => '',
            'created_by' => get_current_user_id()
        );
        
        $data = wp_parse_args($data, $defaults);
        
        // 自动计算结束日期
        if (empty($data['end_date']) && !empty($data['start_date']) && $data['duration'] > 0) {
            $start_date = new DateTime($data['start_date']);
            $start_date->modify('+' . ($data['duration'] - 1) . ' days');
            $data['end_date'] = $start_date->format('Y-m-d');
        }
        
        $wpdb->insert($table, $data);
        
        return $wpdb->insert_id;
    }
    
    // 获取项目任务树
    public static function get_project_tasks($project_id, $flat = false) {
        global $wpdb;
        $table = $wpdb->prefix . 'pmg_tasks';
        
        $tasks = $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM $table WHERE project_id = %d ORDER BY parent_id, sort_order ASC",
            $project_id
        ));
        
        if ($flat) {
            return $tasks;
        }
        
        // 构建层级结构
        return self::build_task_tree($tasks);
    }
    
    // 构建任务树
    private static function build_task_tree($tasks, $parent_id = 0) {
        $tree = array();
        
        foreach ($tasks as $task) {
            if ($task->parent_id == $parent_id) {
                $children = self::build_task_tree($tasks, $task->id);
                if ($children) {
                    $task->children = $children;
                }
                $tree[] = $task;
            }
        }
        
        return $tree;
    }
    
    // 更新任务进度
    public static function update_task_progress($task_id, $progress) {
        global $wpdb;
        $table = $wpdb->prefix . 'pmg_tasks';
        
        $result = $wpdb->update($table, 
            array('progress' => $progress, 'updated_at' => current_time('mysql')),
            array('id' => $task_id)
        );
        
        // 更新父任务和项目进度
        if ($result) {
            self::update_parent_progress($task_id);
        }
        
        return $result;
    }
    
    // 递归更新父任务进度
    private static function update_parent_progress($task_id) {
        global $wpdb;
        $table = $wpdb->prefix . 'pmg_tasks';
        
        $task = $wpdb->get_row($wpdb->prepare("SELECT * FROM $table WHERE id = %d", $task_id));
        
        if ($task && $task->parent_id > 0) {
            // 计算父任务下所有子任务的平均进度
            $children = $wpdb->get_results($wpdb->prepare(
                "SELECT progress FROM $table WHERE parent_id = %d",
                $task->parent_id
            ));
            
            if ($children) {
                $total_progress = 0;
                foreach ($children as $child) {
                    $total_progress += $child->progress;
                }
                $avg_progress = round($total_progress / count($children));
                
                $wpdb->update($table, 
                    array('progress' => $avg_progress),
                    array('id' => $task->parent_id)
                );
                
                // 递归更新
                self::update_parent_progress($task->parent_id);
            }
        }
        
        // 更新项目进度
        if ($task) {
            self::update_project_progress($task->project_id);
        }
    }
    
    // 更新项目进度
    private static function update_project_progress($project_id) {
        global $wpdb;
        $tasks_table = $wpdb->prefix . 'pmg_tasks';
        $projects_table = $wpdb->prefix . 'pmg_projects';
        
        // 计算项目下所有根任务的平均进度
        $root_tasks = $wpdb->get_results($wpdb->prepare(
            "SELECT progress FROM $tasks_table WHERE project_id = %d AND parent_id = 0",
            $project_id
        ));
        
        if ($root_tasks) {
            $total_progress = 0;
            foreach ($root_tasks as $task) {
                $total_progress += $task->progress;
            }
            $avg_progress = round($total_progress / count($root_tasks));
            
            $wpdb->update($projects_table, 
                array('progress' => $avg_progress),
                array('id' => $project_id)
            );
        }
    }
}

4.3 REST API端点

// 注册REST API路由
add_action('rest_api_init', function() {
    
    // 项目相关端点
    register_rest_route('pmg/v1', '/projects', array(
        array(
            'methods' => 'GET',
            'callback' => 'pmg_rest_get_projects',
            'permission_callback' => function() {
                return current_user_can('read');
            }
        ),
        array(
            'methods' => 'POST',
            'callback' => 'pmg_rest_create_project',
            'permission_callback' => function() {
                return current_user_can('edit_posts');
            }
        )
    ));
    
    // 任务相关端点
    register_rest_route('pmg/v1', '/projects/(?P<project_id>d+)/tasks', array(
        'methods' => 'GET',
        'callback' => 'pmg_rest_get_tasks',
        'permission_callback' => function($request) {
            return pmg_check_project_access($request['project_id']);
        }
    ));
    
    register_rest_route('pmg/v1', '/tasks/(?P<task_id>d+)', array(
        array(
            'methods' => 'PUT',
            'callback' => 'pmg_rest_update_task',
            'permission_callback' => function($request) {
                return pmg_check_task_access($request['task_id']);
            }
        ),
        array(
            'methods' => 'DELETE',
            'callback' => 'pmg_rest_delete_task',
            'permission_callback' => function($request) {
                return current_user_can('delete_posts');
            }
        )
    ));
});

// REST API回调函数示例
function pmg_rest_get_projects(WP_REST_Request $request) {
    $args = array(
        'status' => $request->get_param('status') ?: 'active',
        'user_id' => get_current_user_id(),
        'page' => $request->get_param('page') ?: 1
    );
    
    $projects = PMG_Projects::get_projects($args);
    
    return new WP_REST_Response($projects, 200);
}

function pmg_rest_create_project(WP_REST_Request $request) {
    $data = $request->get_json_params();
    
    $project_id = PMG_Projects::create_project($data);
    
    if ($project_id) {
        // 自动将创建者添加为项目管理员
        PMG_Projects::add_project_member($project_id, get_current_user_id(), 'admin');
        
        return new WP_REST_Response(array(
            'id' => $project_id,
            'message' => '项目创建成功'
        ), 201);
    }
    
    return new WP_REST_Response(array(
        'error' => '项目创建失败'
    ), 500);
}

5. 甘特图集成与可视化

5.1 甘特图库选择与集成

5.1.1 选择适合的甘特图库

  • DHTMLX Gantt:功能强大,商业使用需授权
  • Frappe Gantt:开源免费,轻量级
  • Gantt-elastic:基于SVG,响应式设计
  • 自定义实现:完全控制,但开发成本高

5.2 使用Frappe Gantt实现

<!-- public/views/gantt-view.php -->
<div class="pmg-gantt-container">
    <div class="pmg-gantt-toolbar">
        <button class="pmg-btn pmg-btn-zoom-in">放大</button>
        <button class="pmg-btn pmg-btn-zoom-out">缩小</button>
        <button class="pmg-btn pmg-btn-today">今天</button>
        <select class="pmg-select-view">
            <option value="Day">日视图</option>
            <option value="Week">周视图</option>
            <option value="Month">月视图</option>
        </select>
    </div>
    <div id="pmg-gantt-chart"></div>
</div>
// public/js/gantt-chart.js
(function($) {
    'use strict';
    
    class PMG_GanttChart {
        constructor(containerId, projectId) {
            this.container = document.getElementById(containerId);
            this.projectId = projectId;
            this.gantt = null;
            this.init();
        }
        
        init() {
            // 加载Frappe Gantt库
            this.loadGanttLibrary().then(() => {
                this.setupGantt();
                this.loadProjectData();
                this.bindEvents();
            });
        }
        
        loadGanttLibrary() {
            return new Promise((resolve) => {
                if (typeof Gantt !== 'undefined') {
                    resolve();
                    return;
                }
                
                // 动态加载CSS和JS
                const cssLink = document.createElement('link');
                cssLink.rel = 'stylesheet';
                cssLink.href = PMG_Gantt.pluginUrl + 'assets/lib/frappe-gantt/frappe-gantt.css';
                document.head.appendChild(cssLink);
                
                const script = document.createElement('script');
                script.src = PMG_Gantt.pluginUrl + 'assets/lib/frappe-gantt/frappe-gantt.min.js';
                script.onload = resolve;
                document.head.appendChild(script);
            });
        }
        
        setupGantt() {
            this.gantt = new Gantt(this.container, [], {
                header_height: 50,
                column_width: 30,
                step: 24,
                view_modes: ['Day', 'Week', 'Month'],
                bar_height: 20,
                bar_corner_radius: 3,
                arrow_curve: 5,
                padding: 18,
                view_mode: 'Week',
                date_format: 'YYYY-MM-DD',
                custom_popup_html: null,
                on_click: (task) => this.onTaskClick(task),
                on_date_change: (task, start, end) => this.onDateChange(task, start, end),
                on_progress_change: (task, progress) => this.onProgressChange(task, progress),
                on_view_change: (mode) => this.onViewChange(mode)
            });
        }
        
        loadProjectData() {
            $.ajax({
                url: PMG_Gantt.restUrl + 'pmg/v1/projects/' + this.projectId + '/gantt-data',
                method: 'GET',
                beforeSend: (xhr) => {
                    xhr.setRequestHeader('X-WP-Nonce', PMG_Gantt.nonce);
                },
                success: (response) => {
                    this.transformAndLoadData(response);
                },
                error: (error) => {
                    console.error('加载甘特图数据失败:', error);
                }
            });
        }
        
        transformAndLoadData(data) {
            // 转换数据为甘特图所需格式
            const ganttTasks = data.tasks.map(task => ({
                id: task.id.toString(),
                name: task.title,
                start: task.start_date,
                end: task.end_date,
                progress: task.progress,
                dependencies: task.dependencies ? task.dependencies.split(',') : [],
                custom_class: task.priority + '-priority'
            }));
            
            this.gantt.refresh(ganttTasks);
        }
        
        onTaskClick(task) {
            // 打开任务详情模态框
            this.openTaskModal(task.id);
        }
        
        onDateChange(task, start, end) {
            // 更新任务日期
            $.ajax({
                url: PMG_Gantt.restUrl + 'pmg/v1/tasks/' + task.id,
                method: 'PUT',
                beforeSend: (xhr) => {
                    xhr.setRequestHeader('X-WP-Nonce', PMG_Gantt.nonce);
                },
                data: JSON.stringify({
                    start_date: start,
                    end_date: end
                }),
                contentType: 'application/json',
                success: () => {
                    console.log('任务日期更新成功');
                },
                error: (error) => {
                    console.error('更新失败:', error);
                    // 恢复原始日期
                    this.loadProjectData();
                }
            });
        }
        
        onProgressChange(task, progress) {
            // 更新任务进度
            $.ajax({
                url: PMG_Gantt.restUrl + 'pmg/v1/tasks/' + task.id + '/progress',
                method: 'PUT',
                beforeSend: (xhr) => {
                    xhr.setRequestHeader('X-WP-Nonce', PMG_Gantt.nonce);
                },
                data: JSON.stringify({
                    progress: progress
                }),
                contentType: 'application/json',
                success: () => {
                    console.log('任务进度更新成功');
                }
            });
        }
        
        bindEvents() {
            // 工具栏事件绑定
            $('.pmg-btn-zoom-in').on('click', () => this.zoomIn());
            $('.pmg-btn-zoom-out').on('click', () => this.zoomOut());
            $('.pmg-btn-today').on('click', () => this.scrollToToday());
            $('.pmg-select-view').on('change', (e) => this.changeView(e.target.value));
        }
        
        zoomIn() {
            const currentWidth = this.gantt.options.column_width;
            this.gantt.change_view_mode({
                ...this.gantt.options,
                column_width: Math.min(currentWidth + 10, 100)
            });
        }
        
        zoomOut() {
            const currentWidth = this.gantt.options.column_width;
            this.gantt.change_view_mode({
                ...this.gantt.options,
                column_width: Math.max(currentWidth - 10, 10)
            });
        }
        
        scrollToToday() {
            const today = new Date();
            this.gantt.scroll_to(today);
        }
        
        changeView(mode) {
            this.gantt.change_view_mode(mode);
        }
        
        openTaskModal(taskId) {
            // 实现任务详情模态框
            console.log('打开任务详情:', taskId);
        }
    }
    
    // 初始化甘特图
    $(document).ready(function() {
        if ($('#pmg-gantt-chart').length) {
            const projectId = $('#pmg-gantt-chart').data('project-id');
            window.pmgGantt = new PMG_GanttChart('pmg-gantt-chart', projectId);
        }
    });
    
})(jQuery);

5.3 甘特图数据API端点

// 添加甘特图数据端点
add_action('rest_api_init', function() {
    register_rest_route('pmg/v1', '/projects/(?P<project_id>d+)/gantt-data', array(
        'methods' => 'GET',
        'callback' => 'pmg_rest_get_gantt_data',
        'permission_callback' => function($request) {
            return pmg_check_project_access($request['project_id']);
        }
    ));
});

function pmg_rest_get_gantt_data(WP_REST_Request $request) {
    $project_id = $request->get_param('project_id');
    
    // 获取项目任务
    $tasks = PMG_Tasks::get_project_tasks($project_id, true);
    
    // 格式化任务依赖关系
    $formatted_tasks = array();
    foreach ($tasks as $task) {
        $formatted_task = array(
            'id' => $task->id,
            'title' => $task->title,
            'start_date' => $task->start_date,
            'end_date' => $task->end_date,
            'progress' => $task->progress,
            'priority' => $task->priority,
            'dependencies' => $task->dependencies
        );
        
        $formatted_tasks[] = $formatted_task;
    }
    
    // 获取项目信息
    $project = PMG_Projects::get_project($project_id);
    
    return new WP_REST_Response(array(
        'project' => $project,
        'tasks' => $formatted_tasks
    ), 200);
}

5.4 甘特图样式定制

/* public/css/gantt-styles.css */
.pmg-gantt-container {
    background: #fff;
    border-radius: 8px;
    box-shadow: 0 2px 10px rgba(0,0,0,0.1);
    overflow: hidden;
    margin: 20px 0;
}

.pmg-gantt-toolbar {
    padding: 15px;
    background: #f8f9fa;
    border-bottom: 1px solid #e9ecef;
    display: flex;
    gap: 10px;
    align-items: center;
}

.pmg-btn {
    padding: 8px 16px;
    background: #007cba;
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    font-size: 14px;
    transition: background 0.3s;
}

.pmg-btn:hover {
    background: #005a87;
}

.pmg-select-view {
    padding: 8px 12px;
    border: 1px solid #ddd;
    border-radius: 4px;
    background: white;
}

/* 甘特图任务样式 */
.gantt .bar {
    rx: 4;
    ry: 4;
}

.gantt .bar-wrapper {
    cursor: pointer;
}

.gantt .bar-progress {
    fill: #4CAF50;
}

/* 优先级颜色 */
.high-priority .bar {
    fill: #ff6b6b;
}

.medium-priority .bar {
    fill: #4d96ff;
}

.low-priority .bar {
    fill: #6bcf7f;
}

/* 里程碑样式 */
.milestone .bar {
    fill: #ffd166;
    width: 10px;
    rx: 10;
    ry: 10;
}

/* 依赖线样式 */
.gantt .arrow {
    stroke: #666;
    stroke-width: 2;
    fill: none;
}

6. 用户权限与团队协作

6.1 用户角色系统

// includes/class-pmg-permissions.php
class PMG_Permissions {
    
    // 定义项目角色
    const ROLES = array(
        'admin' => array(
            'name' => '管理员',
            'capabilities' => array(
                'edit_project',
                'delete_project',
                'manage_members',
                'create_tasks',
                'edit_all_tasks',
                'delete_tasks',
                'assign_tasks'
            )
        ),
        'manager' => array(
            'name' => '经理',
            'capabilities' => array(
                'edit_project',
                'create_tasks',
                'edit_all_tasks',
                'assign_tasks'
            )
        ),
        'member' => array(
            'name' => '成员',
            'capabilities' => array(
                'view_project',
                'create_tasks',
                'edit_own_tasks'
            )
        ),
        'viewer' => array(
            'name' => '观察者',
            'capabilities' => array(
                'view_project'
            )
        )
    );
    
    // 检查用户权限
    public static function user_can($user_id, $project_id, $capability) {
        $user_role = self::get_user_role($user_id, $project_id);
        
        if (!$user_role) {
            return false;
        }
        
        // 管理员拥有所有权限
        if ($user_role === 'admin') {
            return true;
        }
        
        // 检查角色权限
        if (isset(self::ROLES[$user_role])) {
            return in_array($capability, self::ROLES[$user_role]['capabilities']);
        }
        
        return false;
    }
    
    // 获取用户在项目中的角色
    public static function get_user_role($user_id, $project_id) {
        global $wpdb;
        $table = $wpdb->prefix . 'pmg_project_members';
        
        $role = $wpdb->get_var($wpdb->prepare(
            "SELECT role FROM $table WHERE user_id = %d AND project_id = %d",
            $user_id, $project_id
        ));
        
        return $role ?: false;
    }
    
    // 添加项目成员
    public static function add_project_member($project_id, $user_id, $role = 'member') {
        global $wpdb;
        $table = $wpdb->prefix . 'pmg_project_members';
        
        // 检查是否已是成员
        $existing = $wpdb->get_var($wpdb->prepare(
            "SELECT id FROM $table WHERE project_id = %d AND user_id = %d",
            $project_id, $user_id
        ));
        
        if ($existing) {
            return $wpdb->update($table, 
                array('role' => $role),
                array('id' => $existing)
            );
        }
        
        return $wpdb->insert($table, array(
            'project_id' => $project_id,
            'user_id' => $user_id,
            'role' => $role
        ));
    }
    
    // 获取项目成员列表
    public static function get_project_members($project_id) {
        global $wpdb;
        $members_table = $wpdb->prefix . 'pmg_project_members';
        $users_table = $wpdb->users;
        
        return $wpdb->get_results($wpdb->prepare(
            "SELECT m.*, u.display_name, u.user_email 
             FROM $members_table m 
             LEFT JOIN $users_table u ON m.user_id = u.ID 
             WHERE m.project_id = %d 
             ORDER BY m.joined_at ASC",
            $project_id
        ));
    }
}

6.2 团队协作功能

// includes/class-pmg-collaboration.php
class PMG_Collaboration {
    
    // 添加任务评论
    public static function add_task_comment($task_id, $user_id, $content) {
        global $wpdb;
        $table = $wpdb->prefix . 'pmg_task_comments';
        
        $comment_id = $wpdb->insert($table, array(
            'task_id' => $task_id,
            'user_id' => $user_id,
            'content' => wp_kses_post($content),
            'created_at' => current_time('mysql')
        ));
        
        if ($comment_id) {
            // 发送通知
            self::notify_task_comment($task_id, $user_id, $content);
        }
        
        return $comment_id;
    }
    
    // 获取任务评论
    public static function get_task_comments($task_id) {
        global $wpdb;
        $comments_table = $wpdb->prefix . 'pmg_task_comments';
        $users_table = $wpdb->users;
        
        return $wpdb->get_results($wpdb->prepare(
            "SELECT c.*, u.display_name, u.user_email 
             FROM $comments_table c 
             LEFT JOIN $users_table u ON c.user_id = u.ID 
             WHERE c.task_id = %d 
             ORDER BY c.created_at ASC",
            $task_id
        ));
    }
    
    // 添加文件附件
    public static function add_task_attachment($task_id, $user_id, $file_data) {
        // 使用WordPress媒体库上传文件
        require_once(ABSPATH . 'wp-admin/includes/file.php');
        require_once(ABSPATH . 'wp-admin/includes/media.php');
        require_once(ABSPATH . 'wp-admin/includes/image.php');
        
        $upload = wp_handle_upload($file_data, array('test_form' => false));
        
        if (isset($upload['error'])) {
            return new WP_Error('upload_error', $upload['error']);
        }
        
        // 创建附件记录
        global $wpdb;
        $table = $wpdb->prefix . 'pmg_task_attachments';
        
        $attachment_id = $wpdb->insert($table, array(
            'task_id' => $task_id,
本文来自网络,不代表柔性供应链服务中心立场,转载请注明出处:https://mall.org.cn/5136.html

EXCHANGES®作者

上一篇
下一篇

为您推荐

发表回复

联系我们

联系我们

18559313275

在线咨询: QQ交谈

邮箱: vip@exchanges.center

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