index.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869
  1. <template>
  2. <div class="work-detail">
  3. <custom-header name="农事详情" :showClose="false" isGoBack @goback="handleBack" />
  4. <div class="work-detail-content">
  5. <!-- 顶部状态 -->
  6. <div class="content-status" :class="'status-' + detail?.flowStatus">
  7. <div class="status-l">
  8. <div class="status-title">{{ handleTagType(detail?.flowStatus) }}</div>
  9. <div class="status-sub" v-if="triggerDateText && detail?.flowStatus === 0">
  10. 执行时间已经过去 {{ daysDiff }} 天了
  11. </div>
  12. <div class="status-sub" v-if="detail?.flowStatus === 1">
  13. 距离执行时间还差 {{ daysDiff }} 天
  14. </div>
  15. <div class="status-sub" v-if="!detail?.flowStatus || detail?.flowStatus === 2">
  16. 预计触发时间 {{ detail?.activateTime ? formatDate(detail.activateTime) : "--" }}
  17. </div>
  18. </div>
  19. </div>
  20. <div class="work-wrap">
  21. <!-- 农事组信息 -->
  22. <div class="box-wrap group-info group-box">
  23. <div class="group-name">
  24. 该农事为 <span class="light-text">限时溯源农事</span> ,请在 <span class="light-text">3天内</span>
  25. 完成溯源认证上传,如果逾期未认证,该农事将不可溯源认证,且不计入飞鸟有味平台
  26. </div>
  27. </div>
  28. <!-- 每一段农事 -->
  29. <div v-for="(prescription, index) in stageList" :key="index" class="box-wrap stage-card">
  30. <div class="work-info">
  31. <div class="stage-header">
  32. <div class="stage-title">{{ detail.farmWorkName }}</div>
  33. </div>
  34. <div class="stage-info">
  35. <div class="form-item">
  36. <div class="item-name">农事目的</div>
  37. <div class="item-text">
  38. {{ detail.purpose || prescription.name || "--" }}
  39. </div>
  40. </div>
  41. <div class="form-item">
  42. <div class="item-name">农事时间</div>
  43. <div class="item-text">
  44. {{ detail.intervelTime ? `间隔 ${detail.intervelTime} 天后 执行` : "--" }}
  45. </div>
  46. </div>
  47. <div class="form-item">
  48. <div class="item-name">执行区域</div>
  49. <div class="item-text light-text area-text">
  50. 桂味种植区域
  51. <!-- <div class="area-btn" @click="handleViewArea">查看区域</div> -->
  52. <div class="area-btn area-btn-right" @click="toDraw">建议勾选<el-icon><ArrowRight /></el-icon></div>
  53. </div>
  54. </div>
  55. <div class="form-item">
  56. <div class="item-name">注意事项</div>
  57. <div class="item-text">
  58. {{ detail.remark || "--" }}
  59. </div>
  60. </div>
  61. <div class="form-item">
  62. <div class="item-name">药肥处方</div>
  63. </div>
  64. </div>
  65. <!-- 执行方式 -->
  66. <div class="stage-tabs">
  67. <div v-for="tab in executionTabs" :key="tab.value" class="tab-pill"
  68. :class="{ active: getStageExecutionMethod(index) === tab.value }"
  69. @click="changeExecutionMethod(index, tab.value)">
  70. {{ tab.label }}
  71. </div>
  72. </div>
  73. <!-- 药物处方表 -->
  74. <div class="prescription-wrap"
  75. v-if="prescription.pesticideList && prescription.pesticideList.length">
  76. <div class="prescription-table">
  77. <div class="table-header">
  78. <div class="col col-type">使用功效</div>
  79. <div class="col col-name">药肥名称</div>
  80. <div class="col col-ratio">药肥配比</div>
  81. </div>
  82. <div v-for="(item, i) in prescription.pesticideList" :key="i" class="table-row">
  83. <div class="col col-type">
  84. {{ item.typeName || "--" }}
  85. </div>
  86. <div class="col col-name">
  87. {{ item.name || item.pesticideFertilizerName || "--" }}
  88. </div>
  89. <div class="col col-ratio">
  90. {{ getPesticideParam(item, index)?.ratio || "--" }}倍
  91. </div>
  92. </div>
  93. </div>
  94. <div v-if="hasRemark(prescription, index)" class="prescription-remark">
  95. <span v-for="(item, idx) in [prescription.pesticideList[0]]" :key="idx">
  96. <template v-if="getParamRemark(item, index)">
  97. {{ getParamRemark(item, index) }}
  98. <br />
  99. </template>
  100. </span>
  101. </div>
  102. </div>
  103. </div>
  104. <!-- 农事凭证 -->
  105. <div class="work-info photo-box" v-if="prescription.cropAlbum && prescription.cropAlbum.length">
  106. <div class="photo-title">农事凭证</div>
  107. <div class="photo-sub-title" v-if="info?.appType === 1">来自于 某某某农资机构</div>
  108. <div class="photo-img-wrap">
  109. <photo-provider :photo-closable="true">
  110. <photo-consumer v-for="(src, index) in prescription.cropAlbum" intro="农事凭证" :key="index"
  111. :src="base_img_url2 + src.filename">
  112. <div class="photo-img">
  113. <img :src="base_img_url2 + src.filename" />
  114. </div>
  115. </photo-consumer>
  116. </photo-provider>
  117. </div>
  118. </div>
  119. </div>
  120. <!-- 底部按钮 -->
  121. <div class="fixed-btn-wrap center-btn" v-if="info?.appType === 2">
  122. <div class="fixed-btn" @click="handleConvert">
  123. 转发农事
  124. </div>
  125. </div>
  126. <div class="fixed-btn-wrap execute-action" v-if="info?.appType === 1 && detail?.flowStatus === 1">
  127. <div class="action-item second" @click="handleConvert">转发农事</div>
  128. <div class="action-item primary" @click="handleExecute">溯源认证</div>
  129. </div>
  130. </div>
  131. </div>
  132. <ExecutePopup ref="executePopupRef" />
  133. <upload-tips v-model:show="showUploadTipsPopup" />
  134. </div>
  135. <!-- 执行区域地图弹窗 -->
  136. <popup v-model:show="showMapPopup" closeable class="map-popup">
  137. <map-info :farmId="detail.farmId" />
  138. </popup>
  139. </template>
  140. <script setup>
  141. import wx from "weixin-js-sdk";
  142. import customHeader from "@/components/customHeader.vue";
  143. import { ref, computed, onMounted, onActivated } from "vue";
  144. import { useRouter } from "vue-router";
  145. import { formatDate } from "@/common/commonFun";
  146. import ExecutePopup from "./components/executePopup.vue";
  147. import { base_img_url2 } from "@/api/config";
  148. import UploadTips from "@/components/popup/uploadTips.vue";
  149. import { Popup } from "vant";
  150. import MapInfo from "./components/mapInfo.vue";
  151. import { useRoute } from "vue-router";
  152. const route = useRoute();
  153. const showUploadTipsPopup = ref(false);
  154. const router = useRouter();
  155. // const info = JSON.parse(localStorage.getItem("localUserInfo") || "{}");
  156. const info = { appType: 1 };
  157. /** 接口根级与 detail 合并后的详情(兼容旧 groupList / 新 pesticideList、prescriptionList) */
  158. const detail = ref({
  159. farmId: null,
  160. farmWorkLibId: null,
  161. farmWorkName: "",
  162. flowStatus: null,
  163. purpose: "",
  164. speciesId: null,
  165. speciesName: "",
  166. executeDate: null,
  167. intervelTime: null,
  168. remark: "",
  169. pesticideList: [],
  170. prescriptionList: [],
  171. groupList: [],
  172. confirmPicture: [],
  173. executeEvidence: [],
  174. expertName: "",
  175. expertPrescription: "",
  176. id: null,
  177. postId: null,
  178. post: null,
  179. expertNameFromFarmBasicInfo: "",
  180. rangeWkt: null,
  181. activateTime: null,
  182. });
  183. /** 凭证图片统一为 { filename } */
  184. const normalizeCropAlbum = (album) => {
  185. if (!album || !Array.isArray(album)) return [];
  186. return album
  187. .map((x) => {
  188. if (!x) return null;
  189. if (typeof x === "string") return { filename: x };
  190. if (x.filename) return x;
  191. return null;
  192. })
  193. .filter(Boolean);
  194. };
  195. /**
  196. * prescriptionList.pesticideFertilizerList → 与旧 groupList.pesticideList 一致(含 params 三行执行方式)
  197. */
  198. const mapFertilizerToPesticideItem = (f) => {
  199. if (!f || typeof f !== "object") return null;
  200. return {
  201. code: f.pesticideFertilizerCode || f.code,
  202. name: f.pesticideFertilizerName || f.defaultName || f.name || "",
  203. typeName: f.typeName || "",
  204. brand: f.brand || "",
  205. unit: f.unit,
  206. params: [
  207. {
  208. dosage:
  209. f.muUsage != null && f.muUsage !== ""
  210. ? String(f.muUsage)
  211. : "",
  212. executionMethod: 1,
  213. ratio:
  214. f.ratio != null && f.ratio !== "" ? String(f.ratio) : "",
  215. remark: f.remark || "",
  216. },
  217. {
  218. dosage:
  219. f.muUsage2 != null && f.muUsage2 !== ""
  220. ? String(f.muUsage2)
  221. : "",
  222. executionMethod: 2,
  223. ratio:
  224. f.ratio2 != null && f.ratio2 !== ""
  225. ? String(f.ratio2)
  226. : "",
  227. remark: "",
  228. },
  229. { dosage: "", executionMethod: 3, ratio: "", remark: "" },
  230. ],
  231. };
  232. };
  233. const maybeShowUploadTips = () => {
  234. if (detail.value?.flowStatus !== 1) return;
  235. const shown = localStorage.getItem('upload_tips');
  236. if (shown === "1") return;
  237. localStorage.setItem('upload_tips', "1");
  238. showUploadTipsPopup.value = true;
  239. };
  240. onMounted(() => {
  241. maybeShowUploadTips();
  242. });
  243. onActivated(() => {
  244. getDetail();
  245. });
  246. const getDetail = () => {
  247. const { farmWorkLibId, farmId } = route.query;
  248. VE_API.z_farm_work_record
  249. .getDetailById({ farmWorkLibId, farmId })
  250. .then(({ data }) => {
  251. const inner =
  252. data?.detail && typeof data.detail === "object"
  253. ? { ...data.detail }
  254. : {};
  255. detail.value = {
  256. ...inner,
  257. post: data?.post ?? null,
  258. expertNameFromFarmBasicInfo:
  259. data?.expertNameFromFarmBasicInfo ?? "",
  260. rangeWkt: data?.rangeWkt ?? null,
  261. activateTime: data?.activateTime ?? null,
  262. };
  263. });
  264. };
  265. // 计算距离执行时间的天数差
  266. const daysDiff = computed(() => {
  267. if (!detail.value?.executeDate) {
  268. return 0;
  269. }
  270. const executeDate = new Date(detail.value.executeDate);
  271. const today = new Date();
  272. // 将时间设置为 00:00:00,只比较日期
  273. executeDate.setHours(0, 0, 0, 0);
  274. today.setHours(0, 0, 0, 0);
  275. // 计算天数差(毫秒转天数)
  276. const diffTime = executeDate.getTime() - today.getTime();
  277. const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));
  278. return diffDays;
  279. });
  280. // 执行方式 Tab 配置
  281. const executionTabs = [
  282. { label: "植保机", value: 1 },
  283. { label: "人工手持", value: 2 },
  284. { label: "地面机械", value: 3 }
  285. ];
  286. // 每一段农事的当前执行方式(索引 -> 执行方式),默认 1:植保机
  287. const stageExecutionMethods = ref({});
  288. const executePopupRef = ref(null);
  289. const triggerDateText = computed(() => {
  290. if (!detail.value.executeDate) return "";
  291. const d = formatDate(detail.value.executeDate);
  292. return d.replace(/-/g, ".");
  293. });
  294. /**
  295. * 展示用「分段」列表:旧数据用 groupList;新接口用 detail.pesticideList 或 prescriptionList 推导
  296. */
  297. const stageList = computed(() => {
  298. const d = detail.value;
  299. if (!d) return [];
  300. if (Array.isArray(d.groupList) && d.groupList.length) {
  301. return d.groupList;
  302. }
  303. if (Array.isArray(d.pesticideList) && d.pesticideList.length) {
  304. return [
  305. {
  306. name: d.farmWorkName || "",
  307. pesticideList: d.pesticideList,
  308. cropAlbum: normalizeCropAlbum(
  309. d.confirmPicture?.length
  310. ? d.confirmPicture
  311. : d.executeEvidence
  312. ),
  313. },
  314. ];
  315. }
  316. if (Array.isArray(d.prescriptionList) && d.prescriptionList.length) {
  317. return d.prescriptionList.map((p) => ({
  318. name: p.name || "",
  319. pesticideList: (p.pesticideFertilizerList || [])
  320. .map(mapFertilizerToPesticideItem)
  321. .filter(Boolean),
  322. cropAlbum: normalizeCropAlbum(p.cropAlbum),
  323. }));
  324. }
  325. return [];
  326. });
  327. const hasRemark = (prescription, stageIndex) => {
  328. if (!prescription?.pesticideList || !Array.isArray(prescription.pesticideList)) return false;
  329. const currentMethod = getStageExecutionMethod(stageIndex);
  330. return prescription.pesticideList.some((item) => {
  331. if (!item.params || !Array.isArray(item.params)) return false;
  332. const p = item.params.find((param) => param.executionMethod === currentMethod);
  333. return !!(p && p.remark);
  334. });
  335. };
  336. const handleTagType = (tagType) => {
  337. if (tagType === 0) return "已过期";
  338. if (tagType === 1) return "待认证";
  339. if (tagType === 2) return "待触发";
  340. if (tagType === 3) return "已完成";
  341. return "待触发"
  342. }
  343. const handleExecute = () => {
  344. // wx.miniProgram.navigateTo({
  345. // url: `/pages/subPages/location_check/index?lng=113.264435&lat=23.129163`,
  346. // });
  347. executePopupRef.value.openPopup();
  348. };
  349. const showMapPopup = ref(false);
  350. const handleViewArea = () => {
  351. showMapPopup.value = true;
  352. }
  353. const toDraw = () => {
  354. router.push("/draw_region");
  355. }
  356. const handleBack = () => {
  357. router.back();
  358. };
  359. const handleConvert = () => {
  360. const query = {
  361. askInfo: { title: "农情互动", content: "是否分享该互动给好友" },
  362. shareText: '邀请您农情互动,精准匹配种植方案',
  363. targetUrl: `work_detail`,
  364. paramsPage: JSON.stringify({ id: detail.value.id }),
  365. imageUrl: 'https://birdseye-img.sysuimars.com/birdseye-look-mini/work_img.png',
  366. };
  367. wx.miniProgram.navigateTo({
  368. url: `/pages/subPages/share_page/index?pageParams=${JSON.stringify(query)}&type=sharePage`,
  369. });
  370. };
  371. // 获取当前段的执行方式
  372. const getStageExecutionMethod = (stageIndex) => {
  373. const val = stageExecutionMethods.value[stageIndex];
  374. return val || 1;
  375. };
  376. // 根据当前执行方式,获取对应的参数(配比、单亩用量、备注)
  377. const getPesticideParam = (item, stageIndex) => {
  378. if (!item?.params || !Array.isArray(item.params)) return null;
  379. const currentMethod = getStageExecutionMethod(stageIndex);
  380. return (
  381. item.params.find((param) => param.executionMethod === currentMethod) || null
  382. );
  383. };
  384. const getParamRemark = (item, stageIndex) => {
  385. const param = getPesticideParam(item, stageIndex);
  386. return param?.remark || item.remark || "";
  387. };
  388. const changeExecutionMethod = (stageIndex, value) => {
  389. stageExecutionMethods.value = {
  390. ...stageExecutionMethods.value,
  391. [stageIndex]: value
  392. };
  393. };
  394. </script>
  395. <style scoped lang="scss">
  396. .work-detail {
  397. height: 100vh;
  398. background: #f2f3f5;
  399. display: flex;
  400. flex-direction: column;
  401. .work-detail-content {
  402. flex: 1;
  403. overflow: auto;
  404. }
  405. }
  406. .content-status {
  407. position: relative;
  408. padding: 16px 12px 0 12px;
  409. color: #fff;
  410. z-index: 1;
  411. height: 100px;
  412. box-sizing: border-box;
  413. &::after {
  414. content: "";
  415. z-index: -1;
  416. position: absolute;
  417. left: 0;
  418. top: 0;
  419. height: 100px;
  420. background: #C7C7C7;
  421. // background: #FF953D;
  422. width: 100%;
  423. }
  424. &.status-0 {
  425. &::after {
  426. background: #FF4F4F;
  427. }
  428. }
  429. &.status-1 {
  430. &::after {
  431. background: #FF953D;
  432. }
  433. }
  434. &.status-2 {
  435. &::after {
  436. background: #C7C7C7;
  437. }
  438. }
  439. &.status-3 {
  440. padding-top: 30px;
  441. &::after {
  442. background: #2199F8;
  443. }
  444. }
  445. .status-l {
  446. .status-title {
  447. font-size: 22px;
  448. }
  449. .status-sub {
  450. font-size: 14px;
  451. }
  452. }
  453. }
  454. .work-wrap {
  455. position: relative;
  456. top: -16px;
  457. padding: 0 12px 12px;
  458. z-index: 2;
  459. margin-bottom: 60px;
  460. }
  461. .box-wrap {
  462. // background: #ffffff;
  463. // border-radius: 8px;
  464. // padding: 14px 10px 10px 10px;
  465. // box-shadow: 0 2px 8px rgba(15, 35, 52, 0.06);
  466. .work-info {
  467. background: #ffffff;
  468. border-radius: 8px;
  469. padding: 14px 10px 10px 10px;
  470. box-shadow: 0 2px 8px rgba(15, 35, 52, 0.06);
  471. }
  472. .photo-box {
  473. margin-top: 10px;
  474. padding: 11px 10px;
  475. font-size: 14px;
  476. .photo-title {
  477. color: #000;
  478. padding-bottom: 9px;
  479. }
  480. .photo-sub-title {
  481. padding-bottom: 9px;
  482. color: #767676;
  483. }
  484. }
  485. }
  486. .group-info {
  487. margin-bottom: 10px;
  488. background: #ffffff;
  489. border-radius: 8px;
  490. padding: 14px 10px 10px 10px;
  491. box-shadow: 0 2px 8px rgba(15, 35, 52, 0.06);
  492. &.group-box {
  493. padding: 10px;
  494. .group-name {
  495. font-size: 14px;
  496. color: #767676;
  497. .group-name-text {
  498. color: #000;
  499. }
  500. }
  501. }
  502. .group-name {
  503. font-size: 14px;
  504. color: rgba(0, 0, 0, 0.2);
  505. .group-name-text {
  506. color: #767676;
  507. }
  508. }
  509. .group-sub {
  510. margin-top: 6px;
  511. font-size: 12px;
  512. color: rgba(0, 0, 0, 0.45);
  513. line-height: 1.5;
  514. }
  515. }
  516. .stage-card+.stage-card {
  517. margin-top: 10px;
  518. }
  519. .stage-card {
  520. .stage-header {
  521. padding-bottom: 12px;
  522. display: flex;
  523. align-items: center;
  524. gap: 5px;
  525. .stage-title {
  526. font-size: 16px;
  527. color: #000;
  528. }
  529. .title-tag {
  530. width: fit-content;
  531. font-size: 12px;
  532. height: 26px;
  533. line-height: 26px;
  534. color: #2199F8;
  535. background: rgba(33, 153, 248, 0.1);
  536. border-radius: 20px;
  537. padding: 0 8px;
  538. }
  539. .tag-0 {
  540. color: #FF953D;
  541. background: rgba(255, 149, 61, 0.1);
  542. }
  543. }
  544. .stage-info {
  545. padding: 8px 0 2px;
  546. border-top: 1px solid #f5f5f5;
  547. }
  548. }
  549. .form-item {
  550. display: flex;
  551. font-size: 14px;
  552. color: #767676;
  553. margin-top: 4px;
  554. .area-btn {
  555. border: 1px solid rgba(0, 0, 0, 0.1);
  556. padding: 0 10px;
  557. color: #767676;
  558. }
  559. .area-btn-right {
  560. padding-right: 4px;
  561. display: inline-flex;
  562. align-items: center;
  563. gap: 4px;
  564. }
  565. .item-name {
  566. padding-right: 26px;
  567. color: rgba(0, 0, 0, 0.2);
  568. }
  569. .item-text {
  570. flex: 1;
  571. line-height: 21px;
  572. &.light-text {
  573. color: #2199F8;
  574. }
  575. }
  576. .area-text {
  577. display: inline-flex;
  578. align-items: center;
  579. gap: 10px;
  580. }
  581. }
  582. .light-text {
  583. color: #2199F8;
  584. }
  585. .stage-tabs {
  586. display: inline-flex;
  587. gap: 8px;
  588. margin-top: 8px;
  589. .tab-pill {
  590. padding: 0 8px;
  591. font-size: 14px;
  592. text-align: center;
  593. border-radius: 2px;
  594. height: 28px;
  595. line-height: 28px;
  596. color: #767676;
  597. background: rgba(171, 171, 171, 0.1);
  598. &.active {
  599. background: rgba(33, 153, 248, 0.1);
  600. color: #2199F8;
  601. }
  602. }
  603. }
  604. .prescription-wrap {
  605. margin-top: 10px;
  606. overflow: hidden;
  607. .prescription-title {
  608. padding: 8px 10px;
  609. font-size: 13px;
  610. font-weight: 500;
  611. border-bottom: 1px solid rgba(225, 225, 225, 0.6);
  612. }
  613. }
  614. .prescription-table {
  615. font-size: 12px;
  616. text-align: center;
  617. border-radius: 6px;
  618. border: 1px solid rgba(225, 225, 225, 0.6);
  619. .table-header {
  620. display: flex;
  621. background: rgba(171, 171, 171, 0.1);
  622. padding: 9px 6px;
  623. color: #767676;
  624. }
  625. .table-row {
  626. display: flex;
  627. padding: 12px 6px;
  628. border-bottom: 1px solid rgba(0, 0, 0, 0.08);
  629. color: rgba(0, 0, 0, 0.76);
  630. &:last-child {
  631. border-bottom: none;
  632. }
  633. }
  634. .col {
  635. display: flex;
  636. align-items: center;
  637. justify-content: center;
  638. padding: 0 2px;
  639. }
  640. .col-type {
  641. width: 56px;
  642. }
  643. .col-name {
  644. flex: 1;
  645. }
  646. .col-ratio {
  647. width: 64px;
  648. }
  649. .col-dose {
  650. width: 64px;
  651. }
  652. }
  653. .prescription-remark {
  654. margin-top: 8px;
  655. padding: 7px 10px;
  656. border-radius: 6px;
  657. color: #767676;
  658. background: rgba(171, 171, 171, 0.1);
  659. line-height: 21px;
  660. }
  661. .photo-img-wrap {
  662. display: flex;
  663. flex-wrap: wrap;
  664. gap: 10px;
  665. ::v-deep {
  666. .PhotoConsumer {
  667. width: 31%;
  668. height: 92px;
  669. }
  670. }
  671. .photo-img {
  672. width: 100%;
  673. height: 100%;
  674. position: relative;
  675. box-sizing: border-box;
  676. border: 2px solid transparent;
  677. border-radius: 8px;
  678. overflow: hidden;
  679. img {
  680. width: 100%;
  681. height: 100%;
  682. border-radius: 8px;
  683. object-fit: cover;
  684. }
  685. }
  686. }
  687. .execute-action {
  688. display: flex;
  689. align-items: center;
  690. // justify-content: center;
  691. justify-content: space-between;
  692. gap: 16px;
  693. .action-item {
  694. padding: 0 26px;
  695. height: 40px;
  696. line-height: 40px;
  697. border-radius: 26px;
  698. box-sizing: border-box;
  699. font-size: 14px;
  700. &.second {
  701. background: #ffffff;
  702. border: 0.5px solid rgba(153, 153, 153, 0.5);
  703. color: #999999;
  704. }
  705. &.primary {
  706. background: linear-gradient(180deg, #8ACBFF 0%, #2199F8 100%);
  707. color: #ffffff;
  708. }
  709. }
  710. }
  711. .fixed-btn-wrap {
  712. display: flex;
  713. // justify-content: center;
  714. justify-content: space-between;
  715. &.center-btn {
  716. justify-content: center;
  717. }
  718. position: fixed;
  719. bottom: 0px;
  720. left: 0;
  721. right: 0;
  722. background: #fff;
  723. padding: 10px 12px 16px 12px;
  724. box-sizing: border-box;
  725. // box-shadow: 0 -2px 8px rgba(15, 35, 52, 0.06);
  726. box-shadow: 2px 2px 4.5px 0px #00000066;
  727. .fixed-btn {
  728. min-width: 110px;
  729. height: 40px;
  730. line-height: 40px;
  731. text-align: center;
  732. border-radius: 20px;
  733. background: linear-gradient(180deg, #70bffe, #2199f8);
  734. color: #ffffff;
  735. font-size: 14px;
  736. }
  737. }
  738. .map-popup {
  739. width: 92%;
  740. // max-width: 420px;
  741. border-radius: 8px;
  742. padding: 12px;
  743. box-sizing: border-box;
  744. }
  745. </style>