reviewWork.vue 41 KB

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