fix: :key 强制子组件重建 + 拆除嵌套滚动锁
- detail.vue: 新增 dictVersion,loadUsers 后自增驱动子组件 :key 重建 - WorkspaceArea/TaskSwipeCards/TreeCanvas 绑定 :key='...-'+dictVersion - .page-container: flex → block,让页面自然流式撑开 - .workspace-area: flex:1+overflow:hidden → height:auto - .is-locked: 仅锁定任务模式下才 height:100vh+overflow:hidden - .task-list: flex:1+overflow-y:auto → height:auto
This commit is contained in:
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="workspace-area">
|
<view class="workspace-area" :class="{ 'is-locked': !!lockedTaskId }">
|
||||||
<!-- 0任务 -->
|
<!-- 0任务 -->
|
||||||
<view v-if="!product.task_tree || !product.task_tree.length" class="zero-task">
|
<view v-if="!product.task_tree || !product.task_tree.length" class="zero-task">
|
||||||
<text class="zero-icon">📋</text>
|
<text class="zero-icon">📋</text>
|
||||||
@ -229,11 +229,12 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.workspace-area { flex: 1; display: flex; flex-direction: column; min-height: 0; overflow: hidden; }
|
.workspace-area { height: auto; display: flex; flex-direction: column; }
|
||||||
|
.workspace-area.is-locked { height: 100vh; overflow: hidden; }
|
||||||
.list-header { display: flex; align-items: baseline; justify-content: space-between; padding: 8px 4px; flex-shrink: 0; }
|
.list-header { display: flex; align-items: baseline; justify-content: space-between; padding: 8px 4px; flex-shrink: 0; }
|
||||||
.list-title { font-size: 14px; font-weight: 700; color: #1f2937; }
|
.list-title { font-size: 14px; font-weight: 700; color: #1f2937; }
|
||||||
.list-hint { font-size: 11px; color: #9ca3af; }
|
.list-hint { font-size: 11px; color: #9ca3af; }
|
||||||
.task-list { flex: 1; overflow-y: auto; min-height: 0; }
|
.task-list { height: auto; }
|
||||||
.task-list-item { display: flex; align-items: flex-start; justify-content: space-between; background: #fff; border-radius: 12px; padding: 14px; margin-bottom: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.06); border-left: 4px solid transparent; }
|
.task-list-item { display: flex; align-items: flex-start; justify-content: space-between; background: #fff; border-radius: 12px; padding: 14px; margin-bottom: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.06); border-left: 4px solid transparent; }
|
||||||
.task-list-item.s-yellow { border-left-color: #f59e0b; }
|
.task-list-item.s-yellow { border-left-color: #f59e0b; }
|
||||||
.task-list-item.s-blue { border-left-color: #3b82f6; }
|
.task-list-item.s-blue { border-left-color: #3b82f6; }
|
||||||
|
|||||||
@ -44,6 +44,7 @@
|
|||||||
<WorkspaceArea v-if="currentMode === 'workspace'" :product="product"
|
<WorkspaceArea v-if="currentMode === 'workspace'" :product="product"
|
||||||
:currentUserId="currentUserId" :currentUsername="currentUsername"
|
:currentUserId="currentUserId" :currentUsername="currentUsername"
|
||||||
:initialLockTaskId="autoLockTaskId"
|
:initialLockTaskId="autoLockTaskId"
|
||||||
|
:key="'wa-' + dictVersion"
|
||||||
@action="handleTaskAction" @viewRecords="handleViewRecords" />
|
@action="handleTaskAction" @viewRecords="handleViewRecords" />
|
||||||
|
|
||||||
<!-- 💬 协同留言板 — 产品级功能,所有模式均可见 -->
|
<!-- 💬 协同留言板 — 产品级功能,所有模式均可见 -->
|
||||||
@ -70,11 +71,12 @@
|
|||||||
|
|
||||||
<!-- 📇 流转卡片:探探式单张滑动 -->
|
<!-- 📇 流转卡片:探探式单张滑动 -->
|
||||||
<TaskSwipeCards v-if="currentMode === 'swipe'" :product="product"
|
<TaskSwipeCards v-if="currentMode === 'swipe'" :product="product"
|
||||||
|
:key="'sw-' + dictVersion"
|
||||||
@back="currentMode = 'workspace'" @overview="currentMode = 'tree'"
|
@back="currentMode = 'workspace'" @overview="currentMode = 'tree'"
|
||||||
@viewRecords="handleViewRecords" />
|
@viewRecords="handleViewRecords" />
|
||||||
|
|
||||||
<!-- 🌳 流转树:全屏独立视图 -->
|
<!-- 🌳 流转树:全屏独立视图 -->
|
||||||
<TreeCanvas v-if="currentMode === 'tree'" :product="product" @viewRecords="handleViewRecords" @back="currentMode = 'workspace'" @swipe="currentMode = 'swipe'" />
|
<TreeCanvas v-if="currentMode === 'tree'" :product="product" :key="'tc-' + dictVersion" @viewRecords="handleViewRecords" @back="currentMode = 'workspace'" @swipe="currentMode = 'swipe'" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 状态定调 -->
|
<!-- 状态定调 -->
|
||||||
@ -210,6 +212,8 @@ export default {
|
|||||||
spawnForm: { assignee_id: "", remark: "" },
|
spawnForm: { assignee_id: "", remark: "" },
|
||||||
// 💬 留言板
|
// 💬 留言板
|
||||||
messages: [],
|
messages: [],
|
||||||
|
// 🚀 字典版本号:驱动子组件强制重建,解决 userNameMap 非响应式问题
|
||||||
|
dictVersion: 0,
|
||||||
newMsgText: '',
|
newMsgText: '',
|
||||||
bottomMsgId: '',
|
bottomMsgId: '',
|
||||||
};
|
};
|
||||||
@ -256,7 +260,7 @@ export default {
|
|||||||
openEditProduct() { this.editForm = { order_no: this.product.order_no || "", external_serial: this.product.external_serial || "" }; this.editProductVisible = true; },
|
openEditProduct() { this.editForm = { order_no: this.product.order_no || "", external_serial: this.product.external_serial || "" }; this.editProductVisible = true; },
|
||||||
async doEditProduct() { this.editSaving = true; try { this.product = await patch(`/products/${this.product.id}`, { order_no: this.editForm.order_no.trim(), external_serial: this.editForm.external_serial.trim() }); uni.showToast({ title: "已保存", icon: "success" }); this.editProductVisible = false; } catch {} finally { this.editSaving = false; } },
|
async doEditProduct() { this.editSaving = true; try { this.product = await patch(`/products/${this.product.id}`, { order_no: this.editForm.order_no.trim(), external_serial: this.editForm.external_serial.trim() }); uni.showToast({ title: "已保存", icon: "success" }); this.editProductVisible = false; } catch {} finally { this.editSaving = false; } },
|
||||||
|
|
||||||
async loadUsers() { try { const res = await get("/users/", { limit: 200, dept: "IRIS" }); this.users = (res || []).filter(u => u.department === "IRIS"); this.userOptions = this.users.map(u => ({ id: u.username || u.id, name: u.full_name || u.username })); setUserNameMap(this.users); this.$forceUpdate(); } catch (e) { console.error('[loadUsers] 获取用户列表失败:', e); } },
|
async loadUsers() { try { const res = await get("/users/", { limit: 200, dept: "IRIS" }); this.users = (res || []).filter(u => u.department === "IRIS"); this.userOptions = this.users.map(u => ({ id: u.username || u.id, name: u.full_name || u.username })); setUserNameMap(this.users); this.dictVersion += 1; } catch (e) { console.error('[loadUsers] 获取用户列表失败:', e); } },
|
||||||
loadCurrentUser() { try { let user = uni.getStorageSync("user"); if (typeof user === "string" && user) { try { user = JSON.parse(user); } catch (e) { user = null; } } if (user && typeof user === "object") { this.currentUser = user; this.currentUserId = String(user.id || ""); this.currentUsername = user.username || ""; } } catch {} },
|
loadCurrentUser() { try { let user = uni.getStorageSync("user"); if (typeof user === "string" && user) { try { user = JSON.parse(user); } catch (e) { user = null; } } if (user && typeof user === "object") { this.currentUser = user; this.currentUserId = String(user.id || ""); this.currentUsername = user.username || ""; } } catch {} },
|
||||||
|
|
||||||
onTaskNameChange(e) { const idx = e.detail.value; this.firstForm.taskNameIdx = idx; this.firstForm.task_name = TASK_NAME_OPTIONS[idx]; },
|
onTaskNameChange(e) { const idx = e.detail.value; this.firstForm.taskNameIdx = idx; this.firstForm.task_name = TASK_NAME_OPTIONS[idx]; },
|
||||||
@ -310,7 +314,7 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.page-container { min-height: 100vh; display: flex; flex-direction: column; background-color: #f3f4f6; box-sizing: border-box; padding: 16px; padding-bottom: 24px; overflow-y: auto; }
|
.page-container { min-height: 100vh; display: block; background-color: #f3f4f6; box-sizing: border-box; padding: 16px; padding-bottom: 24px; overflow-y: auto; }
|
||||||
.loading { text-align: center; padding: 48px 0; color: #6b7280; }
|
.loading { text-align: center; padding: 48px 0; color: #6b7280; }
|
||||||
.error-box { padding: 12px; border-radius: 10px; background: #fef2f2; color: #dc2626; font-size: 13px; border: 1px solid #fecaca; }
|
.error-box { padding: 12px; border-radius: 10px; background: #fef2f2; color: #dc2626; font-size: 13px; border: 1px solid #fecaca; }
|
||||||
.overall-bar { display: flex; align-items: center; gap: 8px; padding: 10px 14px; background: #fff; border-radius: 12px; margin-bottom: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.06); }
|
.overall-bar { display: flex; align-items: center; gap: 8px; padding: 10px 14px; background: #fff; border-radius: 12px; margin-bottom: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.06); }
|
||||||
|
|||||||
Reference in New Issue
Block a user