---
url: /blog/8iqfxgdi/index.md
---
# 公告模块开发规范

## 概述

本文档规定了 ShopXO 系统中公告模块的功能说明、技术架构、数据结构和开发规范，供开发人员参考。

## 功能说明

公告模块用于向用户展示系统通知、活动公告、促销信息等内容。支持多业务类型、多平台、多页面的精细化展示控制。

### 核心特性

* **多业务类型**: 支持商城、用户、后台三种业务场景
* **平台过滤**: 支持 PC、H5、APP 三个平台独立配置
* **页面过滤**: 支持指定公告在特定页面显示
* **定时展示**: 支持设置公告的开始和结束时间
* **灵活排序**: 支持自定义排序权重
* **文本内容**: 内容支持多行文本展示

## 技术架构

```
后台管理：admin/notice
├── Controller: app/admin/controller/Notice.php
├── Form: app/admin/form/Notice.php
└── View: app/admin/view/default/notice/

前台 API：api/notice
├── Controller: app/api/controller/Notice.php
└── Service: app/service/NoticeService.php

数据存储：
└── sxo_notice (公告表)
```

## 数据表结构

### sxo\_notice (公告表)

| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `id` | int(11) | - | 主键ID |
| `title` | varchar(200) | - | 公告标题 |
| `content` | text | - | 公告内容（多行文本） |
| `url` | varchar(255) | - | 跳转链接 |
| `business_type` | varchar(50) | 'shop' | 业务类型（shop/user/admin） |
| `platform` | json | NULL | 适用平台（\["pc","h5","app"]） |
| `display_pages` | json | NULL | 展示页面（\["home","list","detail"]） |
| `is_enable` | tinyint(1) | 0 | 是否启用（0=禁用, 1=启用） |
| `start_time` | int(11) | 0 | 开始时间（时间戳） |
| `end_time` | int(11) | 0 | 结束时间（时间戳，0=永久） |
| `sort` | int(11) | 0 | 排序权重（数字越小越靠前） |
| `add_time` | int(11) | - | 添加时间 |
| `upd_time` | int(11) | - | 更新时间 |

## 字段说明

### business\_type (业务类型)

| 值 | 说明 | 语言键 |
|----|------|--------|
| `shop` | 商城公告 | `notice_business_type_shop` |
| `user` | 用户公告 | `notice_business_type_user` |
| `admin` | 后台公告 | `notice_business_type_admin` |

### platform (适用平台)

JSON 数组格式，可多选：

| 值 | 说明 | 语言键 |
|----|------|--------|
| `pc` | PC网站 | `common_service.notice.platform_pc` |
| `h5` | H5手机网站 | `common_service.notice.platform_h5` |
| `app` | APP应用 | `common_service.notice.platform_app` |

**示例**:

```json
["pc", "h5"]
```

**空数组或 NULL** 表示适用于所有平台。

### display\_pages (展示页面)

JSON 数组格式，可多选：

| 值 | 说明 | 语言键 |
|----|------|--------|
| `home` | 首页 | `common_service.notice.page_home` |
| `list` | 商品列表 | `common_service.notice.page_list` |
| `detail` | 商品详情 | `common_service.notice.page_detail` |
| `checkout` | 结算页面 | `common_service.notice.page_checkout` |
| `user` | 用户中心 | `common_service.notice.page_user` |
| `cart` | 购物车 | `common_service.notice.page_cart` |

**示例**:

```json
["home", "user"]
```

**空数组或 NULL** 表示适用于所有页面。

## Service 层方法

### NoticeList

获取公告列表。

**参数**:

```php
[
    'where' => [],          // 查询条件
    'field' => '',          // 查询字段
    'order_by' => '',       // 排序方式
    'm' => 0,               // 偏移量
    'n' => 10,              // 数量
]
```

**返回**:

```php
[
    'code' => 0,
    'msg' => '操作成功',
    'data' => [...],  // 处理后的公告列表
]
```

### NoticeInfo

获取公告详情。

**参数**:

```php
[
    'where' => ['id' => 1],  // 查询条件
]
```

**返回**:

```php
[
    'code' => 0,
    'msg' => '操作成功',
    'data' => [
        'id' => 1,
        'title' => '公告标题',
        'content' => '公告内容',
        'platform' => ['pc', 'h5'],
        'display_pages' => ['home'],
        // ...
    ],
]
```

### NoticeSave

保存公告（新增或更新）。

**参数**:

