reviewWork.vue 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132
  1. <template>
  2. <div class="work-wrap">
  3. <custom-header name="农事详情" :isClose="paramsPage.goBack ? false : true"></custom-header>
  4. <div
  5. class="work-content recheck-title"
  6. :class="{ 'no-bottom': curRole == '0' && (!workItem.reviewImage || !workItem.reviewImage.length) }"
  7. v-loading="loading"
  8. >
  9. <div class="tabs-content-item">
  10. <div class="common-card-title">
  11. <img class="icon" src="@/assets/img/home/label-icon.png" alt="" />
  12. <span>农事信息</span>
  13. </div>
  14. <div class="info-box">
  15. <div class="info-l">
  16. <img class="farm-img" src="@/assets/img/home/farm.png" alt="" />
  17. </div>
  18. <div class="info-r">
  19. <div class="farm-name">{{ workItem.farmName }}</div>
  20. <div class="info-item">
  21. <div class="info-name">农事名称:</div>
  22. <div class="info-value">{{ workItem.farmWorkName }}</div>
  23. </div>
  24. <div class="info-item">
  25. <div class="info-name">执行时间:</div>
  26. <div class="info-value">{{ workItem.executeDate || "--" }}</div>
  27. </div>
  28. <div class="info-item line-item">
  29. <div class="info-name">药肥处方:</div>
  30. <div class="info-value">
  31. <div class="rescription" v-if="workItem?.prescriptionList">
  32. <span
  33. v-for="(fertilizer, fertilizerI) in workItem.prescriptionList"
  34. :key="fertilizerI"
  35. >
  36. <span
  37. v-for="(pest, pestI) in fertilizer.pesticideFertilizerList"
  38. :key="'sub' + pestI"
  39. >
  40. {{ pest.defaultName || pest.pesticideFertilizerName }}
  41. <span
  42. v-if="
  43. pestI !== fertilizer.pesticideFertilizerList.length - 1 ||
  44. fertilizerI !== workItem.prescriptionList.length - 1
  45. "
  46. >
  47. +
  48. </span>
  49. </span>
  50. </span>
  51. </div>
  52. </div>
  53. </div>
  54. </div>
  55. </div>
  56. <div class="info-box subject-content">
  57. <div class="subject-box">
  58. <div class="subject-item cost-l">
  59. <img class="subject-img" src="@/assets/img/home/nz.png" alt="" />
  60. <div class="subject-tag">
  61. {{ workItem.serviceMain }}
  62. </div>
  63. </div>
  64. <div class="subject-item">
  65. <img class="subject-img" :src="workItem.executorIcon" alt="" />
  66. <div class="subject-tag">
  67. {{ workItem.executeName }}
  68. </div>
  69. </div>
  70. </div>
  71. </div>
  72. </div>
  73. <div class="tabs-content-item">
  74. <div class="common-card-title">
  75. <img class="icon" src="@/assets/img/home/label-icon.png" alt="" />
  76. <span>复核成效</span>
  77. </div>
  78. <div class="info-box bottom-box">
  79. <div class="recheck-box">
  80. <div class="recheck-ablum">
  81. <!-- <div class="img-list over-img-box">
  82. <album-carousel :key="1" labelText="农事前" :images="triggerImg"></album-carousel>
  83. </div> -->
  84. <div class="img-list over-img-box">
  85. <album-carousel
  86. class="execute-img"
  87. :key="1"
  88. labelText="执行照片"
  89. :imgData="workItem"
  90. :images="workItem.executeEvidence"
  91. ></album-carousel>
  92. </div>
  93. <div
  94. class="img-list over-img-box"
  95. v-if="workItem.reviewImage && workItem.reviewImage.length"
  96. >
  97. <album-carousel
  98. :key="2"
  99. labelText="复核照片"
  100. :isAchievementImgs="true"
  101. :imgData="workItem"
  102. :images="workItem.reviewImage"
  103. ></album-carousel>
  104. </div>
  105. <!-- <div class="img-list over-img-box" v-if="combinedReviewImages.length">
  106. <album-carousel :key="3" :isAchievementImgs="true" :images="combinedReviewImages"></album-carousel>
  107. </div> -->
  108. <div class="img-list" v-if="!workItem.reviewImage || !workItem.reviewImage.length">
  109. <div
  110. class="recheck-text-wrap active"
  111. :class="{
  112. 'center-wrap': !imageArr.length,
  113. }"
  114. >
  115. <div class="date" v-show="workItem.reviewDate">{{ workItem.reviewDate }}</div>
  116. <upload
  117. exampleImg
  118. @handleUpload="handleUpload"
  119. class="upload-wrap"
  120. :style="{
  121. height:
  122. imageArr.length && !diffInDays(workItem.reviewDate) > 0
  123. ? 'auto'
  124. : '254px',
  125. }"
  126. >
  127. <template
  128. v-if="
  129. diffInDays(workItem.reviewDate) == 0 ||
  130. diffInDays(workItem.reviewDate) == null
  131. "
  132. >
  133. <img
  134. class="img-icon"
  135. :src="require(`@/assets/img/gallery/img-icon-act.png`)"
  136. alt=""
  137. />
  138. <div class="recheck-text">点击上传照片</div>
  139. </template>
  140. <!-- <template v-else>
  141. <img class="img-icon" src="@/assets/img/gallery/img-icon.png" alt="" />
  142. <div class="recheck-text">等待复核</div>
  143. <div class="recheck-desc" v-show="diffInDays(workItem.reviewDate) >= 0">
  144. (剩余{{ diffInDays(workItem.reviewDate) }}天)
  145. </div>
  146. </template> -->
  147. </upload>
  148. <div
  149. class="submit"
  150. v-show="imageArr.length && !diffInDays(workItem.reviewDate) > 0"
  151. @click="handleSubmit('reviewImage2')"
  152. >
  153. 确认上传
  154. </div>
  155. </div>
  156. </div>
  157. <!-- <div class="img-list" v-else>
  158. <div
  159. class="recheck-text-wrap no-events"
  160. :class="{
  161. active: !diffInDays(workItem.reviewDate) > 0 && curRole === '0',
  162. 'yse-events': curRole === '0' && !diffInDays(workItem.reviewDate) > 0,
  163. 'center-wrap': !imageArr2.length,
  164. }"
  165. >
  166. <div class="date" v-show="workItem.reviewDate">{{ workItem.reviewDate }}</div>
  167. <upload
  168. exampleImg
  169. @handleUpload="handleUpload2"
  170. class="upload-wrap"
  171. :style="{
  172. height:
  173. imageArr2.length && !diffInDays(workItem.reviewDate) > 0
  174. ? 'auto'
  175. : '254px',
  176. }"
  177. >
  178. <template
  179. v-if="
  180. diffInDays(workItem.reviewDate) == 0 ||
  181. diffInDays(workItem.reviewDate) == null
  182. "
  183. >
  184. <img
  185. class="img-icon"
  186. :src="
  187. require(`@/assets/img/gallery/img-icon${
  188. curRole === '0' ? '-act' : ''
  189. }.png`)
  190. "
  191. alt=""
  192. />
  193. <div class="recheck-text">
  194. {{ curRole === "2" ? "等待农户上传" : "点击上传照片" }}
  195. </div>
  196. <div
  197. class="recheck-desc"
  198. v-show="curRole === '2' && diffInDays(workItem.reviewDate) != 0"
  199. >
  200. </div>
  201. </template>
  202. <template v-else>
  203. <img class="img-icon" src="@/assets/img/gallery/img-icon.png" alt="" />
  204. <div class="recheck-text">等待复核</div>
  205. <div class="recheck-desc" v-show="diffInDays(workItem.reviewDate) >= 0">
  206. (剩余{{ diffInDays(workItem.reviewDate) }}天)
  207. </div>
  208. </template>
  209. </upload>
  210. <div
  211. class="submit"
  212. v-show="imageArr2.length && !diffInDays(workItem.reviewDate) > 0"
  213. @click="handleSubmit('reviewImage2')"
  214. >
  215. 确认上传
  216. </div>
  217. </div>
  218. </div> -->
  219. </div>
  220. </div>
  221. </div>
  222. </div>
  223. <!-- 按钮 -->
  224. <div class="up-btn-group" v-show="isPlan">
  225. <template v-if="curRole === '2'">
  226. <div
  227. class="up-btn"
  228. :class="{ btn: workItem.executeEvidence && workItem.executeEvidence.length }"
  229. v-show="workItem.reviewImage && !workItem.reviewImage.length"
  230. >
  231. 提醒农户拍照
  232. </div>
  233. </template>
  234. <template v-else>
  235. <div
  236. class="up-btn btn"
  237. @click="handleContact"
  238. v-show="workItem.reviewImage && workItem.reviewImage.length && !imageArr.length"
  239. >
  240. 联系专家
  241. </div>
  242. </template>
  243. </div>
  244. <div class="fixed-btn-wrap" :class="{ center: !paramsPage.isBtn && !getButtonText() }">
  245. <div class="fixed-btn more" @click="handleMore" v-if="paramsPage.isBtn">查看更多农事</div>
  246. <div class="fixed-btn more" @click="handleRemindUser" v-if="getButtonText() && !paramsPage.isBtn">提醒复核</div>
  247. <div class="fixed-btn excute" @click="generateReport">生成成果报告</div>
  248. </div>
  249. <div
  250. class="fixed-btn-wrap center"
  251. v-if="curRole == '0' && workItem.reviewImage && workItem.reviewImage.length"
  252. >
  253. <div class="fixed-btn excute" @click="handleShare">转发</div>
  254. </div>
  255. <!-- 组合照片(用于生成合成图片) -->
  256. <div class="review-hide-box">
  257. <div class="review-image" ref="reviewComboRef">
  258. <div class="review-mask">
  259. <div class="review-text">复核成效</div>
  260. <div class="review-content">
  261. {{ workItem?.reCheckText }}
  262. </div>
  263. </div>
  264. <div class="vs-wrap" v-if="workItem?.reviewImage && workItem?.reviewImage?.length">
  265. <img src="@/assets/img/home/vs.png" alt="" />
  266. </div>
  267. <div class="review-image-item" v-if="triggerImg?.length">
  268. <div class="review-image-item-title">复核照片</div>
  269. <!-- <img
  270. class="review-image-item-img left-img"
  271. :src="base_img_url2 + triggerImg[triggerImg.length - 1].cloudFilename"
  272. alt=""
  273. /> -->
  274. <img
  275. class="review-image-item-img left-img"
  276. :src="leftCoverImg"
  277. style="
  278. width: 100%;
  279. height: 255px;
  280. display: block;
  281. image-rendering: auto;
  282. "
  283. />
  284. </div>
  285. <div class="review-image-item" v-if="workItem?.reviewImage?.length">
  286. <!-- <img
  287. class="review-image-item-img right-img"
  288. :src="base_img_url2 + workItem.reviewImage[workItem.reviewImage.length - 1]"
  289. alt=""
  290. /> -->
  291. <img
  292. class="review-image-item-img right-img"
  293. :src="rightCoverImg"
  294. style="
  295. width: 100%;
  296. height: 255px;
  297. display: block;
  298. image-rendering: auto;
  299. "
  300. />
  301. </div>
  302. </div>
  303. </div>
  304. </div>
  305. <!-- 上传图片弹窗 -->
  306. <upload-popup :executionData="workItem"></upload-popup>
  307. <!-- 分享农事成效弹窗 -->
  308. <review-popup ref="reviewPopupRef" />
  309. <!-- 上传农事成效弹窗 -->
  310. <upload-execute ref="uploadExecuteRef" :onlyShare="true" />
  311. </div>
  312. </template>
  313. <script setup>
  314. import { Tab, Tabs } from "vant";
  315. import customHeader from "@/components/customHeader.vue";
  316. import { onMounted, ref, onDeactivated, onActivated, onUnmounted, nextTick, watch } from "vue";
  317. import { useRoute, useRouter } from "vue-router";
  318. import upload from "@/components/upload";
  319. import AlbumCarousel from "@/components/album_compoents/albumCarousel";
  320. import { ElMessage } from "element-plus";
  321. import uploadPopup from "@/components/popup/uploadPopup.vue";
  322. import { base_img_url2 } from "@/api/config";
  323. import wx from "weixin-js-sdk";
  324. import reviewPopup from "@/views/old_mini/task_condition/components/reviewPopup.vue";
  325. import uploadExecute from "@/views/old_mini/task_condition/components/uploadExecute.vue";
  326. import html2canvas from "html2canvas";
  327. const route = useRoute();
  328. const router = useRouter();
  329. const uploadExecuteRef = ref(null);
  330. const workItem = ref({});
  331. const curRole = ref("");
  332. // 农事规划页面-显示上传农事凭证按钮
  333. const isPlan = ref(false);
  334. const loading = ref(false);
  335. const reviewComboRef = ref(null);
  336. const combinedReviewImages = ref([]);
  337. const diffInDays = (date, type = "minus") => {
  338. const targetDate = new Date(date);
  339. const currentDate = new Date(); // 获取当前系统时间
  340. let diffInMs;
  341. if (type === "minus") {
  342. diffInMs = targetDate - currentDate;
  343. } else {
  344. diffInMs = currentDate - targetDate;
  345. }
  346. const day = Math.floor(diffInMs / (1000 * 60 * 60 * 24));
  347. return day + 1 >= 0 ? day + 1 : null;
  348. };
  349. const paramsPage = ref({});
  350. const agriculturalRole = ref(null);
  351. const userId = ref(null);
  352. onActivated(() => {
  353. const userInfo = JSON.parse(localStorage.getItem("localUserInfo"));
  354. agriculturalRole.value = userInfo.agriculturalRole;
  355. userId.value = userInfo.id;
  356. window.scrollTo(0, 0);
  357. curRole.value = localStorage.getItem("SET_USER_CUR_ROLE");
  358. paramsPage.value = route.query.miniJson ? JSON.parse(route.query.miniJson) : {};
  359. if(paramsPage.value.paramsPage) {
  360. const data = JSON.parse(paramsPage.value.paramsPage);
  361. paramsPage.value.id = data.id;
  362. paramsPage.value.goBack = false;
  363. }
  364. getDetail();
  365. getTriggerImg(paramsPage.value.id);
  366. });
  367. const getButtonText = () => {
  368. return agriculturalRole.value === 1 || workItem.value.executorUserId != userId.value;
  369. };
  370. const getDetail = () => {
  371. if (!paramsPage.value.id) return;
  372. loading.value = true;
  373. VE_API.z_farm_work_record
  374. .getDetail({ id: paramsPage.value.id })
  375. .then(({ data }) => {
  376. workItem.value = data[0];
  377. })
  378. .finally(() => {
  379. loading.value = false;
  380. });
  381. };
  382. const triggerImg = ref([]);
  383. const getTriggerImg = (farmWorkRecordId) => {
  384. VE_API.z_farm_work_record.getTriggerImg({ farmWorkRecordId }).then(({ data }) => {
  385. triggerImg.value = data || [];
  386. });
  387. };
  388. // 生成组合照片,传给相册组件
  389. const generateCombinedReviewImage = async () => {
  390. try {
  391. await prepareCoverImages()
  392. await nextTick()
  393. const canvas = await html2canvas(reviewComboRef.value, {
  394. backgroundColor: null,
  395. useCORS: true,
  396. allowTaint: true,
  397. scale: window.devicePixelRatio || 2,
  398. })
  399. combinedReviewImages.value = [canvas.toDataURL('image/png')]
  400. } catch (e) {
  401. console.error('生成组合照片失败', e)
  402. }
  403. }
  404. const prepareCoverImages = async () => {
  405. await nextTick()
  406. const itemEl =
  407. reviewComboRef.value.querySelector('.review-image-item')
  408. const cssWidth = itemEl.offsetWidth
  409. const cssHeight = 255
  410. if (triggerImg.value?.length) {
  411. leftCoverImg.value = await coverImageToBase64HD(
  412. base_img_url2 + triggerImg.value.at(-1).cloudFilename,
  413. cssWidth,
  414. cssHeight
  415. )
  416. }
  417. if (workItem.value?.reviewImage?.length) {
  418. rightCoverImg.value = await coverImageToBase64HD(
  419. base_img_url2 + workItem.value.reviewImage.at(-1),
  420. cssWidth,
  421. cssHeight
  422. )
  423. }
  424. }
  425. const leftCoverImg = ref('')
  426. const rightCoverImg = ref('')
  427. function coverImageToBase64HD(imgUrl, cssWidth, cssHeight) {
  428. return new Promise((resolve, reject) => {
  429. const dpr = window.devicePixelRatio || 2
  430. const img = new Image()
  431. img.crossOrigin = 'anonymous'
  432. img.src = imgUrl
  433. img.onload = () => {
  434. // ⚠️ 用“物理像素”创建 canvas
  435. const canvas = document.createElement('canvas')
  436. canvas.width = cssWidth * dpr
  437. canvas.height = cssHeight * dpr
  438. const ctx = canvas.getContext('2d')
  439. ctx.scale(dpr, dpr)
  440. const imgRatio = img.width / img.height
  441. const targetRatio = cssWidth / cssHeight
  442. let sx = 0, sy = 0, sw = img.width, sh = img.height
  443. if (imgRatio > targetRatio) {
  444. sw = img.height * targetRatio
  445. sx = (img.width - sw) / 2
  446. } else {
  447. sh = img.width / targetRatio
  448. sy = (img.height - sh) / 2
  449. }
  450. ctx.drawImage(
  451. img,
  452. sx, sy, sw, sh,
  453. 0, 0, cssWidth, cssHeight
  454. )
  455. resolve(canvas.toDataURL('image/png'))
  456. }
  457. img.onerror = reject
  458. })
  459. }
  460. watch(
  461. () => [triggerImg.value, workItem.value.reviewImage],
  462. ([preImgs, reviewImgs]) => {
  463. if (preImgs && preImgs.length && reviewImgs && reviewImgs.length) {
  464. generateCombinedReviewImage();
  465. }
  466. },
  467. { deep: true }
  468. );
  469. //确认上传
  470. const handleSubmit = () => {
  471. const params = {
  472. executeEvidence: imageArr.value,
  473. recordId: workItem.value.id,
  474. };
  475. VE_API.monitor.addReviewImg(params).then(({ code }) => {
  476. if (code === 0) {
  477. getDetail();
  478. ElMessage.success("您已上传成功");
  479. imageArr.value = [];
  480. }
  481. });
  482. };
  483. const reviewPopupRef = ref(null);
  484. const handleShare = () => {
  485. const preImg = triggerImg.value.length
  486. ? base_img_url2 + triggerImg.value[triggerImg.value.length - 1].cloudFilename
  487. : "";
  488. const resImg = workItem.value?.reviewImage?.length
  489. ? base_img_url2 + workItem.value.reviewImage[workItem.value.reviewImage.length - 1]
  490. : "";
  491. reviewPopupRef.value.handleShowPopup(workItem.value.id, preImg, resImg);
  492. };
  493. const generateReport = () => {
  494. router.push({
  495. path: "/achievement_report",
  496. query: { miniJson: JSON.stringify({ id: workItem.value.id }) },
  497. });
  498. };
  499. const handleRemindUser = () => {
  500. const query = {
  501. askInfo: { title: "农事提醒", content: "是否分享该农事提醒给好友" },
  502. shareText: '向您分享了一条农事复核提醒,请您尽快复核',
  503. targetUrl: `review_work`,
  504. paramsPage: JSON.stringify({id: workItem.value.id}),
  505. imageUrl: 'https://birdseye-img.sysuimars.com/birdseye-look-mini/invite_bg.png',
  506. };
  507. wx.miniProgram.navigateTo({
  508. url: `/pages/subPages/share_page/index?pageParams=${JSON.stringify(query)}&type=sharePage`,
  509. });
  510. };
  511. const handleMore = () => {
  512. router.push(`/service_detail?farmId=${workItem.value.farmId}`);
  513. };
  514. // 清理数据的函数
  515. const clearData = () => {
  516. workItem.value = {};
  517. triggerImg.value = [];
  518. imageArr.value = [];
  519. paramsPage.value = {};
  520. isPlan.value = false;
  521. curRole.value = "";
  522. loading.value = false;
  523. };
  524. onDeactivated(() => {
  525. clearData();
  526. });
  527. onUnmounted(() => {
  528. clearData();
  529. });
  530. // //联系专家
  531. // const handleContact = () => {
  532. // router.push(`/dialogue?userId=${workItem.value.expert}&name=${workItem.value.expertUserName}`);
  533. // };
  534. const imageArr = ref([]);
  535. const handleUpload = ({ imgArr }) => {
  536. imageArr.value = imgArr;
  537. };
  538. </script>
  539. <style lang="scss" scoped>
  540. .work-wrap {
  541. .center-wrap {
  542. ::v-deep {
  543. .van-uploader__wrapper {
  544. justify-content: center;
  545. }
  546. }
  547. }
  548. .work-content {
  549. padding-top: 1px;
  550. background: #f5f5f5;
  551. padding-bottom: 12px;
  552. font-size: 14px;
  553. height: calc(100vh - 40px);
  554. box-sizing: border-box;
  555. overflow: auto;
  556. &.recheck-title {
  557. padding-bottom: 86px;
  558. .common-card-title {
  559. font-size: 16px;
  560. display: flex;
  561. align-items: center;
  562. border-bottom: 1px solid #f5f5f5;
  563. padding-bottom: 10px;
  564. .icon {
  565. width: 14px;
  566. height: 8px;
  567. padding-right: 6px;
  568. }
  569. }
  570. &.no-bottom {
  571. padding-bottom: 26px;
  572. }
  573. }
  574. .up-btn-group {
  575. position: fixed;
  576. bottom: 80px;
  577. left: 12px;
  578. display: flex;
  579. justify-content: center;
  580. width: calc(100% - 24px);
  581. .up-btn {
  582. background: linear-gradient(45deg, #9fd5ff, #2199f8);
  583. flex: 1;
  584. height: 40px;
  585. border: 2px solid rgba(255, 255, 255, 0.66);
  586. color: #fff;
  587. font-size: 14px;
  588. border-radius: 40px;
  589. line-height: 38px;
  590. text-align: center;
  591. box-sizing: border-box;
  592. }
  593. .orange {
  594. margin-left: 12px;
  595. background: linear-gradient(45deg, #ffd887, #ed9e1e);
  596. }
  597. .btn {
  598. width: 200px;
  599. flex: none;
  600. }
  601. }
  602. .fixed-btn-wrap {
  603. position: fixed;
  604. z-index: 10;
  605. bottom: 0;
  606. left: 0;
  607. width: 100%;
  608. padding: 10px 12px 25px;
  609. box-sizing: border-box;
  610. display: flex;
  611. align-items: center;
  612. justify-content: space-between;
  613. background: #fff;
  614. box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.4);
  615. &.center {
  616. justify-content: center;
  617. }
  618. .fixed-btn {
  619. width: 120px;
  620. text-align: center;
  621. height: 40px;
  622. line-height: 40px;
  623. background: linear-gradient(180deg, #70bffe, #2199f8);
  624. border-radius: 25px;
  625. color: #fff;
  626. font-size: 14px;
  627. box-sizing: border-box;
  628. &.expert {
  629. width: 180px;
  630. }
  631. &.orange {
  632. color: #ff953d;
  633. border: 1px solid #ff953d;
  634. background: #fff;
  635. }
  636. &.excute {
  637. background: linear-gradient(180deg, #ffd887, #ed9e1e);
  638. }
  639. &.more {
  640. background: #ffffff;
  641. border: 1px solid rgba(153, 153, 153, 0.5);
  642. color: #666666;
  643. }
  644. &.second {
  645. background: #ffffff;
  646. border: 1px solid #2199f8;
  647. color: #2199f8;
  648. }
  649. }
  650. }
  651. .tabs-content-item {
  652. padding: 12px 12px 16px 12px;
  653. margin: 0 12px;
  654. border-radius: 8px;
  655. background: #fff;
  656. margin-top: 12px;
  657. position: relative;
  658. .execute-img {
  659. margin-top: 12px;
  660. }
  661. .card-title {
  662. display: flex;
  663. justify-content: space-between;
  664. align-items: center;
  665. padding-bottom: 10px;
  666. .card-title-l {
  667. display: flex;
  668. align-items: center;
  669. font-size: 16px;
  670. .icon {
  671. width: 14px;
  672. height: 8px;
  673. padding-right: 6px;
  674. }
  675. }
  676. .card-title-r {
  677. font-size: 14px;
  678. color: #2199f8;
  679. }
  680. }
  681. .info-box {
  682. // padding-top: 12px;
  683. display: flex;
  684. align-items: center;
  685. &.subject-content {
  686. border: none;
  687. }
  688. &.cost-wrap {
  689. padding-top: 8px;
  690. }
  691. &.bottom-box {
  692. flex-direction: column;
  693. }
  694. .info-l {
  695. .farm-img {
  696. width: 78px;
  697. width: 78px;
  698. border-radius: 8px;
  699. object-fit: scale-down;
  700. }
  701. }
  702. .info-r {
  703. padding-left: 12px;
  704. }
  705. .farm-name {
  706. font-weight: bold;
  707. font-size: 14px;
  708. color: #000;
  709. padding-bottom: 4px;
  710. }
  711. .info-item {
  712. display: flex;
  713. align-items: center;
  714. font-size: 12px;
  715. &.line-item {
  716. align-items: flex-start;
  717. }
  718. .info-name {
  719. color: #bbbbbb;
  720. flex: none;
  721. }
  722. .info-value {
  723. color: #666666;
  724. }
  725. }
  726. .info-item + .info-item {
  727. margin-top: 4px;
  728. }
  729. }
  730. .subject-box {
  731. width: 100%;
  732. display: flex;
  733. align-items: center;
  734. justify-content: space-around;
  735. background: #fafafa;
  736. .subject-item {
  737. border-radius: 8px;
  738. padding: 4px 4px;
  739. display: flex;
  740. flex-direction: column;
  741. align-items: center;
  742. justify-content: center;
  743. width: 33%;
  744. .subject-img {
  745. width: 30px;
  746. height: 30px;
  747. object-fit: cover;
  748. border-radius: 50%;
  749. padding-bottom: 4px;
  750. }
  751. .subject-tag {
  752. font-size: 12px;
  753. padding: 2px 8px;
  754. background: #e0efff;
  755. color: #2199f8;
  756. border-radius: 4px;
  757. &.cost-text {
  758. margin-left: 8px;
  759. font-size: 16px;
  760. color: #2199f8;
  761. padding: 1px 8px;
  762. }
  763. }
  764. }
  765. .subject-item + .subject-item {
  766. margin-left: 6px;
  767. }
  768. .cost-l {
  769. position: relative;
  770. &::after {
  771. content: "";
  772. position: absolute;
  773. right: 0;
  774. top: 16px;
  775. height: calc(100% - 32px);
  776. width: 1px;
  777. background: rgba(0, 0, 0, 0.05);
  778. }
  779. }
  780. }
  781. .cost-box {
  782. border-radius: 5px;
  783. background: none;
  784. .cost-item {
  785. display: flex;
  786. align-items: center;
  787. flex-direction: row;
  788. }
  789. .subject-item {
  790. background: none;
  791. width: 50%;
  792. }
  793. .cost-l {
  794. position: relative;
  795. &::after {
  796. content: "";
  797. position: absolute;
  798. right: 0;
  799. top: 0;
  800. height: 100%;
  801. width: 1px;
  802. background: rgba(0, 0, 0, 0.05);
  803. }
  804. }
  805. .cost-text {
  806. font-size: 16px;
  807. color: #2199f8;
  808. padding-bottom: 5px;
  809. }
  810. }
  811. .recheck-box,
  812. .recheck-ablum {
  813. width: 100%;
  814. }
  815. .evaluate {
  816. background: #fff;
  817. border-radius: 5px;
  818. padding: 4px 8px 10px 8px;
  819. margin-right: 8px;
  820. .evaluate-title {
  821. font-size: 16px;
  822. font-weight: 500;
  823. display: flex;
  824. align-items: center;
  825. justify-content: space-between;
  826. margin-bottom: 8px;
  827. .more {
  828. font-size: 14px;
  829. color: #999999;
  830. font-weight: 400;
  831. display: flex;
  832. align-items: center;
  833. }
  834. }
  835. .rate {
  836. display: flex;
  837. justify-content: space-between;
  838. ::v-deep {
  839. .el-rate {
  840. --el-rate-icon-margin: 0;
  841. }
  842. .el-rate--small .el-rate__icon {
  843. font-size: 12px;
  844. }
  845. }
  846. .rate-item {
  847. display: flex;
  848. align-items: center;
  849. border-radius: 4px;
  850. padding: 4px 0px;
  851. font-size: 11px;
  852. .name {
  853. margin-right: 2px;
  854. color: #666666;
  855. position: relative;
  856. top: 2px;
  857. }
  858. .num {
  859. color: #f3c11d;
  860. margin-left: 2px;
  861. }
  862. }
  863. .line {
  864. width: 1px;
  865. height: 12px;
  866. background: #cdd7e1;
  867. position: relative;
  868. top: 13px;
  869. margin: 0 3px;
  870. }
  871. }
  872. .comment {
  873. .user-info {
  874. display: flex;
  875. align-items: center;
  876. margin-bottom: 2px;
  877. .user-name {
  878. font-weight: 500;
  879. margin-left: 8px;
  880. span {
  881. font-weight: 400;
  882. font-size: 12px;
  883. color: #999999;
  884. }
  885. }
  886. }
  887. }
  888. }
  889. .img-list + .img-list,
  890. .upload-wrap {
  891. margin-top: 12px;
  892. }
  893. // .over-img-box {
  894. // ::v-deep {
  895. // img {
  896. // border-radius: 8px;
  897. // }
  898. // }
  899. // }
  900. .img-list {
  901. width: 100%;
  902. }
  903. .upload-wrap {
  904. display: flex;
  905. flex-direction: column;
  906. justify-content: center;
  907. height: 254px;
  908. width: 100%;
  909. padding: 25px 0 12px 10px;
  910. box-sizing: border-box;
  911. }
  912. .recheck-text-wrap {
  913. width: 100%;
  914. border-radius: 8px;
  915. background: #f2f3f5;
  916. color: #666666;
  917. font-size: 14px;
  918. position: relative;
  919. &.active {
  920. background: rgba(33, 153, 248, 0.1);
  921. border: 1px solid #2199f8;
  922. color: #2199f8;
  923. .date {
  924. background: linear-gradient(170deg, #9fd5ff, #2199f8);
  925. }
  926. .recheck-desc {
  927. color: #2199f8;
  928. }
  929. }
  930. .submit {
  931. background: #2199f8;
  932. border-radius: 4px;
  933. padding: 8px;
  934. font-size: 16px;
  935. color: #fff;
  936. margin: 0 10px 16px;
  937. text-align: center;
  938. }
  939. .date {
  940. position: absolute;
  941. top: 0;
  942. left: 0;
  943. background: #bebebe;
  944. border-radius: 8px 0 8px 0;
  945. color: #fff;
  946. font-size: 12px;
  947. padding: 3px 6px;
  948. font-family: "PangMenZhengDao";
  949. }
  950. .recheck-text {
  951. padding: 8px 0 2px 0;
  952. }
  953. .recheck-desc {
  954. font-size: 12px;
  955. color: #999999;
  956. }
  957. .img-icon {
  958. width: 40px;
  959. height: 40px;
  960. }
  961. }
  962. .sub-title {
  963. display: flex;
  964. align-items: center;
  965. justify-content: center;
  966. .sub-line {
  967. width: 12px;
  968. height: 2px;
  969. border-radius: 1px;
  970. background: #d9d9d9;
  971. }
  972. .sub-name {
  973. padding: 0 5px;
  974. font-size: 14px;
  975. color: #666666;
  976. }
  977. }
  978. }
  979. }
  980. .review-hide-box {
  981. position: absolute;
  982. left: 0;
  983. width: 100%;
  984. height: 100%;
  985. z-index: -1;
  986. bottom: 0;
  987. }
  988. .review-image {
  989. position: relative;
  990. display: flex;
  991. align-items: center;
  992. justify-content: center;
  993. gap: 8px;
  994. margin: 12px;
  995. background: #fff;
  996. border-radius: 8px;
  997. .review-mask {
  998. z-index: 1;
  999. pointer-events: none;
  1000. position: absolute;
  1001. left: 0;
  1002. top: 0;
  1003. width: 100%;
  1004. height: 100%;
  1005. border-radius: 8px;
  1006. background: linear-gradient(
  1007. 360deg,
  1008. rgba(0, 0, 0, 0.78) 0%,
  1009. rgba(0, 0, 0, 0.437208) 19.87%,
  1010. rgba(0, 0, 0, 0) 33.99%
  1011. );
  1012. display: flex;
  1013. flex-direction: column;
  1014. align-items: baseline;
  1015. justify-content: end;
  1016. padding: 12px;
  1017. box-sizing: border-box;
  1018. color: #fff;
  1019. .review-text {
  1020. font-family: "PangMenZhengDao";
  1021. font-size: 16px;
  1022. margin-bottom: 1px;
  1023. }
  1024. .review-content {
  1025. font-size: 10px;
  1026. line-height: 15px;
  1027. }
  1028. }
  1029. .vs-wrap {
  1030. position: absolute;
  1031. left: 50%;
  1032. top: 50%;
  1033. transform: translate(-50%, -50%);
  1034. width: 40px;
  1035. height: 40px;
  1036. z-index: 10;
  1037. img {
  1038. width: 100%;
  1039. height: 100%;
  1040. object-fit: cover;
  1041. }
  1042. }
  1043. .review-image-item {
  1044. position: relative;
  1045. flex: 1;
  1046. .review-image-item-title {
  1047. position: absolute;
  1048. top: 0;
  1049. left: 0;
  1050. background: rgba(54, 52, 52, 0.6);
  1051. padding: 4px 10px;
  1052. border-radius: 8px 0 8px 0;
  1053. backdrop-filter: 4px;
  1054. font-size: 12px;
  1055. color: #fff;
  1056. }
  1057. // .review-image-item-img {
  1058. // width: 100%;
  1059. // height: 250px;
  1060. // object-fit: cover;
  1061. // }
  1062. .review-image-item-img {
  1063. width: 100%;
  1064. height: 100%;
  1065. object-fit: cover;
  1066. object-position: center;
  1067. }
  1068. .left-img {
  1069. border-radius: 8px 0 0 8px;
  1070. }
  1071. .right-img {
  1072. border-radius: 0 8px 8px 0;
  1073. }
  1074. }
  1075. }
  1076. }
  1077. </style>