hookehuyr

fix(tools): 修复时间格式化函数处理时区的问题

重构 formatDatetime 函数,增加对时区后缀的处理,确保时间显示为当地时间
统一使用 dayjs 进行时间格式化,提高代码可维护性
1 <!-- 1 <!--
2 * @Date: 2024-01-15 16:25:51 2 * @Date: 2024-01-15 16:25:51
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2026-01-12 22:23:03 4 + * @LastEditTime: 2026-01-16 15:12:09
5 * @FilePath: /xyxBooking-weapp/src/pages/submit/index.vue 5 * @FilePath: /xyxBooking-weapp/src/pages/submit/index.vue
6 * @Description: 预约人员信息 6 * @Description: 预约人员信息
7 --> 7 -->
...@@ -9,10 +9,15 @@ ...@@ -9,10 +9,15 @@
9 <view class="submit-page"> 9 <view class="submit-page">
10 <view @tap="goToBooking" class="visit-time"> 10 <view @tap="goToBooking" class="visit-time">
11 <view>参访时间</view> 11 <view>参访时间</view>
12 - <view><text style="font-size: 30rpx;">{{ date }} {{ time }}</text>&nbsp;<IconFont name="rect-right" /></view> 12 + <view class="flex items-center">
13 + <text style="font-size: 30rpx;">{{ date }} {{ time }}</text>
14 + <IconFont name="rect-right" class="ml-1" />
15 + </view>
13 </view> 16 </view>
14 <view @tap="goToVisitor" class="add-visitors"> 17 <view @tap="goToVisitor" class="add-visitors">
15 - <view><IconFont name="plus" /> 添加参观者</view> 18 + <view>
19 + <IconFont name="plus" /> 添加参观者
20 + </view>
16 </view> 21 </view>
17 <view v-if="visitorList.length" class="visitors-list"> 22 <view v-if="visitorList.length" class="visitors-list">
18 <view v-for="(item, index) in visitorList" :key="index" @tap="addVisitor(item)" class="visitor-item"> 23 <view v-for="(item, index) in visitorList" :key="index" @tap="addVisitor(item)" class="visitor-item">
...@@ -23,12 +28,14 @@ ...@@ -23,12 +28,14 @@
23 <view> 28 <view>
24 <view style="color: #A67939;">{{ item.name }}</view> 29 <view style="color: #A67939;">{{ item.name }}</view>
25 <view>证件号:{{ formatId(item.id_number) }}</view> 30 <view>证件号:{{ formatId(item.id_number) }}</view>
26 - <view v-if="item.is_reserve === RESERVE_STATUS.ENABLE" style="color: #9C9A9A; font-size: 26rpx;">*已预约过{{ date }}参观,请不要重复预约</view> 31 + <view v-if="item.is_reserve === RESERVE_STATUS.ENABLE" style="color: #9C9A9A; font-size: 26rpx;">*已预约过{{ date
32 + }}参观,请不要重复预约</view>
27 </view> 33 </view>
28 </view> 34 </view>
29 </view> 35 </view>
30 <view v-else class="no-visitors-list"> 36 <view v-else class="no-visitors-list">
31 - <image src="https://cdn.ipadbiz.cn/xys/booking/%E6%9A%82%E6%97%A0@2x.png" style="width: 320rpx; height: 320rpx;" /> 37 + <image src="https://cdn.ipadbiz.cn/xys/booking/%E6%9A%82%E6%97%A0@2x.png"
38 + style="width: 320rpx; height: 320rpx;" />
32 <view class="no-visitors-list-title">您还没有添加过参观者</view> 39 <view class="no-visitors-list-title">您还没有添加过参观者</view>
33 </view> 40 </view>
34 <view style="height: 160rpx;"></view> 41 <view style="height: 160rpx;"></view>
...@@ -36,7 +43,9 @@ ...@@ -36,7 +43,9 @@
36 <view class="control-wrapper"> 43 <view class="control-wrapper">
37 <view class="left"> 44 <view class="left">
38 <view style="margin-left: 32rpx; display: flex;align-items: center;"> 45 <view style="margin-left: 32rpx; display: flex;align-items: center;">
39 - 订单金额&nbsp;&nbsp;<view style="color: #FF1919;display: inline-block;">¥<view style="font-size: 48rpx;display: inline-block;">&nbsp;{{ total }}</view></view> 46 + 订单金额&nbsp;&nbsp;<view style="color: #FF1919;display: inline-block;">¥<view
47 + style="font-size: 48rpx;display: inline-block;">&nbsp;{{ total }}</view>
48 + </view>
40 </view> 49 </view>
41 </view> 50 </view>
42 <view @tap="submitBtn" class="right">提交订单</view> 51 <view @tap="submitBtn" class="right">提交订单</view>
...@@ -157,10 +166,10 @@ const submitBtn = async () => { ...@@ -157,10 +166,10 @@ const submitBtn = async () => {
157 package: pay_params.package, 166 package: pay_params.package,
158 signType: pay_params.signType, 167 signType: pay_params.signType,
159 paySign: pay_params.paySign, 168 paySign: pay_params.paySign,
160 - success (res) { 169 + success(res) {
161 go('/success', { pay_id }); 170 go('/success', { pay_id });
162 }, 171 },
163 - fail (res) { 172 + fail(res) {
164 // 支付取消或失败,保留 pending_pay_id,允许用户再次点击按钮尝试支付同一订单 173 // 支付取消或失败,保留 pending_pay_id,允许用户再次点击按钮尝试支付同一订单
165 // 只有当 wxPayAPI 获取支付参数失败时(如下面的 else 分支),才重置 ID 以便重新创建订单 174 // 只有当 wxPayAPI 获取支付参数失败时(如下面的 else 分支),才重置 ID 以便重新创建订单
166 Taro.showToast({ title: '支付失败,请重试', icon: 'none' }); 175 Taro.showToast({ title: '支付失败,请重试', icon: 'none' });
...@@ -195,6 +204,7 @@ useDidShow(async () => { ...@@ -195,6 +204,7 @@ useDidShow(async () => {
195 .submit-page { 204 .submit-page {
196 margin: 32rpx; 205 margin: 32rpx;
197 position: relative; 206 position: relative;
207 +
198 .visit-time { 208 .visit-time {
199 background-color: #FFF; 209 background-color: #FFF;
200 display: flex; 210 display: flex;
...@@ -203,6 +213,7 @@ useDidShow(async () => { ...@@ -203,6 +213,7 @@ useDidShow(async () => {
203 padding: 24rpx; 213 padding: 24rpx;
204 border-radius: 16rpx; 214 border-radius: 16rpx;
205 } 215 }
216 +
206 .add-visitors { 217 .add-visitors {
207 border: 2rpx dashed #A67939; 218 border: 2rpx dashed #A67939;
208 color: #A67939; 219 color: #A67939;
...@@ -212,6 +223,7 @@ useDidShow(async () => { ...@@ -212,6 +223,7 @@ useDidShow(async () => {
212 margin: 32rpx 0; 223 margin: 32rpx 0;
213 font-size: 37rpx; 224 font-size: 37rpx;
214 } 225 }
226 +
215 .visitors-list { 227 .visitors-list {
216 .visitor-item { 228 .visitor-item {
217 background-color: #FFF; 229 background-color: #FFF;
...@@ -222,21 +234,25 @@ useDidShow(async () => { ...@@ -222,21 +234,25 @@ useDidShow(async () => {
222 align-items: center; 234 align-items: center;
223 } 235 }
224 } 236 }
237 +
225 .no-visitors-list { 238 .no-visitors-list {
226 display: flex; 239 display: flex;
227 justify-content: center; 240 justify-content: center;
228 align-items: center; 241 align-items: center;
229 flex-direction: column; 242 flex-direction: column;
243 +
230 img { 244 img {
231 margin-top: 32rpx; 245 margin-top: 32rpx;
232 margin-bottom: 32rpx; 246 margin-bottom: 32rpx;
233 width: 320rpx; 247 width: 320rpx;
234 } 248 }
249 +
235 .no-visitors-list-title { 250 .no-visitors-list-title {
236 color: #A67939; 251 color: #A67939;
237 font-size: 34rpx; 252 font-size: 34rpx;
238 } 253 }
239 } 254 }
255 +
240 .submit-wrapper { 256 .submit-wrapper {
241 position: fixed; 257 position: fixed;
242 bottom: 0; 258 bottom: 0;
...@@ -247,19 +263,21 @@ useDidShow(async () => { ...@@ -247,19 +263,21 @@ useDidShow(async () => {
247 // padding: 32rpx; 263 // padding: 32rpx;
248 justify-content: space-between; 264 justify-content: space-between;
249 flex-direction: column; 265 flex-direction: column;
250 - box-shadow: 0 -10rpx 8rpx 0 rgba(0,0,0,0.12); 266 + box-shadow: 0 -10rpx 8rpx 0 rgba(0, 0, 0, 0.12);
251 267
252 .control-wrapper { 268 .control-wrapper {
253 display: flex; 269 display: flex;
254 justify-content: space-between; 270 justify-content: space-between;
255 align-items: center; 271 align-items: center;
256 } 272 }
273 +
257 .left { 274 .left {
258 display: flex; 275 display: flex;
259 justify-content: center; 276 justify-content: center;
260 align-items: center; 277 align-items: center;
261 flex-wrap: nowrap; 278 flex-wrap: nowrap;
262 } 279 }
280 +
263 .right { 281 .right {
264 background-color: #A67939; 282 background-color: #A67939;
265 color: #FFF; 283 color: #FFF;
......
...@@ -87,20 +87,27 @@ const strExist = (array, str) => { ...@@ -87,20 +87,27 @@ const strExist = (array, str) => {
87 */ 87 */
88 const formatDatetime = (data) => { 88 const formatDatetime = (data) => {
89 // 格式化日期 89 // 格式化日期
90 - if (!data) return ''; 90 + if (!data || !data.begin_time || !data.end_time) return '';
91 91
92 - // 截取时间字符串最后6位(去除毫秒/时区等冗余部分) 92 + // 预处理函数:移除时区后缀,统一格式为 ISO 8601 (YYYY-MM-DDTHH:mm:ss)
93 - const begin_time = data?.begin_time?.slice(0, -6) || ''; 93 + // 这样做是为了让 dayjs 把它当作本地时间处理,避免时区转换导致的时间偏差(始终显示景点当地时间/字面时间)
94 - const end_time = data?.end_time?.slice(0, -6) || ''; 94 + const normalize = (timeStr) => {
95 + if (!timeStr) return '';
96 + // 移除 +08, +08:00 等时区后缀
97 + let clean = timeStr.split('+')[0];
98 + // 移除 Z 后缀
99 + clean = clean.split('Z')[0];
100 + // 将空格替换为 T,确保兼容性
101 + clean = clean.trim().replace(/\s+/, 'T');
102 + return clean;
103 + };
95 104
96 - // 拆分时间片段并拼接目标格式:日期 开始时间-结束时间 105 + const start = dayjs(normalize(data.begin_time));
97 - const [date, beginTime] = begin_time.split('T'); 106 + const end = dayjs(normalize(data.end_time));
98 - const [, endTime] = end_time.split('T');
99 107
100 - // 兼容时间拆分失败的情况,避免返回 NaN/-undefined 等异常 108 + if (!start.isValid() || !end.isValid()) return '';
101 - if (!date || !beginTime || !endTime) return '';
102 109
103 - return `${date} ${beginTime}-${endTime}`; 110 + return `${start.format('YYYY-MM-DD')} ${start.format('HH:mm')}-${end.format('HH:mm')}`;
104 }; 111 };
105 112
106 export { formatDate, wxInfo, parseQueryString, strExist, formatDatetime }; 113 export { formatDate, wxInfo, parseQueryString, strExist, formatDatetime };
......