PHP项目群公告如何发布编辑展示

wen PHP项目 27

本文目录导读:

PHP项目群公告如何发布编辑展示

  1. 数据库设计
  2. 核心功能实现
  3. 前端展示
  4. 安全注意事项
  5. 扩展功能建议

我来帮你详细解析PHP项目中群公告的发布、编辑和展示功能实现方案。

数据库设计

-- 群公告表
CREATE TABLE `group_announcements` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `group_id` int(11) NOT NULL COMMENT '群组ID',
    `user_id` int(11) NOT NULL COMMENT '发布者ID', varchar(200) NOT NULL COMMENT '公告标题',
    `content` text NOT NULL COMMENT '公告内容',
    `status` tinyint(1) DEFAULT '1' COMMENT '状态:1显示 0隐藏',
    `is_top` tinyint(1) DEFAULT '0' COMMENT '是否置顶:1是 0否',
    `view_count` int(11) DEFAULT '0' COMMENT '浏览次数',
    `created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
    `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` timestamp NULL DEFAULT NULL,
    PRIMARY KEY (`id`),
    KEY `idx_group_id` (`group_id`),
    KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

核心功能实现

发布公告

<?php
class AnnouncementController {
    public function publish($request) {
        // 验证用户权限
        $userId = $_SESSION['user_id'];
        $groupId = $request['group_id'];
        if (!$this->checkPermission($userId, $groupId)) {
            return json_encode(['code' => 403, 'msg' => '无权发布公告']);
        }
        // 验证数据
        $validator = new Validator();
        $rules = [
            'title' => 'required|max:200',
            'content' => 'required',
            'group_id' => 'required|integer'
        ];
        if (!$validator->validate($request, $rules)) {
            return json_encode(['code' => 400, 'msg' => $validator->getErrors()]);
        }
        // 处理内容(过滤XSS等安全风险)
        $data = [
            'group_id' => intval($request['group_id']),
            'user_id' => $userId,
            'title' => htmlspecialchars($request['title']),
            'content' => $this->filterContent($request['content']),
            'is_top' => isset($request['is_top']) ? intval($request['is_top']) : 0
        ];
        // 如果是置顶公告,取消其他置顶
        if ($data['is_top']) {
            $this->cancelOtherTop($groupId);
        }
        // 发布公告
        $announcementId = Announcement::create($data);
        // 发送通知
        $this->sendNotification($groupId, $data['title']);
        return json_encode(['code' => 200, 'msg' => '发布成功', 'data' => ['id' => $announcementId]]);
    }
    private function filterContent($content) {
        // 使用HTML Purifier过滤XSS
        $config = HTMLPurifier_Config::createDefault();
        $config->set('HTML.Allowed', 'p,b,i,u,a[href],img[src]');
        $purifier = new HTMLPurifier($config);
        return $purifier->purify($content);
    }
    private function checkPermission($userId, $groupId) {
        // 检查用户是否为群管理员或群主
        $groupMember = GroupMember::where('user_id', $userId)
                                  ->where('group_id', $groupId)
                                  ->first();
        return $groupMember && in_array($groupMember->role, ['owner', 'admin']);
    }
}

编辑公告

<?php
class AnnouncementController {
    public function edit($request) {
        $announcementId = $request['id'];
        $userId = $_SESSION['user_id'];
        // 获取公告信息
        $announcement = Announcement::find($announcementId);
        if (!$announcement) {
            return json_encode(['code' => 404, 'msg' => '公告不存在']);
        }
        // 权限验证(发布者或群管理员可编辑)
        $isPublisher = $announcement->user_id == $userId;
        $isAdmin = $this->checkPermission($userId, $announcement->group_id);
        if (!$isPublisher && !$isAdmin) {
            return json_encode(['code' => 403, 'msg' => '无权编辑']);
        }
        // 如果已经发布超过24小时,限制编辑
        if (time() - strtotime($announcement->created_at) > 86400 && !$isAdmin) {
            return json_encode(['code' => 403, 'msg' => '仅限管理员编辑超过24小时的公告']);
        }
        // 更新数据
        $updateData = [];
        if (isset($request['title'])) {
            $updateData['title'] = htmlspecialchars($request['title']);
        }
        if (isset($request['content'])) {
            $updateData['content'] = $this->filterContent($request['content']);
        }
        if (isset($request['is_top']) && $isAdmin) {
            $updateData['is_top'] = intval($request['is_top']);
        }
        if (!empty($updateData)) {
            $announcement->update($updateData);
        }
        // 记录编辑历史
        $this->saveEditHistory($announcementId, $userId, $updateData);
        return json_encode(['code' => 200, 'msg' => '编辑成功']);
    }
    private function saveEditHistory($announcementId, $userId, $changes) {
        AnnouncementHistory::create([
            'announcement_id' => $announcementId,
            'user_id' => $userId,
            'changes' => json_encode($changes),
            'created_at' => date('Y-m-d H:i:s')
        ]);
    }
}

展示公告

<?php
class AnnouncementController {
    public function list($request) {
        $groupId = $request['group_id'];
        $page = isset($request['page']) ? intval($request['page']) : 1;
        $pageSize = isset($request['page_size']) ? intval($request['page_size']) : 10;
        // 查询公告列表
        $query = Announcement::where('group_id', $groupId)
                             ->where('status', 1)
                             ->whereNull('deleted_at');
        // 置顶公告排在前面
        $query->orderBy('is_top', 'desc')
              ->orderBy('created_at', 'desc');
        $total = $query->count();
        $announcements = $query->skip(($page - 1) * $pageSize)
                               ->take($pageSize)
                               ->get();
        // 格式化输出
        $list = $announcements->map(function($item) {
            return [
                'id' => $item->id,
                'title' => $item->title,
                'summary' => mb_substr(strip_tags($item->content), 0, 200),
                'is_top' => $item->is_top,
                'publisher' => $this->getPublisherInfo($item->user_id),
                'view_count' => $item->view_count,
                'created_at' => $item->created_at,
                'updated_at' => $item->updated_at
            ];
        });
        return json_encode([
            'code' => 200,
            'data' => [
                'list' => $list,
                'total' => $total,
                'page' => $page,
                'page_size' => $pageSize
            ]
        ]);
    }
    public function detail($request) {
        $announcementId = $request['id'];
        // 增加浏览次数
        Announcement::where('id', $announcementId)->increment('view_count');
        $announcement = Announcement::find($announcementId);
        if (!$announcement) {
            return json_encode(['code' => 404, 'msg' => '公告不存在']);
        }
        return json_encode([
            'code' => 200,
            'data' => [
                'id' => $announcement->id,
                'title' => $announcement->title,
                'content' => $announcement->content,
                'publisher' => $this->getPublisherInfo($announcement->user_id),
                'view_count' => $announcement->view_count,
                'created_at' => $announcement->created_at,
                'updated_at' => $announcement->updated_at,
                'can_edit' => $this->checkEditPermission($announcementId)
            ]
        ]);
    }
}

前端展示

HTML结构

<!-- 公告列表 -->
<div class="announcement-list">
    <div class="announcement-item" v-for="item in announcements" :key="item.id">
        <div class="announcement-header">
            <span class="announcement-title" v-text="item.title"></span>
            <span v-if="item.is_top" class="top-tag">置顶</span>
            <span class="announcement-time" v-text="formatTime(item.created_at)"></span>
        </div>
        <div class="announcement-summary" v-html="item.summary"></div>
        <div class="announcement-footer">
            <span class="publisher" v-text="item.publisher.nickname"></span>
            <span class="view-count">浏览 {{item.view_count}} 次</span>
        </div>
    </div>
</div>
<!-- 发布/编辑弹窗 -->
<div class="modal" id="announcementModal">
    <div class="modal-content">
        <div class="modal-header">
            <h3>{{modalTitle}}</h3>
            <button class="close" @click="closeModal">&times;</button>
        </div>
        <div class="modal-body">
            <div class="form-group">
                <label>公告标题</label>
                <input type="text" v-model="form.title" maxlength="200" 
                       class="form-control" placeholder="请输入公告标题">
            </div>
            <div class="form-group">
                <label>公告内容</label>
                <textarea v-model="form.content" rows="10" 
                         class="form-control" placeholder="请输入公告内容"></textarea>
            </div>
            <div class="form-group" v-if="isAdmin">
                <label>
                    <input type="checkbox" v-model="form.is_top"> 置顶公告
                </label>
            </div>
        </div>
        <div class="modal-footer">
            <button class="btn btn-secondary" @click="closeModal">取消</button>
            <button class="btn btn-primary" @click="submitForm">发布公告</button>
        </div>
    </div>
</div>

JavaScript示例

// Vue组件示例
new Vue({
    el: '#app',
    data: {
        announcements: [],
        showModal: false,
        isEdit: false,
        currentId: null,
        form: {
            title: '',
            content: '',
            is_top: false
        }
    },
    computed: {
        modalTitle() {
            return this.isEdit ? '编辑公告' : '发布公告';
        },
        isAdmin() {
            // 检查用户权限
        }
    },
    methods: {
        fetchAnnouncements() {
            axios.get('/api/announcements', {
                params: { group_id: this.groupId }
            }).then(response => {
                this.announcements = response.data.data.list;
            });
        },
        showCreateModal() {
            this.isEdit = false;
            this.form = { title: '', content: '', is_top: false };
            this.showModal = true;
        },
        showEditModal(id) {
            this.isEdit = true;
            this.currentId = id;
            axios.get(`/api/announcement/${id}`).then(response => {
                const data = response.data.data;
                this.form = {
                    title: data.title,
                    content: data.content,
                    is_top: data.is_top
                };
                this.showModal = true;
            });
        },
        submitForm() {
            const url = this.isEdit ? 
                `/api/announcement/${this.currentId}/edit` : 
                '/api/announcement/publish';
            axios.post(url, this.form).then(response => {
                if (response.data.code === 200) {
                    this.closeModal();
                    this.fetchAnnouncements();
                    alert('操作成功');
                }
            }).catch(error => {
                alert(error.response.data.msg);
            });
        },
        closeModal() {
            this.showModal = false;
        },
        formatTime(time) {
            // 时间格式化函数
        }
    },
    mounted() {
        this.fetchAnnouncements();
    }
});

安全注意事项

  1. 权限验证:严格验证用户发布、编辑权限
  2. XSS防护:使用HTML Purifier过滤内容
  3. SQL注入防护:使用参数绑定或ORM
  4. 频率限制:限制频繁发布操作审核**:敏感词过滤机制

扩展功能建议

  • 公告分类:支持紧急、重要等分类
  • 消息推送:新公告即时通知群成员
  • 已读统计:查看哪些成员已阅读
  • 定时发布:设置定时发布公告
  • 评论功能:允许成员在公告下评论

需要我详细解释某个具体实现或提供其他功能支持吗?

抱歉,评论功能暂时关闭!