fix(mobile): carry today task into practice

This commit is contained in:
2026-07-09 13:28:52 +08:00
parent dd13936ca9
commit f517cbd2b5
3 changed files with 35 additions and 1 deletions
@@ -224,6 +224,7 @@ mobile-uni/
- PC 成长激励和组织权限页已收口真实数据边界: 派专项必须输入真实员工手机号或 extPartyId,不再写入 `mobile-user`;无项目范围接口时只显示空态,不再展示假项目样例。 - PC 成长激励和组织权限页已收口真实数据边界: 派专项必须输入真实员工手机号或 extPartyId,不再写入 `mobile-user`;无项目范围接口时只显示空态,不再展示假项目样例。
- `mobile-uni` 本地 dev 代理已对齐 portless:默认 `/dev-api -> https://wygj-api.localhost`,不再依赖裸 `8080`;真实浏览器登录链路已复跑通过。 - `mobile-uni` 本地 dev 代理已对齐 portless:默认 `/dev-api -> https://wygj-api.localhost`,不再依赖裸 `8080`;真实浏览器登录链路已复跑通过。
- 员工今日页“今日安排”已优先回读真实 `/api/aihr/mobile/practice/assignments`;有待训练专项或每日三题时覆盖公开 home seed,真实浏览器已验证 `13900000998` 首页显示当天 daily 任务并可跳到练习页。 - 员工今日页“今日安排”已优先回读真实 `/api/aihr/mobile/practice/assignments`;有待训练专项或每日三题时覆盖公开 home seed,真实浏览器已验证 `13900000998` 首页显示当天 daily 任务并可跳到练习页。
- 员工今日页到练习页已补任务上下文传递:首页点“开始”会把当前 assignment 带到练习页,daily 任务高亮并提示填写,主管专项可直接启动,减少跳页后的二次选择。
## 7. 风险 ## 7. 风险
+30 -1
View File
@@ -21,7 +21,7 @@
<button class="ghost-button refresh-button" :disabled="assignmentLoading" @click="loadAssignments">刷新</button> <button class="ghost-button refresh-button" :disabled="assignmentLoading" @click="loadAssignments">刷新</button>
</view> </view>
<view v-if="assignments.length" class="assignment-list"> <view v-if="assignments.length" class="assignment-list">
<view v-for="item in assignments" :key="item.id" class="assignment-row"> <view v-for="item in assignments" :key="item.id" class="assignment-row" :class="{ highlighted: highlightedAssignmentId === item.id }">
<view class="assignment-copy"> <view class="assignment-copy">
<text class="assignment-badge">{{ item.source === 'daily' ? '每日三题' : '主管专项' }}</text> <text class="assignment-badge">{{ item.source === 'daily' ? '每日三题' : '主管专项' }}</text>
<text class="assignment-title">{{ item.question || item.scenarioName }}</text> <text class="assignment-title">{{ item.question || item.scenarioName }}</text>
@@ -174,6 +174,7 @@ type PracticeStatus = 'idle' | 'starting' | 'active' | 'submitting' | 'finished'
const defaultScenarioId = 'complaint-water'; const defaultScenarioId = 'complaint-water';
const defaultScenarioName = '投诉接待'; const defaultScenarioName = '投诉接待';
const pendingAssignmentKey = 'aihr_pending_assignment_id';
const status = ref<PracticeStatus>('idle'); const status = ref<PracticeStatus>('idle');
const sessionId = ref(''); const sessionId = ref('');
const roundIndex = ref(0); const roundIndex = ref(0);
@@ -199,6 +200,7 @@ const drillAnswers = ref<Record<number, string>>({});
const assignmentLoading = ref(false); const assignmentLoading = ref(false);
const answeringId = ref<number | null>(null); const answeringId = ref<number | null>(null);
const activeAssignmentId = ref<number | undefined>(); const activeAssignmentId = ref<number | undefined>();
const highlightedAssignmentId = ref<number | null>(null);
const loggedIn = ref(false); const loggedIn = ref(false);
const busy = computed(() => status.value === 'starting' || status.value === 'submitting'); const busy = computed(() => status.value === 'starting' || status.value === 'submitting');
const canStartPractice = computed(() => status.value === 'idle' || status.value === 'finished'); const canStartPractice = computed(() => status.value === 'idle' || status.value === 'finished');
@@ -257,6 +259,7 @@ const clearPracticeData = () => {
redFlagActive.value = false; redFlagActive.value = false;
answeringId.value = null; answeringId.value = null;
activeAssignmentId.value = undefined; activeAssignmentId.value = undefined;
highlightedAssignmentId.value = null;
}; };
const requireLogin = () => { const requireLogin = () => {
@@ -297,6 +300,7 @@ const loadAssignments = async () => {
try { try {
assignments.value = await getPracticeAssignments(true); assignments.value = await getPracticeAssignments(true);
drillAnswers.value = Object.fromEntries(assignments.value.map((item) => [item.id, item.userAnswer || ''])); drillAnswers.value = Object.fromEntries(assignments.value.map((item) => [item.id, item.userAnswer || '']));
consumePendingAssignment();
} catch (error) { } catch (error) {
handleError(error, '今日任务加载失败'); handleError(error, '今日任务加载失败');
} finally { } finally {
@@ -304,6 +308,25 @@ const loadAssignments = async () => {
} }
}; };
const consumePendingAssignment = () => {
const raw = uni.getStorageSync(pendingAssignmentKey);
if (!raw) return;
uni.removeStorageSync(pendingAssignmentKey);
const id = Number(raw);
if (!Number.isFinite(id)) return;
const item = assignments.value.find((row) => row.id === id);
if (!item) {
message.value = '首页任务已更新,请从列表选择';
return;
}
highlightedAssignmentId.value = item.id;
if (item.source !== 'daily' && item.status === '待训练' && canStartPractice.value) {
startAssignment(item);
return;
}
message.value = item.source === 'daily' ? '已定位首页任务,请填写话术后提交' : '该任务已完成,请选择其他任务';
};
const submitDaily = async (item: PracticeAssignment) => { const submitDaily = async (item: PracticeAssignment) => {
if (answeringId.value) return; if (answeringId.value) return;
const answer = (drillAnswers.value[item.id] || '').trim(); const answer = (drillAnswers.value[item.id] || '').trim();
@@ -560,10 +583,16 @@ onShow(() => {
.assignment-row { .assignment-row {
margin-top: 10px; margin-top: 10px;
padding: 12px; padding: 12px;
border: 1px solid transparent;
border-radius: 14px; border-radius: 14px;
background: #f8fafc; background: #f8fafc;
} }
.assignment-row.highlighted {
border-color: #2563eb;
background: #eff6ff;
}
.assignment-badge { .assignment-badge {
display: inline-flex; display: inline-flex;
width: fit-content; width: fit-content;
@@ -117,6 +117,7 @@ const message = ref('');
const loggedIn = ref(false); const loggedIn = ref(false);
const quickQuestions = ['催费话术', '投诉应对', '收费标准']; const quickQuestions = ['催费话术', '投诉应对', '收费标准'];
const pendingSopQueryKey = 'aihr_sop_pending_query'; const pendingSopQueryKey = 'aihr_sop_pending_query';
const pendingAssignmentKey = 'aihr_pending_assignment_id';
const iconFor = (title: string) => { const iconFor = (title: string) => {
if (title.includes('SOP') || title.includes('查')) return '/static/map-icons/ask.png'; if (title.includes('SOP') || title.includes('查')) return '/static/map-icons/ask.png';
@@ -218,6 +219,9 @@ const goLogin = () => {
}; };
const openPrimarySchedule = () => { const openPrimarySchedule = () => {
if (primaryAssignment.value) {
uni.setStorageSync(pendingAssignmentKey, String(primaryAssignment.value.id));
}
uni.switchTab({ url: '/pages/user/practice/index' }); uni.switchTab({ url: '/pages/user/practice/index' });
}; };