AgriculturalDynamics.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. <template>
  2. <div class="agricultural-dynamics">
  3. <!-- 任务列表 -->
  4. <div class="task-list">
  5. <div v-for="(task, index) in taskList" :key="index" class="task-item">
  6. <div class="task-content" @click="handleTaskAction(task)">
  7. <div class="task-header">
  8. <div class="task-status-tag">待完成</div>
  9. <div class="task-title">{{ task.farmWorkName }}</div>
  10. </div>
  11. <div class="task-time" v-if="task.expectedExecuteDate">执行时间 {{ task.expectedExecuteDate }}</div>
  12. <div class="task-time deadline" v-else>截止时间 {{ task.executeDeadlineDate }}</div>
  13. </div>
  14. <div v-if="task.expectedExecuteDate" class="task-action" @click="showOfferPopup(task)">
  15. 上传照片
  16. </div>
  17. <div v-else class="task-action orange" @click="selectExecuteTime(task)">
  18. 确认执行时间
  19. </div>
  20. </div>
  21. </div>
  22. <div class="title">农情互动</div>
  23. <!-- 内容区域 -->
  24. <div class="agricultural-list">
  25. <div v-if="!unansweredList.length" class="empty-block">暂无数据</div>
  26. <template v-else>
  27. <div class="agricultural-item" v-for="(item, index) in unansweredList" :key="index">
  28. <!-- 头部区域 -->
  29. <div class="header-section">
  30. <div class="header-left">
  31. <div class="farm-name van-ellipsis">{{ item.farmName }}</div>
  32. <div class="tag-group">
  33. <div class="tag tag-blue">{{ item.typeName }}</div>
  34. <div class="tag" :class="{'tag-orange': item.userType === 2}">{{ item.userType === 1 ? '普通客户' : '托管客户' }}</div>
  35. </div>
  36. </div>
  37. <div class="remind-btn" @click="handleRemind(item)">提醒客户</div>
  38. </div>
  39. <!-- 警告通知块 -->
  40. <div
  41. class="warning-block"
  42. v-if="item.latestPhenologyProgressBroadcast"
  43. v-html="item.latestPhenologyProgressBroadcast?.content"
  44. ></div>
  45. <!-- 时间轴组件,只负责时间轴区域 -->
  46. <AgriculturalInteractionCard :item="item" @updateList="updateAllData" />
  47. </div>
  48. </template>
  49. </div>
  50. </div>
  51. <offer-popup ref="offerPopupRef"></offer-popup>
  52. <!-- 确认执行时间 -->
  53. <calendar
  54. teleport="#app"
  55. v-model:show="showCalendar"
  56. @confirm="onConfirmExecuteTime"
  57. :min-date="minDate"
  58. :max-date="maxDate"
  59. />
  60. </template>
  61. <script setup>
  62. import router from "@/router";
  63. import { ref, onMounted, onActivated } from "vue";
  64. import { Calendar } from "vant";
  65. import { ElMessage } from "element-plus";
  66. import offerPopup from "@/components/popup/offerPopup.vue";
  67. import AgriculturalInteractionCard from "@/components/pageComponents/AgriculturalInteractionCard.vue";
  68. import { formatDate } from "@/common/commonFun";
  69. // 任务列表数据
  70. const taskList = ref([]);
  71. const handleTaskAction = (item) => {
  72. router.push({
  73. path: "/completed_work",
  74. query: { miniJson: JSON.stringify({ id: item.id }) },
  75. });
  76. };
  77. const offerPopupRef = ref(null);
  78. const showOfferPopup = (item) => {
  79. offerPopupRef.value.openPopup(item);
  80. };
  81. const showCalendar = ref(false);
  82. const maxDate = ref();
  83. // 最小日期设置为今天,今天可以选择
  84. const minDate = new Date();
  85. const executeItem = ref(null);
  86. const selectExecuteTime = (item) => {
  87. executeItem.value = item;
  88. maxDate.value = new Date(item.executeDeadlineDate);
  89. showCalendar.value = true;
  90. };
  91. const onConfirmExecuteTime = (date) => {
  92. showCalendar.value = false;
  93. VE_API.z_farm_work_record
  94. .updateExpectedExecuteDate({ recordId: executeItem.value.id, expectedExecuteDate: formatDate(date) })
  95. .then((res) => {
  96. if (res.code === 0) {
  97. ElMessage.success("操作成功");
  98. getTaskList();
  99. }
  100. });
  101. };
  102. const handleRemind = (item) => {
  103. router.push(`/remind_customer?farmId=${item.farmId}`);
  104. };
  105. onActivated(() => {
  106. updateAllData();
  107. });
  108. const updateAllData = () => {
  109. getUnansweredFarms();
  110. getTaskList();
  111. };
  112. //农情互动的农场列表接口(分页)
  113. const getTaskList = async () => {
  114. const res = await VE_API.z_farm_work_record.getSimpleList({ role: 2, flowStatus: 4 });
  115. taskList.value = (res.data || []).slice(0, 2);
  116. };
  117. const unansweredList = ref([]);
  118. const getUnansweredFarms = async () => {
  119. const params = {
  120. page: 0,
  121. limit: 3,
  122. flowStatus: 5,
  123. };
  124. const res = await VE_API.home.listUnansweredFarms(params);
  125. unansweredList.value = (res.data || []).map((item) => ({
  126. ...item,
  127. timelineList: [],
  128. }));
  129. // 串行请求,一个完成后再请求下一个
  130. if (unansweredList.value.length) {
  131. for (let i = 0; i < unansweredList.value.length; i++) {
  132. await getFutureFarmWorkWarning(unansweredList.value[i]);
  133. }
  134. }
  135. };
  136. //查询未来农事预警
  137. const getFutureFarmWorkWarning = async (item) => {
  138. const res = await VE_API.home.listFutureFarmWorkWarning({ farmId: item.farmId });
  139. item.timelineList = res.data || [];
  140. };
  141. </script>
  142. <style scoped lang="scss">
  143. .agricultural-dynamics {
  144. padding: 0 10px;
  145. // 任务列表样式
  146. .task-list {
  147. .task-item {
  148. display: flex;
  149. align-items: center;
  150. justify-content: space-between;
  151. background-color: #ffffff;
  152. border-radius: 8px;
  153. padding: 12px;
  154. margin-top: 10px;
  155. position: relative;
  156. overflow: hidden;
  157. &::after {
  158. content: "";
  159. position: absolute;
  160. top: -10px;
  161. right: 0;
  162. width: 72px;
  163. height: 72px;
  164. pointer-events: none;
  165. background: url("@/assets/img/home/task-icon.png") no-repeat center center / 100% 100%;
  166. }
  167. .task-content {
  168. flex: 1;
  169. .task-header {
  170. display: flex;
  171. align-items: center;
  172. margin-bottom: 4px;
  173. gap: 8px;
  174. }
  175. .task-status-tag {
  176. background-color: rgba(33, 153, 248, 0.1);
  177. color: #2199f8;
  178. font-size: 12px;
  179. padding: 1px 6px;
  180. border-radius: 2px;
  181. }
  182. .task-title {
  183. font-size: 16px;
  184. font-weight: 500;
  185. color: #1d2129;
  186. }
  187. .task-time {
  188. font-size: 12px;
  189. color: rgba(78, 89, 105, 0.5);
  190. &.deadline {
  191. color: rgba(255, 85, 85, 0.7);
  192. }
  193. }
  194. }
  195. .task-action {
  196. flex: none;
  197. background-color: rgba(33, 153, 248, 0.1);
  198. color: #2199f8;
  199. border-radius: 25px;
  200. padding: 7px 14px;
  201. font-size: 12px;
  202. &.orange {
  203. color: #ff953d;
  204. background: rgba(255, 149, 61, 0.1);
  205. }
  206. }
  207. }
  208. }
  209. .title {
  210. font-size: 16px;
  211. font-weight: 500;
  212. color: #1d2129;
  213. margin-top: 10px;
  214. }
  215. .agricultural-list {
  216. .empty-block {
  217. display: flex;
  218. align-items: center;
  219. justify-content: center;
  220. height: 120px;
  221. color: #a0a0a0;
  222. font-size: 14px;
  223. background-color: #ffffff;
  224. border-radius: 8px;
  225. margin-top: 8px;
  226. }
  227. .agricultural-item {
  228. background-color: #ffffff;
  229. border-radius: 8px;
  230. padding: 8px 12px;
  231. margin-top: 8px;
  232. // 头部区域样式
  233. .header-section {
  234. display: flex;
  235. align-items: center;
  236. justify-content: space-between;
  237. padding-bottom: 5px;
  238. border-bottom: 0.5px solid rgba(0, 0, 0, 0.1);
  239. .header-left {
  240. display: flex;
  241. align-items: center;
  242. gap: 8px;
  243. width: calc(100% - 80px);
  244. .farm-name {
  245. font-size: 16px;
  246. font-weight: 500;
  247. color: #1d2129;
  248. max-width: calc(100% - 130px);
  249. }
  250. .tag-group {
  251. display: flex;
  252. gap: 4px;
  253. .tag {
  254. padding: 2px 8px;
  255. border-radius: 2px;
  256. font-size: 12px;
  257. color: #848282;
  258. background-color: rgba(148, 148, 148, 0.1);
  259. &.tag-blue {
  260. background-color: #e8f3ff;
  261. color: #2199f8;
  262. }
  263. &.tag-orange {
  264. background-color: rgba(255, 149, 61, 0.1);
  265. color: #ff953d;
  266. }
  267. }
  268. }
  269. }
  270. .remind-btn {
  271. background-color: #2199f8;
  272. color: #ffffff;
  273. border-radius: 25px;
  274. padding: 7px 12px;
  275. font-size: 12px;
  276. }
  277. }
  278. // 警告通知块样式
  279. .warning-block {
  280. background-color: rgba(33, 153, 248, 0.1);
  281. border-radius: 5px;
  282. padding: 5px;
  283. margin-top: 8px;
  284. font-size: 12px;
  285. color: #252525;
  286. ::v-deep {
  287. p {
  288. padding: 0;
  289. margin: 0;
  290. }
  291. }
  292. }
  293. }
  294. }
  295. }
  296. </style>