reviewWork.vue 42 KB

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