|
@@ -2,25 +2,6 @@
|
|
|
<div class="plan-page">
|
|
<div class="plan-page">
|
|
|
<custom-header name="农事规划"></custom-header>
|
|
<custom-header name="农事规划"></custom-header>
|
|
|
<div class="plan-content">
|
|
<div class="plan-content">
|
|
|
- <div class="filter-wrap">
|
|
|
|
|
- <div class="season-tabs">
|
|
|
|
|
- <div
|
|
|
|
|
- v-for="s in seasons"
|
|
|
|
|
- :key="s.value"
|
|
|
|
|
- class="season-tab"
|
|
|
|
|
- :class="{ active: s.value === activeSeason }"
|
|
|
|
|
- @click="handleSeasonClick(s.value)"
|
|
|
|
|
- >
|
|
|
|
|
- {{ s.label }}
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="status-filter">
|
|
|
|
|
- <div v-for="status in statusList" :key="status.value" class="status-item" :class="status.color">
|
|
|
|
|
- <div class="status-dot"></div>
|
|
|
|
|
- <span class="status-text">{{ status.label }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
<div class="timeline-container" ref="timelineContainerRef">
|
|
<div class="timeline-container" ref="timelineContainerRef">
|
|
|
<div class="timeline-list" :style="getListStyle">
|
|
<div class="timeline-list" :style="getListStyle">
|
|
|
<div class="timeline-middle-line"></div>
|
|
<div class="timeline-middle-line"></div>
|
|
@@ -38,30 +19,38 @@
|
|
|
class="reproductive-item"
|
|
class="reproductive-item"
|
|
|
:class="{
|
|
:class="{
|
|
|
'horizontal-text': getReproductiveItemHeight(p) < 30,
|
|
'horizontal-text': getReproductiveItemHeight(p) < 30,
|
|
|
- 'vertical-lr-text': getReproductiveItemHeight(p) >= 30
|
|
|
|
|
|
|
+ 'vertical-lr-text': getReproductiveItemHeight(p) >= 30,
|
|
|
}"
|
|
}"
|
|
|
- :style="getReproductiveItemHeight(p) < 30 ? { '--item-height': `${getReproductiveItemHeight(p)}px` } : {}"
|
|
|
|
|
|
|
+ :style="
|
|
|
|
|
+ getReproductiveItemHeight(p) < 30
|
|
|
|
|
+ ? { '--item-height': `${getReproductiveItemHeight(p)}px` }
|
|
|
|
|
+ : {}
|
|
|
|
|
+ "
|
|
|
>
|
|
>
|
|
|
{{ r.name }}
|
|
{{ r.name }}
|
|
|
- <div class="arranges" :class="{ 'no-wrap': getReproductiveItemHeight(p) <= 35 }">
|
|
|
|
|
|
|
+ <div class="arranges">
|
|
|
<div
|
|
<div
|
|
|
v-for="(fw, aIdx) in Array.isArray(r.farmWorkArrangeList)
|
|
v-for="(fw, aIdx) in Array.isArray(r.farmWorkArrangeList)
|
|
|
? r.farmWorkArrangeList
|
|
? r.farmWorkArrangeList
|
|
|
: []"
|
|
: []"
|
|
|
:key="fw.id ?? aIdx"
|
|
:key="fw.id ?? aIdx"
|
|
|
- class="arrange-box"
|
|
|
|
|
- :class="[
|
|
|
|
|
- getArrangeStatusClass(fw),
|
|
|
|
|
- {
|
|
|
|
|
- 'small-height': getReproductiveItemHeight(p) <= 35,
|
|
|
|
|
- 'two-chars': fw.farmWorkName && fw.farmWorkName.trim().length === 2,
|
|
|
|
|
- 'text-4-6': fw.farmWorkName && getTextLengthClass(fw.farmWorkName) === 'text-4-6',
|
|
|
|
|
- 'text-7-8': fw.farmWorkName && getTextLengthClass(fw.farmWorkName) === 'text-7-8'
|
|
|
|
|
- }
|
|
|
|
|
- ]"
|
|
|
|
|
|
|
+ class="arrange-card"
|
|
|
|
|
+ :class="getArrangeStatusClass(fw)"
|
|
|
@click="handleRowClick(fw)"
|
|
@click="handleRowClick(fw)"
|
|
|
>
|
|
>
|
|
|
- <span class="arrange-text">{{ formatTextWithLineBreak(fw.farmWorkName) }}</span>
|
|
|
|
|
|
|
+ <div class="card-header">
|
|
|
|
|
+ <div class="header-left">
|
|
|
|
|
+ <span class="farm-work-name">{{ fw.farmWorkName || "农事名称" }}</span>
|
|
|
|
|
+ <span class="tag-standard">标准农事</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="header-right">托管农事</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="card-content">
|
|
|
|
|
+ <span>温馨提示:在某某物候期之后,请密切关注荔枝,关注蒂蛀虫的出现!</span>
|
|
|
|
|
+ <span class="edit-link" @click.stop="handleEdit(fw)">编辑</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="card-divider"></div>
|
|
|
|
|
+ <div class="card-footer" @click.stop="handleRowClick(fw)">查看详情</div>
|
|
|
<div
|
|
<div
|
|
|
v-if="
|
|
v-if="
|
|
|
getArrangeStatusClass(fw) === 'status-complete' ||
|
|
getArrangeStatusClass(fw) === 'status-complete' ||
|
|
@@ -91,16 +80,9 @@
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
- <div class="control-section">
|
|
|
|
|
- <div class="toggle-group">
|
|
|
|
|
- <el-switch v-model="isDefaultEnabled" />
|
|
|
|
|
- <span class="toggle-label">{{ isDefaultEnabled ? "默认" : "" }}发起农情需求</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="add-button-group">
|
|
|
|
|
- <div class="add-button button" @click="addNewTask">新增农事</div>
|
|
|
|
|
- <div class="button" @click="manageTask">农事管理</div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="custom-bottom-fixed-btns">
|
|
|
|
|
+ <div class="bottom-btn primary-btn" @click="addNewTask">新增农事</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
<!-- 农事信息弹窗 -->
|
|
<!-- 农事信息弹窗 -->
|
|
@@ -164,7 +146,7 @@ const getFarmWorkPlan = () => {
|
|
|
if (!isInitialLoad.value && timelineContainerRef.value) {
|
|
if (!isInitialLoad.value && timelineContainerRef.value) {
|
|
|
savedScrollTop = timelineContainerRef.value.scrollTop || 0;
|
|
savedScrollTop = timelineContainerRef.value.scrollTop || 0;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
VE_API.monitor
|
|
VE_API.monitor
|
|
|
.farmWorkPlan({ farmId: route.query.farmId })
|
|
.farmWorkPlan({ farmId: route.query.farmId })
|
|
|
.then(({ data, code }) => {
|
|
.then(({ data, code }) => {
|
|
@@ -196,7 +178,7 @@ const getFarmWorkPlan = () => {
|
|
|
reproductiveList: Array.isArray(it.reproductiveList) ? it.reproductiveList : [],
|
|
reproductiveList: Array.isArray(it.reproductiveList) ? it.reproductiveList : [],
|
|
|
}))
|
|
}))
|
|
|
: [];
|
|
: [];
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 等待 DOM 更新后处理滚动
|
|
// 等待 DOM 更新后处理滚动
|
|
|
nextTick(() => {
|
|
nextTick(() => {
|
|
|
if (isInitialLoad.value) {
|
|
if (isInitialLoad.value) {
|
|
@@ -232,7 +214,7 @@ const addNewTask = () => {
|
|
|
const triggerFarmWork = () => {
|
|
const triggerFarmWork = () => {
|
|
|
eventBus.emit("activeUpload:show", {
|
|
eventBus.emit("activeUpload:show", {
|
|
|
gardenIdVal: route.query.farmId,
|
|
gardenIdVal: route.query.farmId,
|
|
|
- problemTitleVal: '请选择您出现' + curFarmObj.value.farmWorkName + '的时间',
|
|
|
|
|
|
|
+ problemTitleVal: "请选择您出现" + curFarmObj.value.farmWorkName + "的时间",
|
|
|
arrangeIdVal: curFarmObj.value.id,
|
|
arrangeIdVal: curFarmObj.value.id,
|
|
|
});
|
|
});
|
|
|
};
|
|
};
|
|
@@ -245,7 +227,7 @@ const handleRowClick = (item) => {
|
|
|
router.push({
|
|
router.push({
|
|
|
path: "/review_work",
|
|
path: "/review_work",
|
|
|
query: {
|
|
query: {
|
|
|
- miniJson: JSON.stringify({ id: item.farmWorkRecordId,goBack: true }),
|
|
|
|
|
|
|
+ miniJson: JSON.stringify({ id: item.farmWorkRecordId, goBack: true }),
|
|
|
},
|
|
},
|
|
|
});
|
|
});
|
|
|
} else if (item.flowStatus === null) {
|
|
} else if (item.flowStatus === null) {
|
|
@@ -260,6 +242,12 @@ const handleRowClick = (item) => {
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+const handleEdit = (item) => {
|
|
|
|
|
+ // 处理编辑逻辑
|
|
|
|
|
+ ElMessage.info("编辑功能开发中");
|
|
|
|
|
+ // 可以在这里添加编辑逻辑,比如打开编辑弹窗等
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
const manageTask = () => {
|
|
const manageTask = () => {
|
|
|
router.push({
|
|
router.push({
|
|
|
path: "/agri_services_manage",
|
|
path: "/agri_services_manage",
|
|
@@ -288,26 +276,47 @@ const safeParseDate = (val) => {
|
|
|
return NaN;
|
|
return NaN;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+// 计算最小progress值(第一个节气的progress)
|
|
|
|
|
+const minProgress = computed(() => {
|
|
|
|
|
+ if (!solarTerms.value || solarTerms.value.length === 0) return 0;
|
|
|
|
|
+ const progresses = solarTerms.value.map((t) => Number(t?.progress) || 0).filter((p) => !isNaN(p));
|
|
|
|
|
+ return progresses.length > 0 ? Math.min(...progresses) : 0;
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 计算最大progress值
|
|
|
|
|
+const maxProgress = computed(() => {
|
|
|
|
|
+ if (!solarTerms.value || solarTerms.value.length === 0) return 100;
|
|
|
|
|
+ const progresses = solarTerms.value.map((t) => Number(t?.progress) || 0).filter((p) => !isNaN(p));
|
|
|
|
|
+ return progresses.length > 0 ? Math.max(...progresses) : 100;
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
// 计算节气列表容器高度与项位置
|
|
// 计算节气列表容器高度与项位置
|
|
|
const getListStyle = computed(() => {
|
|
const getListStyle = computed(() => {
|
|
|
- const total = (solarTerms.value?.length || 0) * 100;
|
|
|
|
|
- const minH = 50 + total + 50; // 上下各 50
|
|
|
|
|
|
|
+ const minP = minProgress.value;
|
|
|
|
|
+ const maxP = maxProgress.value;
|
|
|
|
|
+ const range = Math.max(1, maxP - minP); // 避免除0
|
|
|
|
|
+ const total = (solarTerms.value?.length || 0) * 320;
|
|
|
|
|
+ const minH = total; // 无上下留白
|
|
|
return { minHeight: `${minH}px` };
|
|
return { minHeight: `${minH}px` };
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
const getTermStyle = (t) => {
|
|
const getTermStyle = (t) => {
|
|
|
const p = Math.max(0, Math.min(100, Number(t?.progress) || 0));
|
|
const p = Math.max(0, Math.min(100, Number(t?.progress) || 0));
|
|
|
- const total = (solarTerms.value?.length || 0) * 100;
|
|
|
|
|
- const top = 50 + (p / 100) * total;
|
|
|
|
|
|
|
+ const minP = minProgress.value;
|
|
|
|
|
+ const maxP = maxProgress.value;
|
|
|
|
|
+ const range = Math.max(1, maxP - minP); // 避免除0
|
|
|
|
|
+ const total = (solarTerms.value?.length || 0) * 320;
|
|
|
|
|
+ // 将progress映射到0开始的位置,最小progress对应top: 0
|
|
|
|
|
+ const normalizedP = range > 0 ? ((p - minP) / range) * 100 : 0;
|
|
|
|
|
+ const top = (normalizedP / 100) * total;
|
|
|
return {
|
|
return {
|
|
|
position: "absolute",
|
|
position: "absolute",
|
|
|
top: `${top}px`,
|
|
top: `${top}px`,
|
|
|
left: 0,
|
|
left: 0,
|
|
|
- transform: "translateY(-50%)",
|
|
|
|
|
width: "30px",
|
|
width: "30px",
|
|
|
height: "20px",
|
|
height: "20px",
|
|
|
display: "flex",
|
|
display: "flex",
|
|
|
- alignItems: "center",
|
|
|
|
|
|
|
+ alignItems: "flex-start",
|
|
|
};
|
|
};
|
|
|
};
|
|
};
|
|
|
|
|
|
|
@@ -325,8 +334,12 @@ const handleSeasonClick = (seasonValue) => {
|
|
|
const target = (solarTerms.value || []).find((t) => (t?.displayName || "") === targetName);
|
|
const target = (solarTerms.value || []).find((t) => (t?.displayName || "") === targetName);
|
|
|
if (!target) return;
|
|
if (!target) return;
|
|
|
const p = Math.max(0, Math.min(100, Number(target.progress) || 0));
|
|
const p = Math.max(0, Math.min(100, Number(target.progress) || 0));
|
|
|
- const total = (solarTerms.value?.length || 0) * 100;
|
|
|
|
|
- const targetTop = 50 + (p / 100) * total; // 内容内的像素位置
|
|
|
|
|
|
|
+ const minP = minProgress.value;
|
|
|
|
|
+ const maxP = maxProgress.value;
|
|
|
|
|
+ const range = Math.max(1, maxP - minP);
|
|
|
|
|
+ const total = (solarTerms.value?.length || 0) * 320;
|
|
|
|
|
+ const normalizedP = range > 0 ? ((p - minP) / range) * 100 : 0;
|
|
|
|
|
+ const targetTop = (normalizedP / 100) * total; // 内容内的像素位置
|
|
|
const wrap = timelineContainerRef.value;
|
|
const wrap = timelineContainerRef.value;
|
|
|
if (!wrap) return;
|
|
if (!wrap) return;
|
|
|
const viewH = wrap.clientHeight || 0;
|
|
const viewH = wrap.clientHeight || 0;
|
|
@@ -343,9 +356,38 @@ const getPhenologyBarStyle = (item) => {
|
|
|
const p2 = Math.max(0, Math.min(100, Number(item?.progress2) || 0));
|
|
const p2 = Math.max(0, Math.min(100, Number(item?.progress2) || 0));
|
|
|
const start = Math.min(p1, p2);
|
|
const start = Math.min(p1, p2);
|
|
|
const end = Math.max(p1, p2);
|
|
const end = Math.max(p1, p2);
|
|
|
- const total = (solarTerms.value?.length || 0) * 100; // 有效绘制区高度(px)
|
|
|
|
|
- const topPx = 50 + (start / 100) * total;
|
|
|
|
|
- const heightPx = Math.max(2, ((end - start) / 100) * total);
|
|
|
|
|
|
|
+ const minP = minProgress.value;
|
|
|
|
|
+ const maxP = maxProgress.value;
|
|
|
|
|
+ const range = Math.max(1, maxP - minP);
|
|
|
|
|
+ const total = (solarTerms.value?.length || 0) * 320; // 有效绘制区高度(px)
|
|
|
|
|
+ // 将progress映射到0开始的位置
|
|
|
|
|
+ const normalizedStart = range > 0 ? ((start - minP) / range) * 100 : 0;
|
|
|
|
|
+ const normalizedEnd = range > 0 ? ((end - minP) / range) * 100 : 0;
|
|
|
|
|
+ let topPx = (normalizedStart / 100) * total;
|
|
|
|
|
+ let heightPx = Math.max(2, ((normalizedEnd - normalizedStart) / 100) * total);
|
|
|
|
|
+
|
|
|
|
|
+ // 计算第一个节气的位置(minProgress对应的位置,应该是0)
|
|
|
|
|
+ const firstTermTop = 0; // 第一个节气在top: 0
|
|
|
|
|
+ // 节气文字高度为46px,"小"字大约在文字的上半部分,约在15px位置
|
|
|
|
|
+ // 让蓝色条的顶部对齐到"小"字的位置(firstTermTop + 15px)
|
|
|
|
|
+ const minTop = firstTermTop + 10; // 对齐到"小"字位置(文字高度的约33%)
|
|
|
|
|
+ if (topPx < minTop) {
|
|
|
|
|
+ // 如果顶部小于最小位置,调整top和height
|
|
|
|
|
+ const diff = minTop - topPx;
|
|
|
|
|
+ topPx = minTop;
|
|
|
|
|
+ heightPx = Math.max(2, heightPx - diff);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 计算最后一个节气的位置(maxProgress对应的位置)
|
|
|
|
|
+ const lastTermTop = (100 / 100) * total; // 因为normalizedEnd最大是100
|
|
|
|
|
+ // 节气文字高度为46px,"至"字大约在文字的下半部分,约在30px位置
|
|
|
|
|
+ // 让蓝色条的底部对齐到"至"字的位置(lastTermTop + 30px)
|
|
|
|
|
+ const maxBottom = lastTermTop + 35; // 对齐到"至"字位置(文字高度的约65%)
|
|
|
|
|
+ const barBottom = topPx + heightPx;
|
|
|
|
|
+ if (barBottom > maxBottom) {
|
|
|
|
|
+ heightPx = Math.max(2, maxBottom - topPx);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
const now = Date.now();
|
|
const now = Date.now();
|
|
|
const isFuture = Number.isFinite(item?.startTimeMs) ? item.startTimeMs > now : start > 0; // 无开始时间时按起点>0近似
|
|
const isFuture = Number.isFinite(item?.startTimeMs) ? item.startTimeMs > now : start > 0; // 无开始时间时按起点>0近似
|
|
|
// 反转:大于当前时间用灰色,小于等于当前时间用蓝色
|
|
// 反转:大于当前时间用灰色,小于等于当前时间用蓝色
|
|
@@ -380,8 +422,14 @@ const getPhenologyBarHeight = (item) => {
|
|
|
const p2 = Math.max(0, Math.min(100, Number(item?.progress2) || 0));
|
|
const p2 = Math.max(0, Math.min(100, Number(item?.progress2) || 0));
|
|
|
const start = Math.min(p1, p2);
|
|
const start = Math.min(p1, p2);
|
|
|
const end = Math.max(p1, p2);
|
|
const end = Math.max(p1, p2);
|
|
|
- const total = (solarTerms.value?.length || 0) * 100;
|
|
|
|
|
- const heightPx = Math.max(2, ((end - start) / 100) * total);
|
|
|
|
|
|
|
+ const minP = minProgress.value;
|
|
|
|
|
+ const maxP = maxProgress.value;
|
|
|
|
|
+ const range = Math.max(1, maxP - minP);
|
|
|
|
|
+ const total = (solarTerms.value?.length || 0) * 320;
|
|
|
|
|
+ // 将progress映射到0开始的位置
|
|
|
|
|
+ const normalizedStart = range > 0 ? ((start - minP) / range) * 100 : 0;
|
|
|
|
|
+ const normalizedEnd = range > 0 ? ((end - minP) / range) * 100 : 0;
|
|
|
|
|
+ const heightPx = Math.max(2, ((normalizedEnd - normalizedStart) / 100) * total);
|
|
|
return heightPx;
|
|
return heightPx;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
@@ -409,7 +457,6 @@ const formatTextWithLineBreak = (text) => {
|
|
|
// 在左括号前添加换行符
|
|
// 在左括号前添加换行符
|
|
|
return text.replace(/([((])/g, "\n$1");
|
|
return text.replace(/([((])/g, "\n$1");
|
|
|
};
|
|
};
|
|
|
-
|
|
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
<style scoped lang="scss">
|
|
@@ -418,83 +465,9 @@ const formatTextWithLineBreak = (text) => {
|
|
|
height: 100vh;
|
|
height: 100vh;
|
|
|
background: #fff;
|
|
background: #fff;
|
|
|
.plan-content {
|
|
.plan-content {
|
|
|
- .filter-wrap {
|
|
|
|
|
- background: #fff;
|
|
|
|
|
- padding: 13px 12px;
|
|
|
|
|
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
|
|
|
- border-radius: 0 0 20px 20px;
|
|
|
|
|
- .status-filter {
|
|
|
|
|
- background: #fff;
|
|
|
|
|
- padding: 3px 17px;
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- gap: 16px;
|
|
|
|
|
- font-size: 12px;
|
|
|
|
|
-
|
|
|
|
|
- .status-item {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- justify-content: center;
|
|
|
|
|
- gap: 6px;
|
|
|
|
|
- flex: 1;
|
|
|
|
|
- &.gray {
|
|
|
|
|
- color: #c4c6c9;
|
|
|
|
|
- .status-dot {
|
|
|
|
|
- background-color: #c4c6c9;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- &.blue {
|
|
|
|
|
- color: #2199f8;
|
|
|
|
|
- .status-dot {
|
|
|
|
|
- background-color: #2199f8;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- &.green {
|
|
|
|
|
- color: #1ca900;
|
|
|
|
|
- .status-dot {
|
|
|
|
|
- background-color: #1ca900;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- &.orange {
|
|
|
|
|
- color: #ff953d;
|
|
|
|
|
- .status-dot {
|
|
|
|
|
- background-color: #ff953d;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- .status-dot {
|
|
|
|
|
- width: 6px;
|
|
|
|
|
- height: 6px;
|
|
|
|
|
- border-radius: 50%;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .season-tabs {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- gap: 8px;
|
|
|
|
|
- margin-bottom: 12px;
|
|
|
|
|
- .season-tab {
|
|
|
|
|
- flex: 1;
|
|
|
|
|
- padding: 7px;
|
|
|
|
|
- text-align: center;
|
|
|
|
|
- background: #f3f3f3;
|
|
|
|
|
- color: #898a8a;
|
|
|
|
|
- border-radius: 3px;
|
|
|
|
|
- border: 1px solid transparent;
|
|
|
|
|
- font-size: 12px;
|
|
|
|
|
- }
|
|
|
|
|
- .season-tab.active {
|
|
|
|
|
- background: #ffffff;
|
|
|
|
|
- color: #2199f8;
|
|
|
|
|
- border-color: #2199f8;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ padding: 12px 0;
|
|
|
.timeline-container {
|
|
.timeline-container {
|
|
|
- height: calc(100vh - 93px - 40px - 73px);
|
|
|
|
|
|
|
+ height: calc(100vh - 40px - 73px);
|
|
|
overflow: auto;
|
|
overflow: auto;
|
|
|
position: relative;
|
|
position: relative;
|
|
|
box-sizing: border-box;
|
|
box-sizing: border-box;
|
|
@@ -505,8 +478,8 @@ const formatTextWithLineBreak = (text) => {
|
|
|
.timeline-middle-line {
|
|
.timeline-middle-line {
|
|
|
position: absolute;
|
|
position: absolute;
|
|
|
left: 15px; /* 位于节气文字列中间(列宽约30px) */
|
|
left: 15px; /* 位于节气文字列中间(列宽约30px) */
|
|
|
- top: 50px;
|
|
|
|
|
- bottom: 50px;
|
|
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+ bottom: 0;
|
|
|
width: 2px;
|
|
width: 2px;
|
|
|
background: #e8e8e8;
|
|
background: #e8e8e8;
|
|
|
z-index: 1;
|
|
z-index: 1;
|
|
@@ -516,16 +489,16 @@ const formatTextWithLineBreak = (text) => {
|
|
|
align-items: stretch;
|
|
align-items: stretch;
|
|
|
justify-content: center;
|
|
justify-content: center;
|
|
|
box-sizing: border-box;
|
|
box-sizing: border-box;
|
|
|
- &::before {
|
|
|
|
|
- content: "";
|
|
|
|
|
- position: absolute;
|
|
|
|
|
- top: 0;
|
|
|
|
|
- left: 25px;
|
|
|
|
|
- width: calc(100vw - 100px);
|
|
|
|
|
- height: 100%;
|
|
|
|
|
- background: var(--bar-before-bg, rgba(201, 201, 201, 0.1));
|
|
|
|
|
- z-index: 1;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // &::before {
|
|
|
|
|
+ // content: "";
|
|
|
|
|
+ // position: absolute;
|
|
|
|
|
+ // top: 0;
|
|
|
|
|
+ // left: 25px;
|
|
|
|
|
+ // width: calc(100vw - 100px);
|
|
|
|
|
+ // height: 100%;
|
|
|
|
|
+ // background: var(--bar-before-bg, rgba(201, 201, 201, 0.1));
|
|
|
|
|
+ // z-index: 1;
|
|
|
|
|
+ // }
|
|
|
.reproductive-list {
|
|
.reproductive-list {
|
|
|
display: grid;
|
|
display: grid;
|
|
|
grid-auto-rows: 1fr; /* 子项等高,整体等分父高度 */
|
|
grid-auto-rows: 1fr; /* 子项等高,整体等分父高度 */
|
|
@@ -561,92 +534,106 @@ const formatTextWithLineBreak = (text) => {
|
|
|
.arranges {
|
|
.arranges {
|
|
|
position: absolute;
|
|
position: absolute;
|
|
|
left: 48px; /* 列与中线右侧一段距离 */
|
|
left: 48px; /* 列与中线右侧一段距离 */
|
|
|
- top: 50%;
|
|
|
|
|
- transform: translateY(-50%);
|
|
|
|
|
|
|
+ top: 0;
|
|
|
z-index: 3;
|
|
z-index: 3;
|
|
|
display: flex;
|
|
display: flex;
|
|
|
- flex-wrap: wrap;
|
|
|
|
|
- flex-direction: row;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
max-width: calc(100vw - 100px);
|
|
max-width: calc(100vw - 100px);
|
|
|
- gap: 16px;
|
|
|
|
|
- &.no-wrap {
|
|
|
|
|
- flex-wrap: nowrap;
|
|
|
|
|
- }
|
|
|
|
|
- .arrange-box {
|
|
|
|
|
- width: 36px;
|
|
|
|
|
- height: 36px;
|
|
|
|
|
- border: 1px solid rgba(199, 199, 199, 0.6);
|
|
|
|
|
- border-radius: 2px;
|
|
|
|
|
|
|
+ gap: 12px;
|
|
|
|
|
+ letter-spacing: 0px;
|
|
|
|
|
+ .arrange-card {
|
|
|
|
|
+ width: 94%;
|
|
|
|
|
+ border: 0.5px solid #2199f8;
|
|
|
|
|
+ border-radius: 8px;
|
|
|
background: #fff;
|
|
background: #fff;
|
|
|
- color: #a5a7a9;
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- justify-content: center;
|
|
|
|
|
box-sizing: border-box;
|
|
box-sizing: border-box;
|
|
|
position: relative;
|
|
position: relative;
|
|
|
- font-size: 12px;
|
|
|
|
|
- flex-shrink: 0;
|
|
|
|
|
- &.small-height {
|
|
|
|
|
- height: 20px;
|
|
|
|
|
- width: 70px;
|
|
|
|
|
- &.two-chars {
|
|
|
|
|
- width: 35px;
|
|
|
|
|
|
|
+ padding: 8px;
|
|
|
|
|
+ writing-mode: horizontal-tb;
|
|
|
|
|
+ .card-header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ .header-left {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 8px;
|
|
|
|
|
+ .farm-work-name {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ color: #1d2129;
|
|
|
|
|
+ }
|
|
|
|
|
+ .tag-standard {
|
|
|
|
|
+ padding: 0 8px;
|
|
|
|
|
+ background: rgba(119, 119, 119, 0.1);
|
|
|
|
|
+ border-radius: 25px;
|
|
|
|
|
+ font-weight: 400;
|
|
|
|
|
+ font-size: 11px;
|
|
|
|
|
+ color: #000;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- &.text-4-6 {
|
|
|
|
|
- width: 65px;
|
|
|
|
|
- }
|
|
|
|
|
- &.text-7-8 {
|
|
|
|
|
- width: 66px;
|
|
|
|
|
- }
|
|
|
|
|
- .arrange-text {
|
|
|
|
|
- writing-mode: vertical-lr;
|
|
|
|
|
- white-space: pre-line;
|
|
|
|
|
|
|
+ .header-right {
|
|
|
|
|
+ font-size: 11px;
|
|
|
|
|
+ color: #2199f8;
|
|
|
|
|
+ padding: 0 8px;
|
|
|
|
|
+ border-radius: 25px;
|
|
|
|
|
+ // background: rgba(33, 153, 248, 0.1);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- &.text-4-6 {
|
|
|
|
|
- width: 65px;
|
|
|
|
|
|
|
+ .card-content {
|
|
|
|
|
+ color: #909090;
|
|
|
|
|
+ text-align: left;
|
|
|
|
|
+ line-height: 1.55;
|
|
|
|
|
+ margin: 4px 0 10px 0;
|
|
|
|
|
+ .edit-link {
|
|
|
|
|
+ color: #2199f8;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- &.text-7-8 {
|
|
|
|
|
- width: 66px;
|
|
|
|
|
|
|
+ .card-divider {
|
|
|
|
|
+ height: 0.5px;
|
|
|
|
|
+ background: rgba(0, 0, 0, 0.1);
|
|
|
}
|
|
}
|
|
|
- .arrange-text {
|
|
|
|
|
- writing-mode: horizontal-tb;
|
|
|
|
|
- line-height: 14px;
|
|
|
|
|
|
|
+ .card-footer {
|
|
|
text-align: center;
|
|
text-align: center;
|
|
|
- padding-left: 3px;
|
|
|
|
|
- white-space: pre-line;
|
|
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #adadad;
|
|
|
|
|
+ padding-top: 6px;
|
|
|
}
|
|
}
|
|
|
.status-icon {
|
|
.status-icon {
|
|
|
position: absolute;
|
|
position: absolute;
|
|
|
- right: -10px;
|
|
|
|
|
- bottom: -10px;
|
|
|
|
|
|
|
+ right: -8px;
|
|
|
|
|
+ bottom: -8px;
|
|
|
z-index: 3;
|
|
z-index: 3;
|
|
|
}
|
|
}
|
|
|
&::before {
|
|
&::before {
|
|
|
content: "";
|
|
content: "";
|
|
|
position: absolute;
|
|
position: absolute;
|
|
|
- left: -4px;
|
|
|
|
|
|
|
+ left: -6px;
|
|
|
top: 50%;
|
|
top: 50%;
|
|
|
transform: translateY(-50%);
|
|
transform: translateY(-50%);
|
|
|
width: 0;
|
|
width: 0;
|
|
|
height: 0;
|
|
height: 0;
|
|
|
- border-top: 4px solid transparent;
|
|
|
|
|
- border-bottom: 4px solid transparent;
|
|
|
|
|
- border-right: 4px solid currentColor; /* 与文字/边框颜色一致 */
|
|
|
|
|
|
|
+ border-top: 5px solid transparent;
|
|
|
|
|
+ border-bottom: 5px solid transparent;
|
|
|
|
|
+ border-right: 5px solid #2199f8;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- .arrange-box.status-warning {
|
|
|
|
|
|
|
+ .arrange-card.status-warning {
|
|
|
border-color: #ff953d;
|
|
border-color: #ff953d;
|
|
|
- color: #ff953d;
|
|
|
|
|
|
|
+ &::before {
|
|
|
|
|
+ border-right-color: #ff953d;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- .arrange-box.status-complete {
|
|
|
|
|
|
|
+ .arrange-card.status-complete {
|
|
|
border-color: #1ca900;
|
|
border-color: #1ca900;
|
|
|
- color: #1ca900;
|
|
|
|
|
|
|
+ &::before {
|
|
|
|
|
+ border-right-color: #1ca900;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- .arrange-box.status-normal {
|
|
|
|
|
|
|
+ .arrange-card.status-normal {
|
|
|
border-color: #2199f8;
|
|
border-color: #2199f8;
|
|
|
- color: #2199f8;
|
|
|
|
|
|
|
+ &::before {
|
|
|
|
|
+ border-right-color: #2199f8;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -662,7 +649,7 @@ const formatTextWithLineBreak = (text) => {
|
|
|
width: 30px;
|
|
width: 30px;
|
|
|
padding-right: 16px;
|
|
padding-right: 16px;
|
|
|
display: flex;
|
|
display: flex;
|
|
|
- align-items: center;
|
|
|
|
|
|
|
+ align-items: flex-start;
|
|
|
z-index: 2; /* 置于中线之上 */
|
|
z-index: 2; /* 置于中线之上 */
|
|
|
.term-name {
|
|
.term-name {
|
|
|
display: inline-block;
|
|
display: inline-block;
|
|
@@ -675,53 +662,16 @@ const formatTextWithLineBreak = (text) => {
|
|
|
writing-mode: vertical-rl;
|
|
writing-mode: vertical-rl;
|
|
|
text-orientation: upright;
|
|
text-orientation: upright;
|
|
|
color: rgba(174, 174, 174, 0.6);
|
|
color: rgba(174, 174, 174, 0.6);
|
|
|
- letter-spacing: 2px;
|
|
|
|
|
text-align: center;
|
|
text-align: center;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // 控制区域样式
|
|
|
|
|
- .control-section {
|
|
|
|
|
- position: fixed;
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- left: 0;
|
|
|
|
|
- box-sizing: border-box;
|
|
|
|
|
- bottom: 0px;
|
|
|
|
|
- background: #fff;
|
|
|
|
|
- padding: 16px 12px;
|
|
|
|
|
- display: flex;
|
|
|
|
|
- justify-content: space-between;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- border-top: 1px solid #f0f0f0;
|
|
|
|
|
-
|
|
|
|
|
- .toggle-group {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- gap: 8px;
|
|
|
|
|
-
|
|
|
|
|
- .toggle-label {
|
|
|
|
|
- font-size: 13px;
|
|
|
|
|
- color: #141414;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .add-button-group {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- gap: 8px;
|
|
|
|
|
- .button {
|
|
|
|
|
- color: #2199f8;
|
|
|
|
|
- border-radius: 25px;
|
|
|
|
|
- padding: 9px 15px;
|
|
|
|
|
- border: 1px solid #2199f8;
|
|
|
|
|
- }
|
|
|
|
|
- .add-button {
|
|
|
|
|
- background: linear-gradient(120deg, #76c3ff 0%, #2199f8 100%);
|
|
|
|
|
- color: white;
|
|
|
|
|
- border: 1px solid transparent;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+ // 控制区域样式
|
|
|
|
|
+ .custom-bottom-fixed-btns {
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ .primary-btn {
|
|
|
|
|
+ padding: 10px 34px;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|