```php
[
    'id' => 1,                          // 更新时必填
    'title' => '公告标题',              // 必填
    'content' => '公告内容',            // 必填
    'url' => 'https://example.com',     // 必填
    'business_type' => 'shop',          // 必填
    'platform' => ['pc', 'h5'],         // 数组
    'display_pages' => ['home'],        // 数组
    'is_enable' => 1,
    'start_time' => '2026-01-01 00:00',
    'end_time' => '2026-12-31 23:59',
    'sort' => 100,
]
```

**返回**:

```php
[
    'code' => 0,
    'msg' => '操作成功',
    'data' => ['url' => 'admin/Notice/Index'],
]
```

### NoticeDelete

删除公告。

**参数**:

```php
[
    'ids' => [1, 2, 3],  // 支持数组或逗号分隔字符串
]
```

**返回**:

```php
[
    'code' => 0,
    'msg' => '删除成功',
    'data' => ['url' => 'admin/Notice/Index'],
]
```

### NoticeStatusUpdate

更新公告状态。

**参数**:

```php
[
    'id' => 1,
    'field' => 'is_enable',
    'value' => 1,
]
```

**返回**:

```php
[
    'code' => 0,
    'msg' => '更新成功',
]
```

### NoticeApiList

获取 API 公告列表（带平台和页面过滤）。

**参数**:

```php
[
    'platform' => 'h5',           // 平台（pc/h5/app）
    'page' => 'home',              // 页面（home/list/detail等）
    'business_type' => 'shop',     // 业务类型
]
```

**返回**:

```php
[
    'code' => 0,
    'msg' => 'success',
    'data' => [
        [
            'id' => 1,
            'title' => '公告标题',
            'content' => ['第一行', '第二行'],  // 按换行符分割
            'url' => '',
            'sort' => 100,
            // ...
        ],
    ],
]
```

## 前台 API 调用

### 获取公告列表

**请求**:

```
GET /api.php?s=notice/index
```

**参数**:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `platform` | string | 否 | 平台类型（pc/h5/app），默认 h5 |
| `page` | string | 否 | 页面类型，默认 home |
| `business_type` | string | 否 | 业务类型，默认 shop |

**响应示例**:

```json
{
  "msg": "操作成功",
  "code": 0,
  "data": [
    {
      "id": 1,
      "title": "xxx",
      "content": [
        "xxx",
        "xxx",
        "xxx"
      ],
      "url": "",
      "business_type": "shop",
      "platform": ["pc", "h5"],
      "display_pages": ["home"],
      "is_enable": 1,
      "sort": 100,
      "start_time": "2026-01-20 00:00",
      "end_time": 0,
      "time_range": "2026-01-20 00:00 ~ 永久"
    }
  ]
}
```

## 后台管理操作

### 列表页面

**路由**: `/admin/notice/index`

**功能**:

* 分页展示公告列表
* 搜索筛选（标题、内容、业务类型、平台、页面、状态、时间范围、排序）
* 批量删除
* 状态切换（启用/禁用）

### 添加/编辑页面

**路由**: `/admin/notice/saveinfo`

**表单字段**:

* 标题（必填）
* 内容（必填，多行文本）
* 跳转链接（必填）
* 业务类型（必填，单选）
* 适用平台（多选）
* 展示页面（多选）
* 是否启用（开关）
* 开始时间（日期时间）
* 结束时间（日期时间，留空为永久）
* 排序（数字）

## 语言配置

### 后台语言

**文件**: [`app/admin/lang/zh.php`](app/admin/lang/zh.php)

```php
'notice' => [
    // 表格列
    'form_table' => [
        'id' => 'ID',
        'title' => '标题',
        'content' => '内容',
        'business_type' => '业务类型',
        'platform' => '适用平台',
        'display_pages' => '展示页面',
        'is_enable' => '状态',
        'time_range' => '有效时间',
        'sort' => '排序',
        'add_time' => '添加时间',
    ],
],
```

### 公共语言

**文件**: [`app/lang/zh.php`](app/lang/zh.php)

```php
// 业务类型
'notice_business_type_shop' => '商城',
'notice_business_type_user' => '用户',
'notice_business_type_admin' => '后台',

// 展示页面
'notice_display_page_home' => '首页',
'notice_display_page_list' => '商品列表',
'notice_display_page_detail' => '商品详情',
'notice_display_page_checkout' => '结算页面',
'notice_display_page_user' => '用户中心',
'notice_display_page_cart' => '购物车',
```

## 内容处理规范

### platform 和 display\_pages 字段

这两个字段存储为 JSON 字符串，但代码中会自动处理为数组。

**保存时的处理**:

在 [`NoticeService.php`](app/service/NoticeService.php:263) 中：

