plan.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  1. <template>
  2. <div class="plan-page">
  3. <custom-header
  4. :name="headerTitle"
  5. isGoBack
  6. @goback="goback"
  7. :isClose="route.query.headerTitle ? true : false"
  8. ></custom-header>
  9. <div class="plan-content">
  10. <div class="plan-content-header" v-if="pageType === 'plant'">
  11. <el-select
  12. class="select-item"
  13. v-model="specieValue"
  14. placeholder="选择品类"
  15. @change="() => getListMySchemes('left')"
  16. >
  17. <el-option
  18. v-for="item in options"
  19. :key="item.id"
  20. :label="item.name"
  21. :value="item.defaultContainerId"
  22. />
  23. </el-select>
  24. <tab-list
  25. class="tabs-list"
  26. type="light"
  27. v-model="active"
  28. :tabs="tabs"
  29. :scrollType="scrollType"
  30. @change="handleTabChange"
  31. />
  32. </div>
  33. <div class="tip-box">
  34. <Highlight
  35. :keywords="['关注农事/托管农事', '取消关注']"
  36. source-string="提示:关注农事/托管农事 会触发农情互动,并且为您推送农事,取消关注 则不会为您推送任何与该农事相关的内容"
  37. />
  38. </div>
  39. <div
  40. class="timeline-wrap"
  41. :class="{
  42. 'timeline-container-plant-wrap': pageType == 'plant',
  43. 'timeline-container-no-permission-wrap': !hasPlanPermission,
  44. 'no-default-plan-wrap':
  45. active !== tabs[0]?.id && pageType == 'plant' && tabs[currentTabIndex]?.enabled == 0,
  46. }"
  47. >
  48. <farm-work-plan-timeline
  49. :pageType="pageType"
  50. :farmId="route.query.farmId"
  51. :containerId="containerIdData"
  52. @row-click="handleRowClick"
  53. :disableClick="!hasPlanPermission || active === tabs[0]?.id"
  54. :isStandard="active === tabs[0]?.id"
  55. :schemeId="route.query.schemeId || active"
  56. ref="farmWorkPlanTimelineRef"
  57. />
  58. </div>
  59. </div>
  60. <div
  61. class="custom-bottom-fixed-btns"
  62. :class="{ center: active === tabs[0]?.id && pageType == 'plant' }"
  63. v-has-permission="'农事规划'"
  64. >
  65. <div class="bottom-btn-group-wrap">
  66. <div
  67. class="bottom-btn-group"
  68. :class="{ 'justify-center': active === tabs[0]?.id && pageType == 'plant' }"
  69. >
  70. <div
  71. class="bottom-btn secondary-btn"
  72. @click="handlePhenologySetting"
  73. v-show="active !== tabs[0]?.id"
  74. >
  75. 物候期设置
  76. </div>
  77. <div class="bottom-btn secondary-btn" v-if="pageType === 'plant'" @click="openCopyPlanPopup">
  78. {{ active === tabs[0]?.id ? "复制方案" : "方案设置" }}
  79. </div>
  80. </div>
  81. <div class="bottom-btn primary-btn" @click="addNewTask" v-show="active !== tabs[0]?.id">新增农事</div>
  82. </div>
  83. <template v-if="active !== tabs[0]?.id && pageType == 'plant' && tabs[currentTabIndex]?.enabled == 0">
  84. <div class="bottom-btn-divider"></div>
  85. <div class="bottom-btn primary-btn submit-btn" @click="handleSubmitPlan">提交方案</div>
  86. </template>
  87. </div>
  88. </div>
  89. <!-- 农事信息弹窗 -->
  90. <detail-dialog ref="detailDialogRef" @triggerFarmWork="triggerFarmWork"></detail-dialog>
  91. <!-- 复制方案弹窗 -->
  92. <Popup v-model:show="showCopyPlan" class="copy-plan-popup" round closeable :close-on-click-overlay="false">
  93. <div class="copy-plan-content">
  94. <div class="label">{{ active === tabs[0]?.id ? "复制为" : "方案名称" }}</div>
  95. <el-input v-model="copyPlanName" size="large" placeholder="请输入方案名称" class="copy-plan-input" />
  96. </div>
  97. <div class="copy-plan-footer">
  98. <div class="btn btn-cancel" @click="handleCancelCopyPlan">
  99. {{ active === tabs[0]?.id ? "取消复制" : "删除方案" }}
  100. </div>
  101. <div class="btn btn-confirm" @click="handleConfirmCopyPlan">
  102. {{ active === tabs[0]?.id ? "确定复制" : "确定设置" }}
  103. </div>
  104. </div>
  105. </Popup>
  106. <!-- 物候期设置弹窗 -->
  107. <Popup
  108. v-model:show="showPhenologySetting"
  109. class="copy-plan-popup phenology-popup"
  110. round
  111. closeable
  112. :close-on-click-overlay="false"
  113. >
  114. <div class="phenology-header">物候期时间设置</div>
  115. <div class="phenology-list">
  116. <div class="phenology-item" v-for="(item, index) in mergedReproductiveList" :key="item.id || index">
  117. <div class="item-label">
  118. <span class="label-text">{{ item.name }}</span>
  119. <span>起始时间</span>
  120. </div>
  121. <div class="item-value">
  122. <el-date-picker
  123. style="width: 100%"
  124. size="large"
  125. value-format="YYYY-MM-DD"
  126. v-model="item.startDate"
  127. :clearable="false"
  128. :editable="false"
  129. type="date"
  130. placeholder="选择日期"
  131. @change="(date) => handleStartDateChange(date, index)"
  132. />
  133. </div>
  134. </div>
  135. <div class="phenology-footer-tip">
  136. <span>注:</span>
  137. <span class="text">请从上往下按照时间顺序填写日期</span>
  138. </div>
  139. </div>
  140. <div class="phenology-footer" @click="handleConfirmPhenologySetting">确认设置</div>
  141. </Popup>
  142. <tip-popup
  143. v-model:show="showTipPopup"
  144. type="warning"
  145. text2="还未完善此方案不可用"
  146. :highlightText="highlightText"
  147. buttonText="我知道了"
  148. @confirm="handleBtn"
  149. />
  150. </template>
  151. <script setup>
  152. import { ref, onMounted, computed, watch } from "vue";
  153. import { Popup, Highlight } from "vant";
  154. import customHeader from "@/components/customHeader.vue";
  155. import tabList from "@/components/pageComponents/TabList.vue";
  156. import FarmWorkPlanTimeline from "@/components/pageComponents/FarmWorkPlanTimeline.vue";
  157. import { useRouter, useRoute } from "vue-router";
  158. import detailDialog from "@/components/detailDialog.vue";
  159. import eventBus from "@/api/eventBus";
  160. import tipPopup from "@/components/popup/tipPopup.vue";
  161. import { ElMessage, ElMessageBox } from "element-plus";
  162. const router = useRouter();
  163. const route = useRoute();
  164. const showTipPopup = ref(false);
  165. const highlightText = ref("");
  166. const handleBtn = () => {
  167. showTipPopup.value = false;
  168. setTimeout(() => {
  169. router.go(-1);
  170. }, 10);
  171. };
  172. const goback = () => {
  173. if (
  174. tabs.value[currentTabIndex.value]?.enabled == 0 &&
  175. pageType.value === "plant" &&
  176. active.value !== tabs.value[0]?.id
  177. ) {
  178. highlightText.value = tabs.value[currentTabIndex.value]?.name;
  179. showTipPopup.value = true;
  180. } else {
  181. router.go(-1);
  182. }
  183. };
  184. const userInfoStr = localStorage.getItem("localUserInfo");
  185. const userInfo = userInfoStr ? JSON.parse(userInfoStr) : {};
  186. // 检查是否有"农事规划"权限
  187. const hasPlanPermission = computed(() => {
  188. try {
  189. const permissions = userInfo?.agriculturalPermissions || [];
  190. return permissions.includes("农事规划");
  191. } catch (error) {
  192. console.error("解析用户信息失败:", error);
  193. return false;
  194. }
  195. });
  196. const pageType = ref("");
  197. const headerTitle = ref("");
  198. onMounted(() => {
  199. pageType.value = route.query.pageType || "";
  200. headerTitle.value = route.query.headerTitle || (pageType.value === "plant" ? "种植方案" : "农事规划");
  201. if (!pageType.value) {
  202. getFarmWorkPlanForPhenology();
  203. } else {
  204. getSpecieList();
  205. }
  206. });
  207. // 获取品类列表
  208. const specieValue = ref(null);
  209. const options = ref([]);
  210. const getSpecieList = () => {
  211. VE_API.farm.fetchSpecieList({ agriculturalId: userInfo?.agriculturalId }).then(({ data }) => {
  212. if (data && data.length) {
  213. options.value = data || [];
  214. let schemeType = "left"; // 默认使用left
  215. if (sessionStorage.getItem("specieValue")) {
  216. specieValue.value = sessionStorage.getItem("specieValue");
  217. currentTabIndex.value = sessionStorage.getItem("currentTabIndex");
  218. sessionStorage.removeItem("specieValue");
  219. sessionStorage.removeItem("currentTabIndex");
  220. // 判断恢复的specieValue是否是最后一项
  221. const currentIndex = data.findIndex(item => item.defaultContainerId === specieValue.value);
  222. if (currentIndex === data.length - 1) {
  223. schemeType = "right";
  224. }
  225. } else {
  226. specieValue.value = data[0]?.defaultContainerId;
  227. }
  228. getListMySchemes(schemeType);
  229. }
  230. });
  231. };
  232. // 获取方案列表
  233. const active = ref(null);
  234. const tabs = ref([]);
  235. // 控制标签滚动方向:'left' | 'right' | 'auto' | ''
  236. const scrollType = ref("auto");
  237. const containerIdData = ref(null);
  238. const getListMySchemes = (type = "auto") => {
  239. VE_API.home.listMySchemes({ containerId: specieValue.value }).then(({ data }) => {
  240. tabs.value = data || [];
  241. containerIdData.value = tabs.value[0]?.containerId;
  242. if (sessionStorage.getItem("active")) {
  243. active.value = sessionStorage.getItem("active");
  244. sessionStorage.removeItem("active");
  245. currentTab.value = data[currentTabIndex.value];
  246. } else {
  247. if (type === "right") {
  248. active.value = data[data.length - 1].id;
  249. } else if (type === "left") {
  250. active.value = data[0]?.id;
  251. } else {
  252. if(currentTab.value) {
  253. currentTab.value = data.filter((item) => item.id === currentTab.value?.id)?.[0];
  254. } else {
  255. currentTab.value = data[0];
  256. }
  257. copyPlanName.value = currentTab.value.name;
  258. }
  259. }
  260. scrollType.value = type;
  261. getFarmWorkPlanForPhenology();
  262. });
  263. };
  264. const currentTab = ref(null);
  265. const currentTabIndex = ref(0);
  266. const handleTabChange = (id, item, index) => {
  267. active.value = id;
  268. currentTab.value = item;
  269. currentTabIndex.value = index;
  270. getFarmWorkPlanForPhenology();
  271. };
  272. const mergedReproductiveList = ref([]);
  273. const containerSpaceTimeId = ref(null);
  274. const schemeId = ref(null);
  275. const getPhenologyList = async () => {
  276. const params = {
  277. containerSpaceTimeId: containerSpaceTimeId.value,
  278. agriculturalId: userInfo?.agriculturalId,
  279. farmId: route.query.farmId,
  280. };
  281. const res = await VE_API.monitor.listPhenology(params);
  282. if (res.code === 0) {
  283. // 将intervalDaysArr合并到mergedReproductiveList中
  284. if (intervalDaysArr.value.length > 0 && res.data.length > 0) {
  285. mergedReproductiveList.value = res.data.map((item, index) => {
  286. return {
  287. ...item,
  288. intervalDays: intervalDaysArr.value[index],
  289. };
  290. });
  291. }
  292. }
  293. };
  294. const farmWorkIds = ref([]);
  295. const intervalDaysArr = ref([]);
  296. // 获取农事规划数据以获取 containerSpaceTimeId
  297. const getFarmWorkPlanForPhenology = async () => {
  298. try {
  299. const { data, code } = await VE_API.monitor.farmWorkPlan({
  300. containerId: specieValue.value,
  301. farmId: route.query.farmId,
  302. schemeId: active.value,
  303. });
  304. if (code === 0 && data?.phenologyList?.[0]?.containerSpaceTimeId) {
  305. containerSpaceTimeId.value = data.phenologyList[0].containerSpaceTimeId;
  306. schemeId.value = data.schemeId;
  307. // 收集所有farmWorkId
  308. farmWorkIds.value = [];
  309. intervalDaysArr.value = [];
  310. data.phenologyList.forEach((phenology) => {
  311. intervalDaysArr.value.push(phenology.intervalDays);
  312. if (Array.isArray(phenology.reproductiveList)) {
  313. phenology.reproductiveList.forEach((reproductive) => {
  314. if (Array.isArray(reproductive.farmWorkArrangeList)) {
  315. reproductive.farmWorkArrangeList.forEach((farmWork) => {
  316. if (farmWork.farmWorkId && farmWork.isFollow !== 0) {
  317. farmWorkIds.value.push(farmWork.farmWorkId);
  318. }
  319. });
  320. }
  321. });
  322. }
  323. });
  324. }
  325. } catch (error) {
  326. console.error("获取农事规划数据失败:", error);
  327. }
  328. };
  329. // 复制方案弹窗相关
  330. const showCopyPlan = ref(false);
  331. const showPhenologySetting = ref(false);
  332. const copyPlanName = ref("");
  333. const openCopyPlanPopup = async () => {
  334. copyPlanName.value = "";
  335. showCopyPlan.value = true;
  336. if (active.value !== tabs.value[0]?.id) {
  337. copyPlanName.value = currentTab.value.name;
  338. }
  339. };
  340. // 物候期设置弹窗
  341. const handlePhenologySetting = async () => {
  342. await getPhenologyList();
  343. showPhenologySetting.value = true;
  344. };
  345. /**
  346. * 处理物候期开始时间变化
  347. * 当修改某个物候期的开始时间时,自动更新后续所有物候期的开始时间
  348. */
  349. const handleStartDateChange = (date, currentIndex) => {
  350. if (!date || !mergedReproductiveList.value || mergedReproductiveList.value.length === 0) {
  351. return;
  352. }
  353. // 从当前修改的物候期开始,更新后续所有物候期的开始时间
  354. for (let i = currentIndex; i < mergedReproductiveList.value.length - 1; i++) {
  355. const currentItem = mergedReproductiveList.value[i];
  356. const nextItem = mergedReproductiveList.value[i + 1];
  357. // 获取当前物候期的间隔天数
  358. const intervalDays = currentItem.intervalDays || 0;
  359. if (intervalDays > 0 && currentItem.startDate) {
  360. // 将日期字符串转换为时间戳(毫秒)
  361. const currentStartDateTimestamp = new Date(currentItem.startDate).getTime();
  362. // 在时间戳基础上加上间隔天数(转换为毫秒:天数 * 24小时 * 60分钟 * 60秒 * 1000毫秒)
  363. const nextStartDateTimestamp = currentStartDateTimestamp + (intervalDays * 24 * 60 * 60 * 1000);
  364. // 将时间戳转换回日期对象,然后格式化为 YYYY-MM-DD 格式
  365. const nextStartDate = new Date(nextStartDateTimestamp);
  366. const year = nextStartDate.getFullYear();
  367. const month = String(nextStartDate.getMonth() + 1).padStart(2, '0');
  368. const day = String(nextStartDate.getDate()).padStart(2, '0');
  369. const nextStartDateStr = `${year}-${month}-${day}`;
  370. // 更新下一个物候期的开始时间
  371. nextItem.startDate = nextStartDateStr;
  372. }
  373. }
  374. };
  375. /**
  376. * 确认物候期设置
  377. */
  378. const farmWorkPlanTimelineRef = ref(null);
  379. const handleConfirmPhenologySetting = async () => {
  380. const params = {
  381. farmId: route.query.farmId,
  382. agriculturalId: userInfo?.agriculturalId,
  383. items: mergedReproductiveList.value.map((item) => ({
  384. phenologyId: item.id,
  385. startDate: item.startDate,
  386. })),
  387. };
  388. const res = await VE_API.monitor.batchSaveFarmPhenologyTime(params);
  389. if (res.code === 0) {
  390. ElMessage.success("设置成功");
  391. showPhenologySetting.value = false;
  392. getFarmWorkPlanForPhenology();
  393. farmWorkPlanTimelineRef.value.updateFarmWorkPlan();
  394. }
  395. };
  396. // 取消复制方案
  397. const handleCancelCopyPlan = () => {
  398. if (active.value === tabs.value[0]?.id) {
  399. showCopyPlan.value = false;
  400. } else {
  401. ElMessageBox.confirm("确定要删除该方案吗?", "提示", {
  402. confirmButtonText: "确定",
  403. cancelButtonText: "取消",
  404. type: "warning",
  405. }).then(() => {
  406. VE_API.monitor
  407. .deleteScheme({
  408. schemeId: active.value,
  409. })
  410. .then(({ code }) => {
  411. if (code === 0) {
  412. showCopyPlan.value = false;
  413. ElMessage.success("删除成功");
  414. getListMySchemes("left");
  415. }
  416. });
  417. });
  418. }
  419. };
  420. // 确定复制方案
  421. const handleConfirmCopyPlan = () => {
  422. if (!copyPlanName.value.trim()) {
  423. ElMessage.warning("请输入方案名称");
  424. return;
  425. }
  426. if (active.value === tabs.value[0]?.id) {
  427. VE_API.monitor
  428. .copyScheme({
  429. containerId: specieValue.value,
  430. sourceSchemeId: active.value,
  431. schemeName: copyPlanName.value,
  432. })
  433. .then(({ code, data }) => {
  434. if (code === 0) {
  435. showCopyPlan.value = false;
  436. ElMessage.success("复制成功");
  437. getListMySchemes("right");
  438. currentTab.value = data;
  439. currentTabIndex.value = (tabs.value.length - 1) + 1;
  440. }
  441. });
  442. } else {
  443. VE_API.monitor
  444. .renameScheme({
  445. schemeId: active.value,
  446. name: copyPlanName.value,
  447. })
  448. .then(({ code }) => {
  449. if (code === 0) {
  450. showCopyPlan.value = false;
  451. ElMessage.success("修改成功");
  452. getListMySchemes("auto");
  453. }
  454. });
  455. }
  456. };
  457. // 验证药肥报价信息并返回结果
  458. // 返回: { allTrue: boolean, invalidIds: string[] }
  459. const validatePesticideFertilizerQuotes = async () => {
  460. const { data, code } = await VE_API.monitor.batchValidatePesticideFertilizerQuotes({
  461. ids: farmWorkIds.value,
  462. schemeId: active.value,
  463. });
  464. if (code !== 0 || !data) {
  465. return { allTrue: false, invalidIds: [] };
  466. }
  467. // 判断所有值是否都为true
  468. const allTrue = Object.values(data).every((value) => value === true);
  469. // 收集所有不为true的ID
  470. const invalidIds = Object.keys(data).filter((key) => data[key] !== true);
  471. return { allTrue, invalidIds };
  472. };
  473. // 提交方案
  474. const handleSubmitPlan = async () => {
  475. // 调用验证方法,传入所有ids
  476. if (farmWorkIds.value.length > 0) {
  477. const { allTrue } = await validatePesticideFertilizerQuotes();
  478. if (allTrue) {
  479. VE_API.monitor
  480. .enableScheme({
  481. schemeId: active.value,
  482. })
  483. .then(({ code }) => {
  484. if (code === 0) {
  485. ElMessage.success("提交成功");
  486. if(route.query.headerTitle) {
  487. router.replace({
  488. path: "/home",
  489. });
  490. }else{
  491. getListMySchemes("auto");
  492. }
  493. }
  494. });
  495. } else {
  496. ElMessage.warning("当前方案有未完善报价信息的农事,请先完善报价信息");
  497. }
  498. }
  499. };
  500. const savePlanPageInfo = () => {
  501. if(route.query.pageType !== 'plant') {
  502. return;
  503. }
  504. sessionStorage.setItem("specieValue", specieValue.value);
  505. sessionStorage.setItem("active", active.value);
  506. sessionStorage.setItem("currentTabIndex", currentTabIndex.value);
  507. };
  508. // 新增农事
  509. const addNewTask = () => {
  510. savePlanPageInfo();
  511. router.push({
  512. path: "/add_work",
  513. query: {
  514. containerSpaceTimeId: containerSpaceTimeId.value,
  515. schemeId: route.query.schemeId || schemeId.value,
  516. },
  517. });
  518. };
  519. const triggerFarmWork = () => {
  520. eventBus.emit("activeUpload:show", {
  521. gardenIdVal: route.query.farmId,
  522. problemTitleVal: "请选择您出现" + curFarmObj.value.farmWorkName + "的时间",
  523. arrangeIdVal: curFarmObj.value.id,
  524. needExecutorVal: true,
  525. });
  526. };
  527. const curFarmObj = ref({});
  528. const handleRowClick = (item) => {
  529. curFarmObj.value = item;
  530. savePlanPageInfo();
  531. sessionStorage.setItem("farmWorkAndArrangeIds", JSON.stringify(item.invalidArr));
  532. const enabled = tabs.value[currentTabIndex.value]?.enabled;
  533. router.push({
  534. path: "/modify",
  535. query: {
  536. id: item.id,
  537. noPrice: pageType.value === "plant" ? true : false,
  538. farmId: route.query.farmId,
  539. farmWorkId: item.farmWorkId,
  540. containerSpaceTimeId: item.containerSpaceTimeId,
  541. isDefault: active.value === tabs.value[0]?.id,
  542. enabled: enabled,
  543. isEdit: item.isEdit,
  544. },
  545. });
  546. };
  547. </script>
  548. <style scoped lang="scss">
  549. .plan-page {
  550. width: 100%;
  551. height: 100vh;
  552. background: #f5f7fb;
  553. .plan-content {
  554. .plan-content-header {
  555. display: flex;
  556. align-items: center;
  557. gap: 12px;
  558. margin: 10px 0 10px 12px;
  559. .select-item {
  560. width: 82px;
  561. ::v-deep {
  562. .el-select__wrapper {
  563. box-shadow: none;
  564. border-radius: 25px;
  565. border: 0.5px solid rgba(153, 153, 153, 0.5);
  566. }
  567. }
  568. }
  569. .tabs-list {
  570. width: calc(100% - 94px);
  571. margin-right: 8px;
  572. }
  573. }
  574. .tip-box {
  575. padding: 5px 10px;
  576. background: rgba(33, 153, 248, 0.1);
  577. border-radius: 5px;
  578. font-size: 12px;
  579. margin: 8px 10px;
  580. color: #444;
  581. }
  582. .timeline-wrap {
  583. height: calc(100vh - 90px - 80px);
  584. padding: 0 10px 0 4px;
  585. &.timeline-container-plant-wrap {
  586. height: calc(100vh - 90px - 85px - 38px);
  587. }
  588. &.no-default-plan-wrap {
  589. height: calc(100vh - 90px - 85px - 100px);
  590. }
  591. // 没有权限时,底部按钮不显示,高度增加 73px
  592. &.timeline-container-no-permission-wrap {
  593. height: calc(100vh - 90px - 60px);
  594. }
  595. }
  596. }
  597. // 控制区域样式
  598. .custom-bottom-fixed-btns {
  599. flex-direction: column;
  600. .bottom-btn-group-wrap {
  601. display: flex;
  602. gap: 12px;
  603. width: 100%;
  604. justify-content: space-between;
  605. .bottom-btn-group {
  606. display: flex;
  607. gap: 12px;
  608. &.justify-center {
  609. justify-content: center;
  610. width: 100%;
  611. }
  612. }
  613. }
  614. &.center {
  615. justify-content: center;
  616. .bottom-btn {
  617. padding: 10px 45px;
  618. }
  619. }
  620. .bottom-btn-divider {
  621. width: calc(100% + 24px);
  622. height: 1px;
  623. background: #f0f0f0;
  624. margin: 10px -12px;
  625. }
  626. .submit-btn {
  627. padding: 10px 83px;
  628. }
  629. }
  630. }
  631. .copy-plan-popup {
  632. width: 100%;
  633. padding: 50px 12px 20px 12px;
  634. &::before {
  635. content: "";
  636. position: absolute;
  637. top: 0;
  638. left: 0;
  639. width: 100%;
  640. height: 136px;
  641. pointer-events: none;
  642. background: url("@/assets/img/monitor/popup-header-bg.png") no-repeat center center / 100% 100%;
  643. }
  644. .copy-plan-content {
  645. display: flex;
  646. align-items: center;
  647. gap: 12px;
  648. .label {
  649. font-size: 16px;
  650. font-weight: 500;
  651. }
  652. .copy-plan-input {
  653. width: calc(100% - 80px);
  654. }
  655. }
  656. .copy-plan-footer {
  657. display: flex;
  658. gap: 12px;
  659. margin-top: 20px;
  660. .btn {
  661. flex: 1;
  662. color: #666666;
  663. border: 1px solid #999999;
  664. border-radius: 25px;
  665. padding: 10px 0;
  666. font-size: 16px;
  667. text-align: center;
  668. &.btn-confirm {
  669. color: #fff;
  670. border: 1px solid #2199f8;
  671. background: #2199f8;
  672. }
  673. }
  674. }
  675. }
  676. .phenology-popup {
  677. padding: 28px 20px 20px;
  678. .phenology-header {
  679. font-size: 24px;
  680. text-align: center;
  681. margin-bottom: 20px;
  682. font-family: "PangMenZhengDao";
  683. }
  684. .phenology-list {
  685. width: 100%;
  686. .phenology-item {
  687. width: 100%;
  688. display: flex;
  689. align-items: center;
  690. justify-content: space-between;
  691. .item-label {
  692. display: flex;
  693. align-items: center;
  694. gap: 4px;
  695. font-size: 15px;
  696. color: rgba(0, 0, 0, 0.4);
  697. .label-text {
  698. color: #000;
  699. font-size: 16px;
  700. font-weight: 500;
  701. }
  702. }
  703. .item-value {
  704. width: calc(100% - 156px);
  705. }
  706. }
  707. .phenology-item + .phenology-item {
  708. margin-top: 10px;
  709. }
  710. }
  711. .phenology-footer-tip {
  712. margin-top: 20px;
  713. text-align: center;
  714. .text{
  715. color: rgba(0, 0, 0, 0.4);
  716. }
  717. }
  718. .phenology-footer {
  719. width: 100%;
  720. text-align: center;
  721. font-size: 16px;
  722. margin-top: 10px;
  723. color: #fff;
  724. background: #2199f8;
  725. border-radius: 25px;
  726. padding: 10px 0;
  727. }
  728. }
  729. </style>