task.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. <template>
  2. <div class="task-page" :style="{ height: `calc(100vh - ${tabBarHeight}px - 50px)` }">
  3. <div class="task-top">
  4. <div class="map-container" ref="mapContainer"></div>
  5. <div class="calendar-wrap">
  6. <calendar ref="calendarRef" @dateSelect="handleDateSelect"></calendar>
  7. </div>
  8. </div>
  9. <div class="task-list">
  10. <div class="list-filter">
  11. <div class="filter-item" :class="{ active: activeIndex === 0 }" @click="handleActiveFilter(0)">
  12. 待确认({{ taskCounts[0] || 0 }})
  13. </div>
  14. <!-- <div class="filter-item" :class="{ active: activeIndex === 1 }" @click="handleActiveFilter(1)">
  15. 已确认({{ taskCounts[1] || 0 }})
  16. </div> -->
  17. <div class="filter-item" :class="{ active: activeIndex === 2 }" @click="handleActiveFilter(2)">
  18. 待完成({{ taskCounts[2] || 0 }})
  19. </div>
  20. <div class="filter-item" :class="{ active: activeIndex === 3 }" @click="handleActiveFilter(3)">
  21. 已完成({{ taskCounts[3] || 0 }})
  22. </div>
  23. </div>
  24. <div class="select-group">
  25. <el-select
  26. class="select-item"
  27. v-model="selectParma.farmWorkTypeId"
  28. placeholder="农事类型"
  29. @change="getSimpleList"
  30. >
  31. <el-option v-for="item in farmWorkTypeList" :key="item.id" :label="item.name" :value="item.id" />
  32. </el-select>
  33. <el-select
  34. class="select-item"
  35. v-model="selectParma.districtCode"
  36. placeholder="区域筛选"
  37. @change="getSimpleList"
  38. >
  39. <el-option v-for="item in districtList" :key="item.code" :label="item.name" :value="item.code" />
  40. </el-select>
  41. </div>
  42. <!-- <div class="task-content-loading" v-if="loading && noData" v-loading="loading">
  43. </div> -->
  44. <div class="task-content" v-loading="loading">
  45. <div class="task-item" v-for="(item, index) in taskList" :key="item.id || item.workRecordId">
  46. <task-item
  47. :key="activeIndex + '-' + index"
  48. :itemIndex="activeIndex"
  49. :status="activeIndex === 3 ? 1 : 0"
  50. :item-data="item"
  51. @handleUploadSuccess="handleUploadSuccess"
  52. :ref="(el) => setTaskItemRef(el, index)"
  53. >
  54. <template #footer>
  55. <div class="item-footer" v-if="activeIndex === 0 || activeIndex === 2">
  56. <div class="footer-l" @click="toDetail(item)">查看详情</div>
  57. <div class="footer-r">
  58. <div v-if="activeIndex === 0" class="btn second" @click="handleAction(item)">
  59. 忽略
  60. </div>
  61. <div class="btn primary" v-if="activeIndex === 0" @click="showPriceSheetPopup(item)">
  62. 确认并报价
  63. </div>
  64. <div v-else class="btn primary" @click="showUploadExecutePopup(item)">
  65. 请求确认
  66. </div>
  67. </div>
  68. </div>
  69. <div v-else-if="activeIndex === 1" class="item-footer">
  70. <div class="footer-l" @click="toDetail(item)">查看详情</div>
  71. <div class="footer-r">
  72. <!-- <div class="btn second" @click="handleForward(item)">
  73. 转发给客户
  74. </div> -->
  75. <div class="btn primary" @click="showPriceSheetPopup(item)">确认并报价</div>
  76. </div>
  77. </div>
  78. </template>
  79. </task-item>
  80. </div>
  81. <div class="empty-data" v-if="noData">暂无数据</div>
  82. </div>
  83. </div>
  84. </div>
  85. <upload-execute ref="uploadExecuteRef" :onlyShare="onlyShare" @uploadSuccess="handleUploadSuccess" />
  86. <popup v-model:show="showTaskPopup" round class="task-tips-popup">
  87. <template v-if="taskPopupType === 'warning'">
  88. <img class="create-farm-icon" src="@/assets/img/home/create-farm-icon.png" alt="" />
  89. <div class="create-farm-text">
  90. <div>
  91. 您确认忽略 <span class="main-text">{{ currentTask?.farmName }}</span> 的
  92. <span class="main-text">{{ currentTask?.farmWorkName }}</span> 农事吗
  93. </div>
  94. </div>
  95. </template>
  96. <template v-else>
  97. <img class="farm-check-icon" src="@/assets/img/home/right.png" alt="" />
  98. <div class="create-farm-text success-text">农事已下发成功</div>
  99. </template>
  100. <div class="create-farm-btn" @click="handlePopupBtn">
  101. {{ taskPopupType === "warning" ? "确认忽略" : "我知道了" }}
  102. </div>
  103. </popup>
  104. <!-- 服务报价单 -->
  105. <price-sheet-popup ref="priceSheetPopupRef"></price-sheet-popup>
  106. </template>
  107. <script setup>
  108. import { computed, nextTick, onMounted, ref, watch } from "vue";
  109. import { useStore } from "vuex";
  110. import { Popup } from "vant";
  111. import IndexMap from "../../farm_manage/map/index";
  112. import taskItem from "@/components/taskItem.vue";
  113. import calendar from "./calendar.vue";
  114. import { useRouter } from "vue-router";
  115. import uploadExecute from "./uploadExecute.vue";
  116. import priceSheetPopup from "@/components/popup/priceSheetPopup.vue";
  117. import { ElMessage } from "element-plus";
  118. const store = useStore();
  119. const router = useRouter();
  120. const indexMap = new IndexMap();
  121. const mapContainer = ref(null);
  122. const tabBarHeight = computed(() => store.state.home.tabBarHeight);
  123. const uploadExecuteRef = ref(null);
  124. const dateValue = ref("1");
  125. const calendarRef = ref(null);
  126. const selectParma = ref({
  127. farmWorkTypeId: null,
  128. districtCode: null,
  129. });
  130. // 任务列表数据(用于显示,可能被筛选)
  131. const taskList = ref([]);
  132. // 完整的任务列表数据(用于日历显示,不被筛选影响)
  133. const fullTaskList = ref([]);
  134. // 各状态任务数量
  135. const taskCounts = ref([0, 0, 0]);
  136. // 当前选中的筛选索引
  137. const activeIndex = ref(0);
  138. // 筛选日期(用于按日期筛选)
  139. const filterDate = ref(null);
  140. const noData = ref(false);
  141. const loading = ref(false);
  142. const showTaskPopup = ref(false);
  143. const taskPopupType = ref("warning");
  144. // 根据 activeIndex 计算 startFlowStatus
  145. const getStartFlowStatus = (index) => {
  146. const statusMap = {
  147. 0: 0, // 待确认
  148. 1: "1,2,3", // 待完成
  149. 2: 4, // 待完成
  150. 3: 5, // 已完成
  151. };
  152. return statusMap[index] ?? 0;
  153. };
  154. // 获取单个状态的任务数量
  155. function getTaskCount(flowStatus, index) {
  156. const location = store.state.home.miniUserLocationPoint;
  157. return VE_API.z_farm_work_record
  158. .getSimpleList({ role: 2, location, flowStatus })
  159. .then(({ data }) => {
  160. if (Array.isArray(data)) {
  161. taskCounts.value[index] = data.length;
  162. calendarRef.value && calendarRef.value.setCounts(index, taskCounts.value[index]);
  163. if (index === 2) {
  164. calendarRef.value && calendarRef.value.setSolarTerm(data);
  165. indexMap.initData(data);
  166. }
  167. } else if (data?.total !== undefined) {
  168. taskCounts.value[index] = data.total;
  169. } else {
  170. taskCounts.value[index] = 0;
  171. }
  172. })
  173. .catch((error) => {
  174. console.error(`获取状态${index}任务数量失败:`, error);
  175. taskCounts.value[index] = 0;
  176. });
  177. }
  178. const taskItemRefs = ref([]);
  179. const setTaskItemRef = (el, index) => {
  180. if (el) {
  181. taskItemRefs.value[index] = el;
  182. }
  183. };
  184. const handleUploadSuccess = async () => {
  185. // 先保存当前需要更新的 item id
  186. const currentItemIds = taskList.value.map((item) => item.id || item.workRecordId);
  187. // 刷新列表
  188. await getSimpleList();
  189. // 等待 DOM 更新完成,refs 被重新收集
  190. await nextTick();
  191. // 更新所有task-item的triggerImg
  192. taskItemRefs.value.forEach((ref) => {
  193. if (ref && ref.updateTriggerImg) {
  194. ref.updateTriggerImg();
  195. }
  196. });
  197. };
  198. const cityCode = ref("");
  199. //根据城市的坐标返回区县列表
  200. const districtList = ref([]);
  201. function getDistrictListByCity() {
  202. VE_API.z_farm_work_record.getDistrictListByCity({ point: mapPoint.value }).then(({ data }) => {
  203. districtList.value = data || [];
  204. // cityCode.value = data[0].code.slice(0, -2);
  205. cityCode.value = "";
  206. districtList.value.unshift({ code: cityCode.value, name: "全部" });
  207. selectParma.value.districtCode = cityCode.value;
  208. getSimpleList();
  209. });
  210. }
  211. //农事类型列表
  212. const farmWorkTypeList = ref([]);
  213. function getFarmWorkTypeList() {
  214. VE_API.z_farm_work_record.getFarmWorkTypeList().then(({ data }) => {
  215. farmWorkTypeList.value = data;
  216. farmWorkTypeList.value.unshift({ id: 0, name: "全部" });
  217. });
  218. }
  219. // 初始化时获取所有状态的任务数量
  220. function initTaskCounts() {
  221. const location = store.state.home.miniUserLocationPoint;
  222. // 并行请求三个状态的数量
  223. Promise.all([
  224. getTaskCount(0, 0), // 待确认
  225. getTaskCount("1,2,3", 1), // 待确认
  226. getTaskCount(4, 2), // 待完成
  227. getTaskCount(5, 3), // 已完成
  228. ]);
  229. }
  230. const mapPoint = ref(null);
  231. onMounted(() => {
  232. mapPoint.value = store.state.home.miniUserLocationPoint;
  233. // 初始化时获取所有状态的数量
  234. initTaskCounts();
  235. // 加载当前选中状态的数据列表
  236. getSimpleList();
  237. getDistrictListByCity();
  238. getFarmWorkTypeList();
  239. nextTick(() => {
  240. indexMap.initMap(mapPoint.value, mapContainer.value, true);
  241. });
  242. });
  243. // 标记是否正在通过日期选择切换筛选(避免 watch 清除日期筛选)
  244. const isDateSelecting = ref(false);
  245. // 监听 activeIndex 变化,重新加载数据
  246. watch(activeIndex, () => {
  247. // 如果正在通过日期选择切换,不清除日期筛选
  248. if (isDateSelecting.value) {
  249. isDateSelecting.value = false;
  250. getSimpleList();
  251. return;
  252. }
  253. // 切换筛选时清除日期筛选
  254. filterDate.value = null;
  255. // 清除日历选中状态
  256. if (calendarRef.value) {
  257. calendarRef.value.clearSelection();
  258. }
  259. getSimpleList();
  260. });
  261. function getSimpleList() {
  262. loading.value = true;
  263. noData.value = false;
  264. // 清空refs数组,避免索引错乱
  265. taskItemRefs.value = [];
  266. const startFlowStatus = getStartFlowStatus(activeIndex.value);
  267. const params = {
  268. ...selectParma.value,
  269. role: 2,
  270. location: mapPoint.value,
  271. flowStatus: startFlowStatus,
  272. farmWorkTypeId: selectParma.value.farmWorkTypeId || null,
  273. };
  274. return VE_API.z_farm_work_record
  275. .getSimpleList(params)
  276. .then(({ data }) => {
  277. loading.value = false;
  278. // 假设返回的数据结构是 { list: [], total: 0 } 或者直接是数组
  279. let filteredData = data
  280. // 保存完整数据(用于日历显示)
  281. if (activeIndex.value === 2) {
  282. // 如果是"待完成"状态,保存完整数据用于日历
  283. fullTaskList.value = Array.isArray(data) ? data : [];
  284. }
  285. // 如果有日期筛选,在前端再次过滤(确保数据准确)
  286. if (filterDate.value && Array.isArray(data)) {
  287. filteredData = data.filter((item) => {
  288. if (!item.executeDate) return false;
  289. const itemDate = formatDate(new Date(item.executeDate));
  290. return itemDate === filterDate.value;
  291. });
  292. }
  293. if (Array.isArray(filteredData) && filteredData.length > 0) {
  294. taskList.value = filteredData;
  295. // 更新当前状态的数量
  296. taskCounts.value[activeIndex.value] = filteredData.length;
  297. if (activeIndex.value === 2) {
  298. // 传递给日历的数据应该是完整的未筛选数据
  299. const calendarData = filterDate.value ? fullTaskList.value : taskList.value;
  300. calendarRef.value && calendarRef.value.setSolarTerm(calendarData);
  301. // 地图使用筛选后的数据
  302. indexMap.initData(taskList.value);
  303. }
  304. }else{
  305. noData.value = true;
  306. taskList.value = [];
  307. taskCounts.value[activeIndex.value] = 0;
  308. }
  309. })
  310. .catch((error) => {
  311. console.error("获取任务列表失败:", error);
  312. loading.value = false;
  313. taskList.value = [];
  314. taskCounts.value[activeIndex.value] = 0;
  315. if (activeIndex.value === 2) {
  316. // 即使筛选后没有数据,日历也应该显示完整数据
  317. const calendarData = filterDate.value ? fullTaskList.value : [];
  318. indexMap.initData(taskList.value);
  319. calendarRef.value && calendarRef.value.setSolarTerm(calendarData);
  320. }
  321. noData.value = true;
  322. });
  323. }
  324. // 格式化日期函数(与 calendar 组件保持一致)
  325. function formatDate(date) {
  326. if (typeof date === "string") {
  327. date = new Date(date);
  328. }
  329. return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(
  330. 2,
  331. "0"
  332. )}`;
  333. }
  334. // 处理日历日期选择
  335. const handleDateSelect = (date) => {
  336. if (date) {
  337. // 有日期选择,切换到"待完成"筛选并设置筛选日期
  338. filterDate.value = date;
  339. // 如果当前不是"待完成"状态,切换到"待完成"
  340. if (activeIndex.value !== 2) {
  341. isDateSelecting.value = true; // 标记正在通过日期选择切换
  342. activeIndex.value = 2;
  343. // watch 会处理 getSimpleList
  344. } else {
  345. // 如果已经是"待完成"状态,直接重新加载列表
  346. getSimpleList();
  347. }
  348. } else {
  349. // 取消日期筛选
  350. filterDate.value = null;
  351. // 重新加载列表
  352. getSimpleList();
  353. }
  354. };
  355. function handleActiveFilter(i) {
  356. activeIndex.value = i;
  357. // watch 会自动处理清除日期筛选和日历选中状态
  358. selectParma.value.districtCode = cityCode.value
  359. selectParma.value.farmWorkTypeId = null
  360. }
  361. function toPage(item) {
  362. // router.push("/servicZes_agri")
  363. // if (activeIndex.value === 2) {
  364. // } else {
  365. // // 下发农事请求
  366. // const data = {
  367. // id: item.id,
  368. // };
  369. // VE_API.z_farm_work_record.issueFarmWorkRecord(data).then((res) => {
  370. // if (res.code === 0) {
  371. // taskPopupType.value = "success";
  372. // showTaskPopup.value = true;
  373. // getSimpleList();
  374. // }
  375. // });
  376. // }
  377. }
  378. const showUploadExecutePopup = (item) => {
  379. if (item?.executeEvidence.length) {
  380. onlyShare.value = true;
  381. } else {
  382. onlyShare.value = false;
  383. }
  384. setTimeout(() => {
  385. uploadExecuteRef.value.showPopup(item);
  386. }, 10);
  387. };
  388. function toDetail(item) {
  389. if (activeIndex.value === 0) {
  390. router.push({
  391. path: "/modify_work",
  392. query: { id: item.id },
  393. });
  394. } else {
  395. router.push({
  396. path: "/completed_work",
  397. query: { json: JSON.stringify({ id: item.id }) },
  398. });
  399. }
  400. }
  401. const priceSheetPopupRef = ref(null);
  402. const showPriceSheetPopup = (item) => {
  403. VE_API.z_farm_work_record.getDetail({ id: item.id }).then(({ data }) => {
  404. const res = data[0];
  405. priceSheetPopupRef.value.handleShowPopup(res);
  406. });
  407. };
  408. const onlyShare = ref(false);
  409. const currentTask = ref(null);
  410. function handleAction(item) {
  411. if (activeIndex.value === 0) {
  412. taskPopupType.value = "warning";
  413. showTaskPopup.value = true;
  414. currentTask.value = item;
  415. } else {
  416. onlyShare.value = true;
  417. setTimeout(() => {
  418. uploadExecuteRef.value.showPopup(item, "share-sheet");
  419. }, 10);
  420. }
  421. }
  422. function handlePopupBtn() {
  423. showTaskPopup.value = false;
  424. if (taskPopupType.value === "warning") {
  425. // 确认忽略
  426. } else {
  427. // 待确认
  428. getTaskCount("1,2,3", 1);
  429. }
  430. }
  431. function handleForward(item) {
  432. if (item.quoteCount && item.quoteCount != 0) {
  433. onlyShare.value = true;
  434. setTimeout(() => {
  435. uploadExecuteRef.value.showPopup(
  436. { ...item, type: "quotation", farmWorkOrderId: item.orderId },
  437. "share-sheet"
  438. );
  439. }, 10);
  440. } else {
  441. ElMessage.warning("暂无报价数据,无法分享");
  442. return;
  443. }
  444. }
  445. </script>
  446. <style lang="scss" scoped>
  447. .task-page {
  448. width: 100%;
  449. height: calc(100vh - 50px - 50px);
  450. overflow: auto;
  451. box-sizing: border-box;
  452. background: #f5f7fb;
  453. .map-container {
  454. width: 100%;
  455. height: 162px;
  456. clip-path: inset(0px round 8px);
  457. }
  458. .select-group {
  459. display: flex;
  460. padding: 0 12px;
  461. .select-item {
  462. width: 100%;
  463. ::v-deep {
  464. .el-select__wrapper {
  465. text-align: center;
  466. gap: 2px;
  467. box-shadow: none;
  468. justify-content: center;
  469. background: none;
  470. }
  471. .el-select__selection {
  472. flex: none;
  473. width: fit-content;
  474. }
  475. .el-select__placeholder {
  476. position: static;
  477. transform: none;
  478. width: fit-content;
  479. color: rgba(0, 0, 0, 0.2);
  480. }
  481. .el-select__caret {
  482. color: rgba(0, 0, 0, 0.2);
  483. }
  484. }
  485. }
  486. }
  487. .calendar-wrap {
  488. padding: 10px 0 4px 0;
  489. }
  490. .task-top {
  491. padding: 10px 12px;
  492. }
  493. .task-content-loading {
  494. height: 80px;
  495. border-radius: 8px;
  496. position: absolute;
  497. top: 60px;
  498. left: 0;
  499. width: 100%;
  500. }
  501. .task-content {
  502. min-height: 80px;
  503. }
  504. .empty-data {
  505. text-align: center;
  506. font-size: 14px;
  507. color: #6f7274;
  508. padding: 20px 0;
  509. }
  510. .task-list {
  511. position: relative;
  512. background: #fff;
  513. padding: 8px 12px;
  514. }
  515. .list-filter {
  516. display: flex;
  517. align-items: center;
  518. justify-content: space-around;
  519. .filter-item {
  520. padding: 0 12px;
  521. height: 28px;
  522. color: rgba(0, 0, 0, 0.5);
  523. font-size: 14px;
  524. line-height: 28px;
  525. border-radius: 20px;
  526. &.active {
  527. color: #2199f8;
  528. background: rgba(33, 153, 248, 0.2);
  529. }
  530. }
  531. }
  532. .task-item + .task-item {
  533. margin-top: 10px;
  534. }
  535. .item-footer {
  536. margin-top: 10px;
  537. padding-top: 11px;
  538. border-top: 1px solid rgba(0, 0, 0, 0.1);
  539. display: flex;
  540. align-items: center;
  541. justify-content: space-between;
  542. font-size: 12px;
  543. .footer-l {
  544. color: #8b8b8b;
  545. font-size: 12px;
  546. &.primary-btn {
  547. display: inline-flex;
  548. align-items: center;
  549. border: 1px solid #2199f8;
  550. background: rgba(33, 153, 248, 0.1);
  551. padding: 0 12px;
  552. height: 32px;
  553. box-sizing: border-box;
  554. display: flex;
  555. align-items: center;
  556. border-radius: 20px;
  557. color: #2199f8;
  558. .share-icon {
  559. width: 12px;
  560. padding-right: 4px;
  561. }
  562. }
  563. &.farm-name-text {
  564. font-size: 14px;
  565. color: #6f7274;
  566. .name-text {
  567. padding-left: 4px;
  568. }
  569. }
  570. }
  571. .footer-r {
  572. display: flex;
  573. align-items: center;
  574. .btn {
  575. height: 32px;
  576. line-height: 32px;
  577. padding: 0 12px;
  578. border-radius: 20px;
  579. display: flex;
  580. align-items: center;
  581. box-sizing: border-box;
  582. &.second {
  583. // border: 1px solid #8B8B8B;
  584. // color: #8B8B8B;
  585. color: #2199f8;
  586. background: rgba(33, 153, 248, 0.1);
  587. }
  588. &.primary {
  589. background: #2199f8;
  590. color: #fff;
  591. }
  592. .btn-icon {
  593. padding-right: 4px;
  594. }
  595. &.warning {
  596. color: #ff953d;
  597. background: #fff;
  598. border: 1px solid #ff953d;
  599. }
  600. &.secondary-text {
  601. color: #2199f8;
  602. border: 1px solid #2199f8;
  603. }
  604. }
  605. .btn + .btn {
  606. margin-left: 8px;
  607. }
  608. }
  609. }
  610. }
  611. .task-tips-popup {
  612. width: 75%;
  613. padding: 28px 28px 20px;
  614. display: flex;
  615. flex-direction: column;
  616. align-items: center;
  617. justify-content: center;
  618. .create-farm-icon {
  619. width: 40px;
  620. height: 40px;
  621. margin-bottom: 12px;
  622. }
  623. .farm-check-icon {
  624. width: 68px;
  625. height: 68px;
  626. margin-bottom: 12px;
  627. }
  628. .create-farm-text {
  629. font-size: 20px;
  630. font-weight: 500;
  631. line-height: 40px;
  632. margin-bottom: 32px;
  633. text-align: center;
  634. &.success-text {
  635. font-size: 23px;
  636. font-weight: 400;
  637. }
  638. }
  639. .main-text {
  640. color: #2199f8;
  641. }
  642. .create-farm-btn {
  643. width: 100%;
  644. box-sizing: border-box;
  645. padding: 8px;
  646. border-radius: 25px;
  647. font-size: 16px;
  648. background: #2199f8;
  649. color: #fff;
  650. text-align: center;
  651. }
  652. }
  653. </style>