```php
// 处理数组字段，过滤空值
private static function ProcessArrayField($params, $field, $default = [])
{
    if (!isset($params[$field])) {
        return $default;
    }

    $value = $params[$field];

    // 确保是数组并过滤空值
    if (is_array($value)) {
        return array_filter($value, function($item) {
            return $item !== '' && $item !== null;
        });
    }

    // 处理字符串格式（ShopXO框架将checkbox处理成逗号分隔的字符串）
    if (is_string($value) && trim($value) !== '') {
        $arr = explode(',', $value);
        return array_filter($arr, function($item) {
            return trim($item) !== '';
        });
    }

    return $default;
}
```

**读取时的处理**:

在 [`NoticeService.php`](app/service/NoticeService.php:297) 中的 `NoticeListHandle` 方法会自动将 JSON 字符串解析为数组，并生成显示文本。

### content 字段处理

* **存储格式**: 原始多行文本，保留换行符
* **API 返回**: 按换行符 `\n` 分割成数组
* **显示**: API 端按行展示

**示例**:

```
存储: "第一行内容\n第二行内容\n第三行内容"
API返回: ["第一行内容", "第二行内容", "第三行内容"]
```

## 过滤逻辑

API 获取公告时会应用以下过滤：

### 时间范围过滤

```php
// 检查是否在有效时间范围内
$current_time = time();
if ($notice['start_time'] > 0 && $notice['start_time'] > $current_time) {
    // 未到开始时间，跳过
}
if ($notice['end_time'] > 0 && $notice['end_time'] < $current_time) {
    // 已过结束时间，跳过
}
```

### 平台过滤

```php
// 如果公告指定了平台且不包含当前平台，跳过
$notice_platform = $notice['platform'];
if (!empty($notice_platform) && !in_array($current_platform, $notice_platform)) {
    continue;
}
```

### 页面过滤

```php
// 如果公告指定了页面且不包含当前页面，跳过
$display_pages = $notice['display_pages'];
if (!empty($display_pages) && !in_array($current_page, $display_pages)) {
    continue;
}
```

### 状态过滤

```php
// 只返回启用的公告
$where[] = ['is_enable', '=', 1];
```

## 使用示例

### 后台添加公告

```php
use app\service\NoticeService;

$result = NoticeService::NoticeSave([
    'title' => '双11大促开启',
    'content' => "全场满300减30\n满500减60\n上不封顶",
    'url' => '/activity/double11',
    'business_type' => 'shop',
    'platform' => ['pc', 'h5'],
    'display_pages' => ['home', 'list'],
    'is_enable' => 1,
    'start_time' => '2026-11-01 00:00',
    'end_time' => '2026-11-11 23:59',
    'sort' => 100,
]);
```

### 前台获取公告

```php
use app\service\NoticeService;

// H5 首页的商城公告
$result = NoticeService::NoticeApiList([
    'platform' => 'h5',
    'page' => 'home',
    'business_type' => 'shop',
]);

if ($result['code'] == 0) {
    $notices = $result['data'];
    foreach ($notices as $notice) {
        echo $notice['title'] . "\n";
        foreach ($notice['content'] as $line) {
            echo $line . "\n";
        }
    }
}
```

## 开发注意事项

### 1. JSON 字段处理

* `platform` 和 `display_pages` 在数据库中存储为 JSON 字符串
* Service 层会自动处理 JSON 和数组之间的转换
* 前端表单提交时可以是数组或逗号分隔字符串

### 2. 时间处理

* `start_time` 和 `end_time` 存储为时间戳
* 0 值表示无限制
* API 返回时会格式化为可读时间范围

### 3. 内容换行

* `content` 字段保留原始换行符
* API 返回时会按 `\n` 分割成数组
* 前端遍历数组逐行展示

### 4. 排序规则

* 按 `sort` 字段升序（数字越小越靠前）
* 相同 `sort` 值时按 `id` 降序

### 5. 空数组语义

* `platform` 为空数组 → 适用于所有平台
* `display_pages` 为空数组 → 适用于所有页面

## 相关文件清单

| 文件路径 | 类型 | 说明 |
|---------|------|------|
| [`app/service/NoticeService.php`](app/service/NoticeService.php) | Service | 公告服务层 |
| [`app/admin/controller/Notice.php`](app/admin/controller/Notice.php) | Controller | 后台控制器 |
| [`app/api/controller/Notice.php`](app/api/controller/Notice.php) | Controller | API 控制器 |
| [`app/admin/form/Notice.php`](app/admin/form/Notice.php) | Form | 表格配置 |
| [`app/admin/view/default/notice/`](app/admin/view/default/notice/) | View | 后台视图 |
| [`app/lang/zh.php`](app/lang/zh.php) | Lang | 语言配置 |
| [`app/admin/lang/zh.php`](app/admin/lang/zh.php) | Lang | 后台语言配置 |
