| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160 |
- <template>
- <div class="agri-file-page" :style="{ height: `calc(100vh - ${tabBarHeight}px)` }">
- <farm-header />
- <div class="nav-cards">
- <div
- v-for="item in navCards"
- :key="item.key"
- class="nav-card-wrap"
- :class="{ 'nav-card-wrap--report': item.key === 'report' }"
- >
- <div
- class="nav-card"
- :class="{ 'is-active': activeNav === item.key }"
- @click="handleNavClick(item)"
- >
- <img class="nav-card__icon" :src="item.icon" alt="" />
- <span class="nav-card__label">{{ t(item.labelKey) }}</span>
- </div>
- <div v-if="item.key === 'report' && guideVisible" class="report-guide-bubble">
- <span class="report-guide-bubble__arrow"></span>
- <div class="report-guide-bubble__content">
- {{ t("agriFile.diagnosisReportGuidePrefix") }}
- <span class="report-guide-bubble__link" @click.stop="handleGuideUpload">
- {{ t("agriFile.uploadPhoto") }}
- </span>
- {{ t("agriFile.diagnosisReportGuideSuffix") }}
- </div>
- </div>
- </div>
- </div>
- <div class="content-panel">
- <div v-show="activeNav === 'patrol'">
- <div v-for="item in patrolList" :key="item.id" class="tracking-item"
- :class="`tracking-item--${item.theme}`" @click="goGrowthTrack(item)">
- <div class="tracking-item__header">
- <div class="tracking-item__header-row">
- <div class="tracking-item__header-left">
- <span class="tracking-item__level">
- <el-icon><BellFilled /></el-icon>
- {{ item.level }}
- </span>
- <span class="tracking-item__title van-ellipsis">
- {{ item.title }}<span v-if="item.zone" class="tracking-item__zone"> ({{ item.zone }})</span>
- </span>
- </div>
- <!-- <div class="tracking-item__share" @click.stop="handleShare(item)">
- <Icon size="14" color="#2199F8" name="share" />
- <span>{{ t("agriFile.forward") }}</span>
- </div> -->
- </div>
- </div>
- <div class="tracking-item__body">
- <div class="tracking-item__action">
- <div class="tracking-item__action-main">
- <div class="tracking-item__icon">
- <img :src="item.icon" alt="" />
- <span class="tracking-item__reason">{{ item.subject }}</span>
- </div>
- <div class="tracking-item__issue">{{ item.issue }}</div>
- </div>
- <!-- <div class="tracking-item__btn" @click.stop="handleUploadClick(item)">
- <el-icon>
- <Plus />
- </el-icon>
- <span>{{ t("agriFile.uploadPhoto") }}</span>
- </div> -->
- </div>
- </div>
- </div>
- <div class="crop-archive">
- <div class="crop-archive__title">{{ t("agriFile.cropArchive") }}</div>
- <PhenologyTrackTimelineItem :list="cropArchiveList" />
- </div>
- </div>
- <div v-show="activeNav === 'album'">
- <div class="map-card" @click="goAlbumMap">
- <div ref="mapContainer" class="map-container"></div>
- <!-- <div v-if="noFarmRange" class="map-mask" @click.stop="goAddZone('farm')">
- <div class="mask-content">
- <div class="mask-content__title">勾画种植区域,关联作物照片</div>
- <div class="mask-content__btn">去勾选</div>
- </div>
- </div> -->
- <!-- <div v-else class="add-zone-btn" @click.stop="goAddZone('region')">
- <el-icon>
- <Plus />
- </el-icon>
- <span>{{ t("agriFile.addZone") }}</span>
- </div> -->
- <div v-for="item in zoneList" :key="item.id" :ref="(el) => setMarkerEl(item.id, el)"
- class="zone-marker">
- <div class="zone-marker__label">{{ item.name }}</div>
- <div class="zone-marker__thumb">
- <img :src="item.cover" alt="" />
- <span class="zone-marker__badge">{{ item.count }}</span>
- </div>
- <div class="zone-marker__arrow"></div>
- </div>
- </div>
- <div class="album-grid" v-if="!noFarmRange">
- <!-- <div class="album-add" @click.stop="goAddZone('region')">
- <el-icon class="album-add__icon">
- <Plus />
- </el-icon>
- <span>{{ t("agriFile.addAlbum") }}</span>
- </div> -->
- <div v-for="item in albumList" :key="item.id" class="album-card" :class="{ 'is-empty': !item.count }">
- <div class="album-card__cover" @click.stop="goAlbumDetail(item)">
- <img v-if="item.count && item.cover" :src="item.cover" alt="" />
- <img v-else class="album-card__empty-icon" src="@/assets/img/agricultural/photo.png" alt="" />
- <span class="album-card__count">{{ t("agriFile.photoCount", { count: item.count }) }}</span>
- <!-- <div class="album-card__add" @click.stop="openUploadPopup">
- <el-icon>
- <Plus />
- </el-icon>
- </div> -->
- </div>
- <div class="album-card__name">{{ item.name }}</div>
- </div>
- </div>
- </div>
- <div v-show="activeNav === 'report'">
- <div v-for="item in reportList" :key="item.id" class="report-card">
- <div class="report-card__cover">
- <img :src="item.cover" alt="" />
- <span class="report-card__date">{{ item.date }}</span>
- <span class="report-card__status">
- <i class="report-card__dot"></i>
- {{ t("agriFile.reportUpdate") }}
- </span>
- </div>
- <div class="report-card__body">
- <div class="report-card__title">{{ item.title }}</div>
- <div class="report-card__desc">{{ item.desc }}</div>
- </div>
- </div>
- </div>
- </div>
- <album-upload-popup v-model:show="showUploadPopup" />
- <complete-farm-info-popup v-model:show="showCompleteFarmPopup" @confirm="goCompleteFarmInfo" />
- <!-- 诊断报告弹窗 -->
- <diagnosis-report-popup
- v-model:show="showDiagnosisReportPopup"
- @confirm="goDiagnosisReport" />
- <!-- 恢复种植弹窗 -->
- <restore-planting-popup />
- <!-- 代管弹窗:后续由接口控制是否展示 -->
- <proxy-auth-popup
- v-model:show="showProxyAuthPopup"
- :service-name="proxyServiceName"
- @reject="handleProxyReject"
- @allow="handleProxyAllow"
- />
- <!-- 申请更换物候期弹窗:后续由接口控制是否展示 -->
- <phenology-update-popup
- v-model:show="showPhenologyUpdatePopup"
- :service-name="phenologyUpdateInfo.serviceName"
- :current-stage="phenologyUpdateInfo.currentStage"
- :target-stage="phenologyUpdateInfo.targetStage"
- :current-image="phenologyUpdateInfo.currentImage"
- :farm-location="phenologyUpdateInfo.farmLocation"
- @reject="handlePhenologyUpdateReject"
- @confirm="handlePhenologyUpdateConfirm"
- />
- </div>
- </template>
- <script setup>
- import { computed, nextTick, onActivated, onBeforeUnmount, onMounted, ref, watch } from "vue";
- import { useStore } from "vuex";
- import { useRouter } from "vue-router";
- import Overlay from "ol/Overlay";
- import { useI18n } from "@/i18n";
- import { Icon } from 'vant';
- import FileMap from "./fileMap";
- import * as util from "@/common/ol_common.js";
- import farmHeader from "@/components/farmHeader.vue";
- import albumUploadPopup from "./components/albumUploadPopup.vue";
- import completeFarmInfoPopup from "@/components/popup/completeFarmInfoPopup.vue";
- import diagnosisReportPopup from "@/components/popup/diagnosisReportPopup.vue";
- import restorePlantingPopup from "@/components/popup/restorePlantingPopup.vue";
- import proxyAuthPopup from "@/components/popup/proxyAuthPopup.vue";
- import phenologyUpdatePopup from "@/components/popup/phenologyUpdatePopup.vue";
- import PhenologyTrackTimelineItem from "@/components/pageComponents/PhenologyTrackTimelineItem.vue";
- import wx from "weixin-js-sdk";
- const { t } = useI18n();
- const store = useStore();
- const router = useRouter();
- const tabBarHeight = computed(() => store.state.home.tabBarHeight);
- const DIAGNOSIS_GUIDE_STORAGE_KEY = "AGRI_FILE_DIAGNOSIS_REPORT_GUIDE";
- const ENTRY_FARM_DATA_KEY = "ENTRY_FARM_DATA";
- const CROP_ARCHIVE_KEY = "CROP_ARCHIVE_RECORDS";
- const guideVisible = ref(false);
- const defaultCover = require("@/assets/img/home/banner.png");
- const DEFAULT_CENTER = [113.6142086995688, 23.585836479509055];
- const activeNav = ref("patrol");
- const mapContainer = ref(null);
- const fileMap = new FileMap();
- const markerEls = {};
- const mapOverlays = [];
- const noFarmRange = ref(false);
- const navCards = [
- {
- key: "patrol",
- labelKey: "agriFile.patrolRecord",
- icon: require("@/assets/img/agricultural/icon-1.png"),
- },
- {
- key: "album",
- labelKey: "agriFile.agriAlbum",
- icon: require("@/assets/img/agricultural/icon-2.png"),
- },
- {
- key: "report",
- labelKey: "agriFile.diagnosisReport",
- icon: require("@/assets/img/agricultural/icon-3.png"),
- },
- ];
- /** 读取用户新增农场时选中的点位 */
- function readEntryFarmCoordinate() {
- try {
- const data = JSON.parse(localStorage.getItem(ENTRY_FARM_DATA_KEY) || "null");
- if (Array.isArray(data?.coordinate) && data.coordinate.length === 2) {
- return [Number(data.coordinate[0]), Number(data.coordinate[1])];
- }
- const point =
- data?.point ||
- localStorage.getItem("GROWTH_REPORT_MAP_POINT") ||
- localStorage.getItem("selectedFarmPoint");
- if (typeof point === "string" && /^POINT\s*\(/i.test(point.trim())) {
- return util.wktCastGeom(point).getFirstCoordinate();
- }
- } catch {
- // ignore
- }
- return null;
- }
- function buildZoneList(coordinate = readEntryFarmCoordinate() || DEFAULT_CENTER) {
- return [
- {
- id: 1,
- name: "",
- count: 2,
- cover: defaultCover,
- longitude: Number(coordinate[0]),
- latitude: Number(coordinate[1]),
- },
- ];
- }
- const zoneList = ref(buildZoneList());
- const albumList = ref([
- { id: 1, name: "", count: 125, cover: defaultCover },
- ]);
- const reportCover = require("@/assets/img/common/sd-1.jpg");
- const reportList = ref([
- { id: 1, title: "", desc: "", date: "", cover: reportCover },
- { id: 2, title: "", desc: "", date: "", cover: require("@/assets/img/common/sd-2.jpg") },
- { id: 3, title: "", desc: "", date: "", cover: require("@/assets/img/common/sd-3.jpg") },
- ]);
- const showUploadPopup = ref(false);
- const showCompleteFarmPopup = ref(false);
- const showDiagnosisReportPopup = ref(true);
- // 后续由接口控制是否展示代管授权弹窗
- const showProxyAuthPopup = ref(false);
- const proxyServiceName = ref("农服名称");
- const handleProxyReject = () => {
- // TODO: 调用拒绝代管接口
- };
- const handleProxyAllow = () => {
- // TODO: 调用允许代管接口
- };
- // 后续由接口控制是否展示申请更换物候期弹窗
- const showPhenologyUpdatePopup = ref(false);
- const phenologyUpdateInfo = ref({
- serviceName: "某某农服",
- currentStage: "花穗期",
- targetStage: "小果期",
- varietyName: "荔枝-桂味",
- farmLocation: "位置位置位置",
- });
- const handlePhenologyUpdateReject = () => {
- // TODO: 调用暂不更新接口
- };
- const handlePhenologyUpdateConfirm = () => {
- // TODO: 调用确认更新接口
- };
- const patrolList = ref([
- {
- id: 1,
- type: "growth",
- theme: "blue",
- level: "",
- title: "",
- subject: "",
- issue: "",
- icon: require("@/assets/img/report/wh-icon.png"),
- },
- {
- id: 2,
- type: "abnormal",
- theme: "blue",
- level: "",
- title: "",
- subject: "",
- issue: "",
- icon: require("@/assets/img/report/wh-icon.png"),
- },
- ]);
- const MOCK_CROP_ARCHIVE = [
- { id: "mock-2", date: "2025-04-18", contentKey: "agriFile.cropArchiveAbnormal" },
- { id: "mock-3", date: "2025-04-10", contentKey: "agriFile.cropArchiveMetric" },
- ];
- const cropArchiveList = ref([]);
- function readCropArchiveAnswers() {
- try {
- const list = JSON.parse(localStorage.getItem(CROP_ARCHIVE_KEY) || "[]");
- return Array.isArray(list) ? list : [];
- } catch {
- return [];
- }
- }
- const setMarkerEl = (id, el) => {
- if (el) markerEls[id] = el;
- else delete markerEls[id];
- };
- const getFarmCenter = () => {
- const entryCoordinate = readEntryFarmCoordinate();
- if (entryCoordinate) return entryCoordinate;
- try {
- const farm = JSON.parse(localStorage.getItem("selectedFarmData") || "{}");
- const wkt = farm.wkt || farm.geom_wkt || farm.farm_location;
- if (typeof wkt === "string" && /^POINT\s*\(/i.test(wkt.trim())) {
- return util.wktCastGeom(wkt).getFirstCoordinate();
- }
- } catch {
- // ignore
- }
- return DEFAULT_CENTER;
- };
- const clearMapOverlays = () => {
- if (!fileMap.kmap?.map) {
- mapOverlays.length = 0;
- return;
- }
- mapOverlays.forEach((overlay) => fileMap.kmap.map.removeOverlay(overlay));
- mapOverlays.length = 0;
- };
- const bindZoneOverlays = () => {
- if (!fileMap.kmap?.map) return;
- clearMapOverlays();
- zoneList.value.forEach((zone) => {
- const el = markerEls[zone.id];
- if (!el || zone.longitude == null || zone.latitude == null) return;
- const overlay = new Overlay({
- element: el,
- position: [zone.longitude, zone.latitude],
- positioning: "bottom-center",
- stopEvent: false,
- });
- fileMap.kmap.map.addOverlay(overlay);
- mapOverlays.push(overlay);
- });
- };
- const syncZoneFromEntry = () => {
- const coordinate = readEntryFarmCoordinate() || getFarmCenter();
- const zoneName = zoneList.value[0]?.name || "";
- zoneList.value = buildZoneList(coordinate).map((item) => ({
- ...item,
- name: zoneName,
- }));
- };
- const initAlbumMap = async () => {
- await nextTick();
- if (!mapContainer.value) return;
- syncZoneFromEntry();
- const center = getFarmCenter();
- fileMap.initMap(`POINT(${center[0]} ${center[1]})`, mapContainer.value);
- await nextTick();
- if (noFarmRange.value) {
- zoneList.value = [];
- albumList.value = [];
- return;
- }
- bindZoneOverlays();
- fileMap.kmap?.map?.updateSize?.();
- };
- const fillMockLabels = () => {
- const zoneName = t("agriFile.zoneLabel", { n: 1 });
- const albumName = t("agriFile.zoneOne");
- zoneList.value = zoneList.value.map((item) => ({ ...item, name: zoneName }));
- albumList.value = albumList.value.map((item) => ({ ...item, name: albumName }));
- reportList.value = reportList.value.map((item) => ({
- ...item,
- title: t("agriFile.reportTitle"),
- desc: t("agriFile.reportDesc"),
- date: t("agriFile.reportDate"),
- }));
- patrolList.value = patrolList.value.map((item, index) => ({
- ...item,
- level: t("agriFile.riskLevel2"),
- title: t(index === 0 ? "agriFile.patrolGrowthTitle" : "agriFile.patrolAbnormalTitle"),
- zone: albumName,
- subject: t("agriFile.patrolSubject"),
- issue: t("agriFile.patrolIssue"),
- }));
- cropArchiveList.value = [
- ...readCropArchiveAnswers(),
- ...MOCK_CROP_ARCHIVE.map((item) => ({
- id: item.id,
- date: item.date,
- zone_name: albumName,
- content: t(item.contentKey),
- })),
- ];
- };
- const goAddZone = (type) => {
- router.push(
- {
- path: "/add_zone",
- query: {
- type,
- isSuccessPopup: type === 'farm' ? '1' : '0',
- },
- }
- );
- };
- const goAlbumMap = () => {
- router.push("/album_map");
- };
- const goGrowthTrack = (item) => {
- router.push({
- path: "/growth_track",
- query: { id: item?.id, type: item?.type || "growth" },
- });
- };
- const handleShare = (item) => {
- const query = {
- askInfo: { title: "转发巡园要点", content: "是否分享给好友" },
- shareText: item?.title || "速长窗口不追肥?后期发育慢人一步,直接掉队!",
- targetUrl: "growth_track",
- paramsPage: JSON.stringify({
- id: item?.id,
- type: item?.type || "growth",
- fromShare: 1,
- }),
- imageUrl: "https://birdseye-img.sysuimars.com/temp/field.png",
- };
- wx.miniProgram.navigateTo({
- url: `/pages/subPages/share_page/index?pageParams=${JSON.stringify(query)}&type=sharePage`,
- });
- };
- const needDraw = ref(true);
- const openUploadPopup = () => {
- showUploadPopup.value = true;
- };
- /** 与 growthTrack 上传一致:需勾画 → add_zone;异常 → pest_interact;否则弹上传 */
- const handleUploadClick = (item) => {
- const isAbnormal = item?.type === "abnormal";
- if (needDraw.value) {
- router.push({
- path: "/add_zone",
- query: {
- type: "farm",
- targetUrl: isAbnormal ? "/pest_interact" : "/growth_track",
- ...(isAbnormal ? { isAbnormal: "true" } : {}),
- ...(item?.id != null ? { trackId: item.id } : {}),
- ...(item?.type ? { trackType: item.type } : {}),
- },
- });
- return;
- }
- if (isAbnormal) {
- router.push({ path: "/pest_interact" });
- return;
- }
- showUploadPopup.value = true;
- };
- const dismissGuide = () => {
- if (!guideVisible.value) return;
- guideVisible.value = false;
- localStorage.setItem(DIAGNOSIS_GUIDE_STORAGE_KEY, "1");
- };
- const tryShowGuide = () => {
- if (localStorage.getItem(DIAGNOSIS_GUIDE_STORAGE_KEY)) return;
- guideVisible.value = true;
- };
- const handleGuideUpload = () => {
- dismissGuide();
- openUploadPopup();
- };
- const handleNavClick = (item) => {
- if (item.key === "report") dismissGuide();
- activeNav.value = item.key;
- };
- const handleOutsideClick = (event) => {
- if (!guideVisible.value) return;
- const target = event.target;
- if (
- target?.closest?.(".report-guide-bubble") ||
- target?.closest?.(".nav-card-wrap--report .nav-card")
- ) {
- return;
- }
- dismissGuide();
- };
- const goCompleteFarmInfo = () => {
- router.push("/entry_information");
- };
- const goDiagnosisReport = () => {
- router.push("/diagnosis_report");
- };
- const goAlbumDetail = (item) => {
- router.push({
- path: "/region_albums",
- query: {
- id: item?.id,
- name: item?.name || "",
- noImage: item?.count ? "false" : "true",
- },
- });
- };
- onMounted(() => {
- fillMockLabels();
- initAlbumMap();
- tryShowGuide();
- document.addEventListener("click", handleOutsideClick, true);
- });
- onActivated(() => {
- fillMockLabels();
- initAlbumMap();
- tryShowGuide();
- });
- onBeforeUnmount(() => {
- clearMapOverlays();
- document.removeEventListener("click", handleOutsideClick, true);
- });
- watch(activeNav, (key) => {
- if (key === "album") {
- initAlbumMap();
- }
- });
- </script>
- <style lang="scss" scoped>
- .agri-file-page {
- position: relative;
- display: flex;
- flex-direction: column;
- width: 100%;
- height: 100%;
- overflow: hidden;
- background: linear-gradient(180deg, #D1EBFF 0%, #FFFFFF 100%);
- .nav-cards {
- position: relative;
- z-index: 2;
- display: flex;
- justify-content: space-around;
- padding: 10px 10px;
- margin-bottom: 10px;
- .nav-card-wrap {
- position: relative;
- &--report {
- z-index: 5;
- }
- }
- .nav-card {
- position: relative;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- border-radius: 8px;
- background: #fff;
- width: 90px;
- height: 64px;
- box-shadow: 0px 4px 4px 0px #0000000D;
- .nav-card__icon {
- width: 26px;
- height: 26px;
- margin-bottom: 4px;
- }
- &.is-active {
- background: linear-gradient(180deg, #5BB8FF 0%, #2199F8 100%);
- box-shadow: 0 4px 10px rgba(33, 153, 248, 0.28);
- .nav-card__icon {
- filter: brightness(0) invert(1);
- }
- .nav-card__label {
- color: #fff;
- }
- &::after {
- content: "";
- position: absolute;
- left: 50%;
- bottom: -5px;
- transform: translateX(-50%);
- border-left: 6px solid transparent;
- border-right: 6px solid transparent;
- border-top: 6px solid #2199F8;
- z-index: 3;
- }
- }
- }
- .report-guide-bubble {
- position: absolute;
- top: calc(100% + 10px);
- right: 22px;
- width: 216px;
- padding: 6px 10px;
- border-radius: 6px;
- background: rgba(0, 0, 0, 0.8);
- backdrop-filter: blur(4px);
- box-sizing: border-box;
- z-index: 20;
- pointer-events: auto;
- &__arrow {
- position: absolute;
- top: -5px;
- right: 16px;
- width: 0;
- height: 0;
- border-left: 6px solid transparent;
- border-right: 6px solid transparent;
- border-bottom: 6px solid rgba(0, 0, 0, 0.8);
- }
- &__content {
- font-size: 14px;
- line-height: 22px;
- color: #fff;
- word-break: break-all;
- text-align: justify;
- }
- &__link {
- padding: 0 2px;
- color: #2199f8;
- cursor: pointer;
- }
- }
- }
- .content-panel {
- flex: 1;
- overflow-y: auto;
- background: linear-gradient(360deg, rgba(229, 243, 255, 0.55) 0%, rgba(255, 255, 255, 0.55) 100%);
- border-radius: 20px 20px 0 0;
- border: 1px solid #FFFFFF;
- padding: 18px 10px;
- &::-webkit-scrollbar {
- display: none;
- }
- .map-card {
- position: relative;
- height: 210px;
- }
- .map-container {
- width: 100%;
- height: 100%;
- clip-path: inset(0px round 8px);
- }
- .map-mask {
- position: absolute;
- top: 0;
- left: 0;
- z-index: 5;
- width: 100%;
- height: 100%;
- background: rgba(0, 0, 0, 0.5);
- border-radius: 8px;
- display: flex;
- align-items: center;
- justify-content: center;
- pointer-events: auto;
- cursor: pointer;
- .mask-content {
- background: rgba(255, 255, 255, 0.2);
- backdrop-filter: blur(4px);
- padding: 8px 10px;
- border-radius: 4px;
- width: fit-content;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- gap: 12px;
- color: #fff;
- pointer-events: none;
- &__title {
- font-size: 18px;
- font-family: "PangMenZhengDao";
- }
- &__btn {
- padding: 0 24px;
- height: 32px;
- line-height: 32px;
- border-radius: 24px;
- background: #2199F8;
- }
- }
- }
- .zone-marker {
- display: flex;
- flex-direction: column;
- align-items: center;
- pointer-events: none;
- &__label {
- padding: 3px 14px;
- border-radius: 25px;
- background: #fff;
- color: #0A0A0A;
- font-size: 12px;
- }
- &__thumb {
- position: relative;
- width: 42px;
- height: 42px;
- margin-top: 8px;
- img {
- width: 100%;
- height: 100%;
- object-fit: cover;
- border: 2px solid #fff;
- border-radius: 6px;
- box-sizing: border-box;
- }
- }
- &__badge {
- position: absolute;
- top: -6px;
- right: -6px;
- min-width: 18px;
- height: 18px;
- line-height: 16px;
- border-radius: 50%;
- background: #fff;
- color: #0A0A0A;
- font-size: 12px;
- text-align: center;
- }
- &__arrow {
- width: 0;
- height: 0;
- border-left: 5px solid transparent;
- border-right: 5px solid transparent;
- border-top: 6px solid #fff;
- }
- }
- .add-zone-btn {
- position: absolute;
- right: 5px;
- bottom: 10px;
- z-index: 5;
- display: flex;
- align-items: center;
- gap: 2px;
- padding: 5px 10px;
- border-radius: 4px;
- background: #fff;
- color: #2199F8;
- font-weight: 500;
- }
- .album-grid {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 16px;
- margin-top: 16px;
- box-sizing: border-box;
- .album-add {
- align-self: start;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- width: 100%;
- aspect-ratio: 1;
- border-radius: 5px;
- background: #FFFFFF;
- color: #969494;
- font-size: 16px;
- &__icon {
- margin-bottom: 6px;
- font-size: 20px;
- }
- }
- .album-card {
- width: 100%;
- &.is-empty {
- .album-card__cover {
- display: flex;
- align-items: center;
- justify-content: center;
- overflow: hidden;
- border-radius: 8px;
- background: linear-gradient(180deg, #E0F1FF 0%, #C2E4FF 100%);
- }
- }
- &__cover {
- position: relative;
- width: 100%;
- aspect-ratio: 1;
- img:not(.album-card__empty-icon) {
- width: 100%;
- height: 100%;
- object-fit: cover;
- border-radius: 6px;
- }
- }
- &__empty-icon {
- width: 50px;
- height: 50px;
- }
- &__count {
- position: absolute;
- top: 1px;
- right: 0;
- padding: 1px 5px;
- border-radius: 0 5px 0 5px;
- background: rgba(0, 0, 0, 0.4);
- backdrop-filter: blur(4px);
- color: #fff;
- }
- &__add {
- position: absolute;
- right: 8px;
- bottom: 8px;
- z-index: 1;
- display: flex;
- align-items: center;
- justify-content: center;
- width: 44px;
- height: 44px;
- border-radius: 50%;
- background: #2199F8;
- color: #fff;
- font-size: 20px;
- box-shadow: 0 2px 8px rgba(33, 153, 248, 0.35);
- }
- &__name {
- margin-top: 10px;
- color: #1F1F1F;
- }
- }
- }
- .report-card {
- margin-bottom: 10px;
- border-radius: 8px;
- background: #fff;
- &:last-child {
- margin-bottom: 0;
- }
- &__cover {
- position: relative;
- width: 100%;
- height: 158px;
- img {
- display: block;
- width: 100%;
- height: 100%;
- object-fit: cover;
- border-radius: 5px;
- }
- }
- &__date {
- position: absolute;
- top: 0;
- padding: 5px 12px;
- border-radius: 4px;
- background: rgba(0, 0, 0, 0.45);
- backdrop-filter: blur(4px);
- color: #fff;
- font-size: 16px;
- border-radius: 5px 0 5px 0;
- }
- &__status {
- position: absolute;
- top: 10px;
- right: 0;
- display: flex;
- align-items: center;
- gap: 4px;
- padding: 2px 13px;
- border-radius: 20px 0 0 20px;
- background: #FF5454;
- color: #fff;
- font-size: 12px;
- }
- &__dot {
- width: 6px;
- height: 6px;
- border-radius: 50%;
- background: #fff;
- }
- &__body {
- padding: 10px;
- margin-top: 4px;
- }
- &__title {
- font-size: 16px;
- font-weight: 500;
- }
- &__desc {
- margin-top: 4px;
- color: #9E9B9B;
- }
- }
- .tracking-item {
- width: 100%;
- margin-bottom: 16px;
- box-shadow: 0px 4px 4px 0px rgba(33, 153, 248, 0.1);
- &:last-of-type {
- margin-bottom: 0;
- }
- &__header {
- position: relative;
- padding: 10px 10px 20px;
- border-radius: 10px 10px 0 0;
- background: linear-gradient(180deg, #86CAFF 0%, #2199F8 48.5%);
- }
- &__header-row {
- display: flex;
- align-items: center;
- justify-content: space-between;
- }
- &__header-left {
- display: flex;
- align-items: center;
- gap: 5px;
- }
- &__level {
- display: flex;
- align-items: center;
- gap: 4px;
- padding: 1px 4px;
- border-radius: 2px;
- background: #fff;
- color: #FF6A6A;
- font-size: 12px;
- }
- &__title {
- color: #fff;
- font-size: 16px;
- font-weight: 500;
- }
- &__zone {
- font-size: 12px;
- }
- &__share {
- display: flex;
- align-items: center;
- gap: 4px;
- padding: 2px 10px;
- border-radius: 25px;
- background: #fff;
- color: #2199F8;
- font-size: 12px;
- }
- &__body {
- position: relative;
- padding: 10px;
- margin-top: -8px;
- border-radius: 10px;
- background: #fff;
- &::before {
- content: "";
- position: absolute;
- top: -6px;
- left: 21%;
- width: 0;
- height: 0;
- border-left: 7px solid transparent;
- border-right: 7px solid transparent;
- border-bottom: 7px solid #fff;
- transform: translateX(-50%);
- }
- }
- &__action {
- display: flex;
- align-items: center;
- justify-content: space-between;
- border: 1px solid rgba(33, 153, 248, 0.2);
- border-radius: 6px;
- padding: 8px;
- }
- &__icon {
- display: flex;
- align-items: center;
- gap: 5px;
- img {
- width: 18px;
- height: 16px;
- }
- }
- &__reason {
- color: #2199f8;
- font-weight: 500;
- }
- &__issue {
- margin-top: 2px;
- color: #2199f8;
- font-size: 12px;
- }
- &__action-main {
- flex: 1;
- padding-right: 4px;
- }
- &__btn {
- flex: none;
- display: flex;
- align-items: center;
- gap: 2px;
- padding: 7px 10px;
- border-radius: 5px;
- background: #2199f8;
- color: #fff;
- font-size: 12px;
- }
- }
- .crop-archive {
- padding: 10px;
- border-radius: 10px;
- background: #fff;
- &__title {
- position: relative;
- display: inline-block;
- z-index: 1;
- font-size: 16px;
- font-weight: 500;
- margin-bottom: 5px;
- &::after {
- content: "";
- position: absolute;
- left: 0;
- bottom: 2px;
- z-index: -1;
- width: 90px;
- height: 6px;
- border-radius: 25px;
- background: linear-gradient(90deg, #2199f8 0%, rgba(255, 255, 255, 0.37) 100%);
- opacity: 0.4;
- }
- }
- }
- }
- }
- </style>
|