From 3055d2bec99541e8c03de17adc9b6bc2b92f2d33 Mon Sep 17 00:00:00 2001 From: let5sne Date: Sat, 25 Jul 2026 23:57:06 +0800 Subject: [PATCH] fix(mobile): replace App-Plus unsupported date and query APIs `URLSearchParams` is absent from the App-Plus JS core, and `toLocaleDateString('sv-SE', { timeZone: 'Asia/Shanghai' })` depends on full ICU data that the App runtime does not ship, so the work-result pages built either a broken query string or the device-local date. Build query strings with `encodeURIComponent`, and centralise the business day in `currentShanghaiDate()`, which shifts the epoch by a fixed UTC+8 offset before slicing the ISO date. Asia/Shanghai has no DST, so the fixed offset is exact rather than an approximation. Co-Authored-By: Claude Opus 5 (1M context) --- .../src/components/WorkDateSelector.vue | 4 +-- .../src/pages/supervisor/review/index.vue | 6 ++-- .../pages/supervisor/work-results/index.vue | 6 ++-- .../src/pages/user/work-results/index.vue | 6 ++-- mobile-uni/src/services/work-results.ts | 10 +++---- mobile-uni/src/utils/date.ts | 1 + mobile-uni/tests/work-results.test.mjs | 29 ++++++++++++++++++- 7 files changed, 45 insertions(+), 17 deletions(-) create mode 100644 mobile-uni/src/utils/date.ts diff --git a/mobile-uni/src/components/WorkDateSelector.vue b/mobile-uni/src/components/WorkDateSelector.vue index 7049a07a..a115dd9c 100644 --- a/mobile-uni/src/components/WorkDateSelector.vue +++ b/mobile-uni/src/components/WorkDateSelector.vue @@ -20,6 +20,7 @@ diff --git a/mobile-uni/src/pages/user/work-results/index.vue b/mobile-uni/src/pages/user/work-results/index.vue index 088e5c88..c871d0f4 100644 --- a/mobile-uni/src/pages/user/work-results/index.vue +++ b/mobile-uni/src/pages/user/work-results/index.vue @@ -73,14 +73,14 @@ import { fetchMobileIdentity } from '@/services/position'; import { updateAssistantCaptureStatus } from '@/services/personal-assistant'; import { openProtectedSource } from '@/services/source-preview'; import { generateMyWorkResult } from '@/services/work-results'; +import { currentShanghaiDate } from '@/utils/date'; import WorkDateSelector from '@/components/WorkDateSelector.vue'; const result = ref(null); const currentProject = ref(getCurrentProject()); const loading = ref(false); const message = ref(''); -const currentDate = () => new Date().toLocaleDateString('sv-SE', { timeZone: 'Asia/Shanghai' }); -const today = ref(currentDate()); +const today = ref(currentShanghaiDate()); const workDate = ref(today.value); const isToday = computed(() => workDate.value === today.value); const emptyTitle = computed(() => isToday.value ? '今天还没有已确认的工作记录' : '这一天没有已确认的工作记录'); @@ -147,7 +147,7 @@ const handleEmptyAction = () => isToday.value ? goAssistant() : changeWorkDate(t const goBack = () => uni.navigateBack({ fail: () => uni.switchTab({ url: '/pages/user/today/index' }) }); onShow(() => { - today.value = currentDate(); + today.value = currentShanghaiDate(); load(); }); diff --git a/mobile-uni/src/services/work-results.ts b/mobile-uni/src/services/work-results.ts index 9baf6f47..5faee848 100644 --- a/mobile-uni/src/services/work-results.ts +++ b/mobile-uni/src/services/work-results.ts @@ -2,11 +2,11 @@ import type { ProjectWorkResult, WorkResult } from '@/types/api'; import { apiRequest } from './api'; const params = (projectCode: string, workDate?: string, pageNum?: number, pageSize?: number) => { - const query = new URLSearchParams({ projectCode }); - if (workDate) query.set('workDate', workDate); - if (pageNum) query.set('pageNum', String(pageNum)); - if (pageSize) query.set('pageSize', String(pageSize)); - return query.toString(); + const query = [`projectCode=${encodeURIComponent(projectCode)}`]; + if (workDate) query.push(`workDate=${encodeURIComponent(workDate)}`); + if (pageNum) query.push(`pageNum=${pageNum}`); + if (pageSize) query.push(`pageSize=${pageSize}`); + return query.join('&'); }; export const generateMyWorkResult = (projectCode: string, workDate?: string) => diff --git a/mobile-uni/src/utils/date.ts b/mobile-uni/src/utils/date.ts new file mode 100644 index 00000000..1414fdc6 --- /dev/null +++ b/mobile-uni/src/utils/date.ts @@ -0,0 +1 @@ +export const currentShanghaiDate = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString().slice(0, 10); diff --git a/mobile-uni/tests/work-results.test.mjs b/mobile-uni/tests/work-results.test.mjs index 3841ea04..79da62fe 100644 --- a/mobile-uni/tests/work-results.test.mjs +++ b/mobile-uni/tests/work-results.test.mjs @@ -32,6 +32,33 @@ test('员工成果页与主管成果页复用真实项目成果接口', async () assert.match(service, /pageSize/); }); +test('App-Plus 查询参数不依赖 URLSearchParams', async () => { + const [service, supervisorReview] = await Promise.all([ + read('../src/services/work-results.ts'), + read('../src/pages/supervisor/review/index.vue') + ]); + + assert.doesNotMatch(`${service}\n${supervisorReview}`, /URLSearchParams/); + assert.match(service, /encodeURIComponent\(projectCode\)/); + assert.match(supervisorReview, /encodeURIComponent\(assignedScenario\)/); +}); + +test('App-Plus 工作成果日期固定为上海 yyyy-MM-dd', async () => { + const [dateUtil, selector, employeePage, supervisorPage] = await Promise.all([ + read('../src/utils/date.ts'), + read('../src/components/WorkDateSelector.vue'), + read('../src/pages/user/work-results/index.vue'), + read('../src/pages/supervisor/work-results/index.vue') + ]); + + assert.match(dateUtil, /Date\.now\(\) \+ 8 \* 60 \* 60 \* 1000/); + assert.match(dateUtil, /toISOString\(\)\.slice\(0, 10\)/); + assert.doesNotMatch(`${selector}\n${employeePage}\n${supervisorPage}`, /toLocaleDateString/); + for (const source of [selector, employeePage, supervisorPage]) { + assert.match(source, /currentShanghaiDate/); + } +}); + test('主管成果页显式分页,避免把接口上限误当作完整团队', async () => { const [supervisorPage, service, types] = await Promise.all([ read('../src/pages/supervisor/work-results/index.vue'), @@ -80,7 +107,7 @@ test('员工与主管成果页复用日期选择器查看历史成果且禁止 assert.match(supervisorPage, /getProjectWorkResult\(currentProject\.value\.projectCode, workDate\.value, pageNum\.value, pageSize\)/); assert.match(dateSelector, /mode="date"/); assert.match(dateSelector, /:end="today"/); - assert.match(dateSelector, /props\.maxDate \|\| currentDate\(\)/); + assert.match(dateSelector, /props\.maxDate \|\| currentShanghaiDate\(\)/); assert.match(dateSelector, /nextDate > today\.value/); assert.match(employeePage, /这一天没有已确认的工作记录/); assert.match(employeePage, /回到今天/);