index.vue 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605
  1. <template>
  2. <div class="achievement-report-page" :style="{ height: `calc(100vh - ${tabBarHeight}px)` }">
  3. <!-- 天气遮罩 -->
  4. <div class="weather-mask" v-show="isExpanded" @click="handleMaskClick"></div>
  5. <!-- 组件:天气 -->
  6. <div class="weather-info-wrap">
  7. <weather-info ref="weatherInfoRef" from="growth_report" class="weather-info" :showTabMask="showTabMask"
  8. @weatherExpanded="weatherExpanded" @changeGarden="changeGarden" @changeGardenTab="changeGardenTab"
  9. @closeTabMask="closeTabMask">
  10. </weather-info>
  11. <!-- 邀请关注 -->
  12. <!-- <div class="invite-follow" v-if="currentFarmName && activeGardenTab === 'current'">
  13. <div class="invite-content">
  14. <icon name="share" />
  15. <span>{{ t('邀请关注') }}</span>
  16. </div>
  17. </div> -->
  18. </div>
  19. <!-- 农场列表 -->
  20. <div v-show="activeGardenTab === 'list'">
  21. <garden-list ref="gardenListRef" :garden-id="selectedGardenId" @loaded="handleGardenLoaded"
  22. @selectGarden="handleGardenSelected" />
  23. </div>
  24. <div class="report-content-wrap" v-if="hasReport && activeGardenTab === 'current'" v-loading="loading"
  25. element-loading-background="rgba(0, 0, 0, 0.1)">
  26. <div class="history-risk-report-btn" @click="handleHistoryRiskReportClick">
  27. <span class="risk-report-icon">
  28. <i></i>
  29. </span>
  30. <span class="risk-report-text">{{ t('历史风险报告') }}</span>
  31. </div>
  32. <div class="report-content has-report" :style="{ minHeight: `calc(100vh - ${tabBarHeight}px)` }">
  33. <!-- <img src="@/assets/img/home/qrcode.png" alt="" class="code-icon" /> -->
  34. <img class="header-img" src="@/assets/img/home/report.png" alt="" />
  35. <div class="report-header">
  36. <!-- <div class="type-tabs report-tabs">
  37. <div class="type-item" :class="{ 'type-item-active': activeReportIndex === 0 }">{{ t('作物长势') }}</div>
  38. <div class="type-item" :class="{ 'type-item-active': activeReportIndex === 1 }">{{ t('历史风险') }}</div>
  39. <div class="type-item" :class="{ 'type-item-active': activeReportIndex === 2 }">{{ t('土壤改良') }}</div>
  40. <div class="type-item" :class="{ 'type-item-active': activeReportIndex === 3 }">{{ t('种植建议') }}</div>
  41. </div> -->
  42. <div class="type-tabs" v-if="subjectData.length > 1">
  43. <div
  44. @click="handleTypeTabClick(item, index)"
  45. class="type-item"
  46. v-for="(item, index) in visibleSubjectData"
  47. :class="{ 'type-item-active': activeSubjectIndex === index }"
  48. :key="index">{{ item.speciesName }}</div>
  49. <div
  50. v-if="showSubjectToggle"
  51. class="subject-toggle"
  52. @click="typeTabsExpanded = !typeTabsExpanded"
  53. >
  54. {{ typeTabsExpanded ? t("common.collapse") : t("common.expandMore") }}
  55. </div>
  56. </div>
  57. <div class="time-tag">{{ workItems?.[0]?.reportDate || new Date().toISOString().split('T')[0] }}</div>
  58. <div
  59. class="report-title"
  60. :class="{ 'report-title-toggle': localeToggleEnabled }"
  61. @click="onReportTitleClick"
  62. >{{ varietyName }}{{ t("growthReport.title") }}</div>
  63. <div class="report-info">
  64. <div class="info-item">
  65. <img class="info-icon" src="@/assets/img/home/farm.png" alt="" />
  66. <span class="info-text">{{ currentFarmName }}</span>
  67. </div>
  68. </div>
  69. </div>
  70. <div class="report-box">
  71. <div class="box-title">{{ t("growthReport.weatherRisk") }}</div>
  72. <div class="box-text">
  73. <div class="box-bg">
  74. <!-- <div class="types-info">
  75. 当前 <span class="text-bold">{{ t('水稻') }}</span>{{ t('处于为 分蘖初期') }}<span class="text-link" @click="handleAdjustPopup">{{ t('(校准物候期)') }}</span>
  76. </div> -->
  77. <div class="types-info">
  78. {{ t("common.current") }}
  79. <span class="text-bold">{{ varietyName }}</span>
  80. {{ t("growthReport.inStage", { stage: currentPhenologyStage }) }}
  81. </div>
  82. <div class="tp-img" v-if="currentFarmVariety === 1">
  83. <img src="@/assets/img/common/tp-1.png" alt="">
  84. <img src="@/assets/img/common/tp-2.png" alt="">
  85. <img src="@/assets/img/common/tp-3.png" alt="">
  86. <img src="@/assets/img/common/tp-4.png" alt="">
  87. <img src="@/assets/img/common/tp-5.png" alt="">
  88. <img src="@/assets/img/common/tp-6.png" alt="">
  89. </div>
  90. <div class="tp-img" v-else>
  91. <img src="@/assets/img/common/sd-1.jpg" alt="">
  92. <img src="@/assets/img/common/sd-2.jpg" alt="">
  93. <img src="@/assets/img/common/sd-3.jpg" alt="">
  94. <img src="@/assets/img/common/sd-4.jpg" alt="">
  95. <img src="@/assets/img/common/sd-5.jpg" alt="">
  96. <img src="@/assets/img/common/sd-6.jpg" alt="">
  97. </div>
  98. </div>
  99. <div class="warning-part">
  100. <div class="warning-title">
  101. <div class="title-l">
  102. <div class="title-line"></div>
  103. <div class="title-block"></div>
  104. </div>
  105. <div>{{ t("growthReport.futureWeatherRisk") }}</div>
  106. <div class="title-l">
  107. <div class="title-block"></div>
  108. <div class="title-line title-line-right"></div>
  109. </div>
  110. </div>
  111. <div class="report-part" v-for="(part, partI) in riskList" :key="partI">
  112. <div class="part-title">{{ part.title }}</div>
  113. <div class="part-text" v-html="boldKeywordsInText(part.description, part.boldKeywords)"></div>
  114. </div>
  115. </div>
  116. </div>
  117. </div>
  118. <div class="report-box">
  119. <div class="box-title">{{ t("growthReport.farmAdvice") }}</div>
  120. <div class="box-text">
  121. <div class="warning-part" v-for="(part, partI) in adviceList" :key="partI">
  122. <div class="report-part">
  123. <div class="part-top">
  124. <div class="part-title">{{ part.title }}</div>
  125. <!-- <div class="part-link">
  126. <el-icon class="part-link-icon"><Link /></el-icon>
  127. <div class="text-link">{{ t('查看农事') }}</div>
  128. </div> -->
  129. </div>
  130. <div class="part-text" v-html="boldKeywordsInText(part.description, part.boldKeywords)"></div>
  131. </div>
  132. </div>
  133. </div>
  134. </div>
  135. <div class="report-box">
  136. <div class="box-title">{{ t("growthReport.patrolFocus") }}</div>
  137. <div class="box-text">
  138. <div class="warning-part" v-for="(part, partI) in patrolList" :key="partI">
  139. <div class="report-part">
  140. <div class="part-top">
  141. <div class="part-title">{{ part.title }}</div>
  142. <!-- <div class="part-link">
  143. <el-icon class="part-link-icon"><Link /></el-icon>
  144. <div class="text-link">{{ t('查看互动') }}</div>
  145. </div> -->
  146. </div>
  147. <div class="part-text" v-html="boldKeywordsInText(part.description, part.boldKeywords)"></div>
  148. </div>
  149. </div>
  150. </div>
  151. </div>
  152. <div class="report-box" v-for="(work, workI) in workItems" :key="workI">
  153. <div class="box-title">{{ work?.title }}</div>
  154. <div class="box-text">
  155. <div class="box-bg" v-show="work?.backgroundDesc">
  156. <span class="box-subtitle">{{ t("common.backgroundDesc") }}</span>
  157. <div class="pre-text">{{ work?.backgroundDesc }}</div>
  158. </div>
  159. <div class="box-advice" v-show="work?.suggestion">
  160. <span class="box-subtitle">{{ t("common.suggestion") }}</span>
  161. <div class="pre-text">{{ work?.suggestion }}</div>
  162. </div>
  163. <div class="box-sum pre-text" v-show="work?.summary">{{ work?.summary }}</div>
  164. </div>
  165. </div>
  166. </div>
  167. <!-- <swipe ref="swipeRef" class="my-swipe" :loop="false" indicator-color="white" @change="handleSwipeChange">
  168. <swipe-item v-for="(item, index) in regionsData" :key="index">
  169. </swipe-item>
  170. </swipe> -->
  171. </div>
  172. <div v-else-if="activeGardenTab === 'current'" class="fake-report-wrap report-content-wrap">
  173. <div class="report-content">
  174. <img class="header-img" src="@/assets/img/home/report.png" alt="" />
  175. <div class="report-header" :class="{ 'no-farm': !currentFarmName }">
  176. <!-- <img class="header-book" src="@/assets/img/home/book.png" alt="" /> -->
  177. <div class="time-tag">{{ new Date().toISOString().split('T')[0] }}</div>
  178. <div
  179. class="report-title"
  180. :class="{ 'report-title-toggle': localeToggleEnabled }"
  181. @click="onReportTitleClick"
  182. >{{ t("growthReport.cropTitle") }}</div>
  183. <div class="report-info pb-4">
  184. <div class="info-item">
  185. <img class="info-icon" src="@/assets/img/home/farm.png" alt="" />
  186. <span class="info-text">{{ t("common.demoFarm") }}</span>
  187. </div>
  188. </div>
  189. </div>
  190. <div class="fake-img">
  191. <img src="@/assets/img/home/fake.png" alt="" class="fake-img-item" />
  192. </div>
  193. <div class="lock-img">
  194. <img @click="handleLockClick" src="@/assets/img/home/lock-blue.png" alt=""
  195. class="has-click lock-img-item" />
  196. <div class="lock-text">
  197. {{ t("growthReport.lockTitle") }}
  198. <div>{{ t("growthReport.lockSub") }}</div>
  199. </div>
  200. <div @click="handleLockClick" class="lock-btn has-click">{{ t("common.unlock") }}</div>
  201. </div>
  202. <div class="lock-bg"></div>
  203. </div>
  204. </div>
  205. <!-- 农场列表引导 -->
  206. <div class="mask-wrap" @click="closeTabMask" v-if="showTabMask"></div>
  207. <tip-popup v-model:show="showBindSuccess" type="success" :text="t('growthReport.bindSuccess')" hideBtn />
  208. <start-interact-popup ref="startInteractPopupRef" />
  209. <agri-execute-popup ref="agriExecutePopupRef" />
  210. <!-- 校准物候期 -->
  211. <adjust-popup ref="adjustPopupRef" />
  212. </div>
  213. </template>
  214. <script setup>
  215. import wx from "weixin-js-sdk";
  216. import weatherInfo from "@/components/weatherInfo.vue";
  217. import { ref, onActivated, onDeactivated, onUnmounted, computed, nextTick } from "vue";
  218. import { useRoute, useRouter } from "vue-router";
  219. import { useStore } from "vuex";
  220. import { Swipe, SwipeItem, Badge, Icon } from 'vant';
  221. import tipPopup from "@/components/popup/tipPopup.vue";
  222. import startInteractPopup from "@/components/popup/startInteractPopup.vue";
  223. import agriExecutePopup from "@/components/popup/agriExecutePopup.vue";
  224. import gardenList from "@/components/gardenList.vue";
  225. import adjustPopup from "./adjustPopup.vue";
  226. import { useI18n } from "@/i18n";
  227. import { boldKeywordsInText } from "@/utils/boldKeywords";
  228. const { t, toggleLocale: dispatchToggleLocale } = useI18n();
  229. const store = useStore();
  230. /** 暂时隐藏标题中英切换,恢复时改为 true */
  231. const localeToggleEnabled = false;
  232. const tabBarHeight = computed(() => store.state.home.tabBarHeight);
  233. const route = useRoute();
  234. const router = useRouter();
  235. const loading = ref(false);
  236. const hasReport = ref(true);
  237. const workItems = ref([]);
  238. const swipeRef = ref(null);
  239. //
  240. const riskList = computed(() => [
  241. {
  242. title: t("growthReport.risk.pest.title"),
  243. description:
  244. currentFarmVariety.value == 1
  245. ? t("growthReport.risk.pest.desc")
  246. : t("growthReport.risk.pest.descRice"),
  247. boldKeywords:
  248. currentFarmVariety.value == 1
  249. ? ["高温干旱", "中等水平", "果皮灼伤"]
  250. : ["低等水平", "对水分会更加敏感"],
  251. },
  252. // {
  253. // title: t("growthReport.risk.rain.title"),
  254. // description: t("growthReport.risk.rain.desc"),
  255. // },
  256. ]);
  257. const adviceList = computed(() => [
  258. {
  259. title:
  260. currentFarmVariety.value == 1
  261. ? t("growthReport.advice.foliar.title")
  262. : t("growthReport.advice.foliar.titleRice"),
  263. description:
  264. currentFarmVariety.value == 1
  265. ? t("growthReport.advice.foliar.desc")
  266. : t("growthReport.advice.foliar.descRice"),
  267. boldKeywords:
  268. currentFarmVariety.value == 1 ? ["需及时喷撒清水"] : ["建议喷灌清水"],
  269. },
  270. // {
  271. // title: t("growthReport.advice.pestControl.title"),
  272. // description: t("growthReport.advice.pestControl.desc"),
  273. // },
  274. ]);
  275. const patrolList = computed(() => {
  276. const isLychee = currentFarmVariety.value == 1;
  277. return [
  278. {
  279. title: t("growthReport.patrol.process.title"),
  280. description: isLychee
  281. ? t("growthReport.patrol.process.desc")
  282. : t("growthReport.patrol.process.descRice"),
  283. boldKeywords: isLychee ? ["5%", "果实转色期"] : ["60%", "分蘖末期"],
  284. },
  285. {
  286. title: t("growthReport.patrol.growth.title"),
  287. description: isLychee
  288. ? t("growthReport.patrol.growth.desc")
  289. : t("growthReport.patrol.growth.descRice"),
  290. boldKeywords: isLychee ? ["10%", "抽生新梢"] : ["10%", "干旱缺素"],
  291. },
  292. ];
  293. // {
  294. // title: t("growthReport.patrol.pest.title"),
  295. // description: t("growthReport.patrol.pest.desc"),
  296. // },
  297. });
  298. //
  299. const paramsPage = ref({});
  300. const showBindSuccess = ref(false);
  301. const startInteractPopupRef = ref(null);
  302. const agriExecutePopupRef = ref(null);
  303. const adjustPopupRef = ref(null);
  304. const handleAdjustPopup = () => {
  305. adjustPopupRef.value.open();
  306. }
  307. // 天气组件相关
  308. const isExpanded = ref(false);
  309. const weatherInfoRef = ref(null);
  310. const showTabMask = ref(false);
  311. const TAB_GUIDE_SHOWN_KEY = "GROWTH_REPORT_TAB_GUIDE_SHOWN";
  312. const weatherExpanded = (isExpandedValue) => {
  313. isExpanded.value = isExpandedValue;
  314. };
  315. // 点击遮罩时收起天气
  316. const handleMaskClick = () => {
  317. if (weatherInfoRef.value && weatherInfoRef.value.toggleExpand) {
  318. weatherInfoRef.value.toggleExpand();
  319. }
  320. };
  321. const currentFarmName = ref('');
  322. const selectedGardenId = ref(null);
  323. const gardenListRef = ref(null);
  324. const activeGardenTab = ref('current');
  325. const changeGardenTab = (tab) => {
  326. activeGardenTab.value = tab;
  327. }
  328. const handleGardenLoaded = ({ hasFarm }) => {
  329. weatherInfoRef.value?.setGardenLoaded?.(hasFarm);
  330. };
  331. const handleGardenSelected = (garden) => {
  332. selectedGardenId.value = garden?.id ?? null;
  333. weatherInfoRef.value?.setSelectedGarden?.(garden);
  334. };
  335. const currentFarmVariety = ref(null);
  336. const varietyName = ref(null);
  337. const currentPhenologyStage = computed(() =>
  338. currentFarmVariety.value == 1
  339. ? t("growthReport.phenologyFruitExpansion")
  340. : t("growthReport.phenologyLateTillering")
  341. );
  342. // 切换农场时,更新报告数据
  343. const changeGarden = async ({ id, name,farm_variety,variety_name }) => {
  344. currentFarmVariety.value = farm_variety;
  345. varietyName.value = variety_name;
  346. if (!id) return;
  347. currentFarmName.value = name;
  348. if (sessionStorage.getItem('activeSwipeIndex')) {
  349. currentIndex.value = Number(sessionStorage.getItem('activeSwipeIndex'));
  350. } else {
  351. currentIndex.value = 0;
  352. swipeRef.value && swipeRef.value.swipeTo(0, { immediate: true });
  353. }
  354. paramsPage.value = {
  355. ...(paramsPage.value || {}),
  356. subjectId: id,
  357. };
  358. // 初始化品种/大物候期转换
  359. startInteractPopupRef.value.getPhenologyInitOrConfirmStatus();
  360. await getSubjectData(id);
  361. hasReport.value = true;
  362. // await getRegions();
  363. };
  364. onActivated(() => {
  365. if (!localeToggleEnabled) {
  366. store.dispatch("locale/setLocale", "zh");
  367. }
  368. window.scrollTo(0, 0);
  369. // 从新增农场页返回时,优先用缓存中的最新选中农场
  370. const savedFarmId = localStorage.getItem("selectedFarmId");
  371. selectedGardenId.value = savedFarmId ? Number(savedFarmId) : null;
  372. gardenListRef.value?.refreshFarmList?.();
  373. // 如果路由中带有 miniJson,并且其中有 showBind,则展示绑定成功弹窗
  374. const { miniJson } = route.query || {};
  375. if (miniJson) {
  376. try {
  377. const parsed = typeof miniJson === "string" ? JSON.parse(miniJson) : miniJson;
  378. if (parsed && parsed.showBind) {
  379. showBindSuccess.value = true;
  380. // 处理完后清空路由中的 miniJson 参数,避免重复弹出
  381. const newQuery = { ...(route.query || {}) };
  382. delete newQuery.miniJson;
  383. router.replace({ path: route.path, query: newQuery });
  384. }
  385. } catch (e) {
  386. // miniJson 解析失败时忽略,不影响正常流程
  387. }
  388. }
  389. // getResultReport();
  390. });
  391. const closeTabMask = () => {
  392. showTabMask.value = false;
  393. };
  394. const userInfo = localStorage.getItem("localUserInfo");
  395. const userInfoObj = userInfo ? JSON.parse(userInfo) : {};
  396. const handleLockClick = () => {
  397. if (currentFarmName.value) {
  398. // router.push("/interaction?subjectId=" + localStorage.getItem("selectedFarmId"));
  399. router.push(`/create_farm?from=growth_report&isReload=true`);
  400. return;
  401. }
  402. if (userInfoObj?.tel) {
  403. router.push(`/create_farm?from=growth_report&isReload=true`);
  404. return;
  405. }
  406. wx.miniProgram.navigateTo({
  407. url: '/pages/subPages/phone_auth/index',
  408. });
  409. }
  410. const handleAddFarm = () => {
  411. router.push(`/create_farm?from=growth_report&isReload=true`);
  412. }
  413. const handleHistoryRiskReportClick = () => {
  414. router.push("/history_risk_report?farmVariety=" + currentFarmVariety.value + "&currentFarmName=" + currentFarmName.value);
  415. }
  416. const todayPatrolFocus = ref([]);
  417. const pendingFarmWork = ref([]);
  418. const handlePendingFarmWorkClick = (card) => {
  419. router.push({
  420. path: "/work_detail",
  421. query: {
  422. miniJson: JSON.stringify({
  423. paramsPage: JSON.stringify({
  424. farmId: paramsPage.value.farmId,
  425. farmWorkLibId: card?.farmWorkLibId,
  426. recordId: card?.recordId,
  427. typeId: regionsData.value[currentIndex.value].typeId
  428. }),
  429. }),
  430. },
  431. });
  432. }
  433. // 点击今日巡园重点
  434. const handleTodayPatrolFocusClick = (card) => {
  435. if (!card.interactionTypeId) return;
  436. router.push(`/interaction_list?farmId=${paramsPage.value.farmId}&regionId=${paramsPage.value.regionId}&interactionTypeId=${card.interactionTypeId}`);
  437. }
  438. const getTodayPatrolFocus = () => {
  439. VE_API.report.todayPatrolFocus({ farmId: paramsPage.value.farmId }).then(({ data }) => {
  440. todayPatrolFocus.value = data || [];
  441. });
  442. }
  443. const getPendingFarmWork = () => {
  444. VE_API.report.pendingFarmWork({ farmId: paramsPage.value.farmId, regionId: paramsPage.value.regionId }).then(({ data }) => {
  445. pendingFarmWork.value = data || [];
  446. });
  447. }
  448. const currentIndex = ref(0);
  449. const handleSwipeChange = (index) => {
  450. currentIndex.value = index;
  451. if (paramsPage.value.regionId !== regionsData.value[index].regionId) {
  452. paramsPage.value = {
  453. ...(paramsPage.value || {}),
  454. farmId: regionsData.value[index].farmId,
  455. regionId: regionsData.value[index].regionId,
  456. };
  457. getTodayPatrolFocus();
  458. getPendingFarmWork();
  459. getDetail();
  460. }
  461. }
  462. const getDetail = () => {
  463. if (!paramsPage.value.farmId) return;
  464. loading.value = true;
  465. VE_API.report
  466. .reproductiveReport({ farmId: paramsPage.value.farmId, regionId: paramsPage.value.regionId })
  467. .then(({ data }) => {
  468. workItems.value = data || [];
  469. })
  470. .finally(() => {
  471. loading.value = false;
  472. });
  473. };
  474. const subjectData = ref([])
  475. const typeTabsExpanded = ref(false);
  476. const visibleSubjectData = computed(() => {
  477. if (typeTabsExpanded.value) {
  478. return subjectData.value;
  479. }
  480. return subjectData.value.slice(0, 4);
  481. });
  482. const showSubjectToggle = computed(() => subjectData.value.length > 4);
  483. const getSubjectData = async (id) => {
  484. const res = await VE_API.monitor.listFarmsBySubjectId({ subjectId: id });
  485. // subjectData.value = res.data || [];
  486. subjectData.value = [...res.data, ...res.data, ...res.data, ...res.data];
  487. typeTabsExpanded.value = false;
  488. }
  489. const activeReportIndex = ref(0);
  490. const activeSubjectIndex = ref(0);
  491. const handleTypeTabClick = (item, index) => {
  492. activeSubjectIndex.value = index;
  493. paramsPage.value = {
  494. ...(paramsPage.value || {}),
  495. farmId: item.farmId,
  496. };
  497. getTodayPatrolFocus();
  498. }
  499. const regionsData = ref([]);
  500. const getRegions = async () => {
  501. VE_API.monitor.listRegionsBySubjectId({
  502. subjectId: paramsPage.value.subjectId,
  503. }).then(({ data }) => {
  504. console.log(data);
  505. regionsData.value = data || [];
  506. if (regionsData.value.length > 0) {
  507. hasReport.value = true;
  508. const hasShownTabGuide = localStorage.getItem(TAB_GUIDE_SHOWN_KEY) === "1";
  509. // 首次进入且有分区数据:显示农场列表引导
  510. if (!hasShownTabGuide) {
  511. showTabMask.value = true;
  512. localStorage.setItem(TAB_GUIDE_SHOWN_KEY, "1");
  513. } else {
  514. showTabMask.value = false;
  515. }
  516. // 切换农场tab回到当前农场tab
  517. weatherInfoRef.value && weatherInfoRef.value.handleGardenClick('current');
  518. // 如果不是点击农情报告已生成弹窗过来的,则显示农情互动弹窗
  519. if (!route.query.hideInteraction) {
  520. agriExecutePopupRef.value.showPopup(regionsData.value[currentIndex.value].farmId);
  521. }
  522. paramsPage.value = {
  523. ...(paramsPage.value || {}),
  524. farmId: regionsData.value[currentIndex.value].farmId,
  525. regionId: regionsData.value[currentIndex.value].regionId,
  526. };
  527. getTodayPatrolFocus();
  528. getPendingFarmWork();
  529. getDetail();
  530. // 如果是新增品种后跳转过来的,等待 Swipe 实例挂载后再定位
  531. if (route.query.addVarietyCount) {
  532. const targetIndex = Number(route.query.addVarietyCount);
  533. if (!Number.isNaN(targetIndex) && targetIndex >= 0) {
  534. const safeIndex = Math.min(targetIndex, regionsData.value.length - 1);
  535. const reverseIndex = Math.min(
  536. regionsData.value.length - 1,
  537. Math.max(0, regionsData.value.length - safeIndex)
  538. );
  539. nextTick(() => {
  540. swipeRef.value?.swipeTo?.(reverseIndex, { immediate: true });
  541. });
  542. }
  543. }
  544. if (sessionStorage.getItem('activeSwipeIndex')) {
  545. nextTick(() => {
  546. swipeRef.value?.swipeTo?.(currentIndex.value, { immediate: true });
  547. });
  548. sessionStorage.removeItem('activeSwipeIndex');
  549. }
  550. } else {
  551. // 切换农场tab回到当前农场tab
  552. // weatherInfoRef.value && weatherInfoRef.value.handleGardenClick('current');
  553. showTabMask.value = false;
  554. hasReport.value = false;
  555. }
  556. });
  557. }
  558. /** 切换语言后,用新 lang 参数重新请求页面数据 */
  559. const reloadPageDataAfterLocaleChange = () => {
  560. gardenListRef.value?.refreshFarmList?.();
  561. const subjectId = paramsPage.value.subjectId || localStorage.getItem("selectedFarmId");
  562. if (subjectId) {
  563. getSubjectData(subjectId);
  564. }
  565. if (paramsPage.value.farmId) {
  566. getTodayPatrolFocus();
  567. getPendingFarmWork();
  568. getDetail();
  569. }
  570. startInteractPopupRef.value?.getPhenologyInitOrConfirmStatus?.();
  571. };
  572. const toggleLocale = async () => {
  573. await dispatchToggleLocale();
  574. reloadPageDataAfterLocaleChange();
  575. };
  576. const onReportTitleClick = () => {
  577. if (!localeToggleEnabled) return;
  578. toggleLocale();
  579. };
  580. // 清理数据的函数
  581. const clearData = () => {
  582. workItems.value = [];
  583. paramsPage.value = {};
  584. loading.value = false;
  585. };
  586. onDeactivated(() => {
  587. sessionStorage.setItem('activeSwipeIndex', currentIndex.value);
  588. clearData();
  589. });
  590. onUnmounted(() => {
  591. clearData();
  592. });
  593. </script>
  594. <style lang="scss" scoped>
  595. .mask-wrap {
  596. position: fixed;
  597. bottom: 0;
  598. left: 0;
  599. width: 100%;
  600. height: 300px;
  601. background-color: rgba(0, 0, 0, 0.52);
  602. z-index: 99999;
  603. }
  604. .achievement-report-page {
  605. width: 100%;
  606. height: 100vh;
  607. background: linear-gradient(195.35deg, #d4e4ff 16.34%, rgba(93, 189, 255, 0) 50.3%),
  608. linear-gradient(156.64deg, rgba(255, 255, 255, 0.16) 27.7%, rgba(255, 255, 255, 0) 72.82%);
  609. .weather-mask {
  610. position: fixed;
  611. top: 0;
  612. left: 0;
  613. width: 100%;
  614. height: 100%;
  615. background-color: rgba(0, 0, 0, 0.52);
  616. z-index: 11;
  617. }
  618. .weather-info-wrap {
  619. width: calc(100% - 20px);
  620. position: absolute;
  621. z-index: 12;
  622. left: 10px;
  623. top: 10px;
  624. .weather-info {
  625. width: 100%;
  626. }
  627. .invite-follow {
  628. position: absolute;
  629. right: -6px;
  630. top: 50px;
  631. .invite-content {
  632. display: flex;
  633. align-items: center;
  634. gap: 4px;
  635. font-size: 14px;
  636. font-family: "PangMenZhengDao";
  637. color: #fff;
  638. line-height: 30px;
  639. padding: 0 12px;
  640. border-radius: 20px 0 0 20px;
  641. height: 30px;
  642. cursor: pointer;
  643. background: #2199F8;
  644. position: relative;
  645. &::after {
  646. content: '';
  647. position: absolute;
  648. bottom: -6px;
  649. right: 0;
  650. width: 0px;
  651. height: 0px;
  652. border-right: 3px solid transparent;
  653. border-top: 3px solid #75a8cd;
  654. border-left: 3px solid #75a8cd;
  655. border-bottom: 3px solid transparent;
  656. }
  657. }
  658. }
  659. }
  660. .fake-report-wrap {
  661. width: 100%;
  662. .no-report-img {
  663. width: 100%;
  664. }
  665. .fake-img {
  666. position: relative;
  667. .fake-img-item {
  668. width: 100%;
  669. }
  670. }
  671. }
  672. .report-content-wrap {
  673. height: 100%;
  674. // padding-bottom: 60px;
  675. overflow: auto;
  676. box-sizing: border-box;
  677. position: relative;
  678. .history-risk-report-btn {
  679. position: absolute;
  680. right: 0px;
  681. // top: 155px;
  682. top: 120px;
  683. z-index: 13;
  684. height: 26px;
  685. padding: 0 10px 0 8px;
  686. display: inline-flex;
  687. align-items: center;
  688. gap: 4px;
  689. color: #ffffff;
  690. font-size: 14px;
  691. border-radius: 13px 0 0 13px;
  692. background: linear-gradient(180deg, #60c2ff 0%, #2199f8 100%);
  693. box-shadow: 0 2px 6px rgba(33, 153, 248, 0.3);
  694. cursor: pointer;
  695. .risk-report-icon {
  696. width: 14px;
  697. height: 14px;
  698. border-radius: 2px;
  699. background: #ffffff;
  700. position: relative;
  701. display: inline-flex;
  702. align-items: center;
  703. justify-content: center;
  704. transform: rotate(-12deg);
  705. i {
  706. width: 8px;
  707. height: 2px;
  708. border-radius: 2px;
  709. background: #42a7ff;
  710. box-shadow: 0 3px 0 #42a7ff;
  711. }
  712. }
  713. .risk-report-text {
  714. line-height: 1;
  715. white-space: nowrap;
  716. }
  717. }
  718. .bottom-btn {
  719. z-index: 2;
  720. position: fixed;
  721. bottom: 0;
  722. left: 0;
  723. width: 100%;
  724. background: #fff;
  725. height: 60px;
  726. display: flex;
  727. align-items: center;
  728. justify-content: space-between;
  729. padding: 0 12px;
  730. box-sizing: border-box;
  731. box-shadow: 2px 2px 4.5px 0px rgba(0, 0, 0, 0.4);
  732. .btn-item {
  733. height: 40px;
  734. line-height: 40px;
  735. padding: 0 24px;
  736. border-radius: 20px;
  737. font-size: 14px;
  738. &.second {
  739. color: #666666;
  740. border: 1px solid rgba(153, 153, 153, 0.5);
  741. }
  742. &.primay {
  743. padding: 0 34px;
  744. background: linear-gradient(180deg, #76c3ff, #2199f8);
  745. color: #fff;
  746. }
  747. }
  748. }
  749. }
  750. .code-icon {
  751. position: absolute;
  752. right: 10px;
  753. top: 12px;
  754. width: 48px;
  755. }
  756. .report-content {
  757. // background: url("@/assets/img/home/report_bg.png") no-repeat center center;
  758. // background: linear-gradient(0deg, #9BCCFF, #9BCCFF),
  759. // linear-gradient(160deg, rgba(255, 255, 255, 0.16) 30%, rgba(255, 255, 255, 0) 72%);
  760. background: #abd4ff;
  761. background-size: 100% auto;
  762. background-position: top center;
  763. padding: 0 10px 26px 10px;
  764. box-sizing: border-box;
  765. position: relative;
  766. &.has-report {
  767. min-height: 100%;
  768. background: linear-gradient(0deg, #9BCCFF, #9BCCFF),
  769. linear-gradient(156.64deg, rgba(255, 255, 255, 0.16) 27.7%, rgba(255, 255, 255, 0) 72.82%);
  770. }
  771. .lock-bg {
  772. position: absolute;
  773. top: 230px;
  774. left: 0;
  775. width: 100%;
  776. height: calc(100% - 230px);
  777. background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.38) 50%, rgba(255, 255, 255, 0) 100%),
  778. linear-gradient(0deg, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2));
  779. }
  780. .lock-img {
  781. pointer-events: none;
  782. position: fixed;
  783. z-index: 10;
  784. top: 50%;
  785. left: 50%;
  786. transform: translate(-50%, -20%);
  787. width: 100%;
  788. display: flex;
  789. align-items: center;
  790. justify-content: center;
  791. flex-direction: column;
  792. gap: 16px;
  793. .lock-img-item {
  794. width: 57px;
  795. }
  796. .has-click {
  797. pointer-events: auto;
  798. }
  799. .lock-text {
  800. font-size: 14px;
  801. color: #000;
  802. padding: 5px 64px;
  803. line-height: 21px;
  804. background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, #FFFFFF 50%, rgba(255, 255, 255, 0) 100%);
  805. }
  806. .lock-btn {
  807. width: 140px;
  808. height: 40px;
  809. line-height: 40px;
  810. text-align: center;
  811. background: linear-gradient(180deg, #76C3FF 0%, #2199F8 100%);
  812. border-radius: 25px;
  813. color: #fff;
  814. font-size: 16px;
  815. }
  816. }
  817. .header-img {
  818. position: absolute;
  819. top: 0;
  820. left: 0;
  821. width: 100%;
  822. }
  823. .type-tabs {
  824. background: rgba(255, 255, 255, 0.8);
  825. display: flex;
  826. align-items: center;
  827. flex-wrap: wrap;
  828. gap: 8px;
  829. width: fit-content;
  830. border-radius: 5px;
  831. padding: 5px;
  832. margin-bottom: 22px;
  833. &.report-tabs {
  834. padding: 0 5px;
  835. height: 38px;
  836. background: none;
  837. margin-bottom: 6px;
  838. .type-item {
  839. height: 34px;
  840. line-height: 34px;
  841. font-size: 14px;
  842. color: #858585;
  843. }
  844. }
  845. .type-item {
  846. height: 28px;
  847. line-height: 28px;
  848. text-align: center;
  849. padding: 0 6px;
  850. min-width: 80px;
  851. color: #9A9A9A;
  852. background: #FFFFFF;
  853. box-sizing: border-box;
  854. border-radius: 2px;
  855. &.type-item-active {
  856. background: #2199F8;
  857. color: #fff;
  858. }
  859. }
  860. }
  861. .subject-toggle {
  862. margin-top: 4px;
  863. margin-bottom: 5px;
  864. font-size: 14px;
  865. color: rgba(0, 0, 0, 0.6);
  866. width: 100%;
  867. cursor: pointer;
  868. text-align: center;
  869. }
  870. .report-header {
  871. position: relative;
  872. // padding-top: 148px;
  873. padding-top: 120px;
  874. &.no-farm {
  875. padding-top: 102px;
  876. }
  877. .header-book {
  878. position: absolute;
  879. right: 0;
  880. bottom: -6px;
  881. height: 88px;
  882. z-index: 10;
  883. }
  884. .time-tag {
  885. background: #2199F8;
  886. border-radius: 5px 0 5px 0;
  887. height: 23px;
  888. line-height: 23px;
  889. font-size: 13px;
  890. font-weight: 500;
  891. color: #fff;
  892. padding: 0 9px;
  893. width: fit-content;
  894. margin-bottom: 4px;
  895. }
  896. .report-title {
  897. font-family: "PangMenZhengDao";
  898. font-size: 34px;
  899. line-height: 38px;
  900. &.report-title-toggle {
  901. cursor: pointer;
  902. user-select: none;
  903. }
  904. color: #000000;
  905. }
  906. .report-info {
  907. padding: 12px 0 28px 0;
  908. &.pb-4 {
  909. padding-bottom: 4px;
  910. }
  911. .info-item {
  912. width: fit-content;
  913. display: flex;
  914. height: 33px;
  915. align-items: center;
  916. padding: 0 18px 0 6px;
  917. background: rgba(255, 255, 255, 0.58);
  918. backdrop-filter: blur(5px);
  919. border-radius: 20px;
  920. gap: 6px;
  921. .info-icon {
  922. width: 26px;
  923. height: 26px;
  924. object-fit: cover;
  925. border-radius: 50%;
  926. }
  927. .info-text {
  928. font-size: 14px;
  929. color: #000;
  930. }
  931. }
  932. .info-item+.info-item {
  933. margin-top: 5px;
  934. }
  935. }
  936. // 左滑查看更多标签
  937. .swipe-more-tag {
  938. position: absolute;
  939. bottom: 10px;
  940. right: -16px;
  941. box-sizing: border-box;
  942. width: 36px;
  943. height: 86px;
  944. // padding: 0px 10px 2px 0;
  945. background: rgba(0, 0, 0, 0.7);
  946. border-radius: 10px 0 0 10px;
  947. letter-spacing: 2px;
  948. color: #ffffff;
  949. font-size: 12px;
  950. text-align: center;
  951. line-height: 14px;
  952. writing-mode: vertical-rl;
  953. text-orientation: mixed;
  954. padding-right: 5px;
  955. }
  956. }
  957. .report-box {
  958. display: flex;
  959. align-items: center;
  960. padding: 8px 12px;
  961. // background: linear-gradient(0deg, #ffffff 86%, #2199f8 136%);
  962. background: #fff;
  963. border: 1px solid #ffffff;
  964. border-radius: 8px;
  965. gap: 5px;
  966. position: relative;
  967. &.warning-bg {
  968. background: linear-gradient(0deg, #FFFFFF 86%, #FF9B48 136%);
  969. }
  970. .report-box-item {
  971. flex: 1;
  972. background: rgba(33, 153, 248, 0.1);
  973. border-radius: 8px;
  974. min-height: 62px;
  975. box-sizing: border-box;
  976. padding: 2px 4px;
  977. display: flex;
  978. flex-direction: column;
  979. justify-content: center;
  980. .item-content {
  981. color: #2199f8;
  982. font-size: 14px;
  983. text-align: center;
  984. }
  985. .item-title {
  986. color: #000000;
  987. font-size: 10px;
  988. text-align: center;
  989. padding-top: 5px;
  990. }
  991. }
  992. .box-title {
  993. position: absolute;
  994. top: -8px;
  995. left: -1px;
  996. height: 32px;
  997. line-height: 26px;
  998. font-family: "PangMenZhengDao";
  999. font-size: 14px;
  1000. padding: 0 10px;
  1001. color: #ffffff;
  1002. background: url("@/assets/img/home/title-bg.png") no-repeat center center / 100% 100%;
  1003. &.warning {
  1004. background: url("@/assets/img/home/title-bg-warning.png") no-repeat center center / 100% 100%;
  1005. }
  1006. }
  1007. .w-100 {
  1008. width: 100%;
  1009. }
  1010. .box-text {
  1011. padding: 22px 0 8px 0;
  1012. font-weight: 350;
  1013. line-height: 21px;
  1014. width: 100%;
  1015. box-sizing: border-box;
  1016. .pre-text {
  1017. white-space: pre-line;
  1018. word-break: break-word;
  1019. }
  1020. .box-subtitle {
  1021. color: #000;
  1022. }
  1023. .box-bg {
  1024. font-weight: 400;
  1025. color: rgba(0, 0, 0, 0.5);
  1026. margin-bottom: 8px;
  1027. }
  1028. .types-info {
  1029. background: rgba(33, 153, 248, 0.1);
  1030. color: #000000;
  1031. padding: 6px;
  1032. border-radius: 5px;
  1033. .text-bold {
  1034. font-weight: bold;
  1035. }
  1036. }
  1037. .tp-img {
  1038. display: grid;
  1039. grid-template-columns: repeat(3, 1fr);
  1040. gap: 6px;
  1041. width: 100%;
  1042. margin-top: 8px;
  1043. box-sizing: border-box;
  1044. img {
  1045. width: 100%;
  1046. height: 78px;
  1047. object-fit: contain;
  1048. }
  1049. }
  1050. .text-link {
  1051. color: #2199F8;
  1052. text-decoration: underline;
  1053. }
  1054. .report-part {
  1055. color: rgba(0, 0, 0, 0.5);
  1056. .part-title {
  1057. background: #2199F8;
  1058. height: 24px;
  1059. line-height: 24px;
  1060. padding: 0 8px;
  1061. color: #fff;
  1062. border-radius: 2px;
  1063. width: fit-content;
  1064. }
  1065. .part-text {
  1066. padding-top: 6px;
  1067. :deep(.text-bold) {
  1068. font-weight: bold;
  1069. }
  1070. }
  1071. .part-top {
  1072. display: flex;
  1073. align-items: center;
  1074. justify-content: space-between;
  1075. .part-link {
  1076. display: inline-flex;
  1077. align-items: center;
  1078. gap: 4px;
  1079. color: #2199F8;
  1080. .part-link-icon {
  1081. transform: rotate(270deg);
  1082. }
  1083. }
  1084. }
  1085. }
  1086. .warning-part + .warning-part {
  1087. margin-top: 8px;
  1088. }
  1089. .report-part + .report-part {
  1090. margin-top: 8px;
  1091. }
  1092. .warning-part {
  1093. background: rgba(178, 178, 178, 0.08);
  1094. border-radius: 5px;
  1095. padding: 11px 6px 6px;
  1096. color: rgba(0, 0, 0, 0.5);
  1097. width: 100%;
  1098. box-sizing: border-box;
  1099. .warning-title {
  1100. display: flex;
  1101. align-items: center;
  1102. justify-content: center;
  1103. gap: 10px;
  1104. padding-bottom: 13px;
  1105. .title-l {
  1106. display: flex;
  1107. align-items: center;
  1108. .title-line {
  1109. width: 68px;
  1110. height: 1px;
  1111. background: linear-gradient(90deg, rgba(118, 118, 118, 0) 0%, rgba(118, 118, 118, 0.4) 100%);
  1112. &.title-line-right {
  1113. background: linear-gradient(270deg, rgba(118, 118, 118, 0) 0%, rgba(118, 118, 118, 0.4) 100%);
  1114. }
  1115. }
  1116. .title-block {
  1117. width: 6px;
  1118. height: 6px;
  1119. background: rgba(61, 61, 61, 0.2);
  1120. transform: rotate(45deg);
  1121. }
  1122. }
  1123. }
  1124. }
  1125. .box-advice {
  1126. color: rgba(0, 0, 0, 0.5);
  1127. padding-top: 10px;
  1128. }
  1129. .box-sum {
  1130. margin-top: 10px;
  1131. background: rgba(33, 153, 248, 0.1);
  1132. border-radius: 5px;
  1133. padding: 10px;
  1134. line-height: 20px;
  1135. color: #2199F8;
  1136. }
  1137. &.next-info {
  1138. padding: 8px 0 8px 0;
  1139. }
  1140. }
  1141. .row {
  1142. display: grid;
  1143. grid-template-columns: repeat(3, 1fr);
  1144. gap: 6px;
  1145. .status-card {
  1146. border-radius: 2px;
  1147. padding: 7px 0;
  1148. background: #ffffff;
  1149. border: 0.5px solid #e5e6eb;
  1150. color: #000;
  1151. display: flex;
  1152. flex-direction: column;
  1153. align-items: center;
  1154. justify-content: center;
  1155. &.today-red {
  1156. background: #FF6A6A;
  1157. color: #fff;
  1158. .status-sub {
  1159. color: #fff;
  1160. }
  1161. }
  1162. &.pending-card {
  1163. color: #fff;
  1164. position: relative;
  1165. padding: 9px 0 7px 0;
  1166. .tag-name {
  1167. position: absolute;
  1168. top: -8px;
  1169. right: 0;
  1170. background: #fff;
  1171. color: #FF6A6A;
  1172. font-size: 10px;
  1173. height: 17px;
  1174. line-height: 17px;
  1175. padding: 0 3px;
  1176. border-radius: 2px;
  1177. box-sizing: border-box;
  1178. border: 0.5px solid #FF6A6A;
  1179. }
  1180. }
  1181. .status-badge {
  1182. // position: absolute;
  1183. // top: 0;
  1184. // right: 0;
  1185. }
  1186. .status-title {
  1187. font-size: 16px;
  1188. line-height: 24px;
  1189. &.status-title-small {
  1190. font-size: 13px;
  1191. line-height: 18px;
  1192. }
  1193. }
  1194. .status-sub {
  1195. font-size: 10px;
  1196. color: rgba(32, 32, 32, 0.4);
  1197. line-height: 15px;
  1198. &.pending-sub {
  1199. color: #fff;
  1200. line-height: 13px;
  1201. }
  1202. }
  1203. &.risk-strong {
  1204. background: #FF6A6A;
  1205. border-color: #FF6A6A;
  1206. .status-title,
  1207. .status-sub {
  1208. color: #ffffff;
  1209. }
  1210. }
  1211. &.danger {
  1212. background: #FFE9E9;
  1213. border-color: #ff8e8e;
  1214. .status-sub {
  1215. color: #FF6A6A;
  1216. }
  1217. }
  1218. }
  1219. }
  1220. }
  1221. .report-box+.report-box {
  1222. margin-top: 20px;
  1223. }
  1224. .report-excute {
  1225. position: relative;
  1226. margin-top: 12px;
  1227. .tag-label {
  1228. position: absolute;
  1229. top: 0;
  1230. left: 0;
  1231. padding: 4px 10px;
  1232. background: rgba(54, 52, 52, 0.8);
  1233. color: #fff;
  1234. font-size: 12px;
  1235. border-radius: 8px 0 8px 0;
  1236. z-index: 1;
  1237. }
  1238. ::v-deep {
  1239. .carousel-container .carousel-wrapper .carousel-img {
  1240. min-width: calc(100vw - 32px);
  1241. width: calc(100vw - 32px);
  1242. }
  1243. }
  1244. }
  1245. }
  1246. .download-btn {
  1247. position: fixed;
  1248. bottom: 20px;
  1249. left: 50%;
  1250. // background: #fff;
  1251. // box-shadow: 2px 2px 4.5px 0px #00000066;
  1252. // width: 100%;
  1253. transform: translateX(-50%);
  1254. }
  1255. .review-hide-box {
  1256. position: absolute;
  1257. left: 0;
  1258. width: 100%;
  1259. height: 100%;
  1260. z-index: -1;
  1261. bottom: 0;
  1262. }
  1263. .review-image {
  1264. position: relative;
  1265. display: flex;
  1266. align-items: center;
  1267. justify-content: center;
  1268. gap: 8px;
  1269. margin: 12px;
  1270. background: #fff;
  1271. border-radius: 8px;
  1272. .review-mask {
  1273. z-index: 1;
  1274. pointer-events: none;
  1275. position: absolute;
  1276. left: 0;
  1277. top: 0;
  1278. width: 100%;
  1279. height: 100%;
  1280. border-radius: 8px;
  1281. background: linear-gradient(360deg,
  1282. rgba(0, 0, 0, 0.78) 0%,
  1283. rgba(0, 0, 0, 0.437208) 19.87%,
  1284. rgba(0, 0, 0, 0) 33.99%);
  1285. display: flex;
  1286. flex-direction: column;
  1287. align-items: baseline;
  1288. justify-content: end;
  1289. padding: 12px;
  1290. box-sizing: border-box;
  1291. color: #fff;
  1292. .review-text {
  1293. font-family: "PangMenZhengDao";
  1294. font-size: 16px;
  1295. margin-bottom: 1px;
  1296. }
  1297. .review-content {
  1298. font-size: 10px;
  1299. line-height: 15px;
  1300. }
  1301. }
  1302. .vs-wrap {
  1303. position: absolute;
  1304. left: 50%;
  1305. top: 50%;
  1306. transform: translate(-50%, -50%);
  1307. width: 40px;
  1308. height: 40px;
  1309. z-index: 10;
  1310. img {
  1311. width: 100%;
  1312. height: 100%;
  1313. object-fit: cover;
  1314. }
  1315. }
  1316. .review-image-item {
  1317. position: relative;
  1318. flex: 1;
  1319. .review-image-item-title {
  1320. position: absolute;
  1321. top: 0;
  1322. left: 0;
  1323. background: rgba(54, 52, 52, 0.6);
  1324. padding: 4px 10px;
  1325. border-radius: 8px 0 8px 0;
  1326. backdrop-filter: 4px;
  1327. font-size: 12px;
  1328. color: #fff;
  1329. }
  1330. // .review-image-item-img {
  1331. // width: 100%;
  1332. // height: 250px;
  1333. // object-fit: cover;
  1334. // }
  1335. .review-image-item-img {
  1336. width: 100%;
  1337. height: 100%;
  1338. object-fit: cover;
  1339. object-position: center;
  1340. }
  1341. .left-img {
  1342. border-radius: 8px 0 0 8px;
  1343. }
  1344. .right-img {
  1345. border-radius: 0 8px 8px 0;
  1346. }
  1347. }
  1348. }
  1349. }
  1350. .cavans-popup {
  1351. width: 100%;
  1352. max-width: 100%;
  1353. max-height: 92vh;
  1354. background: none;
  1355. border-radius: 12px;
  1356. overflow: auto;
  1357. display: flex;
  1358. flex-direction: column;
  1359. backdrop-filter: 4px;
  1360. .cavans-content {
  1361. text-align: center;
  1362. padding: 0 12px;
  1363. height: fit-content;
  1364. overflow: auto;
  1365. .current-img {
  1366. width: 100%;
  1367. }
  1368. }
  1369. // 底部操作按钮
  1370. .bottom-actions {
  1371. flex-shrink: 0;
  1372. .action-buttons {
  1373. padding: 12px 0 4px 0;
  1374. display: flex;
  1375. justify-content: space-around;
  1376. .action-btn {
  1377. display: flex;
  1378. flex-direction: column;
  1379. align-items: center;
  1380. cursor: pointer;
  1381. &.text-btn {
  1382. font-size: 12px;
  1383. color: rgba(255, 255, 255, 0.7);
  1384. }
  1385. .icon-circle {
  1386. width: 48px;
  1387. height: 48px;
  1388. border-radius: 50%;
  1389. display: flex;
  1390. align-items: center;
  1391. justify-content: center;
  1392. color: #fff;
  1393. margin-bottom: 4px;
  1394. .el-icon {
  1395. color: #fff;
  1396. }
  1397. img {
  1398. width: 50px;
  1399. }
  1400. }
  1401. &.blue-btn .icon-circle {
  1402. background: #2199f8;
  1403. }
  1404. &.green-btn .icon-circle {
  1405. background: #07c160;
  1406. }
  1407. &.orange-btn .icon-circle {
  1408. background: #ff790b;
  1409. }
  1410. .btn-label {
  1411. font-size: 12px;
  1412. color: #fff;
  1413. }
  1414. }
  1415. }
  1416. .cancel-btn {
  1417. text-align: center;
  1418. font-size: 18px;
  1419. color: #fff;
  1420. cursor: pointer;
  1421. }
  1422. }
  1423. }
  1424. </style>