diff --git a/App.vue b/App.vue
index 2605455..06337e4 100644
--- a/App.vue
+++ b/App.vue
@@ -39,6 +39,17 @@
},
onShow: function() {
console.log('App Show')
+ // #ifdef H5
+ // 在 onShow 中也检查一次登录,因为有时候 onLaunch 可能没有正确执行
+ const isWeixinBrowser = /MicroMessenger/i.test(navigator.userAgent)
+ if (isWeixinBrowser && process.env.NODE_ENV !== 'development') {
+ const token = uni.getStorageSync('token')
+ if (!token) {
+ console.log('[App] onShow 检测到没有 token,重新尝试登录')
+ this.wxH5AuthLogin()
+ }
+ }
+ // #endif
},
onHide: function() {
console.log('App Hide')
@@ -145,50 +156,108 @@
// 判断是否在微信客户端中打开
const isWeixinBrowser = /MicroMessenger/i.test(navigator.userAgent)
if (!isWeixinBrowser) {
- uni.showModal({
- title: '提示',
- content: '请在微信客户端中打开',
- showCancel: false
- })
+ console.log('[App] 非微信环境,跳过登录')
return
}
+
+ // 检查是否已经有 token
+ const existingToken = uni.getStorageSync('token')
+ if (existingToken) {
+ console.log('[App] 已存在 token,跳过登录')
+ return
+ }
+
let link = window.location.href;
- if (/code=/.test(link) || link.indexOf("code") > -1) {
- let temp = decodeURIComponent((new RegExp('[?|&]' + 'code' + '=' + '([^&;]+?)(&|#|;|$)').exec(
- link) || [, ''])[1].replace(/\+/g, '%20')) || null;
- console.log("code",temp)
+ console.log('[App] 当前 URL:', link)
+
+ // 改进 code 提取逻辑,支持多种 URL 格式
+ let code = null;
+ try {
+ // 方法1: 使用 URLSearchParams (更可靠)
+ if (typeof URLSearchParams !== 'undefined') {
+ const url = new URL(link)
+ code = url.searchParams.get('code')
+ }
+
+ // 方法2: 如果方法1失败,使用正则表达式
+ if (!code) {
+ const match = link.match(/[?&]code=([^&?#]+)/)
+ if (match && match[1]) {
+ code = decodeURIComponent(match[1].replace(/\+/g, '%20'))
+ }
+ }
+
+ // 方法3: 备用正则表达式
+ if (!code) {
+ const regex = new RegExp('[?|&]' + 'code' + '=' + '([^&;]+?)(&|#|;|$)')
+ const match = regex.exec(link)
+ if (match && match[1]) {
+ code = decodeURIComponent(match[1].replace(/\+/g, '%20'))
+ }
+ }
+ } catch (e) {
+ console.error('[App] 提取 code 失败:', e)
+ }
+
+ console.log('[App] 提取到的 code:', code)
+
+ if (code) {
+ // 清理 URL 中的 code 参数,避免重复登录
+ try {
+ const url = new URL(link)
+ url.searchParams.delete('code')
+ url.searchParams.delete('state')
+ // 使用 replaceState 更新 URL,但不刷新页面
+ if (window.history && window.history.replaceState) {
+ window.history.replaceState({}, '', url.toString())
+ }
+ } catch (e) {
+ console.warn('[App] 清理 URL 参数失败:', e)
+ }
// 上传 code 到服务器获取 token
+ console.log('[App] 开始调用登录接口,code:', code)
uni.request({
- url: API.WX_LOGIN,
- method: 'POST',
- data: { code: temp },
- success: (res) => {
- const result = res.data
- if (result.errcode === 0) {
- const token = result.data.access_token
- console.log('获取 token 成功:', token)
- uni.setStorageSync('token', token)
- } else {
- console.error('登录失败:', result.errmsg)
- uni.showToast({ title: result.errmsg, icon: 'none' })
- }
- },
- fail: (err) => {
- console.error('获取 token 失败:', err)
+ url: API.WX_LOGIN,
+ method: 'POST',
+ data: { code: code },
+ success: (res) => {
+ console.log('[App] 登录接口响应:', res.data)
+ const result = res.data
+ if (result.errcode === 0) {
+ const token = result.data.access_token
+ console.log('[App] 获取 token 成功:', token)
+ uni.setStorageSync('token', token)
+ // 触发登录成功事件,通知其他页面 token 已就绪
+ uni.$emit('loginSuccess', { token })
+ } else {
+ console.error('[App] 登录失败:', result.errmsg)
+ uni.showToast({ title: result.errmsg || '登录失败', icon: 'none' })
}
- })
- }else{
+ },
+ fail: (err) => {
+ console.error('[App] 获取 token 失败:', err)
+ uni.showToast({ title: '网络错误,请重试', icon: 'none' })
+ }
+ })
+ } else {
+ // 没有 code,需要跳转到授权页面
+ console.log('[App] 未找到 code,跳转到授权页面')
const appId = 'wx9538bc740fe87fce'
- const currentUrl = window.location.href
- const redirectUri = encodeURIComponent(currentUrl.replace(/#\//, ""));
+ // 获取当前 URL,去掉 hash 和已有的 code 参数
+ let currentUrl = window.location.href.split('#')[0]
+ // 清理已有的 code 和 state 参数
+ currentUrl = currentUrl.replace(/[?&]code=[^&]*/g, '').replace(/[?&]state=[^&]*/g, '')
+ // 如果清理后以 ? 结尾,去掉 ?
+ currentUrl = currentUrl.replace(/\?$/, '')
+ const redirectUri = encodeURIComponent(currentUrl)
const scope = 'snsapi_userinfo'
const state = 'STATE'
- console.log(redirectUri)
- const authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirectUri}&
- response_type=code&scope=${scope}&state=${state}#wechat_redirect`
+ console.log('[App] redirectUri:', redirectUri)
+ const authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirectUri}&response_type=code&scope=${scope}&state=${state}#wechat_redirect`
// 重定向到微信授权页面
+ console.log('[App] 跳转到授权页面:', authUrl)
window.location.href = authUrl
}
},
@@ -206,8 +275,11 @@
// this.handleWxH5Login(res.data.code)
} else if (res.data && res.data.data.access_token) {
// 或者直接返回 token
- uni.setStorageSync('token', res.data.data.access_token)
+ const token = res.data.data.access_token
+ uni.setStorageSync('token', token)
uni.showToast({ title: '登录成功', icon: 'success' })
+ // 触发登录成功事件
+ uni.$emit('loginSuccess', { token })
} else {
uni.showToast({ title: '登录失败', icon: 'none' })
}
diff --git a/config/index.js b/config/index.js
index 384798f..621b977 100644
--- a/config/index.js
+++ b/config/index.js
@@ -35,5 +35,7 @@ export const API = {
GET_INVOICE: `${BASE_URL}/api/customer/reservation/get-invoice`,
GET_DAILY_RESERVATION_DEADLINE: `${BASE_URL}/api/customer/setting/get-daily-reservation-deadline`,
GET_GEOFENCE_BY_DIRECTION: `${BASE_URL}/api/customer/geofence/get-by-direction`,
-
+ GET_WATER_LEVEL: `${BASE_URL}/api/customer/setting/get-water-level`,
+ GET_UNIT_PRICE: `${BASE_URL}/api/customer/setting/get-unit-price`,
+ GET_SHIP_INSPECTION_EXAMPLES: `${BASE_URL}/api/customer/setting/get-ship-inspection-examples`,
}
\ No newline at end of file
diff --git a/pages/index/index.vue b/pages/index/index.vue
index cb21890..2fbbeb4 100644
--- a/pages/index/index.vue
+++ b/pages/index/index.vue
@@ -5,27 +5,58 @@
-
+
-
- {{ item.direction==='in'?'去胥江':'去太湖' }}{{ item.name }}
-
-
-
+
+ {{
+ item.direction === "in" ? "去胥江" : "去太湖"
+ }}
+ {{ item.name }}
+
+
+
-
-
@@ -36,17 +67,29 @@
-
+
先预约
>
-
+
再购票
>
-
+
排队过闸
@@ -55,7 +98,11 @@
-
+
过闸预约
{{ statistics.total_count }}
@@ -63,7 +110,11 @@
-
+
在线付款
{{ statistics.unpaid_count }}
@@ -71,7 +122,11 @@
-
+
排队过闸
{{ statistics.paid_count }}
@@ -79,7 +134,11 @@
-
+
我的开票
{{ statistics.billed_count }}
@@ -103,7 +162,7 @@
北向南2025040102准备过闸
-->
-
+
+
+
+
+ 计算单价:
+ {{ unitPrice }}元
+
+
+ 计算规则:
+ {{ calculationDescription }}
+
+
预约信息
@@ -157,6 +168,8 @@ export default {
shipTypeEnum: [],
reservationStatusEnum: [],
qrContent: "",
+ unitPrice: '', // 单价
+ calculationDescription: '', // 计算规则
};
},
onLoad(options) {
@@ -175,6 +188,8 @@ export default {
// #endif
},
onShow() {
+ // 获取单价和计算规则
+ this.fetchUnitPrice();
this.fetchShipTypeEnum().then(() => {
if (this.item.id && this.item.status === "unpaid") {
this.fetchQrcode(this.item.id);
@@ -184,6 +199,26 @@ export default {
},
methods: {
formatChinaDate: base.formatChinaDate,
+ // 获取单价和计算规则
+ async fetchUnitPrice() {
+ const token = uni.getStorageSync('token')
+ if (!token) {
+ return
+ }
+ const res = await new Promise((resolve, reject) => {
+ uni.request({
+ url: `${API.GET_UNIT_PRICE}?token=${token}`,
+ method: 'get',
+ success: resolve,
+ fail: reject
+ })
+ })
+ if (res.data && res.data.errcode === 0) {
+ const data = res.data.data;
+ this.unitPrice = data.unit_price || '';
+ this.calculationDescription = data.calculation_description || '';
+ }
+ },
async fetchQrcode(id) {
const token = uni.getStorageSync("token");
if (!token || !id) return;
@@ -639,4 +674,36 @@ export default {
border: none;
}
}
+.price-info-section {
+ background: #fff;
+ border-radius: 24rpx;
+ margin: 0 24rpx 32rpx 24rpx;
+ box-shadow: 0 4rpx 16rpx rgba(59, 124, 255, 0.08);
+ padding: 32rpx 24rpx;
+ margin-top: 20px;
+}
+.price-info-item {
+ display: flex;
+ align-items: flex-start;
+ margin-bottom: 16rpx;
+ font-size: 28rpx;
+}
+.price-info-item:last-child {
+ margin-bottom: 0;
+}
+.price-label {
+ color: #666;
+ min-width: 140rpx;
+ flex-shrink: 0;
+}
+.price-value {
+ color: #217aff;
+ font-weight: 600;
+ flex: 1;
+}
+.price-desc {
+ color: #222;
+ flex: 1;
+ line-height: 1.6;
+}
diff --git a/pages/reservation/index.vue b/pages/reservation/index.vue
index bb833b1..37e9c38 100644
--- a/pages/reservation/index.vue
+++ b/pages/reservation/index.vue
@@ -4,7 +4,17 @@
-
+
+
+
+ 计算单价:
+ {{ unitPrice }}元
+
+
+ 计算规则:
+ {{ calculationDescription }}
+
+
船舶信息
@@ -118,6 +128,8 @@ export default {
isDateDisabled: false, // 是否禁用日期选择
userLocation: null, // 用户位置信息 {latitude, longitude}
isInGeofence: null, // 是否在围栏范围内,null表示未检查,true表示在范围内,false表示不在范围内
+ unitPrice: '', // 单价
+ calculationDescription: '', // 计算规则
}
},
onLoad() {
@@ -126,6 +138,8 @@ export default {
// #endif
},
async onShow() {
+ // 获取单价和计算规则
+ this.fetchUnitPrice();
// 先拉取方向、船型和可用船舶信息,如果没有可用船舶,则直接返回,不再进行后续操作(如获取位置信息等)
await this.fetchDirectionEnum();
await this.fetchShipTypeEnum();
@@ -159,6 +173,26 @@ export default {
this.fetchDailyReservationDeadline();
},
methods: {
+ // 获取单价和计算规则
+ async fetchUnitPrice() {
+ const token = uni.getStorageSync('token')
+ if (!token) {
+ return
+ }
+ const res = await new Promise((resolve, reject) => {
+ uni.request({
+ url: `${API.GET_UNIT_PRICE}?token=${token}`,
+ method: 'get',
+ success: resolve,
+ fail: reject
+ })
+ })
+ if (res.data && res.data.errcode === 0) {
+ const data = res.data.data;
+ this.unitPrice = data.unit_price || '';
+ this.calculationDescription = data.calculation_description || '';
+ }
+ },
// 获取用户位置
getUserLocation() {
// #ifdef H5
@@ -924,4 +958,36 @@ export default {
background: #217aff;
color: #fff;
}
+.price-info-section {
+ background: #fff;
+ border-radius: 18px;
+ margin: 0 16px 16px 16px;
+ box-shadow: 0 2px 8px rgba(0,0,0,0.04);
+ padding: 18px 18px 12px 18px;
+ margin-top: 20px;
+}
+.price-info-item {
+ display: flex;
+ align-items: flex-start;
+ margin-bottom: 12px;
+ font-size: 14px;
+}
+.price-info-item:last-child {
+ margin-bottom: 0;
+}
+.price-label {
+ color: #666;
+ min-width: 100px;
+ flex-shrink: 0;
+}
+.price-value {
+ color: #217aff;
+ font-weight: 600;
+ flex: 1;
+}
+.price-desc {
+ color: #222;
+ flex: 1;
+ line-height: 1.6;
+}
\ No newline at end of file
diff --git a/收尾20251215.markdown b/收尾20251215.markdown
new file mode 100644
index 0000000..03ea3fa
--- /dev/null
+++ b/收尾20251215.markdown
@@ -0,0 +1,35 @@
+后台:
+
+1. 价格计算参数、吃水深度计算参数;
+2. 短信通知、模版消息/订阅消息;
+3. 初审之后就可以预约;
+4. 退款处理流程
+
+前台:(新增的三个接口在swagger的[用户端系统设置](https://xukoushuniu.115.langye.net/swagger/#/用户端系统设置))
+
+-1. “总吨位”改成“载重吨位”,直接给出价格算法和结果,分别在填写船舶信息、查看船舶信息、预约界面展示;
+
+2. 船检簿示例及文字说明,通过接口获取,展示在录入船舶信息的页面;
+
+3. 订阅消息(优先级低,相关文档请参照公众号订阅消息文档,后端接口暂未提供):(1)_v39TguWNu6ALEpdXSuy8hHFep0m4NrARAutSvl5sRE,预约成功之后订阅,后台排班确认后触发
+
+ _v39TguWNu6ALEpdXSuy8hHFep0m4NrARAutSvl5sRE
+
+ 
+
+
+
+ (1)4ydgM4-nHNOfYiotYFmvxZR_fOwHlQcgc-aXu4KZ8Hs,支付成功之后订阅,后台开始检票后触发
+
+ 
+
+4. 初次进入页面未自动登录的BUG:初次进入首页的时候,携带了code但是没有自动登录。
+
+5. 水位信息展示修改:通过/api/customer/setting/get-water-level获取数据,前端展示水位和吃水深度
+
+其他:
+
+1. 操作手册
+2. 上线节点梳理
+3. 后台用户清单
+
diff --git a/用户操作手册.md b/用户操作手册.md
new file mode 100644
index 0000000..c1698e2
--- /dev/null
+++ b/用户操作手册.md
@@ -0,0 +1,406 @@
+# 胥口闸站购票系统 - 用户操作手册
+
+## 目录
+1. [系统简介](#系统简介)
+2. [首次使用](#首次使用)
+3. [主要功能](#主要功能)
+ - [3.1 首页](#31-首页)
+ - [3.2 船舶管理](#32-船舶管理)
+ - [3.3 过闸预约](#33-过闸预约)
+ - [3.4 订单管理](#34-订单管理)
+ - [3.5 在线付款](#35-在线付款)
+ - [3.6 发票管理](#36-发票管理)
+ - [3.7 消息中心](#37-消息中心)
+ - [3.8 个人中心](#38-个人中心)
+
+---
+
+## 系统简介
+
+胥口闸站购票系统是一款为船舶过闸提供预约、购票、支付等服务的移动端应用。系统支持微信小程序和H5网页两种使用方式。
+
+**核心流程:先预约 → 再购票 → 排队过闸**
+
+---
+
+## 首次使用
+
+### 1. 登录/授权
+
+#### 微信小程序用户
+- 打开微信,搜索"胥口闸站购票"小程序
+- 首次打开会自动弹出微信授权提示
+- 点击"允许"完成授权登录
+
+#### 微信H5用户
+- 在微信中打开系统链接
+- 系统会自动跳转到微信授权页面
+- 点击"同意"完成授权登录
+
+**注意:** 系统需要获取您的位置信息用于预约验证,请允许位置权限。
+
+---
+
+## 主要功能
+
+### 3.1 首页
+
+首页是系统的核心入口,显示以下信息:
+
+#### 3.1.1 闸站状态信息
+- **今日太湖水位**:显示当前太湖水位高度(单位:米)
+- **今日胥江水位**:显示当前胥江水位高度(单位:米)
+- **当前批次**:显示正在进行的过闸批次信息(最多显示2个)
+
+#### 3.1.2 闸站流程指引
+系统提供清晰的流程指引:
+1. **先预约** - 选择航行方向和过闸日期进行预约
+2. **再购票** - 预约成功后进行在线支付
+3. **排队过闸** - 支付完成后等待过闸
+
+#### 3.1.3 功能入口卡片
+首页提供四个主要功能入口:
+
+1. **过闸预约**
+ - 显示预约总数
+ - 点击进入预约页面
+
+2. **在线付款**
+ - 显示待支付订单数量
+ - 点击进入付款列表
+
+3. **排队过闸**
+ - 显示已支付订单数量
+ - 点击查看排队状态
+
+4. **我的开票**
+ - 显示已开票数量
+ - 点击进入发票管理
+
+---
+
+### 3.2 船舶管理
+
+在预约过闸前,您需要先添加并审核通过船舶信息。
+
+#### 3.2.1 进入船舶管理
+- 方式一:从首页点击"过闸预约",如果没有可用船舶会自动跳转到船舶管理
+- 方式二:从"我的"页面进入船舶管理
+
+#### 3.2.2 添加船舶
+1. 点击"添加船只"按钮
+2. 按步骤填写信息:
+
+ **第一步:基本信息**
+ - 船舶所有人(必填):姓名需与身份证一致
+ - 身份证号(必填):18位身份证号码
+ - 联系电话(必填):11位手机号码
+ - 船舶编号(必填)
+ - 船舶类型(必填):选择货船或客船
+
+ **第二步:船舶参数**
+ - 总吨位(必填,单位:吨)
+ - 总长度(必填,单位:米)
+ - 总宽(必填,单位:米)
+ - 型深(必填,单位:米)
+ - 参考载重吨位(必填):选择A/B/C/D等级
+ - 船型(必填):根据实际情况选择
+
+ **第三步:船检簿上传**
+ - 第一页(必填):上传船检簿第一页照片
+ - 第二页(必填):上传船检簿第二页照片
+ - 第三页(必填):上传船检簿第三页照片
+ - 可点击"查看示例"了解上传要求
+
+ **第四步:签名确认**
+ - 勾选承诺声明:"本人承诺所提供材料皆真实有效;如有虚假,本人承担因此造成的全部责任。"
+ - 手写签名:在签名区域完成手写签名
+ - 可点击"重新签名"清除重签
+ - 可点击"预览签名"查看签名效果
+
+3. 点击"提交"完成添加
+4. 提交后等待审核,审核状态可在船舶列表中查看
+
+#### 3.2.3 查看船舶详情
+- 在船舶列表中点击任意船舶卡片
+- 查看船舶的详细信息、审核状态和签名图片
+
+#### 3.2.4 编辑船舶
+- 在船舶详情页点击"编辑"按钮
+- 或从船舶管理列表点击"编辑"
+- 修改信息后重新提交审核
+
+**注意:** 编辑时如果已有签名,系统会显示原有签名,您可以选择使用原签名或重新签名。
+
+#### 3.2.5 删除船舶
+- 在船舶详情页点击"删除"按钮
+- 确认删除后,该船舶信息将被永久删除
+
+#### 3.2.6 船舶审核状态
+- **待审核**:已提交,等待审核
+- **已通过**:审核通过,可用于预约
+- **已拒绝**:审核未通过,需修改后重新提交
+
+---
+
+### 3.3 过闸预约
+
+预约是过闸的第一步,需要选择航行方向和过闸日期。
+
+#### 3.3.1 进入预约页面
+- 从首页点击"过闸预约"卡片
+- 系统会先检查是否有可用船舶:
+ - 如果没有可用船舶,会提示并跳转到船舶管理页面
+ - 如果有可用船舶,继续预约流程
+
+#### 3.3.2 位置信息获取
+- 进入预约页面时,系统会弹出提示:"预约前需要先获取您的位置信息"
+- 点击"确定"允许获取位置
+- 系统会自动获取您当前的经纬度信息
+- **重要:** 位置信息用于验证您是否在闸站可预约范围内
+
+#### 3.3.3 选择航行方向
+- 系统会显示可选的航行方向(如:去胥江、去太湖等)
+- 点击选择您要前往的方向
+- **注意:** 必须选择航行方向才能继续
+
+#### 3.3.4 选择过闸日期
+- 系统会根据当前时间和截止时间自动设置默认日期:
+ - 如果当前时间早于截止时间:默认选择"今天",可更改
+ - 如果当前时间晚于截止时间:默认选择"明天",不可更改(按钮显示为橙色渐变背景)
+- **注意:** 过闸日期一旦确定后不可更改
+
+#### 3.3.5 位置范围验证
+- 选择航行方向后,系统会自动验证您的位置是否在可预约范围内
+- 如果不在范围内,会弹出提示:"您的当前位置不在闸站可预约范围内"
+- 此时无法提交预约,请移动到可预约范围内后重试
+
+#### 3.3.6 阅读并同意预约须知
+- 勾选"我已阅读并同意《过闸预约服务协议》"
+- 必须同意才能提交预约
+
+#### 3.3.7 提交预约
+- 确认所有信息无误后,点击底部"预约"按钮
+- 系统会验证:
+ - 是否同意预约须知
+ - 是否选择航行方向
+ - 位置是否在可预约范围内
+ - 是否有可用船舶
+- 验证通过后提交成功,跳转到订单页面
+
+---
+
+### 3.4 订单管理
+
+在"订单"页面可以查看所有预约订单,进行支付、取消、重新预约等操作。
+
+#### 3.4.1 查看订单列表
+- 点击底部导航栏"订单"标签
+- 显示所有预约订单,按时间倒序排列
+- 每个订单卡片显示:
+ - 订单状态(待支付、已支付、已取消等)
+ - 开票状态(如已开票)
+ - 创建时间
+ - 订单编号和船舶编号
+ - 航行方向和批次信息
+
+#### 3.4.2 订单状态说明
+- **待支付**:预约成功,等待支付
+- **已支付**:已支付,等待过闸
+- **已取消**:订单已取消
+- **其他状态**:根据实际情况显示
+
+#### 3.4.3 订单操作
+
+**取消预约**
+- 仅"待支付"状态的订单可以取消
+- 点击"取消预约"按钮
+- 确认后订单状态变为"已取消"
+
+**重新预约**
+- 某些状态下可以重新预约
+- 点击"重新预约"按钮
+- 跳转到预约页面,重新填写信息
+
+**去支付**
+- "待支付"状态的订单可以支付
+- 点击"去支付"按钮
+- 跳转到支付页面
+
+**去开票**
+- 已支付的订单可以开具发票
+- 点击"去开票"按钮
+- 跳转到发票开具页面
+
+**查看详情**
+- 点击"查看详情"按钮
+- 查看订单的完整信息
+
+#### 3.4.4 下拉刷新和上拉加载
+- 下拉页面可以刷新订单列表
+- 上拉到底部可以加载更多订单
+
+---
+
+### 3.5 在线付款
+
+#### 3.5.1 进入付款页面
+- 方式一:从首页点击"在线付款"卡片
+- 方式二:从订单列表点击"去支付"按钮
+
+#### 3.5.2 查看待支付订单
+- 显示所有待支付的订单列表
+- 每个订单显示:
+ - 订单编号
+ - 船舶信息
+ - 航行方向
+ - 过闸日期
+ - 应付金额
+
+#### 3.5.3 支付订单
+1. 选择要支付的订单
+2. 确认订单信息
+3. 选择支付方式
+4. 完成支付
+5. 支付成功后订单状态更新为"已支付"
+
+#### 3.5.4 查看支付详情
+- 点击订单可以查看支付详情
+- 包括支付时间、支付金额、支付方式等信息
+
+---
+
+### 3.6 发票管理
+
+#### 3.6.1 进入发票管理
+- 方式一:从首页点击"我的开票"卡片
+- 方式二:从"我的"页面进入发票管理
+
+#### 3.6.2 查看发票列表
+- 显示所有已开具的发票
+- 每个发票显示:
+ - 发票类型
+ - 发票金额
+ - 开具时间
+ - 发票状态
+
+#### 3.6.3 开具发票
+1. 从订单详情页点击"去开票"
+2. 或从发票管理页面点击"开具发票"
+3. 选择要开具发票的订单
+4. 填写发票信息:
+ - 发票类型(个人/单位)
+ - 发票抬头
+ - 税号(单位必填)
+ - 联系方式
+5. 提交开具申请
+6. 开具成功后可在发票列表中查看
+
+#### 3.6.4 查看发票详情
+- 点击发票卡片查看发票详情
+- 可以查看发票的完整信息
+- 可以下载或打印发票
+
+---
+
+### 3.7 消息中心
+
+#### 3.7.1 进入消息中心
+- 点击底部导航栏"消息"标签
+
+#### 3.7.2 查看消息
+- 显示所有系统通知和公告消息
+- 每条消息显示:
+ - 消息类型标签(带颜色区分)
+ - 消息标题
+ - 消息内容
+ - 发布时间
+
+#### 3.7.3 消息类型
+- 系统会根据消息类型显示不同颜色的标签
+- 包括:公告、通知、提醒等类型
+
+#### 3.7.4 刷新和加载
+- 下拉可以刷新消息列表
+- 上拉可以加载更多消息
+
+---
+
+### 3.8 个人中心
+
+#### 3.8.1 进入个人中心
+- 点击底部导航栏"我的"标签
+
+#### 3.8.2 个人信息
+- 显示头像、昵称、手机号等信息
+- 点击个人信息区域可以编辑
+
+#### 3.8.3 编辑个人信息
+1. 点击个人信息区域或设置图标
+2. 在弹出的编辑窗口中修改:
+ - 姓名
+ - 交款人类型(个人/单位)
+ - 手机号
+ - 证件号(身份证号)
+3. 点击"保存"完成修改
+
+#### 3.8.4 功能菜单
+个人中心提供以下功能入口:
+- **船舶管理**:管理您的船舶信息
+- **发票管理**:查看和管理发票
+- **关于我们**:查看系统相关信息
+
+---
+
+## 常见问题
+
+### Q1: 为什么无法预约?
+**A:** 可能的原因:
+1. 没有可用船舶或船舶未审核通过
+2. 未选择航行方向
+3. 当前位置不在闸站可预约范围内
+4. 未同意预约须知
+
+### Q2: 为什么过闸日期不能更改?
+**A:** 系统根据当前时间和截止时间自动设置过闸日期,一旦确定后不可更改,这是为了确保预约的准确性。
+
+### Q3: 如何知道我的位置是否在可预约范围内?
+**A:** 选择航行方向后,系统会自动验证。如果不在范围内,会弹出提示信息。
+
+### Q4: 船舶审核需要多长时间?
+**A:** 审核时间由管理员决定,请耐心等待。审核结果会通过消息通知您。
+
+### Q5: 可以取消已支付的订单吗?
+**A:** 已支付的订单无法取消,如需取消请联系客服。
+
+### Q6: 发票可以重复开具吗?
+**A:** 每个订单只能开具一次发票,请谨慎操作。
+
+### Q7: 忘记登录怎么办?
+**A:** 系统使用微信授权登录,重新打开应用会自动登录。
+
+---
+
+## 注意事项
+
+1. **位置权限**:预约功能需要获取您的位置信息,请务必允许位置权限
+2. **船舶信息**:请确保船舶信息真实有效,虚假信息将承担相应责任
+3. **预约时间**:请在截止时间前完成预约,过期将无法预约当日
+4. **支付时效**:预约成功后请及时支付,避免订单过期
+5. **网络环境**:建议在良好的网络环境下使用,避免操作失败
+
+---
+
+## 技术支持
+
+如遇到问题,可通过以下方式联系:
+- 查看系统消息中的通知
+- 联系客服(如有提供联系方式)
+
+---
+
+**版本信息**
+- 文档版本:v1.0
+- 更新日期:2025年
+- 适用平台:微信小程序、微信H5
+