|
@@ -38,7 +38,7 @@
|
|
|
<div class="card-content">
|
|
<div class="card-content">
|
|
|
<div class="card-left" @click.stop="handleStatusDetail(fw)" style="width: 100%">
|
|
<div class="card-left" @click.stop="handleStatusDetail(fw)" style="width: 100%">
|
|
|
<div class="left-info">
|
|
<div class="left-info">
|
|
|
- <div class="left-date">{{ formatDate(fw.createTime) }}</div>
|
|
|
|
|
|
|
+ <!-- <div class="left-date">{{ formatDate(fw.createTime) }}</div> -->
|
|
|
<div class="text">
|
|
<div class="text">
|
|
|
<span class="van-ellipsis">{{ fw.title }}</span>
|
|
<span class="van-ellipsis">{{ fw.title }}</span>
|
|
|
<div class="text-status" v-if="farmWorkTypeObj[fw.farm_work_type]" :style="farmWorkTypeObjColor[fw.farm_work_type]">{{ farmWorkTypeObj[fw.farm_work_type] }}</div>
|
|
<div class="text-status" v-if="farmWorkTypeObj[fw.farm_work_type]" :style="farmWorkTypeObjColor[fw.farm_work_type]">{{ farmWorkTypeObj[fw.farm_work_type] }}</div>
|
|
@@ -63,8 +63,10 @@
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="status-right" :style="getStatusColorObj(fw)"
|
|
<div class="status-right" :style="getStatusColorObj(fw)"
|
|
|
- v-if="fw.work_status !== 3 && fw.work_status !== 5">{{
|
|
|
|
|
- workStatusObj[fw.work_status] }}</div>
|
|
|
|
|
|
|
+ v-if="fw.work_status !== 3 && fw.work_status !== 5">
|
|
|
|
|
+ <img v-if="fw.work_status === 4" src="@/assets/img/common/rz-icon.png" alt="">
|
|
|
|
|
+ <span>{{ workStatusObj[fw.work_status] }}</span>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -214,28 +216,60 @@ const hasSavedTimelineScrollBeyondTop = () => {
|
|
|
const getAgriRecordParentScrollKey = () =>
|
|
const getAgriRecordParentScrollKey = () =>
|
|
|
`agriRecordArchivesOuterScroll:${props.farmId ?? "none"}:${route.path}`;
|
|
`agriRecordArchivesOuterScroll:${props.farmId ?? "none"}:${route.path}`;
|
|
|
|
|
|
|
|
-/** 外层滚动:任意已写入数值(含 0)均视为已建立缓存,避免返回后被 scrollIntoView 拉走 */
|
|
|
|
|
-const hasSavedParentArchivesScroll = () => {
|
|
|
|
|
|
|
+/** 外层滚动:仅当明显离开过顶部时才视为有效缓存,避免 scrollTop=0 误挡首次定位 */
|
|
|
|
|
+const hasSavedParentArchivesScrollBeyondTop = () => {
|
|
|
const raw = sessionStorage.getItem(getAgriRecordParentScrollKey());
|
|
const raw = sessionStorage.getItem(getAgriRecordParentScrollKey());
|
|
|
if (raw == null) return false;
|
|
if (raw == null) return false;
|
|
|
const n = Number(raw);
|
|
const n = Number(raw);
|
|
|
- return !Number.isNaN(n);
|
|
|
|
|
|
|
+ return !Number.isNaN(n) && n > 4;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const clearSavedParentArchivesScroll = () => {
|
|
|
|
|
+ sessionStorage.removeItem(getAgriRecordParentScrollKey());
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 查找可滚动的祖先容器(优先匹配农事记录页外层 `.archives-time-line-content`) */
|
|
|
|
|
+const findScrollParentForCard = (card) => {
|
|
|
|
|
+ if (!card) return null;
|
|
|
|
|
+ const archivesArea = card.closest(".archives-time-line-content");
|
|
|
|
|
+ if (archivesArea) return archivesArea;
|
|
|
|
|
+ let node = card.parentElement;
|
|
|
|
|
+ while (node && node !== document.body) {
|
|
|
|
|
+ const style = window.getComputedStyle(node);
|
|
|
|
|
+ const canScrollY =
|
|
|
|
|
+ (style.overflowY === "auto" || style.overflowY === "scroll") &&
|
|
|
|
|
+ node.scrollHeight > node.clientHeight + 1;
|
|
|
|
|
+ const canScrollX =
|
|
|
|
|
+ (style.overflowX === "auto" || style.overflowX === "scroll") &&
|
|
|
|
|
+ node.scrollWidth > node.clientWidth + 1;
|
|
|
|
|
+ if (canScrollY || canScrollX) return node;
|
|
|
|
|
+ node = node.parentElement;
|
|
|
|
|
+ }
|
|
|
|
|
+ return null;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 在「农事记录」等页面中,真正滚动的是外层 `.archives-time-line`,本组件 `.timeline-container` 往往随内容撑开、不产生内部滚动条,
|
|
|
|
|
- * 只改 timeline 的 scrollTop 无效。使用 scrollIntoView 让浏览器滚动实际产生滚动的祖先容器,并把目标块垂直居中。
|
|
|
|
|
|
|
+ * 在「农事记录」等页面中,真正滚动的是外层 `.archives-time-line-content`,本组件 `.timeline-container` 往往随内容撑开、不产生内部滚动条。
|
|
|
|
|
+ * 手动计算 scrollTop / scrollLeft,将目标卡片对齐到滚动区域顶部。
|
|
|
*/
|
|
*/
|
|
|
-const scrollCardIntoNearestScrollportCenter = (card) => {
|
|
|
|
|
- card.scrollIntoView({ block: "center", behavior: "auto", inline: "nearest" });
|
|
|
|
|
|
|
+const scrollCardIntoNearestScrollportTop = (card) => {
|
|
|
|
|
+ const scrollParent = findScrollParentForCard(card);
|
|
|
|
|
+ if (!scrollParent) {
|
|
|
|
|
+ card.scrollIntoView({ block: "start", behavior: "auto", inline: "start" });
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ const cardRect = card.getBoundingClientRect();
|
|
|
|
|
+ const parentRect = scrollParent.getBoundingClientRect();
|
|
|
|
|
+ scrollParent.scrollTop += cardRect.top - parentRect.top;
|
|
|
|
|
+ scrollParent.scrollLeft += cardRect.left - parentRect.left;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-/** 默认滚动到首个「待执行」(work_status=2),并在可视滚动区域内垂直居中;若无则回退到首个右侧有状态标签的卡片(3、5 不展示标签) */
|
|
|
|
|
|
|
+/** 默认滚动到首个「待执行」(work_status=2),并在可视滚动区域内对齐顶部;若无则回退到首个右侧有状态标签的卡片(3、5 不展示标签) */
|
|
|
const scrollToFirstVisibleStatusCard = () => {
|
|
const scrollToFirstVisibleStatusCard = () => {
|
|
|
const root = timelineContainerRef.value;
|
|
const root = timelineContainerRef.value;
|
|
|
if (!root || isEmpty.value) return;
|
|
if (!root || isEmpty.value) return;
|
|
|
if (hasSavedTimelineScrollBeyondTop()) return;
|
|
if (hasSavedTimelineScrollBeyondTop()) return;
|
|
|
- if (hasSavedParentArchivesScroll()) return;
|
|
|
|
|
|
|
+ if (hasSavedParentArchivesScrollBeyondTop()) return;
|
|
|
const cards = root.querySelectorAll(".arrange-card[data-work-status]");
|
|
const cards = root.querySelectorAll(".arrange-card[data-work-status]");
|
|
|
|
|
|
|
|
let target = null;
|
|
let target = null;
|
|
@@ -258,21 +292,19 @@ const scrollToFirstVisibleStatusCard = () => {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
if (!target) return;
|
|
if (!target) return;
|
|
|
- scrollCardIntoNearestScrollportCenter(target);
|
|
|
|
|
|
|
+ scrollCardIntoNearestScrollportTop(target);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const scrollToFirstVisibleStatusCardAfterPaint = () => {
|
|
const scrollToFirstVisibleStatusCardAfterPaint = () => {
|
|
|
|
|
+ const tryScroll = () => scrollToFirstVisibleStatusCard();
|
|
|
nextTick(() => {
|
|
nextTick(() => {
|
|
|
requestAnimationFrame(() => {
|
|
requestAnimationFrame(() => {
|
|
|
- scrollToFirstVisibleStatusCard();
|
|
|
|
|
- // 外层布局(flex/高度)晚一帧才稳定时再滚一次,避免第一次滚到错误视口
|
|
|
|
|
- requestAnimationFrame(() => {
|
|
|
|
|
- scrollToFirstVisibleStatusCard();
|
|
|
|
|
|
|
+ tryScroll();
|
|
|
|
|
+ requestAnimationFrame(tryScroll);
|
|
|
|
|
+ // 与父页 restoreArchivesOuterScrollTopWithRetry 异步布局错开,多次尝试确保滚到位
|
|
|
|
|
+ [120, 300, 500, 800].forEach((ms) => {
|
|
|
|
|
+ window.setTimeout(tryScroll, ms);
|
|
|
});
|
|
});
|
|
|
- // 与父页 `restoreArchivesOuterScrollTopWithRetry` 等异步布局错开,避免刚滚好又被恢复成旧位置
|
|
|
|
|
- window.setTimeout(() => {
|
|
|
|
|
- scrollToFirstVisibleStatusCard();
|
|
|
|
|
- }, 120);
|
|
|
|
|
});
|
|
});
|
|
|
});
|
|
});
|
|
|
};
|
|
};
|
|
@@ -372,7 +404,7 @@ const getStatusColorObj = (fw) => {
|
|
|
color = "#FF6A6A";
|
|
color = "#FF6A6A";
|
|
|
background = "#fff";
|
|
background = "#fff";
|
|
|
}else{
|
|
}else{
|
|
|
- color = "#2199F8";
|
|
|
|
|
|
|
+ color = "#8B8B8B";
|
|
|
background = "#fff";
|
|
background = "#fff";
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -401,7 +433,7 @@ const getArrangeStatusClass = (fw) => {
|
|
|
return "status-normal";
|
|
return "status-normal";
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- if (status === 0 || status === 1) return "status-normal";
|
|
|
|
|
|
|
+ if (status === 0 || status === 1 || status === 4) return "status-normal";
|
|
|
return "future-card";
|
|
return "future-card";
|
|
|
};
|
|
};
|
|
|
|
|
|
|
@@ -574,6 +606,7 @@ watch(
|
|
|
oldFarmId == null || farmId !== oldFarmId || tab !== oldTab;
|
|
oldFarmId == null || farmId !== oldFarmId || tab !== oldTab;
|
|
|
if (scopeChanged) {
|
|
if (scopeChanged) {
|
|
|
lastRequestedScopeKey.value = null;
|
|
lastRequestedScopeKey.value = null;
|
|
|
|
|
+ clearSavedParentArchivesScroll();
|
|
|
}
|
|
}
|
|
|
updateFarmWorkPlan();
|
|
updateFarmWorkPlan();
|
|
|
},
|
|
},
|
|
@@ -652,21 +685,21 @@ onBeforeRouteLeave(() => {
|
|
|
background: $content-bg;
|
|
background: $content-bg;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- .card-left {
|
|
|
|
|
- .title-text {
|
|
|
|
|
- @if $color !=null {
|
|
|
|
|
- color: $color;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // .card-left {
|
|
|
|
|
+ // .title-text {
|
|
|
|
|
+ // @if $color !=null {
|
|
|
|
|
+ // color: $color;
|
|
|
|
|
+ // }
|
|
|
|
|
|
|
|
- @if $content-color !=null {
|
|
|
|
|
- background: $content-color;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // @if $content-color !=null {
|
|
|
|
|
+ // background: $content-color;
|
|
|
|
|
+ // }
|
|
|
|
|
|
|
|
- @if $border-color !=null {
|
|
|
|
|
- border-color: $border-color;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // @if $border-color !=null {
|
|
|
|
|
+ // border-color: $border-color;
|
|
|
|
|
+ // }
|
|
|
|
|
+ // }
|
|
|
|
|
+ // }
|
|
|
|
|
|
|
|
&::before {
|
|
&::before {
|
|
|
border-right-color: $color;
|
|
border-right-color: $color;
|
|
@@ -872,6 +905,7 @@ onBeforeRouteLeave(() => {
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
gap: 4px;
|
|
gap: 4px;
|
|
|
width: calc(100% - 90px);
|
|
width: calc(100% - 90px);
|
|
|
|
|
+ color: #414141;
|
|
|
}
|
|
}
|
|
|
.text-status {
|
|
.text-status {
|
|
|
background: rgba(33, 153, 248, 0.1);
|
|
background: rgba(33, 153, 248, 0.1);
|
|
@@ -896,7 +930,7 @@ onBeforeRouteLeave(() => {
|
|
|
top: -5px;
|
|
top: -5px;
|
|
|
width: 13px;
|
|
width: 13px;
|
|
|
height: 13px;
|
|
height: 13px;
|
|
|
- background: #2199F8;
|
|
|
|
|
|
|
+ background: #C5C5C5;
|
|
|
border-radius: 50%;
|
|
border-radius: 50%;
|
|
|
display: flex;
|
|
display: flex;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
@@ -909,12 +943,12 @@ onBeforeRouteLeave(() => {
|
|
|
width: fit-content;
|
|
width: fit-content;
|
|
|
max-width: 100%;
|
|
max-width: 100%;
|
|
|
text-align: left;
|
|
text-align: left;
|
|
|
- color: rgba(0, 0, 0, 0.4);
|
|
|
|
|
|
|
+ color: rgba(91, 91, 91, 0.6);
|
|
|
padding: 0 6px;
|
|
padding: 0 6px;
|
|
|
border-radius: 2px;
|
|
border-radius: 2px;
|
|
|
font-size: 12px;
|
|
font-size: 12px;
|
|
|
box-sizing: border-box;
|
|
box-sizing: border-box;
|
|
|
- border: 0.5px solid rgba(0, 0, 0, 0.4);
|
|
|
|
|
|
|
+ border: 0.5px solid rgba(91, 91, 91, 0.2);
|
|
|
position: relative;
|
|
position: relative;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -948,6 +982,13 @@ onBeforeRouteLeave(() => {
|
|
|
background: #FF953D;
|
|
background: #FF953D;
|
|
|
border-radius: 0 8px 0 4px;
|
|
border-radius: 0 8px 0 4px;
|
|
|
padding: 0 5px;
|
|
padding: 0 5px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 3px;
|
|
|
|
|
+ img{
|
|
|
|
|
+ width: 12px;
|
|
|
|
|
+ height: 13px;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -966,7 +1007,8 @@ onBeforeRouteLeave(() => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.arrange-card.status-normal {
|
|
.arrange-card.status-normal {
|
|
|
- @include arrange-card-status(#2199F8, null, #2199F8, null);
|
|
|
|
|
|
|
+ @include arrange-card-status(#2199F8, null, #2199F8, rgba(33, 153, 248, 0.1));
|
|
|
|
|
+ border-width: 0.8px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.arrange-card.status-orange {
|
|
.arrange-card.status-orange {
|