diff --git a/api/index.js b/api/index.js
index c1b0a6a..1bf53a4 100644
--- a/api/index.js
+++ b/api/index.js
@@ -3,6 +3,7 @@ export { assetApi } from './modules/asset.js';
export { deviceApi } from './modules/device.js';
export { exchangeApi } from './modules/exchange.js';
export { orderApi } from './modules/order.js';
+export { notificationApi } from './modules/notification.js';
export { realnameApi } from './modules/realname.js';
export { walletApi } from './modules/wallet.js';
-export { wechatApi } from './modules/wechat.js';
\ No newline at end of file
+export { wechatApi } from './modules/wechat.js';
diff --git a/api/modules/notification.js b/api/modules/notification.js
new file mode 100644
index 0000000..b07aeb8
--- /dev/null
+++ b/api/modules/notification.js
@@ -0,0 +1,32 @@
+import request from '@/utils/request.js';
+
+export const notificationApi = {
+ getList(page = 1, page_size = 20) {
+ return request({
+ url: '/api/c/v1/notifications',
+ method: 'GET',
+ data: { page, page_size }
+ });
+ },
+
+ getUnreadCount() {
+ return request({
+ url: '/api/c/v1/notifications/unread-count',
+ method: 'GET'
+ });
+ },
+
+ markRead(id) {
+ return request({
+ url: `/api/c/v1/notifications/${id}/read`,
+ method: 'PUT'
+ });
+ },
+
+ markAllRead() {
+ return request({
+ url: '/api/c/v1/notifications/read-all',
+ method: 'PUT'
+ });
+ }
+};
diff --git a/components/FunctionCard.vue b/components/FunctionCard.vue
index be23dd3..28ff139 100644
--- a/components/FunctionCard.vue
+++ b/components/FunctionCard.vue
@@ -29,6 +29,14 @@
套餐订购
+
+
+
+ {{ unreadCount > 99 ? '99+' : unreadCount }}
+
+ 站内通知
+
@@ -132,6 +140,10 @@
walletBalance: {
type: [Number, String],
default: 0
+ },
+ unreadCount: {
+ type: Number,
+ default: 0
}
});
@@ -188,6 +200,22 @@
}
}
+ .function-icon-badge { position: relative; }
+ .unread-badge {
+ position: absolute;
+ top: -8rpx;
+ right: -12rpx;
+ min-width: 34rpx;
+ height: 34rpx;
+ padding: 0 8rpx;
+ border-radius: 20rpx;
+ background: var(--danger);
+ color: #fff;
+ font-size: 18rpx;
+ line-height: 34rpx;
+ text-align: center;
+ }
+
.function-name {
font-size: 28rpx;
font-weight: 500;
diff --git a/docs/产品迭代7月份/个人客户站内通知.md b/docs/产品迭代7月份/个人客户站内通知.md
new file mode 100644
index 0000000..320bd82
--- /dev/null
+++ b/docs/产品迭代7月份/个人客户站内通知.md
@@ -0,0 +1,45 @@
+# 个人客户站内通知
+
+为个人客户增加通知入口,支持查询通知、查看未读数以及标记已读。所有接口均需要登录,使用 `Bearer Token` 鉴权。
+
+## 查询通知列表
+
+`GET /api/c/v1/notifications`
+
+查询当前客户可见的未过期业务通知,按创建时间和通知 ID 倒序排列。
+
+| 参数 | 必填 | 说明 |
+| --- | --- | --- |
+| `page` | 否 | 页码,默认 1,范围 1~10000 |
+| `page_size` | 否 | 每页数量,默认 20,范围 1~50 |
+
+返回:包含通知列表 `items`、当前页 `page`、每页数量 `size` 和总数 `total`。通知项包含标题、正文、类型、类别、级别、关联资源、已读状态及创建/已读时间。
+
+## 标记单条通知已读
+
+`PUT /api/c/v1/notifications/{id}/read`
+
+将当前客户可见的指定通知标记为已读。通知不存在、属于其他客户或已经已读时,也返回成功,接口幂等。
+
+返回:`{ "success": true }`
+
+## 全部标记已读
+
+`PUT /api/c/v1/notifications/read-all`
+
+将当前客户可见的未过期未读业务通知全部标记为已读,重复调用幂等。
+
+返回:`{ "updated_count": 3 }`
+
+## 查询未读数
+
+`GET /api/c/v1/notifications/unread-count`
+
+查询当前客户未过期业务通知的未读数量;平台同步和系统运维通知不计入结果。
+
+返回:`{ "count": 3, "display_count": "3" }`,数量超过 99 时 `display_count` 为 `99+`。
+
+## 通用约定
+
+- 所有接口均使用 `Bearer Token` 鉴权。
+- 未登录、参数错误、无权访问和服务异常沿用统一错误响应。
diff --git a/openspec/changes/add-personal-notifications/proposal.md b/openspec/changes/add-personal-notifications/proposal.md
new file mode 100644
index 0000000..8f5bcc7
--- /dev/null
+++ b/openspec/changes/add-personal-notifications/proposal.md
@@ -0,0 +1,19 @@
+# Change: Add personal customer notifications
+
+## Why
+
+个人客户缺少统一的站内通知入口,无法查看业务通知、获取未读数量或管理通知已读状态。
+
+## What Changes
+
+- 增加个人客户通知列表查询接口,支持分页和固定倒序排列。
+- 增加单条通知已读和全部通知已读接口。
+- 增加个人客户通知未读数查询接口。
+- 限制通知数据仅返回当前认证客户可见且未过期的业务通知。
+- 统一返回通知内容、关联资源、通知级别、已读状态及时间信息。
+
+## Impact
+
+- Affected specs: `personal-notifications`
+- Affected code: 个人客户通知 API、通知列表入口、未读数展示和已读状态处理
+- No breaking changes to existing APIs
diff --git a/openspec/changes/add-personal-notifications/specs/personal-notifications/spec.md b/openspec/changes/add-personal-notifications/specs/personal-notifications/spec.md
new file mode 100644
index 0000000..0744350
--- /dev/null
+++ b/openspec/changes/add-personal-notifications/specs/personal-notifications/spec.md
@@ -0,0 +1,56 @@
+## ADDED Requirements
+
+### Requirement: Personal customers SHALL be able to query notifications
+
+The system SHALL provide `GET /api/c/v1/notifications` for authenticated personal customers. The endpoint SHALL return only visible, unexpired business notifications for the current customer, ordered by creation time descending and notification ID descending.
+
+#### Scenario: Query the first notification page
+- **WHEN** an authenticated customer requests the notification list without pagination parameters
+- **THEN** the system SHALL return page 1 with up to 20 notifications
+- **AND** the response SHALL include `items`, `page`, `size`, and `total`
+
+#### Scenario: Apply valid pagination
+- **WHEN** the request includes `page` from 1 to 10000 and `page_size` from 1 to 50
+- **THEN** the system SHALL return the requested page and page size
+
+#### Scenario: Reject invalid pagination
+- **WHEN** `page` or `page_size` is outside its allowed range
+- **THEN** the system SHALL return a parameter validation error
+
+### Requirement: Notification items SHALL expose client-readable status and metadata
+
+Each notification item SHALL include `id`, `title`, `body`, `type`, `category`, `severity`, `ref_type`, `ref_id`, `ref_key`, `is_read`, `created_at`, and nullable `read_at`.
+
+#### Scenario: Return an unread notification
+- **WHEN** a visible notification has not been read by the current customer
+- **THEN** the system SHALL return `is_read: false` and `read_at: null`
+
+### Requirement: Personal customers SHALL be able to mark one notification as read
+
+The system SHALL provide `PUT /api/c/v1/notifications/{id}/read` for authenticated personal customers. The operation SHALL be idempotent and SHALL only update a notification visible to the current customer.
+
+#### Scenario: Mark a visible unread notification
+- **WHEN** the customer marks a visible unread notification as read
+- **THEN** the system SHALL set its read state and return `{ "success": true }`
+
+#### Scenario: Mark an unavailable or already-read notification
+- **WHEN** the notification does not exist, belongs to another customer, or is already read
+- **THEN** the system SHALL return `{ "success": true }` without exposing ownership information
+
+### Requirement: Personal customers SHALL be able to mark all notifications as read
+
+The system SHALL provide `PUT /api/c/v1/notifications/read-all` to mark all visible, unexpired, unread business notifications for the current customer as read.
+
+#### Scenario: Mark all unread notifications
+- **WHEN** the customer calls the mark-all-read endpoint
+- **THEN** the system SHALL return the number of notifications actually updated in `updated_count`
+- **AND** repeated calls SHALL remain successful and return zero when nothing needs updating
+
+### Requirement: Personal customers SHALL be able to query unread count
+
+The system SHALL provide `GET /api/c/v1/notifications/unread-count`. The count SHALL include only visible, unexpired business notifications and SHALL exclude platform sync and system operations notifications.
+
+#### Scenario: Return unread count and badge text
+- **WHEN** an authenticated customer queries the unread count
+- **THEN** the system SHALL return numeric `count` and string `display_count`
+- **AND** `display_count` SHALL be `99+` when `count` exceeds 99
diff --git a/openspec/changes/add-personal-notifications/tasks.md b/openspec/changes/add-personal-notifications/tasks.md
new file mode 100644
index 0000000..ed3d06e
--- /dev/null
+++ b/openspec/changes/add-personal-notifications/tasks.md
@@ -0,0 +1,26 @@
+## 1. API and Data Contract
+
+- [x] 1.1 Define the client-side personal notification item and paginated list contract
+- [x] 1.2 Define the client-side unread count and read-operation contracts
+- [x] 1.3 Add authenticated notification API wrappers
+
+## 2. Notification Behavior
+
+- [ ] 2.1 Return only current customer's visible, unexpired business notifications
+- [ ] 2.2 Apply creation-time and notification-ID descending ordering
+- [ ] 2.3 Support idempotent single-read and read-all operations
+- [ ] 2.4 Exclude platform sync and system operations notifications from unread count
+
+## 3. Client Entry
+
+- [x] 3.1 Add the personal notification list entry and pagination handling
+- [x] 3.2 Add unread-count display and refresh behavior
+- [x] 3.3 Mark notifications read from list actions and support mark-all-read
+
+## 4. Verification
+
+- [ ] 4.1 Test authentication, pagination limits, ordering, and visibility isolation
+- [ ] 4.2 Test idempotent read behavior and unread-count updates
+- [x] 4.3 Verify the H5 build and unified success/error response handling
+
+> Note: The repository contains the H5 client only. Tasks 2.1-2.4 and 4.1-4.2 require implementation and verification in the backend service repository.
diff --git a/pages.json b/pages.json
index cfba92c..7ffd700 100644
--- a/pages.json
+++ b/pages.json
@@ -44,6 +44,12 @@
"navigationBarTitleText": "我的订单"
}
},
+ {
+ "path": "pages/notifications/notifications",
+ "style": {
+ "navigationBarTitleText": "站内通知"
+ }
+ },
{
"path": "pages/bind/bind",
"style": {
diff --git a/pages/index/index.vue b/pages/index/index.vue
index 591ae13..ecbcbcb 100644
--- a/pages/index/index.vue
+++ b/pages/index/index.vue
@@ -17,7 +17,8 @@
+ :isDevice="userInfo.isDevice" :walletBalance="deviceInfo.walletBalance" :unreadCount="notificationUnreadCount"
+ @enter="enterDetail" @sync="onSync">