فهرست منبع

fix: correct activity poster time formatting

Developer 1 هفته پیش
والد
کامیت
8eab288e2d
2فایلهای تغییر یافته به همراه116 افزوده شده و 4 حذف شده
  1. 27 4
      pagesHome/activityDetail.vue
  2. 89 0
      tests/activity-poster-time.test.js

+ 27 - 4
pagesHome/activityDetail.vue

@@ -671,13 +671,36 @@
 				return proxy.$showToast(res.msg)
 			} 
 			activityInfo.value = res.data;
-			if(activityInfo.value.activityStartTime) activityInfo.value.activityStartTime = new Date(activityInfo.value.activityStartTime).Format('yyyy年MM月dd日 hh:mm')
-			if(activityInfo.value.activityEndTime) activityInfo.value.activityEndTime = new Date(activityInfo.value.activityEndTime).Format('yyyy年MM月dd日 hh:mm')
+			const parseActivityDate = (value) => {
+				if(!value) return null;
+				if(typeof value === 'string') {
+					const match = value.match(/^(\d{4})-(\d{1,2})-(\d{1,2})[ T](\d{1,2}):(\d{1,2})(?::(\d{1,2}))?$/);
+					if(!match) return null;
+					const year = Number(match[1]);
+					const month = Number(match[2]);
+					const day = Number(match[3]);
+					const hour = Number(match[4]);
+					const minute = Number(match[5]);
+					const second = Number(match[6] || 0);
+					const date = new Date(year, month - 1, day, hour, minute, second);
+					return date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day
+						&& date.getHours() === hour && date.getMinutes() === minute && date.getSeconds() === second
+						? date : null;
+				}
+				const date = new Date(value);
+				return Number.isNaN(date.getTime()) ? null : date;
+			};
+			const activityStartDate = parseActivityDate(activityInfo.value.activityStartTime);
+			const activityEndDate = parseActivityDate(activityInfo.value.activityEndTime);
+			if(activityStartDate) activityInfo.value.activityStartTime = activityStartDate.Format('yyyy年MM月dd日 hh:mm')
+			if(activityEndDate) activityInfo.value.activityEndTime = activityEndDate.Format('yyyy年MM月dd日 hh:mm')
 			if(activityInfo.value.signupStartTime) activityInfo.value.signupStartTime = new Date(activityInfo.value.signupStartTime).Format('yyyy.MM.dd hh:mm')
 			if(activityInfo.value.signupEndTime) activityInfo.value.signupEndTime = new Date(activityInfo.value.signupEndTime).Format('yyyy.MM.dd hh:mm')
 			// 更新海报数据
 			posterData.title = activityInfo.value?.activityName || posterData.title;
-			posterData.time = `${new Date(activityInfo.value?.activityStartTime).Format('M.d-HH:mm') } ~ ${new Date(activityInfo.value?.activityEndTime).Format('M.d-HH:mm')}` || posterData.time;
+			posterData.time = activityStartDate && activityEndDate
+				? `${activityStartDate.Format('M.d-hh:mm')} ~ ${activityEndDate.Format('M.d-hh:mm')}`
+				: '时间待定';
 			posterData.address = `${activityInfo.value?.provinceName||''}${activityInfo.value?.cityName||''}${activityInfo.value?.address||''}` || posterData.address;
 			posterData.organizer = activityInfo.value?.channelName || posterData.organizer;
 			if(activityInfo.value?.coverFile) posterData.mainImg = activityInfo.value?.coverFile;
@@ -1330,4 +1353,4 @@
 			}
 		}
 	}
-</style>
+</style>

+ 89 - 0
tests/activity-poster-time.test.js

@@ -0,0 +1,89 @@
+import test from 'node:test'
+import assert from 'node:assert/strict'
+import fs from 'node:fs'
+import path from 'node:path'
+import vm from 'node:vm'
+
+const detailFile = path.resolve('pagesHome/activityDetail.vue')
+const dateFormatFile = path.resolve('common/utils/dateFormat.js')
+
+function loadActivityDetail (activityOverrides = {}) {
+  const source = fs.readFileSync(detailFile, 'utf8')
+  const start = source.indexOf('\tconst getActivityDetail = (id) => {')
+  const end = source.indexOf('\n\twatch(()=>userStore.token', start)
+  assert.notEqual(start, -1, '应找到活动详情加载方法')
+  assert.notEqual(end, -1, '应找到活动详情加载方法的结束位置')
+
+  const activityInfo = { value: {} }
+  const posterData = {
+    title: '默认标题',
+    time: '默认时间',
+    address: '默认地址',
+    organizer: '默认组织者',
+    mainImg: '默认封面'
+  }
+  const response = {
+    code: 0,
+    data: {
+      id: 'activity-1',
+      activityName: '测试活动',
+      activityStartTime: '2026-10-12 09:30:00',
+      activityEndTime: '2026-10-13 18:05:00',
+      signupStartTime: '2026-10-01 09:00:00',
+      signupEndTime: '2026-10-11 18:00:00',
+      provinceName: '广东省',
+      cityName: '深圳市',
+      address: '测试地址',
+      channelName: '测试机构',
+      coverFile: 'cover.png',
+      signupState: 0,
+      activeState: 1,
+      recruitmentNow: 0,
+      recruitmentMax: 10,
+      imageFiles: '',
+      ...activityOverrides
+    }
+  }
+  const context = {
+    activityInfo,
+    posterData,
+    shareADId: { value: '' },
+    imgList: { value: [] },
+    avatars: { value: [] },
+    proxy: {
+      $api: { get: () => Promise.resolve({ data: response }) },
+      $showToast: () => {}
+    },
+    uni: { showModal: () => {}, reLaunch: () => {} },
+    console
+  }
+  vm.createContext(context)
+  vm.runInContext(fs.readFileSync(dateFormatFile, 'utf8'), context)
+  vm.runInContext(`${source.slice(start, end)}\nthis.getActivityDetail = getActivityDetail`, context)
+
+  return { getActivityDetail: context.getActivityDetail, activityInfo, posterData }
+}
+
+test('海报使用接口原始活动时间生成有效的月日和时分', async () => {
+  const { getActivityDetail, activityInfo, posterData } = loadActivityDetail()
+
+  getActivityDetail('activity-1')
+  await new Promise(resolve => setImmediate(resolve))
+
+  assert.equal(activityInfo.value.activityStartTime, '2026年10月12日 09:30')
+  assert.equal(activityInfo.value.activityEndTime, '2026年10月13日 18:05')
+  assert.equal(posterData.time, '10.12-09:30 ~ 10.13-18:05')
+})
+
+test('活动时间无效时海报显示时间待定且不残留示例时间', async () => {
+  const { getActivityDetail, posterData } = loadActivityDetail({
+    activityStartTime: '2026-02-31 09:30:00',
+    activityEndTime: '2026-03-01 18:00:00'
+  })
+
+  getActivityDetail('activity-1')
+  await new Promise(resolve => setImmediate(resolve))
+
+  assert.equal(posterData.time, '时间待定')
+  assert.equal(posterData.time.includes('NaN'), false)
+})