| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294 |
- <template>
- <div class="cockpit-dashboard" :class="{ 'fullscreen-mode': isFullscreenMode }">
- <!-- 顶部区域 -->
- <header class="dashboard-header">
- <div class="header-left">
- <div class="title-section">
- <h1 class="dashboard-title">智慧农业驾驶舱</h1>
- <p class="dashboard-subtitle">{{ getCurrentFarmDescription() }}</p>
- </div>
- </div>
-
- <div class="header-right">
- <div class="action-buttons">
- <div class="location-selector-group">
- <el-cascader
- v-model="selectedLocation"
- :options="locationOptions"
- :props="cascaderProps"
- size="small"
- style="width: 200px"
- placeholder="选择农场/地块"
- clearable>
- </el-cascader>
- <el-button
- icon="el-icon-check"
- type="primary"
- size="small"
- class="btn-confirm"
- @click="confirmLocationChange"
- :disabled="!hasLocationChanged">
- 确认
- </el-button>
- </div>
- <el-button
- icon="el-icon-refresh"
- type="success"
- size="small"
- class="btn-refresh"
- @click="refreshData">
- 刷新
- </el-button>
- <el-button
- icon="el-icon-full-screen"
- type="warning"
- size="small"
- class="btn-fullscreen"
- @click="openFullscreenCockpit">
- 全屏驾驶舱
- </el-button>
- </div>
- </div>
- </header>
- <!-- 主体区域 -->
- <div class="dashboard-body">
- <!-- 左侧面板 -->
- <div class="dashboard-left">
- <!-- 农机数量统计 -->
- <div class="panel-card">
- <div class="panel-header">
- <h3 class="panel-title">葡萄生长状况</h3>
- <el-radio-group v-model="cropTimeRange" size="mini">
- <el-radio-button label="week">本周</el-radio-button>
- <el-radio-button label="month">本月</el-radio-button>
- <el-radio-button label="season">本季</el-radio-button>
- </el-radio-group>
- </div>
- <div class="panel-content">
- <div class="chart-wrapper">
- <div id="cropStatusChart"></div>
- </div>
- <div class="chart-legend-mini">
- <div class="legend-item-mini" v-for="item in getCurrentCropLegend()" :key="item.name">
- <span class="legend-dot" :style="{ background: item.color }"></span>
- <span class="legend-text">{{ item.name }} ({{ item.value }}亩)</span>
- </div>
- </div>
- </div>
- </div>
- <!-- 设备运行状态 -->
- <div class="panel-card">
- <div class="panel-header">
- <h3 class="panel-title">设备运行状态</h3>
- <div class="device-summary-mini">
- <span>总: {{ deviceStats.total }}</span>
- <span class="online-text">在线: {{ deviceStats.online }}</span>
- </div>
- </div>
- <div class="panel-content">
- <div class="chart-wrapper">
- <div id="deviceStatusChart"></div>
- </div>
- <div class="device-stats-mini">
- <div class="stat-item">
- <span class="stat-label">在线率</span>
- <span class="stat-value success">{{ Math.round(deviceStats.online / deviceStats.total * 100) }}%</span>
- </div>
- <div class="stat-item">
- <span class="stat-label">离线</span>
- <span class="stat-value danger">{{ deviceStats.offline }}台</span>
- </div>
- </div>
- </div>
- </div>
- <!-- 环境监测 -->
- <div class="panel-card">
- <div class="panel-header">
- <h3 class="panel-title">环境监测</h3>
- </div>
- <div class="panel-content">
- <div class="env-grid-mini">
- <div class="env-item">
- <div class="env-name">温度</div>
- <div class="env-value-text">26.5°C</div>
- <div class="env-chart-mini" id="temperatureChart"></div>
- </div>
- <div class="env-item">
- <div class="env-name">湿度</div>
- <div class="env-value-text">68%</div>
- <div class="env-chart-mini" id="humidityChart"></div>
- </div>
- <div class="env-item">
- <div class="env-name">土壤</div>
- <div class="env-value-text">良好</div>
- <div class="env-chart-mini" id="soilChart"></div>
- </div>
- <div class="env-item">
- <div class="env-name">光照</div>
- <div class="env-value-text">85%</div>
- <div class="env-chart-mini" id="lightChart"></div>
- </div>
- </div>
- </div>
- </div>
- </div>
- <!-- 中央地图区域 -->
- <div class="dashboard-center">
- <div class="map-wrapper">
- <div class="map-header">
- <h3 class="map-title">农场地图</h3>
- </div>
- <div class="map-container-full">
- <div id="farmMap"></div>
- </div>
- </div>
- </div>
- <!-- 右侧面板 -->
- <div class="dashboard-right">
- <!-- 生产数据统计 -->
- <div class="panel-card">
- <div class="panel-header">
- <h3 class="panel-title">生产数据统计</h3>
- <el-radio-group v-model="productionTimeRange" size="mini">
- <el-radio-button label="month">月</el-radio-button>
- <el-radio-button label="quarter">季</el-radio-button>
- <el-radio-button label="year">年</el-radio-button>
- </el-radio-group>
- </div>
- <div class="panel-content">
- <div class="chart-wrapper">
- <div id="productionChart"></div>
- </div>
- </div>
- </div>
- <!-- 系统告警 -->
- <div class="panel-card">
- <div class="panel-header">
- <h3 class="panel-title">系统告警</h3>
- <el-badge :value="alertCount" class="badge-mini" type="danger">
- <span class="badge-text">待处理</span>
- </el-badge>
- </div>
- <div class="panel-content">
- <div class="alert-list-mini">
- <div class="alert-item-mini" v-for="alert in alertList" :key="alert.id" :class="alert.level">
- <div class="alert-icon-mini">
- <i :class="getAlertIcon(alert.level)"></i>
- </div>
- <div class="alert-info">
- <div class="alert-title-mini">{{ alert.title }}</div>
- <div class="alert-time-mini">{{ alert.time }}</div>
- </div>
- <div class="alert-status-mini" :class="alert.status">
- {{ getAlertStatusText(alert.status) }}
- </div>
- </div>
- </div>
- </div>
- </div>
- <!-- 农事任务执行进度 -->
- <div class="panel-card">
- <div class="panel-header">
- <h3 class="panel-title">农事任务执行进度</h3>
- </div>
- <div class="panel-content">
- <div class="task-progress-wrapper">
- <div class="task-chart-container">
- <div id="taskProgressChart"></div>
- </div>
- <div class="task-stats-grid">
- <div class="task-stat-item">
- <div class="stat-value total">{{ taskStats.total }}</div>
- <div class="stat-label">总任务数</div>
- </div>
- <div class="task-stat-item">
- <div class="stat-value completed">{{ taskStats.completed }}</div>
- <div class="stat-label">已完成</div>
- </div>
- <div class="task-stat-item">
- <div class="stat-value pending">{{ taskStats.pending }}</div>
- <div class="stat-label">待执行</div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
-
- <!-- 底部汇总数据卡片 - 浮在地图上方 -->
- <div class="dashboard-summary-bottom">
- <div class="overview-card-mini" v-for="(item, index) in overviewData" :key="index">
- <div class="card-icon-mini" :style="{ backgroundColor: item.color }">
- <i :class="item.icon"></i>
- </div>
- <div class="card-info">
- <div class="card-value-mini">{{ item.value }}</div>
- <div class="card-label-mini">{{ item.label }}</div>
- </div>
- </div>
- </div>
- </div>
- </template>
- <script>
- export default {
- name: "Index",
- data() {
- return {
- // 版本号
- version: "3.6.5",
- selectedLocation: [], // 级联选择器的值
- confirmedLocation: [], // 已确认的筛选条件
- cropTimeRange: 'month',
- productionTimeRange: 'month',
- alertCount: 5,
-
- // 农事任务统计数据
- taskStats: {
- total: 12, // 总任务数
- completed: 9, // 已完成
- pending: 3, // 待执行
- completionRate: 75 // 完成率
- },
-
- // 全屏模式标志
- isFullscreenMode: false,
-
- // 级联选择器配置
- cascaderProps: {
- checkStrictly: true, // 允许选择任意一级
- label: 'label',
- value: 'value',
- children: 'children'
- },
-
- // 级联选择器选项
- locationOptions: [
- {
- label: '全部农场',
- value: 'all',
- children: []
- },
- {
- label: '东区智慧农场',
- value: 'east',
- children: [
- { label: 'A1地块', value: 'east_a1' },
- { label: 'A2地块', value: 'east_a2' },
- { label: 'A3地块', value: 'east_a3' }
- ]
- },
- {
- label: '西区智慧农场',
- value: 'west',
- children: [
- { label: 'B1地块', value: 'west_b1' },
- { label: 'B2地块', value: 'west_b2' }
- ]
- },
- {
- label: '南区智慧农场',
- value: 'south',
- children: [
- { label: 'C1地块', value: 'south_c1' },
- { label: 'C2地块', value: 'south_c2' },
- { label: 'C3地块', value: 'south_c3' }
- ]
- },
- {
- label: '北区智慧农场',
- value: 'north',
- children: [
- { label: 'D1地块', value: 'north_d1' },
- { label: 'D2地块', value: 'north_d2' }
- ]
- },
- {
- label: '中心监测农场',
- value: 'center',
- children: [
- { label: '实验地块1', value: 'center_test1' },
- { label: '实验地块2', value: 'center_test2' },
- { label: '示范地块', value: 'center_demo' }
- ]
- }
- ],
-
- // 概览数据
- overviewData: [
- {
- label: '农场总面积',
- value: '2,560',
- unit: '亩',
- change: '+5.2%',
- trend: 'up',
- color: '#10b981',
- icon: 'el-icon-location'
- },
- {
- label: '设备在线率',
- value: '95.8%',
- change: '+2.1%',
- trend: 'up',
- color: '#3b82f6',
- icon: 'el-icon-cpu'
- },
- {
- label: '葡萄健康率',
- value: '87.3%',
- change: '+1.8%',
- trend: 'up',
- color: '#8b5cf6',
- icon: 'el-icon-sunny'
- },
- {
- label: '月产量预期',
- value: '1,850',
- unit: '吨',
- change: '+8.5%',
- trend: 'up',
- color: '#f59e0b',
- icon: 'el-icon-box'
- }
- ],
-
- // 设备统计
- deviceStats: {
- total: 42,
- online: 38,
- offline: 4
- },
-
- // 告警列表
- alertList: [
- {
- id: 1,
- title: '东区土壤湿度过低',
- time: '2分钟前',
- level: 'warning',
- status: 'pending'
- },
- {
- id: 2,
- title: '西区温度传感器离线',
- time: '15分钟前',
- level: 'error',
- status: 'pending'
- },
- {
- id: 3,
- title: '南区灌溉系统异常',
- time: '1小时前',
- level: 'warning',
- status: 'processing'
- },
- {
- id: 4,
- title: '北区葡萄病虫害预警',
- time: '2小时前',
- level: 'info',
- status: 'resolved'
- }
- ],
-
- // 高德地图相关
- farmMap: null,
- farmMarkers: [],
- plotPolygons: []
- }
- },
-
- mounted() {
- // 初始化确认的位置为默认状态(全部农场)
- this.confirmedLocation = [];
-
- // 检测是否为全屏模式
- this.isFullscreenMode = this.$route.query.fullscreen === 'true';
-
- this.$nextTick(() => {
- // 等待页面完全渲染后再初始化图表
- this.waitForElementsAndInit();
- // 添加窗口调整监听器
- window.addEventListener('resize', this.handleResize);
- });
- },
-
- computed: {
- hasLocationChanged() {
- return JSON.stringify(this.selectedLocation) !== JSON.stringify(this.confirmedLocation);
- }
- },
-
- watch: {
- confirmedLocation: {
- handler(newLocation) {
- this.handleLocationDataUpdate();
- },
- deep: true
- },
- cropTimeRange: {
- handler(newRange, oldRange) {
- this.updateCropChart();
- }
- },
- productionTimeRange: {
- handler(newRange) {
- this.updateProductionChart();
- }
- }
- },
-
- beforeDestroy() {
- window.removeEventListener('resize', this.handleResize);
-
- // 清理高德地图资源
- if (this.farmMap) {
- if (this.farmMarkers) {
- this.farmMap.remove(this.farmMarkers);
- }
- if (this.plotPolygons) {
- this.farmMap.remove(this.plotPolygons);
- }
- this.farmMap.destroy();
- }
- },
-
- methods: {
- refreshData() {
- this.$message.success('数据刷新成功');
- // 这里可以添加实际的数据刷新逻辑
- console.log('手动刷新数据和图表...');
- this.directInitCharts();
- },
-
- goToDigitalDashboard() {
- // 使用新标签页打开农业数字化决策大屏(无菜单版本)
- const baseUrl = window.location.origin;
- window.open(`${baseUrl}/agri-digital/dashboard`, '_blank');
- },
-
- openFullscreenCockpit() {
- // 打开全屏驾驶舱
- const baseUrl = window.location.origin;
- const currentPath = this.$route.path;
- // 添加 fullscreen=true 参数
- window.open(`${baseUrl}${currentPath}?fullscreen=true`, '_blank');
- },
-
- getCurrentFarmDescription() {
- const currentSelection = this.getCurrentSelection();
-
- if (currentSelection.type === 'farm') {
- const farmDescriptions = {
- all: '全面展示各农场运营状况,实时监控智慧农业数据',
- east: '东区智慧农场 - 专注高效种植,数据驱动精准农业',
- west: '西区智慧农场 - 生态循环种植,科技助力绿色发展',
- south: '南区智慧农场 - 现代化设施农业,智能管控优质产出',
- north: '北区智慧农场 - 规模化种植基地,机械化智能化并重',
- center: '中心监测农场 - 技术研发示范,引领农业创新发展'
- };
- return farmDescriptions[currentSelection.id] || farmDescriptions.all;
- } else if (currentSelection.type === 'plot') {
- return `${currentSelection.farmName} - ${currentSelection.plotName} 地块详细监测数据`;
- }
-
- return '全面展示各农场运营状况,实时监控智慧农业数据';
- },
-
- getCurrentSelection() {
- if (!this.confirmedLocation || this.confirmedLocation.length === 0) {
- return { type: 'farm', id: 'all' };
- }
-
- if (this.confirmedLocation.length === 1) {
- // 选择的是农场
- return { type: 'farm', id: this.confirmedLocation[0] };
- } else if (this.confirmedLocation.length === 2) {
- // 选择的是地块
- const farmId = this.confirmedLocation[0];
- const plotId = this.confirmedLocation[1];
- const farmNames = {
- east: '东区智慧农场',
- west: '西区智慧农场',
- south: '南区智慧农场',
- north: '北区智慧农场',
- center: '中心监测农场'
- };
-
- // 从级联选择器中找到地块名称
- const farm = this.locationOptions.find(f => f.value === farmId);
- const plot = farm ? farm.children.find(p => p.value === plotId) : null;
-
- return {
- type: 'plot',
- farmId: farmId,
- plotId: plotId,
- farmName: farmNames[farmId] || '未知农场',
- plotName: plot ? plot.label : '未知地块'
- };
- }
-
- return { type: 'farm', id: 'all' };
- },
-
- confirmLocationChange() {
- // 确认选择的位置
- if (!this.selectedLocation || this.selectedLocation.length === 0) {
- this.confirmedLocation = [];
- this.$message.success('已切换为全部农场视图');
- } else {
- // 先设置确认的位置
- this.confirmedLocation = [...this.selectedLocation];
-
- // 基于选择的位置获取信息
- if (this.selectedLocation.length === 1) {
- const farmNames = {
- all: '全部农场',
- east: '东区智慧农场',
- west: '西区智慧农场',
- south: '南区智慧农场',
- north: '北区智慧农场',
- center: '中心监测农场'
- };
- this.$message.success(`已切换为 ${farmNames[this.selectedLocation[0]] || '未知农场'} 视图`);
- } else if (this.selectedLocation.length === 2) {
- const farmId = this.selectedLocation[0];
- const plotId = this.selectedLocation[1];
- const farmNames = {
- east: '东区智慧农场',
- west: '西区智慧农场',
- south: '南区智慧农场',
- north: '北区智慧农场',
- center: '中心监测农场'
- };
-
- // 从级联选择器中找到地块名称
- const farm = this.locationOptions.find(f => f.value === farmId);
- const plot = farm ? farm.children.find(p => p.value === plotId) : null;
- const farmName = farmNames[farmId] || '未知农场';
- const plotName = plot ? plot.label : '未知地块';
-
- this.$message.success(`已切换为 ${farmName} - ${plotName} 视图`);
- }
- }
- },
-
- clearLocation() {
- // 清空选择
- this.selectedLocation = [];
- this.confirmedLocation = [];
- this.$message.info('筛选条件已清空');
- },
-
- handleLocationDataUpdate() {
- const currentSelection = this.getCurrentSelection();
-
- if (currentSelection.type === 'farm') {
- // 选择农场时更新农场数据
- this.updateFarmData(currentSelection.id);
- } else if (currentSelection.type === 'plot') {
- // 选择地块时更新农场数据和地块特定数据
- this.updateFarmData(currentSelection.farmId);
- this.updatePlotData(currentSelection.plotId);
- }
-
- // 重新初始化图表和地图
- this.$nextTick(() => {
- this.initCharts();
- // 只更新地图内容,不重新创建地图
- this.updateMapContent();
- });
- },
-
- updatePlotData(plotId) {
- // 根据选择的地块更新特定数据
- console.log('更新地块数据:', plotId);
- // 这里可以添加地块特定的数据更新逻辑
- // 比如更新环境监测数据为该地块的具体数据
- },
-
- updateFarmData(farmId) {
- // 根据选择的农场更新数据
- this.updateOverviewData(farmId);
- this.updateDeviceStats(farmId);
- this.updateAlertList(farmId);
- // 重新初始化图表
- this.$nextTick(() => {
- // 延迟重新初始化图表
- setTimeout(() => {
- this.initCharts();
- }, 100);
- });
- },
-
- updateOverviewData(farmId) {
- // 模拟不同农场的数据
- const farmData = {
- all: {
- area: '2,560',
- deviceRate: '95.8%',
- healthRate: '87.3%',
- production: '1,850'
- },
- east: {
- area: '680',
- deviceRate: '97.2%',
- healthRate: '89.1%',
- production: '520'
- },
- west: {
- area: '590',
- deviceRate: '94.5%',
- healthRate: '86.8%',
- production: '450'
- },
- south: {
- area: '720',
- deviceRate: '96.8%',
- healthRate: '88.9%',
- production: '580'
- },
- north: {
- area: '570',
- deviceRate: '93.2%',
- healthRate: '85.4%',
- production: '300'
- }
- };
-
- const data = farmData[farmId] || farmData.all;
- this.overviewData[0].value = data.area;
- this.overviewData[1].value = data.deviceRate;
- this.overviewData[2].value = data.healthRate;
- this.overviewData[3].value = data.production;
- },
-
- updateDeviceStats(farmId) {
- // 模拟不同农场的设备统计
- const deviceData = {
- all: { total: 42, online: 38, offline: 4 },
- east: { total: 12, online: 11, offline: 1 },
- west: { total: 10, online: 9, offline: 1 },
- south: { total: 14, online: 13, offline: 1 },
- north: { total: 6, online: 5, offline: 1 }
- };
-
- const data = deviceData[farmId] || deviceData.all;
- this.deviceStats = data;
- },
-
- updateAlertList(farmId) {
- // 模拟不同农场的告警信息
- const alertData = {
- all: [
- { id: 1, title: '多个地块环境异常', time: '2分钟前', level: 'warning', status: 'pending' },
- { id: 2, title: '设备离线告警汇总', time: '15分钟前', level: 'error', status: 'pending' },
- { id: 3, title: '生产数据异常统计', time: '1小时前', level: 'warning', status: 'processing' },
- { id: 4, title: '综合监测预警信息', time: '2小时前', level: 'info', status: 'resolved' }
- ],
- east: [
- { id: 1, title: '东区A地块土壤湿度过低', time: '2分钟前', level: 'warning', status: 'pending' },
- { id: 2, title: '东区温度传感器离线', time: '15分钟前', level: 'error', status: 'pending' }
- ],
- west: [
- { id: 1, title: '西区B地块光照不足', time: '5分钟前', level: 'warning', status: 'pending' },
- { id: 2, title: '西区灌溉系统压力异常', time: '30分钟前', level: 'warning', status: 'processing' }
- ],
- south: [
- { id: 1, title: '南区C地块病虫害预警', time: '10分钟前', level: 'info', status: 'pending' },
- { id: 2, title: '南区设备维护提醒', time: '1小时前', level: 'info', status: 'resolved' }
- ],
- north: [
- { id: 1, title: '北区D地块温度过高', time: '8分钟前', level: 'warning', status: 'pending' }
- ]
- };
-
- const alerts = alertData[farmId] || alertData.all;
- this.alertList = alerts;
- this.alertCount = alerts.filter(alert => alert.status === 'pending').length;
- },
-
- handleResize() {
- // 响应式调整图表大小
- setTimeout(() => {
- this.resizeAllCharts();
- }, 100);
- },
-
- resizeAllCharts() {
- const chartIds = ['temperatureChart', 'humidityChart', 'soilChart', 'lightChart',
- 'cropStatusChart', 'deviceStatusChart', 'productionChart', 'farmMap'];
- chartIds.forEach(id => {
- const element = document.getElementById(id);
- if (element && this.$echarts) {
- const chart = this.$echarts.getInstanceByDom(element);
- if (chart) {
- chart.resize();
- }
- }
- });
-
- // 调整高德地图大小
- if (this.farmMap && typeof this.farmMap.resize === 'function') {
- try {
- this.farmMap.resize();
- } catch (error) {
- console.warn('地图resize失败:', error);
- }
- }
- },
-
- getAlertIcon(level) {
- const icons = {
- error: 'el-icon-warning',
- warning: 'el-icon-warning-outline',
- info: 'el-icon-info'
- };
- return icons[level] || 'el-icon-info';
- },
-
- getAlertStatusText(status) {
- const statusMap = {
- pending: '待处理',
- processing: '处理中',
- resolved: '已解决'
- };
- return statusMap[status] || '未知';
- },
-
- waitForElementsAndInit(attempt = 0) {
- const maxAttempts = 10;
- const delay = 200;
-
- console.log(`等待图表容器准备就绪... (尝试 ${attempt + 1}/${maxAttempts})`);
-
- // 检查关键元素是否有正确的尺寸
- const cropElement = document.getElementById('cropStatusChart');
- const deviceElement = document.getElementById('deviceStatusChart');
-
- if (cropElement && deviceElement) {
- const cropRect = cropElement.getBoundingClientRect();
- const deviceRect = deviceElement.getBoundingClientRect();
-
- console.log('Crop element size:', cropRect.width, 'x', cropRect.height);
- console.log('Device element size:', deviceRect.width, 'x', deviceRect.height);
-
- if (cropRect.width > 0 && cropRect.height > 0 &&
- deviceRect.width > 0 && deviceRect.height > 0) {
- // 元素有正确的尺寸,可以初始化图表
- console.log('图表容器准备就绪,开始初始化图表');
- this.directInitCharts();
- return;
- }
- }
-
- // 如果元素还没准备好,继续等待
- if (attempt < maxAttempts - 1) {
- setTimeout(() => {
- this.waitForElementsAndInit(attempt + 1);
- }, delay);
- } else {
- console.warn('图表容器等待超时,强制初始化');
- this.directInitCharts();
- }
- },
-
- directInitCharts() {
- console.log('Direct chart initialization...');
- console.log('ECharts available:', !!this.$echarts);
- console.log('ECharts object:', this.$echarts);
-
- // 直接初始化作物状况图表
- try {
- const cropElement = document.getElementById('cropStatusChart');
- console.log('cropStatusChart element:', cropElement);
- if (cropElement) {
- // 检查元素尺寸
- const rect = cropElement.getBoundingClientRect();
- console.log('cropElement dimensions:', rect.width, 'x', rect.height);
-
- // 如果尺寸为0,强制设置尺寸
- if (rect.width === 0 || rect.height === 0) {
- cropElement.style.width = '100%';
- cropElement.style.height = '300px';
- cropElement.style.display = 'block';
- }
-
- const cropChart = this.$echarts.init(cropElement);
- console.log('cropChart instance:', cropChart);
- cropChart.setOption({
- tooltip: {
- trigger: 'item',
- formatter: '{b}: {c}亩 ({d}%)'
- },
- series: [{
- name: '作物分布',
- type: 'pie',
- radius: ['45%', '75%'],
- center: ['50%', '50%'],
- data: [
- { value: 1200, name: '水稻', itemStyle: { color: '#10b981' } },
- { value: 580, name: '小麦', itemStyle: { color: '#3b82f6' } },
- { value: 520, name: '玉米', itemStyle: { color: '#f59e0b' } },
- { value: 260, name: '蔬菜', itemStyle: { color: '#8b5cf6' } }
- ],
- label: {
- show: true,
- position: 'inside',
- formatter: '{d}%',
- fontSize: 12,
- fontWeight: 'bold',
- color: 'white'
- },
- emphasis: {
- itemStyle: {
- shadowBlur: 10,
- shadowOffsetX: 0,
- shadowColor: 'rgba(0, 0, 0, 0.5)'
- }
- }
- }]
- });
- console.log('作物图表初始化成功');
- } else {
- console.error('cropStatusChart element not found!');
- }
-
- // 直接初始化设备状况图表
- const deviceElement = document.getElementById('deviceStatusChart');
- console.log('deviceStatusChart element:', deviceElement);
- if (deviceElement) {
- // 检查元素尺寸
- const rect = deviceElement.getBoundingClientRect();
- console.log('deviceElement dimensions:', rect.width, 'x', rect.height);
-
- // 如果尺寸为0,强制设置尺寸
- if (rect.width === 0 || rect.height === 0) {
- deviceElement.style.width = '100%';
- deviceElement.style.height = '300px';
- deviceElement.style.display = 'block';
- }
-
- const deviceChart = this.$echarts.init(deviceElement);
- console.log('deviceChart instance:', deviceChart);
- deviceChart.setOption({
- tooltip: {
- trigger: 'item',
- formatter: '{b}: {c}台 ({d}%)'
- },
- series: [{
- name: '设备状态',
- type: 'pie',
- radius: '70%',
- center: ['50%', '50%'],
- data: [
- { value: this.deviceStats.online, name: '在线', itemStyle: { color: '#10b981' } },
- { value: this.deviceStats.offline, name: '离线', itemStyle: { color: '#ef4444' } }
- ],
- label: {
- show: true,
- position: 'inside',
- formatter: '{d}%',
- fontSize: 12,
- fontWeight: 'bold',
- color: 'white'
- },
- emphasis: {
- itemStyle: {
- shadowBlur: 10,
- shadowOffsetX: 0,
- shadowColor: 'rgba(0, 0, 0, 0.5)'
- }
- }
- }]
- });
- console.log('设备图表初始化成功');
- } else {
- console.error('deviceStatusChart element not found!');
- }
- } catch (error) {
- console.error('图表初始化错误:', error);
- }
-
- // 初始化其他图表
- this.initEnvironmentCharts();
- this.initProductionChart();
- this.initTaskProgressChart();
- this.initFarmMap();
- },
-
- initChartsWithRetry(retryCount = 0) {
- const maxRetries = 3;
- const delay = 200 * (retryCount + 1); // 200ms, 400ms, 600ms
-
- setTimeout(() => {
- console.log(`Initializing charts... (attempt ${retryCount + 1})`);
-
- // 检查关键图表容器是否存在
- const cropChart = document.getElementById('cropStatusChart');
- const deviceChart = document.getElementById('deviceStatusChart');
-
- if (!cropChart || !deviceChart) {
- console.warn(`Key chart elements not ready, retrying... (${retryCount + 1}/${maxRetries})`);
- if (retryCount < maxRetries - 1) {
- this.initChartsWithRetry(retryCount + 1);
- return;
- }
- }
-
- this.initCharts();
- }, delay);
- },
-
- initCharts() {
- console.log('Initializing charts...');
-
- // 检查所有图表容器是否存在
- const chartElements = [
- 'temperatureChart', 'humidityChart', 'soilChart', 'lightChart',
- 'cropStatusChart', 'deviceStatusChart', 'productionChart', 'farmMap'
- ];
-
- chartElements.forEach(id => {
- const element = document.getElementById(id);
- if (!element) {
- console.warn(`Chart element ${id} not found`);
- } else {
- console.log(`Chart element ${id} found`);
- }
- });
-
- this.initEnvironmentCharts();
- this.initCropStatusChart();
- this.initDeviceStatusChart();
- this.initProductionChart();
- this.initTaskProgressChart();
- this.initFarmMap();
-
- console.log('Charts initialization completed');
- },
-
- initEnvironmentCharts() {
- // 温度图表
- const tempElement = document.getElementById('temperatureChart');
- if (!tempElement) {
- console.error('temperatureChart element not found');
- return;
- }
- const tempChart = this.$echarts.init(tempElement);
- tempChart.setOption({
- grid: { top: 10, right: 10, bottom: 10, left: 10 },
- xAxis: { show: false, type: 'category', data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'] },
- yAxis: { show: false, type: 'value' },
- series: [{
- type: 'line',
- data: [22, 24, 26, 25, 27, 26, 25],
- smooth: true,
- lineStyle: { color: '#10b981', width: 2 },
- areaStyle: {
- color: {
- type: 'linear',
- x: 0, y: 0, x2: 0, y2: 1,
- colorStops: [
- { offset: 0, color: 'rgba(16, 185, 129, 0.3)' },
- { offset: 1, color: 'rgba(16, 185, 129, 0.1)' }
- ]
- }
- },
- showSymbol: false
- }]
- });
-
- // 湿度图表
- const humidityElement = document.getElementById('humidityChart');
- if (!humidityElement) return;
- const humidityChart = this.$echarts.init(humidityElement);
- humidityChart.setOption({
- grid: { top: 10, right: 10, bottom: 10, left: 10 },
- xAxis: { show: false, type: 'category', data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'] },
- yAxis: { show: false, type: 'value' },
- series: [{
- type: 'line',
- data: [65, 68, 70, 66, 69, 68, 67],
- smooth: true,
- lineStyle: { color: '#3b82f6', width: 2 },
- areaStyle: {
- color: {
- type: 'linear',
- x: 0, y: 0, x2: 0, y2: 1,
- colorStops: [
- { offset: 0, color: 'rgba(59, 130, 246, 0.3)' },
- { offset: 1, color: 'rgba(59, 130, 246, 0.1)' }
- ]
- }
- },
- showSymbol: false
- }]
- });
-
- // 土壤图表
- const soilElement = document.getElementById('soilChart');
- if (!soilElement) return;
- const soilChart = this.$echarts.init(soilElement);
- soilChart.setOption({
- grid: { top: 10, right: 10, bottom: 10, left: 10 },
- xAxis: { show: false, type: 'category', data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'] },
- yAxis: { show: false, type: 'value' },
- series: [{
- type: 'bar',
- data: [7.2, 7.1, 7.3, 7.0, 7.2, 7.1, 7.2],
- itemStyle: {
- color: {
- type: 'linear',
- x: 0, y: 0, x2: 0, y2: 1,
- colorStops: [
- { offset: 0, color: '#8b5cf6' },
- { offset: 1, color: 'rgba(139, 92, 246, 0.6)' }
- ]
- }
- },
- barWidth: '60%'
- }]
- });
-
- // 光照图表
- const lightElement = document.getElementById('lightChart');
- if (!lightElement) return;
- const lightChart = this.$echarts.init(lightElement);
- lightChart.setOption({
- grid: { top: 10, right: 10, bottom: 10, left: 10 },
- xAxis: { show: false, type: 'category', data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'] },
- yAxis: { show: false, type: 'value' },
- series: [{
- type: 'line',
- data: [80, 85, 88, 82, 87, 85, 86],
- smooth: true,
- lineStyle: { color: '#f59e0b', width: 2 },
- areaStyle: {
- color: {
- type: 'linear',
- x: 0, y: 0, x2: 0, y2: 1,
- colorStops: [
- { offset: 0, color: 'rgba(245, 158, 11, 0.3)' },
- { offset: 1, color: 'rgba(245, 158, 11, 0.1)' }
- ]
- }
- },
- showSymbol: false
- }]
- });
- },
-
- initCropStatusChart() {
- const chartElement = document.getElementById('cropStatusChart');
- if (!chartElement) {
- console.error('cropStatusChart element not found');
- return;
- }
-
- const chart = this.$echarts.init(chartElement);
- const cropData = this.getCropDataByTimeRange(this.cropTimeRange);
-
- chart.setOption({
- tooltip: {
- trigger: 'item',
- formatter: '{b}: {c}亩 ({d}%)'
- },
- legend: {
- show: false // 不显示图例,因为我们有自定义的图例
- },
- series: [{
- type: 'pie',
- radius: ['45%', '75%'],
- center: ['50%', '50%'],
- data: cropData,
- label: {
- show: true,
- position: 'inside',
- formatter: '{d}%',
- fontSize: 12,
- fontWeight: 'bold',
- color: 'white'
- },
- emphasis: {
- itemStyle: {
- shadowBlur: 10,
- shadowOffsetX: 0,
- shadowColor: 'rgba(0, 0, 0, 0.5)'
- }
- }
- }]
- });
- },
-
- initDeviceStatusChart() {
- const chartElement = document.getElementById('deviceStatusChart');
- if (!chartElement) {
- console.error('deviceStatusChart element not found');
- return;
- }
-
- const chart = this.$echarts.init(chartElement);
- chart.setOption({
- tooltip: {
- trigger: 'item',
- formatter: '{b}: {c}台 ({d}%)'
- },
- legend: {
- show: false // 不显示图例,因为我们有自定义的统计信息
- },
- series: [{
- type: 'pie',
- radius: '70%',
- center: ['50%', '50%'],
- data: [
- { value: this.deviceStats.online, name: '在线', itemStyle: { color: '#10b981' } },
- { value: this.deviceStats.offline, name: '离线', itemStyle: { color: '#ef4444' } },
- { value: this.deviceStats.total - this.deviceStats.online - this.deviceStats.offline, name: '故障', itemStyle: { color: '#f59e0b' } }
- ],
- label: {
- show: true,
- position: 'inside',
- formatter: '{d}%',
- fontSize: 12,
- fontWeight: 'bold',
- color: 'white'
- },
- emphasis: {
- itemStyle: {
- shadowBlur: 10,
- shadowOffsetX: 0,
- shadowColor: 'rgba(0, 0, 0, 0.5)'
- }
- }
- }]
- });
- },
-
- initProductionChart() {
- const chartElement = document.getElementById('productionChart');
- if (!chartElement) {
- console.error('productionChart element not found');
- return;
- }
- const chart = this.$echarts.init(chartElement);
- const productionData = this.getProductionDataByTimeRange(this.productionTimeRange);
-
- chart.setOption({
- grid: { left: '15%', right: '10%', top: '15%', bottom: '15%' },
- xAxis: {
- type: 'category',
- data: productionData.xAxis,
- axisLine: { lineStyle: { color: '#e5e7eb' } },
- axisTick: { show: false },
- axisLabel: { color: '#6b7280', fontSize: 12 }
- },
- yAxis: {
- type: 'value',
- axisLine: { show: false },
- axisTick: { show: false },
- axisLabel: { color: '#6b7280', fontSize: 12 },
- splitLine: { lineStyle: { color: '#f3f4f6' } }
- },
- tooltip: {
- trigger: 'axis',
- formatter: '{b}: {c}吨'
- },
- series: [{
- type: 'bar',
- data: productionData.data,
- itemStyle: {
- color: {
- type: 'linear',
- x: 0, y: 0, x2: 0, y2: 1,
- colorStops: [
- { offset: 0, color: '#10b981' },
- { offset: 1, color: 'rgba(16, 185, 129, 0.6)' }
- ]
- }
- },
- barWidth: '50%'
- }]
- });
- },
-
- initTaskProgressChart() {
- const chartElement = document.getElementById('taskProgressChart');
- if (!chartElement) {
- console.error('taskProgressChart element not found');
- return;
- }
-
- const chart = this.$echarts.init(chartElement);
- chart.setOption({
- tooltip: {
- trigger: 'item',
- formatter: '{b}: {c}个 ({d}%)'
- },
- legend: {
- show: false
- },
- series: [{
- name: '任务进度',
- type: 'pie',
- radius: ['50%', '75%'],
- center: ['50%', '50%'],
- avoidLabelOverlap: false,
- label: {
- show: true,
- position: 'center',
- formatter: '{d}%',
- fontSize: 24,
- fontWeight: 'bold',
- color: '#52c41a'
- },
- emphasis: {
- label: {
- show: true,
- fontSize: 28,
- fontWeight: 'bold'
- }
- },
- labelLine: {
- show: false
- },
- data: [
- {
- value: this.taskStats.completed,
- name: '已完成',
- itemStyle: {
- color: {
- type: 'linear',
- x: 0, y: 0, x2: 0, y2: 1,
- colorStops: [
- { offset: 0, color: '#52c41a' },
- { offset: 1, color: '#73d13d' }
- ]
- }
- }
- },
- {
- value: this.taskStats.pending,
- name: '待执行',
- itemStyle: {
- color: 'rgba(255, 255, 255, 0.15)'
- }
- }
- ]
- }]
- });
- },
-
- initFarmMap() {
- const mapElement = document.getElementById('farmMap');
- if (!mapElement) {
- console.error('farmMap element not found');
- return;
- }
-
- // 检查高德地图API是否加载
- if (typeof AMap === 'undefined') {
- console.error('高德地图API未加载,使用备用方案');
- this.renderFallbackMap();
- return;
- }
-
- try {
- // 初始化高德地图 - 使用纯卫星影像图层(无路网)
- // 图层说明:
- // - TileLayer.Satellite: 卫星影像底图(纯影像,无道路标注)
- // 如需添加路网图层,可添加: new AMap.TileLayer.RoadNet()
- // 如需切换回矢量地图,可使用 mapStyle: 'amap://styles/whitesmoke' 并移除 layers 配置
- this.farmMap = new AMap.Map('farmMap', {
- zoom: 10,
- center: [117.015029, 34.197274], // 默认中心点
- viewMode: '2D',
- resizeEnable: true,
- layers: [
- new AMap.TileLayer.Satellite() // 卫星影像底图(纯影像)
- // new AMap.TileLayer.RoadNet() // 路网图层(已注释,如需显示道路名称可取消注释)
- ]
- });
-
- // 等待地图加载完成
- this.farmMap.on('complete', () => {
- console.log('地图加载完成');
-
- // 添加地图控件
- this.farmMap.addControl(new AMap.Scale());
- this.farmMap.addControl(new AMap.ToolBar({
- position: 'RB'
- }));
-
- const currentSelection = this.getCurrentSelection();
-
- if (currentSelection.type === 'farm' && currentSelection.id === 'all') {
- // 显示所有农场位置概览
- this.renderFarmOverviewOnMap();
- } else if (currentSelection.type === 'farm') {
- // 显示特定农场的地块详情
- this.renderFarmDetailsOnMap(currentSelection.id);
- } else if (currentSelection.type === 'plot') {
- // 显示特定农场的地块详情,并高亮选中的地块
- this.renderFarmDetailsOnMap(currentSelection.farmId, currentSelection.plotId);
- }
- });
-
- } catch (error) {
- console.error('地图初始化失败:', error);
- this.renderFallbackMap();
- }
- },
-
- renderFallbackMap() {
- // 备用方案:使用ECharts显示农场分布
- const mapElement = document.getElementById('farmMap');
- if (!mapElement) return;
-
- // 清空容器
- mapElement.innerHTML = '';
-
- // 使用ECharts作为备用方案
- const chart = this.$echarts.init(mapElement);
-
- const currentSelection = this.getCurrentSelection();
-
- if (currentSelection.type === 'farm' && currentSelection.id === 'all') {
- // 显示所有农场位置概览
- chart.setOption({
- title: {
- text: '农场分布图(模拟地图)',
- subtext: '地图API加载失败,显示备用方案',
- left: 'center',
- top: 20,
- textStyle: {
- fontSize: 16,
- color: '#333'
- },
- subtextStyle: {
- fontSize: 12,
- color: '#666'
- }
- },
- backgroundColor: '#f8fafc',
- grid: { left: 0, right: 0, top: 60, bottom: 0 },
- xAxis: {
- show: false,
- type: 'value',
- min: 0,
- max: 100
- },
- yAxis: {
- show: false,
- type: 'value',
- min: 0,
- max: 100
- },
- tooltip: {
- trigger: 'item',
- backgroundColor: 'transparent',
- borderWidth: 0,
- padding: 0,
- formatter: function(params) {
- const data = params.data;
- return `
- <div style="
- padding: 0;
- margin: 0;
- min-width: 240px;
- background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);
- border-radius: 12px;
- box-shadow: 0 8px 25px rgba(0,0,0,0.15);
- border: 1px solid #e2e8f0;
- overflow: hidden;
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
- ">
- <div style="
- background: linear-gradient(135deg, #10b981 0%, #059669 100%);
- padding: 12px 16px;
- color: white;
- ">
- <div style="font-size: 15px; font-weight: 600; margin: 0;">${data[2]}</div>
- <div style="font-size: 11px; opacity: 0.9; margin-top: 2px;">智慧农业基地</div>
- </div>
- <div style="padding: 14px;">
- <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 12px;">
- <div style="text-align: center; padding: 8px; background: #f1f5f9; border-radius: 6px;">
- <div style="font-size: 16px; font-weight: 700; color: #1e293b;">${data[3]}</div>
- <div style="font-size: 10px; color: #64748b;">面积(亩)</div>
- </div>
- <div style="text-align: center; padding: 8px; background: #ecfdf5; border-radius: 6px;">
- <div style="font-size: 16px; font-weight: 700; color: #059669;">${data[5]}</div>
- <div style="font-size: 10px; color: #64748b;">在线率</div>
- </div>
- </div>
- <div style="display: flex; justify-content: space-between; align-items: center; padding: 6px 0; border-bottom: 1px solid #f1f5f9;">
- <span style="color: #64748b; font-size: 12px;">设备数量</span>
- <span style="color: #1e293b; font-weight: 600; font-size: 12px;">${data[4]}台</span>
- </div>
- <div style="display: flex; justify-content: space-between; align-items: center; padding: 6px 0;">
- <span style="color: #64748b; font-size: 12px;">主要品种</span>
- <span style="color: #1e293b; font-weight: 500; font-size: 12px;">${data[6]}</span>
- </div>
- </div>
- </div>
- `;
- }
- },
- series: [{
- type: 'scatter',
- data: [
- [20, 80, '东区智慧农场', '680', '12', '97.2%', '阳光玫瑰、玫瑰香'],
- [70, 25, '西区智慧农场', '590', '10', '94.5%', '巨峰、红提'],
- [80, 75, '南区智慧农场', '720', '14', '96.8%', '阳光玫瑰、夏黑'],
- [25, 30, '北区智慧农场', '570', '6', '93.2%', '玫瑰香、巨峰'],
- [50, 50, '中心监测农场', '200', '8', '98.5%', '克瑞森无核']
- ],
- symbolSize: function(value) {
- return Math.max(35, parseInt(value[3]) / 20);
- },
- itemStyle: {
- color: {
- type: 'radial',
- x: 0.5,
- y: 0.5,
- r: 0.8,
- colorStops: [
- { offset: 0, color: '#34d399' },
- { offset: 0.7, color: '#10b981' },
- { offset: 1, color: '#059669' }
- ]
- },
- borderColor: '#ffffff',
- borderWidth: 2,
- shadowBlur: 15,
- shadowColor: 'rgba(16, 185, 129, 0.4)',
- shadowOffsetY: 3
- },
- emphasis: {
- itemStyle: {
- color: {
- type: 'radial',
- x: 0.5,
- y: 0.5,
- r: 0.8,
- colorStops: [
- { offset: 0, color: '#6ee7b7' },
- { offset: 0.7, color: '#059669' },
- { offset: 1, color: '#047857' }
- ]
- },
- borderColor: '#ffffff',
- borderWidth: 3,
- shadowBlur: 25,
- shadowColor: 'rgba(16, 185, 129, 0.6)',
- shadowOffsetY: 5
- },
- scale: 1.2
- },
- label: {
- show: true,
- position: 'bottom',
- formatter: function(params) {
- return params.data[2];
- },
- color: '#1f2937',
- fontSize: 13,
- fontWeight: '600',
- backgroundColor: 'rgba(255, 255, 255, 0.9)',
- borderColor: '#e5e7eb',
- borderWidth: 1,
- borderRadius: 8,
- padding: [4, 8],
- shadowBlur: 3,
- shadowColor: 'rgba(0, 0, 0, 0.1)',
- shadowOffsetY: 1
- },
- emphasis: {
- label: {
- backgroundColor: '#ffffff',
- borderColor: '#10b981',
- color: '#059669'
- }
- }
- }]
- });
- } else {
- // 显示地块详情的备用方案
- this.renderFarmDetailsECharts(chart, currentSelection.farmId || currentSelection.id, currentSelection.plotId);
- }
- },
-
- renderFarmDetailsECharts(chart, farmId, highlightPlotId = null) {
- // ECharts版本的农场详情
- const farmDetailsMap = {
- east: {
- boundary: [[10, 70], [30, 90], [40, 85], [35, 65], [10, 70]],
- plots: [
- [15, 85, 'A1地块', '220', '4', '健康', '阳光玫瑰'],
- [25, 80, 'A2地块', '230', '4', '健康', '玫瑰香'],
- [35, 75, 'A3地块', '230', '4', '良好', '阳光玫瑰']
- ]
- },
- west: {
- boundary: [[60, 15], [80, 35], [75, 40], [55, 25], [60, 15]],
- plots: [
- [65, 25, 'B1地块', '295', '5', '健康', '巨峰'],
- [75, 30, 'B2地块', '295', '5', '良好', '红提']
- ]
- },
- south: {
- boundary: [[70, 65], [90, 85], [85, 90], [65, 75], [70, 65]],
- plots: [
- [75, 75, 'C1地块', '240', '5', '健康', '阳光玫瑰'],
- [80, 80, 'C2地块', '240', '5', '健康', '夏黑'],
- [85, 75, 'C3地块', '240', '4', '良好', '阳光玫瑰']
- ]
- },
- north: {
- boundary: [[15, 20], [35, 40], [30, 45], [10, 30], [15, 20]],
- plots: [
- [20, 30, 'D1地块', '285', '3', '良好', '玫瑰香'],
- [30, 35, 'D2地块', '285', '3', '健康', '巨峰']
- ]
- },
- center: {
- boundary: [[40, 40], [60, 60], [55, 65], [35, 50], [40, 40]],
- plots: [
- [45, 50, '实验地块1', '67', '3', '优秀', '克瑞森无核'],
- [50, 55, '实验地块2', '67', '3', '优秀', '阳光玫瑰'],
- [55, 50, '示范地块', '66', '2', '优秀', '醉金香']
- ]
- }
- };
-
- const farmData = farmDetailsMap[farmId];
- if (!farmData) return;
-
- chart.setOption({
- title: {
- text: `${farmId === 'east' ? '东区' : farmId === 'west' ? '西区' : farmId === 'south' ? '南区' : farmId === 'north' ? '北区' : '中心'}智慧农场地块分布`,
- left: 'center',
- top: 20,
- textStyle: {
- fontSize: 16,
- color: '#333'
- }
- },
- backgroundColor: '#f8fafc',
- grid: { left: 0, right: 0, top: 60, bottom: 0 },
- xAxis: {
- show: false,
- type: 'value',
- min: 0,
- max: 100
- },
- yAxis: {
- show: false,
- type: 'value',
- min: 0,
- max: 100
- },
- tooltip: {
- trigger: 'item',
- backgroundColor: 'transparent',
- borderWidth: 0,
- padding: 0,
- formatter: function(params) {
- if (params.seriesIndex === 0) return '';
- const data = params.data;
- const isHighlighted = params.color && (params.color.colorStops || params.color).toString().includes('#f59e0b');
- const healthColor = data[5] === '优秀' ? '#10b981' : data[5] === '健康' ? '#059669' : data[5] === '良好' ? '#f59e0b' : '#ef4444';
- const healthBgColor = data[5] === '优秀' ? '#ecfdf5' : data[5] === '健康' ? '#f0fdf4' : data[5] === '良好' ? '#fefbf3' : '#fef2f2';
-
- return `
- <div style="
- padding: 0;
- margin: 0;
- min-width: 220px;
- background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);
- border-radius: 12px;
- box-shadow: 0 8px 25px rgba(0,0,0,0.15);
- border: 1px solid #e2e8f0;
- overflow: hidden;
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
- ">
- <div style="
- background: linear-gradient(135deg, ${healthColor} 0%, ${healthColor}dd 100%);
- padding: 12px 14px;
- color: white;
- ">
- <div style="font-size: 14px; font-weight: 600; margin: 0;">${data[2]}</div>
- <div style="font-size: 10px; opacity: 0.9; margin-top: 2px;">农业种植地块</div>
- </div>
- <div style="padding: 12px;">
- <div style="
- display: inline-flex;
- align-items: center;
- padding: 4px 10px;
- background: ${healthBgColor};
- border-radius: 16px;
- margin-bottom: 10px;
- ">
- <div style="
- width: 5px;
- height: 5px;
- background: ${healthColor};
- border-radius: 50%;
- margin-right: 6px;
- "></div>
- <span style="color: ${healthColor}; font-size: 10px; font-weight: 600;">${data[5]}状态</span>
- </div>
- <div>
- <div style="display: flex; justify-content: space-between; align-items: center; padding: 5px 0; border-bottom: 1px solid #f1f5f9;">
- <span style="color: #64748b; font-size: 11px;">地块面积</span>
- <span style="color: #1e293b; font-weight: 600; font-size: 12px;">${data[3]} 亩</span>
- </div>
- <div style="display: flex; justify-content: space-between; align-items: center; padding: 5px 0; border-bottom: 1px solid #f1f5f9;">
- <span style="color: #64748b; font-size: 11px;">监测设备</span>
- <span style="color: #1e293b; font-weight: 600; font-size: 12px;">${data[4]} 台</span>
- </div>
- <div style="display: flex; justify-content: space-between; align-items: center; padding: 5px 0;">
- <span style="color: #64748b; font-size: 11px;">种植品种</span>
- <span style="color: #1e293b; font-weight: 500; font-size: 12px;">${data[6]}</span>
- </div>
- </div>
- </div>
- </div>
- `;
- }
- },
- series: [
- {
- type: 'line',
- data: farmData.boundary,
- lineStyle: {
- color: '#059669',
- width: 3,
- type: 'dashed'
- },
- symbol: 'none',
- silent: true
- },
- {
- type: 'scatter',
- data: farmData.plots.map(plot => {
- const isHighlighted = highlightPlotId && plot[2].includes(highlightPlotId.split('_')[1]);
- return {
- value: plot,
- itemStyle: isHighlighted ? {
- color: '#f59e0b',
- shadowBlur: 20,
- shadowColor: 'rgba(245, 158, 11, 0.8)',
- borderColor: '#dc2626',
- borderWidth: 3
- } : {
- color: '#10b981',
- shadowBlur: 8,
- shadowColor: 'rgba(16, 185, 129, 0.4)'
- }
- };
- }),
- symbolSize: function(value) {
- const isHighlighted = highlightPlotId && value[2].includes(highlightPlotId.split('_')[1]);
- return isHighlighted ? 35 : 25;
- }
- }
- ]
- });
- },
-
- renderFarmOverviewOnMap() {
- // 清除之前的标记
- if (this.farmMarkers) {
- this.farmMap.remove(this.farmMarkers);
- }
-
- // 农场数据(基于新的中心位置分布)
- const farmData = [
- {
- name: '东区智慧农场',
- position: [117.065029, 34.227274],
- area: '680',
- devices: '12',
- onlineRate: '97.2%',
- crops: '阳光玫瑰、玫瑰香'
- },
- {
- name: '西区智慧农场',
- position: [116.965029, 34.167274],
- area: '590',
- devices: '10',
- onlineRate: '94.5%',
- crops: '巨峰、红提'
- },
- {
- name: '南区智慧农场',
- position: [117.025029, 34.147274],
- area: '720',
- devices: '14',
- onlineRate: '96.8%',
- crops: '阳光玫瑰、夏黑'
- },
- {
- name: '北区智慧农场',
- position: [116.985029, 34.247274],
- area: '570',
- devices: '6',
- onlineRate: '93.2%',
- crops: '玫瑰香、巨峰'
- },
- {
- name: '中心监测农场',
- position: [117.015029, 34.197274],
- area: '200',
- devices: '8',
- onlineRate: '98.5%',
- crops: '克瑞森无核'
- }
- ];
-
- this.farmMarkers = [];
-
- farmData.forEach((farm, index) => {
- console.log('创建农场标记:', farm.name, farm.position);
-
- // 创建简单的标记先测试
- const marker = new AMap.Marker({
- position: farm.position,
- title: farm.name
- });
-
- // 完全避免SVG,使用高德地图内置样式
- // 创建自定义HTML标记元素
- const markerContent = document.createElement('div');
- markerContent.style.cssText = `
- width: 20px;
- height: 20px;
- background: #10b981;
- border: 2px solid white;
- border-radius: 50%;
- box-shadow: 0 2px 6px rgba(0,0,0,0.3);
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 3px;
- `;
-
- // 创建田地的4个小方格
- const fieldGrid = document.createElement('div');
- fieldGrid.style.cssText = `
- display: grid;
- grid-template-columns: 1fr 1fr;
- grid-template-rows: 1fr 1fr;
- gap: 1px;
- width: 8px;
- height: 8px;
- `;
-
- // 创建4个小方格
- for (let i = 0; i < 4; i++) {
- const gridItem = document.createElement('div');
- gridItem.style.cssText = `
- background: white;
- border-radius: 1px;
- opacity: 0.9;
- `;
- fieldGrid.appendChild(gridItem);
- }
-
- markerContent.appendChild(fieldGrid);
- marker.setContent(markerContent);
- marker.setOffset(new AMap.Pixel(-10, -10));
-
- // 创建信息窗体 - 自定义样式 + 手动添加三角箭头
- const infoWindow = new AMap.InfoWindow({
- isCustom: true,
- content: `
- <div style="
- padding: 0;
- margin: 0;
- min-width: 280px;
- position: relative;
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
- ">
- <!-- 主悬浮框 -->
- <div style="
- background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);
- border-radius: 12px;
- box-shadow: 0 8px 25px rgba(0,0,0,0.15);
- border: 1px solid #e2e8f0;
- overflow: hidden;
- position: relative;
- margin-bottom: 8px;
- ">
- <div style="
- background: linear-gradient(135deg, #10b981 0%, #059669 100%);
- padding: 16px 20px;
- color: white;
- position: relative;
- ">
- <div style="
- position: absolute;
- top: -10px;
- right: -10px;
- width: 40px;
- height: 40px;
- background: rgba(255,255,255,0.1);
- border-radius: 50%;
- "></div>
- <h4 style="
- margin: 0;
- font-size: 18px;
- font-weight: 600;
- text-shadow: 0 1px 2px rgba(0,0,0,0.1);
- ">${farm.name}</h4>
- <div style="
- font-size: 12px;
- opacity: 0.9;
- margin-top: 4px;
- ">智慧农业基地</div>
- <!-- 关闭按钮 -->
- <div onclick="this.parentElement.parentElement.parentElement.style.display='none'" style="
- position: absolute;
- top: 8px;
- right: 8px;
- width: 20px;
- height: 20px;
- border-radius: 50%;
- background: rgba(255,255,255,0.2);
- display: flex;
- align-items: center;
- justify-content: center;
- cursor: pointer;
- font-size: 12px;
- color: white;
- font-weight: bold;
- ">×</div>
- </div>
- <div style="padding: 20px;">
- <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 16px;">
- <div style="text-align: center; padding: 12px; background: #f1f5f9; border-radius: 8px;">
- <div style="font-size: 20px; font-weight: 700; color: #1e293b; margin-bottom: 4px;">${farm.area}</div>
- <div style="font-size: 12px; color: #64748b;">总面积(亩)</div>
- </div>
- <div style="text-align: center; padding: 12px; background: #ecfdf5; border-radius: 8px;">
- <div style="font-size: 20px; font-weight: 700; color: #059669; margin-bottom: 4px;">${farm.onlineRate}</div>
- <div style="font-size: 12px; color: #64748b;">设备在线率</div>
- </div>
- </div>
- <div style="space-y: 12px;">
- <div style="
- display: flex;
- align-items: center;
- padding: 8px 0;
- border-bottom: 1px solid #f1f5f9;
- ">
- <div style="
- width: 8px;
- height: 8px;
- background: #3b82f6;
- border-radius: 50%;
- margin-right: 12px;
- "></div>
- <span style="color: #475569; font-size: 14px; flex: 1;">设备数量</span>
- <span style="color: #1e293b; font-weight: 600; font-size: 14px;">${farm.devices}台</span>
- </div>
- <div style="
- display: flex;
- align-items: center;
- padding: 8px 0;
- ">
- <div style="
- width: 8px;
- height: 8px;
- background: #f59e0b;
- border-radius: 50%;
- margin-right: 12px;
- "></div>
- <span style="color: #475569; font-size: 14px; flex: 1;">主要品种</span>
- <span style="color: #1e293b; font-weight: 500; font-size: 14px;">${farm.crops}</span>
- </div>
- </div>
- </div>
- </div>
-
- <!-- 自定义三角箭头 -->
- <div style="
- position: absolute;
- bottom: -12px;
- left: 50%;
- transform: translateX(-50%);
- width: 0;
- height: 0;
- border-left: 12px solid transparent;
- border-right: 12px solid transparent;
- border-top: 12px solid #cbd5e1;
- z-index: 1;
- filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1));
- "></div>
- <div style="
- position: absolute;
- bottom: -10px;
- left: 50%;
- transform: translateX(-50%);
- width: 0;
- height: 0;
- border-left: 10px solid transparent;
- border-right: 10px solid transparent;
- border-top: 10px solid #ffffff;
- z-index: 2;
- "></div>
- </div>
- `,
- offset: new AMap.Pixel(0, -5)
- });
-
- // 点击标记显示信息窗体
- marker.on('click', () => {
- // 关闭其他可能打开的信息窗体
- this.farmMap.clearInfoWindow();
- // 在标记位置打开信息窗体
- infoWindow.open(this.farmMap, marker.getPosition());
- });
-
- this.farmMarkers.push(marker);
- });
-
- // 添加标记到地图
- console.log('添加标记到地图,标记数量:', this.farmMarkers.length);
- this.farmMap.add(this.farmMarkers);
-
- // 检查标记是否成功添加
- setTimeout(() => {
- console.log('地图上的标记数量:', this.farmMap.getAllOverlays('marker').length);
- }, 500);
-
- // 自适应显示所有农场
- const bounds = new AMap.Bounds();
- farmData.forEach(farm => {
- bounds.extend(farm.position);
- });
- this.farmMap.setBounds(bounds, false, [50, 50, 50, 50]);
-
- console.log('地图边界设置完成');
- },
-
- renderFarmDetailsOnMap(farmId, highlightPlotId = null) {
- // 清除之前的标记
- if (this.farmMarkers) {
- this.farmMap.remove(this.farmMarkers);
- }
- if (this.plotPolygons) {
- this.farmMap.remove(this.plotPolygons);
- }
-
- // 农场详情数据
- const farmDetailsMap = {
- east: {
- center: [117.065029, 34.227274],
- plots: [
- {
- name: 'A1地块',
- area: '220',
- devices: '4',
- health: '健康',
- crop: '阳光玫瑰',
- polygon: [
- [117.063029, 34.237274],
- [117.067029, 34.237274],
- [117.067029, 34.217274],
- [117.063029, 34.217274]
- ]
- },
- {
- name: 'A2地块',
- area: '230',
- devices: '4',
- health: '健康',
- crop: '玫瑰香',
- polygon: [
- [117.067029, 34.237274],
- [117.071029, 34.237274],
- [117.071029, 34.217274],
- [117.067029, 34.217274]
- ]
- },
- {
- name: 'A3地块',
- area: '230',
- devices: '4',
- health: '良好',
- crop: '阳光玫瑰',
- polygon: [
- [117.063029, 34.217274],
- [117.071029, 34.217274],
- [117.071029, 34.197274],
- [117.063029, 34.197274]
- ]
- }
- ]
- },
- west: {
- center: [116.965029, 34.167274],
- plots: [
- {
- name: 'B1地块',
- area: '295',
- devices: '5',
- health: '健康',
- crop: '巨峰',
- polygon: [
- [116.963029, 34.177274],
- [116.967029, 34.177274],
- [116.967029, 34.157274],
- [116.963029, 34.157274]
- ]
- },
- {
- name: 'B2地块',
- area: '295',
- devices: '5',
- health: '良好',
- crop: '红提',
- polygon: [
- [116.967029, 34.177274],
- [116.971029, 34.177274],
- [116.971029, 34.157274],
- [116.967029, 34.157274]
- ]
- }
- ]
- },
- south: {
- center: [117.025029, 34.147274],
- plots: [
- {
- name: 'C1地块',
- area: '240',
- devices: '5',
- health: '健康',
- crop: '阳光玫瑰',
- polygon: [
- [117.023029, 34.157274],
- [117.027029, 34.157274],
- [117.027029, 34.137274],
- [117.023029, 34.137274]
- ]
- },
- {
- name: 'C2地块',
- area: '240',
- devices: '5',
- health: '健康',
- crop: '夏黑',
- polygon: [
- [117.027029, 34.157274],
- [117.031029, 34.157274],
- [117.031029, 34.137274],
- [117.027029, 34.137274]
- ]
- },
- {
- name: 'C3地块',
- area: '240',
- devices: '4',
- health: '良好',
- crop: '阳光玫瑰',
- polygon: [
- [117.023029, 34.137274],
- [117.031029, 34.137274],
- [117.031029, 34.117274],
- [117.023029, 34.117274]
- ]
- }
- ]
- },
- north: {
- center: [116.985029, 34.247274],
- plots: [
- {
- name: 'D1地块',
- area: '285',
- devices: '3',
- health: '良好',
- crop: '玫瑰香',
- polygon: [
- [116.983029, 34.257274],
- [116.987029, 34.257274],
- [116.987029, 34.237274],
- [116.983029, 34.237274]
- ]
- },
- {
- name: 'D2地块',
- area: '285',
- devices: '3',
- health: '健康',
- crop: '巨峰',
- polygon: [
- [116.987029, 34.257274],
- [116.991029, 34.257274],
- [116.991029, 34.237274],
- [116.987029, 34.237274]
- ]
- }
- ]
- },
- center: {
- center: [117.015029, 34.197274],
- plots: [
- {
- name: '实验地块1',
- area: '67',
- devices: '3',
- health: '优秀',
- crop: '克瑞森无核',
- polygon: [
- [117.013029, 34.207274],
- [117.017029, 34.207274],
- [117.017029, 34.187274],
- [117.013029, 34.187274]
- ]
- },
- {
- name: '实验地块2',
- area: '67',
- devices: '3',
- health: '优秀',
- crop: '阳光玫瑰',
- polygon: [
- [117.017029, 34.207274],
- [117.021029, 34.207274],
- [117.021029, 34.187274],
- [117.017029, 34.187274]
- ]
- },
- {
- name: '示范地块',
- area: '66',
- devices: '2',
- health: '优秀',
- crop: '醉金香',
- polygon: [
- [117.013029, 34.187274],
- [117.021029, 34.187274],
- [117.021029, 34.167274],
- [117.013029, 34.167274]
- ]
- }
- ]
- }
- };
-
- const farmData = farmDetailsMap[farmId];
- if (!farmData) return;
-
- // 设置地图中心
- this.farmMap.setCenter(farmData.center);
- this.farmMap.setZoom(14);
-
- this.plotPolygons = [];
- this.farmMarkers = [];
-
- farmData.plots.forEach((plot, index) => {
- const isHighlighted = highlightPlotId && plot.name.includes(highlightPlotId.split('_')[1]);
-
- // 创建地块多边形
- const polygon = new AMap.Polygon({
- path: plot.polygon,
- strokeColor: isHighlighted ? '#f59e0b' : '#10b981',
- strokeWeight: isHighlighted ? 3 : 2,
- strokeOpacity: 0.8,
- fillColor: isHighlighted ? '#f59e0b' : '#10b981',
- fillOpacity: isHighlighted ? 0.4 : 0.2,
- cursor: 'pointer'
- });
-
- // 地块中心点坐标
- const centerLng = plot.polygon.reduce((sum, point) => sum + point[0], 0) / plot.polygon.length;
- const centerLat = plot.polygon.reduce((sum, point) => sum + point[1], 0) / plot.polygon.length;
-
- // 创建地块标记
- const marker = new AMap.Marker({
- position: [centerLng, centerLat],
- title: plot.name
- });
-
- // 添加自定义图标
- try {
- marker.setIcon(new AMap.Icon({
- size: new AMap.Size(32, 32),
- image: 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(`
- <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
- <defs>
- <filter id="plotShadow" x="-50%" y="-50%" width="200%" height="200%">
- <feDropShadow dx="0" dy="2" stdDeviation="2" flood-color="rgba(0,0,0,0.25)"/>
- </filter>
- <linearGradient id="plotGradient${index}" x1="0%" y1="0%" x2="100%" y2="100%">
- <stop offset="0%" style="stop-color:${isHighlighted ? '#f59e0b' : '#10b981'};stop-opacity:1" />
- <stop offset="100%" style="stop-color:${isHighlighted ? '#d97706' : '#059669'};stop-opacity:1" />
- </linearGradient>
- </defs>
- <circle cx="16" cy="16" r="13" fill="url(#plotGradient${index})" filter="url(#plotShadow)"/>
- <circle cx="16" cy="16" r="13" fill="none" stroke="${isHighlighted ? '#ffffff' : '#ffffff'}" stroke-width="2" opacity="0.9"/>
- ${isHighlighted ?
- '<circle cx="16" cy="16" r="13" fill="none" stroke="#dc2626" stroke-width="3" opacity="0.6" stroke-dasharray="4,2"/>' :
- ''
- }
- <g transform="translate(16,16)">
- <rect x="-6" y="-6" width="12" height="12" fill="none" stroke="white" stroke-width="1.5" opacity="0.9" rx="1"/>
- <path d="M-3,-6 L-3,6 M0,-6 L0,6 M3,-6 L3,6" stroke="white" stroke-width="0.8" opacity="0.7"/>
- <path d="M-6,-3 L6,-3 M-6,0 L6,0 M-6,3 L6,3" stroke="white" stroke-width="0.8" opacity="0.7"/>
- <circle cx="0" cy="0" r="1.5" fill="white" opacity="0.95"/>
- </g>
- </svg>
- `),
- imageOffset: new AMap.Pixel(-16, -16)
- }));
- } catch (iconError) {
- console.warn('设置地块图标失败:', iconError);
- }
-
- // 创建信息窗体 - 自定义样式 + 手动添加三角箭头
- const healthColor = plot.health === '优秀' ? '#10b981' : plot.health === '健康' ? '#059669' : plot.health === '良好' ? '#f59e0b' : '#ef4444';
- const healthBgColor = plot.health === '优秀' ? '#ecfdf5' : plot.health === '健康' ? '#f0fdf4' : plot.health === '良好' ? '#fefbf3' : '#fef2f2';
-
- const infoWindow = new AMap.InfoWindow({
- isCustom: true,
- content: `
- <div style="
- padding: 0;
- margin: 0;
- min-width: 260px;
- position: relative;
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
- ">
- <!-- 主悬浮框 -->
- <div style="
- background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);
- border-radius: 12px;
- box-shadow: 0 8px 25px rgba(0,0,0,0.15);
- border: 1px solid #e2e8f0;
- overflow: hidden;
- position: relative;
- margin-bottom: 8px;
- ">
- <div style="
- background: linear-gradient(135deg, ${healthColor} 0%, ${healthColor}dd 100%);
- padding: 14px 18px;
- color: white;
- position: relative;
- ">
- <div style="
- position: absolute;
- top: -8px;
- right: -8px;
- width: 32px;
- height: 32px;
- background: rgba(255,255,255,0.15);
- border-radius: 50%;
- "></div>
- <h4 style="
- margin: 0;
- font-size: 16px;
- font-weight: 600;
- text-shadow: 0 1px 2px rgba(0,0,0,0.1);
- ">${plot.name}</h4>
- <div style="
- font-size: 11px;
- opacity: 0.9;
- margin-top: 2px;
- ">农业种植地块</div>
- <!-- 关闭按钮 -->
- <div onclick="this.parentElement.parentElement.parentElement.style.display='none'" style="
- position: absolute;
- top: 6px;
- right: 6px;
- width: 18px;
- height: 18px;
- border-radius: 50%;
- background: rgba(255,255,255,0.2);
- display: flex;
- align-items: center;
- justify-content: center;
- cursor: pointer;
- font-size: 10px;
- color: white;
- font-weight: bold;
- ">×</div>
- </div>
- <div style="padding: 16px;">
- <div style="
- display: inline-flex;
- align-items: center;
- padding: 6px 12px;
- background: ${healthBgColor};
- border-radius: 20px;
- margin-bottom: 14px;
- ">
- <div style="
- width: 6px;
- height: 6px;
- background: ${healthColor};
- border-radius: 50%;
- margin-right: 8px;
- "></div>
- <span style="color: ${healthColor}; font-size: 12px; font-weight: 600;">${plot.health}状态</span>
- </div>
- <div style="space-y: 10px;">
- <div style="
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 8px 0;
- border-bottom: 1px solid #f1f5f9;
- ">
- <span style="color: #64748b; font-size: 13px;">地块面积</span>
- <span style="color: #1e293b; font-weight: 600; font-size: 14px;">${plot.area} 亩</span>
- </div>
- <div style="
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 8px 0;
- border-bottom: 1px solid #f1f5f9;
- ">
- <span style="color: #64748b; font-size: 13px;">监测设备</span>
- <span style="color: #1e293b; font-weight: 600; font-size: 14px;">${plot.devices} 台</span>
- </div>
- <div style="
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 8px 0;
- ">
- <span style="color: #64748b; font-size: 13px;">种植品种</span>
- <span style="color: #1e293b; font-weight: 500; font-size: 14px;">${plot.crop}</span>
- </div>
- </div>
- </div>
- </div>
-
- <!-- 自定义三角箭头 -->
- <div style="
- position: absolute;
- bottom: -12px;
- left: 50%;
- transform: translateX(-50%);
- width: 0;
- height: 0;
- border-left: 12px solid transparent;
- border-right: 12px solid transparent;
- border-top: 12px solid #cbd5e1;
- z-index: 1;
- filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1));
- "></div>
- <div style="
- position: absolute;
- bottom: -10px;
- left: 50%;
- transform: translateX(-50%);
- width: 0;
- height: 0;
- border-left: 10px solid transparent;
- border-right: 10px solid transparent;
- border-top: 10px solid #ffffff;
- z-index: 2;
- "></div>
- </div>
- `,
- offset: new AMap.Pixel(-130, -15)
- });
-
- // 点击事件
- const showInfo = () => {
- // 关闭其他可能打开的信息窗体
- this.farmMap.clearInfoWindow();
- // 在地块中心位置打开信息窗体
- infoWindow.open(this.farmMap, [centerLng, centerLat]);
- };
-
- marker.on('click', showInfo);
- polygon.on('click', showInfo);
-
- this.plotPolygons.push(polygon);
- this.farmMarkers.push(marker);
- });
-
- // 添加到地图
- this.farmMap.add(this.plotPolygons);
- this.farmMap.add(this.farmMarkers);
- },
-
- updateMapContent() {
- // 更新地图内容,不重新创建地图实例
- if (this.farmMap) {
- const currentSelection = this.getCurrentSelection();
-
- if (currentSelection.type === 'farm' && currentSelection.id === 'all') {
- this.renderFarmOverviewOnMap();
- } else if (currentSelection.type === 'farm') {
- this.renderFarmDetailsOnMap(currentSelection.id);
- } else if (currentSelection.type === 'plot') {
- this.renderFarmDetailsOnMap(currentSelection.farmId, currentSelection.plotId);
- }
- } else {
- // 如果地图实例不存在,使用备用方案更新
- const mapElement = document.getElementById('farmMap');
- if (mapElement && this.$echarts) {
- const chart = this.$echarts.getInstanceByDom(mapElement);
- if (chart) {
- const currentSelection = this.getCurrentSelection();
- if (currentSelection.type === 'farm' && currentSelection.id === 'all') {
- this.renderFallbackMap();
- } else {
- this.renderFarmDetailsECharts(chart, currentSelection.farmId || currentSelection.id, currentSelection.plotId);
- }
- }
- }
- }
- },
-
- getCropDataByTimeRange(timeRange) {
- // 根据时间范围返回不同的葡萄品种数据
- const cropDataMap = {
- week: [
- { value: 280, name: '阳光玫瑰', itemStyle: { color: '#10b981' } }, // 43.8%
- { value: 180, name: '玫瑰香', itemStyle: { color: '#3b82f6' } }, // 28.1%
- { value: 120, name: '巨峰', itemStyle: { color: '#f59e0b' } }, // 18.8%
- { value: 60, name: '夏黑', itemStyle: { color: '#8b5cf6' } } // 9.4%
- ],
- month: [
- { value: 1200, name: '阳光玫瑰', itemStyle: { color: '#10b981' } }, // 46.9%
- { value: 580, name: '玫瑰香', itemStyle: { color: '#3b82f6' } }, // 22.7%
- { value: 520, name: '巨峰', itemStyle: { color: '#f59e0b' } }, // 20.3%
- { value: 260, name: '夏黑', itemStyle: { color: '#8b5cf6' } } // 10.2%
- ],
- season: [
- { value: 3800, name: '阳光玫瑰', itemStyle: { color: '#10b981' } }, // 50.0%
- { value: 1520, name: '玫瑰香', itemStyle: { color: '#3b82f6' } }, // 20.0%
- { value: 1520, name: '巨峰', itemStyle: { color: '#f59e0b' } }, // 20.0%
- { value: 760, name: '夏黑', itemStyle: { color: '#8b5cf6' } } // 10.0%
- ]
- };
-
- return cropDataMap[timeRange] || cropDataMap.month;
- },
-
- getProductionDataByTimeRange(timeRange) {
- // 根据时间范围返回不同的生产数据
- const productionDataMap = {
- month: {
- xAxis: ['1月', '2月', '3月', '4月', '5月', '6月'],
- data: [120, 200, 150, 80, 70, 110]
- },
- quarter: {
- xAxis: ['第一季度', '第二季度', '第三季度', '第四季度'],
- data: [470, 340, 380, 420]
- },
- year: {
- xAxis: ['2019年', '2020年', '2021年', '2022年', '2023年', '2024年'],
- data: [1350, 1480, 1620, 1750, 1680, 1800]
- }
- };
- return productionDataMap[timeRange] || productionDataMap.month;
- },
-
- updateCropChart() {
- // 更新葡萄生长状况图表
- this.$nextTick(() => {
- const chartElement = document.getElementById('cropStatusChart');
- if (!chartElement || !this.$echarts) return;
-
- const chart = this.$echarts.getInstanceByDom(chartElement);
- if (!chart) {
- this.initCropStatusChart();
- return;
- }
-
- const cropData = this.getCropDataByTimeRange(this.cropTimeRange);
-
- chart.setOption({
- tooltip: {
- trigger: 'item',
- formatter: '{b}: {c}亩 ({d}%)'
- },
- legend: {
- show: false
- },
- series: [{
- type: 'pie',
- radius: ['45%', '75%'],
- center: ['50%', '50%'],
- data: cropData,
- label: {
- show: true,
- position: 'inside',
- formatter: '{d}%',
- fontSize: 12,
- fontWeight: 'bold',
- color: 'white'
- },
- emphasis: {
- itemStyle: {
- shadowBlur: 10,
- shadowOffsetX: 0,
- shadowColor: 'rgba(0, 0, 0, 0.5)'
- }
- }
- }]
- });
-
- // 强制触发Vue响应式更新
- this.$forceUpdate();
- });
- },
-
- updateProductionChart() {
- // 更新生产数据统计图表
- this.$nextTick(() => {
- const chartElement = document.getElementById('productionChart');
- if (!chartElement || !this.$echarts) return;
-
- const chart = this.$echarts.getInstanceByDom(chartElement);
- if (!chart) return;
-
- const productionData = this.getProductionDataByTimeRange(this.productionTimeRange);
-
- chart.setOption({
- xAxis: {
- data: productionData.xAxis
- },
- series: [{
- data: productionData.data
- }]
- });
- });
- },
-
- updateCropLegend() {
- // 根据当前时间范围更新葡萄品种图例显示
- const cropData = this.getCropDataByTimeRange(this.cropTimeRange);
- // 这里可以动态更新页面上的图例显示,如果需要的话
- },
-
- getCurrentCropLegend() {
- // 获取当前时间范围的葡萄品种图例数据
- const cropData = this.getCropDataByTimeRange(this.cropTimeRange);
- return cropData.map(item => ({
- name: item.name,
- value: item.value,
- color: item.itemStyle.color
- }));
- }
- }
- }
- </script>
- <style scoped lang="scss">
- // ============ 驾驶舱整体布局 ============
- .cockpit-dashboard {
- width: 100%;
- height: 100vh;
- overflow: hidden;
- background: #001528;
- display: flex;
- flex-direction: column;
- color: #fff;
-
- &.fullscreen-mode {
- // 全屏模式下可以进一步定制样式
- .dashboard-header {
- height: 80px;
- }
- }
- }
- // ============ 头部区域 ============
- .dashboard-header {
- height: 100px;
- background: linear-gradient(180deg, #002140 0%, #001528 100%);
- border-bottom: 2px solid rgba(24, 144, 255, 0.3);
- display: flex;
- align-items: center;
- padding: 0 20px;
- gap: 20px;
- flex-shrink: 0;
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
-
- .header-left {
- flex: 1;
-
- .title-section {
- .dashboard-title {
- font-size: 24px;
- font-weight: 700;
- color: #fff;
- margin: 0 0 4px 0;
- background: linear-gradient(135deg, #1890ff, #36cfc9);
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- background-clip: text;
- text-shadow: 0 0 20px rgba(24, 144, 255, 0.5);
- }
-
- .dashboard-subtitle {
- font-size: 12px;
- color: rgba(255, 255, 255, 0.65);
- margin: 0;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- }
- }
-
- .header-right {
- flex: 0 0 auto;
-
- .action-buttons {
- display: flex;
- gap: 8px;
- align-items: center;
-
- .location-selector-group {
- display: flex;
- gap: 6px;
- align-items: center;
- padding: 6px 10px;
- background: rgba(24, 144, 255, 0.08);
- border-radius: 6px;
- border: 1px solid rgba(24, 144, 255, 0.3);
- }
-
- // ============ 自定义按钮样式 ============
-
- // 确认按钮 - 青绿色
- .btn-confirm {
- background: #00C48F !important;
- border-color: #00C48F !important;
- color: #ffffff !important;
- border-radius: 6px;
- font-weight: 500;
- transition: all 0.3s ease;
-
- &:hover:not(:disabled) {
- background: #00E5A0 !important;
- border-color: #00E5A0 !important;
- box-shadow: 0 0 12px rgba(0, 196, 143, 0.5);
- transform: translateY(-1px);
- }
-
- &:active:not(:disabled) {
- transform: translateY(0);
- }
-
- &:disabled {
- background: rgba(0, 196, 143, 0.3) !important;
- border-color: rgba(0, 196, 143, 0.3) !important;
- color: rgba(255, 255, 255, 0.5) !important;
- cursor: not-allowed;
- }
- }
-
- // 刷新按钮 - 科技蓝
- .btn-refresh {
- background: #409EFF !important;
- border-color: #409EFF !important;
- color: #ffffff !important;
- border-radius: 6px;
- font-weight: 500;
- transition: all 0.3s ease;
-
- &:hover {
- background: #66b1ff !important;
- border-color: #66b1ff !important;
- box-shadow: 0 0 12px rgba(64, 158, 255, 0.5);
- transform: translateY(-1px);
- }
-
- &:active {
- transform: translateY(0);
- }
- }
-
- // 全屏驾驶舱按钮 - 高亮蓝色
- .btn-fullscreen {
- background: linear-gradient(135deg, #2E65F3 0%, #00A6FF 100%) !important;
- border-color: transparent !important;
- color: #ffffff !important;
- border-radius: 6px;
- font-weight: 500;
- transition: all 0.3s ease;
- box-shadow: 0 2px 8px rgba(46, 101, 243, 0.3);
-
- &:hover {
- background: linear-gradient(135deg, #4578ff 0%, #1eb8ff 100%) !important;
- box-shadow: 0 4px 16px rgba(46, 101, 243, 0.6);
- transform: translateY(-1px);
- }
-
- &:active {
- transform: translateY(0);
- }
- }
- }
- }
- }
- // ============ 主体区域 ============
- .dashboard-body {
- flex: 1;
- display: flex;
- gap: 12px;
- padding: 12px;
- overflow: hidden;
-
- // 左侧面板
- .dashboard-left {
- width: 320px;
- flex-shrink: 0;
- display: flex;
- flex-direction: column;
- gap: 12px;
- overflow-y: auto;
-
- &::-webkit-scrollbar {
- width: 4px;
- }
-
- &::-webkit-scrollbar-thumb {
- background: rgba(24, 144, 255, 0.3);
- border-radius: 2px;
- }
-
- // 左侧最后一个卡片扩展填充剩余空间
- .panel-card:last-child {
- flex: 1;
- display: flex;
- flex-direction: column;
- min-height: 0;
-
- .panel-content {
- flex: 1;
- display: flex;
- flex-direction: column;
- min-height: 0;
- }
- }
- }
-
- // 中央地图区域
- .dashboard-center {
- flex: 1;
- display: flex;
- flex-direction: column;
- overflow: hidden;
- }
-
- // 右侧面板
- .dashboard-right {
- width: 320px;
- flex-shrink: 0;
- display: flex;
- flex-direction: column;
- gap: 12px;
- overflow-y: auto;
-
- &::-webkit-scrollbar {
- width: 4px;
- }
-
- &::-webkit-scrollbar-thumb {
- background: rgba(24, 144, 255, 0.3);
- border-radius: 2px;
- }
-
- // 右侧最后一个卡片扩展填充剩余空间
- .panel-card:last-child {
- flex: 1;
- display: flex;
- flex-direction: column;
- min-height: 0;
-
- .panel-content {
- flex: 1;
- display: flex;
- flex-direction: column;
- min-height: 0;
- }
- }
- }
- }
- // ============ 面板卡片通用样式 ============
- .panel-card {
- background: rgba(0, 33, 64, 0.6);
- border: 1px solid rgba(24, 144, 255, 0.3);
- border-radius: 8px;
- overflow: hidden;
- backdrop-filter: blur(10px);
- flex-shrink: 0;
-
- .panel-header {
- background: rgba(24, 144, 255, 0.1);
- border-bottom: 1px solid rgba(24, 144, 255, 0.3);
- padding: 12px 16px;
- display: flex;
- justify-content: space-between;
- align-items: center;
-
- .panel-title {
- font-size: 14px;
- font-weight: 600;
- color: #1890ff;
- margin: 0;
- text-shadow: 0 0 10px rgba(24, 144, 255, 0.5);
- }
-
- .device-summary-mini {
- font-size: 11px;
- color: rgba(255, 255, 255, 0.65);
- display: flex;
- gap: 8px;
-
- .online-text {
- color: #52c41a;
- }
- }
- }
-
- .panel-content {
- padding: 12px;
- }
- }
- // ============ 图表容器 ============
- .chart-wrapper {
- height: 180px;
- width: 100%;
-
- #cropStatusChart,
- #deviceStatusChart,
- #productionChart {
- width: 100% !important;
- height: 100% !important;
- }
- }
- .chart-legend-mini {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 6px 8px;
- margin-top: 12px;
-
- .legend-item-mini {
- display: flex;
- align-items: center;
- gap: 6px;
- font-size: 11px;
- color: rgba(255, 255, 255, 0.85);
- line-height: 1.4;
-
- .legend-dot {
- width: 8px;
- height: 8px;
- border-radius: 50%;
- flex-shrink: 0;
- }
-
- .legend-text {
- flex: 1;
- word-break: break-all;
- }
- }
- }
- // 设备统计
- .device-stats-mini {
- display: flex;
- justify-content: space-around;
- margin-top: 12px;
- padding-top: 12px;
- border-top: 1px solid rgba(24, 144, 255, 0.2);
-
- .stat-item {
- text-align: center;
-
- .stat-label {
- display: block;
- font-size: 11px;
- color: rgba(255, 255, 255, 0.65);
- margin-bottom: 4px;
- }
-
- .stat-value {
- font-size: 16px;
- font-weight: 600;
-
- &.success {
- color: #52c41a;
- }
-
- &.danger {
- color: #ff4d4f;
- }
- }
- }
- }
- // 环境监测网格
- .env-grid-mini {
- display: grid;
- grid-template-columns: 1fr 1fr;
- grid-template-rows: 1fr 1fr;
- gap: 12px;
- flex: 1;
- min-height: 0;
-
- .env-item {
- background: rgba(24, 144, 255, 0.05);
- border: 1px solid rgba(24, 144, 255, 0.2);
- border-radius: 6px;
- padding: 12px;
- text-align: center;
- display: flex;
- flex-direction: column;
- min-height: 0;
-
- .env-name {
- font-size: 11px;
- color: rgba(255, 255, 255, 0.65);
- margin-bottom: 6px;
- flex-shrink: 0;
- }
-
- .env-value-text {
- font-size: 14px;
- font-weight: 600;
- color: #1890ff;
- margin-bottom: 8px;
- flex-shrink: 0;
- }
-
- .env-chart-mini {
- flex: 1;
- min-height: 40px;
- width: 100%;
- }
- }
- }
- // ============ 告警列表 ============
- .alert-list-mini {
- max-height: 300px;
- overflow-y: auto;
-
- &::-webkit-scrollbar {
- width: 4px;
- }
-
- &::-webkit-scrollbar-thumb {
- background: rgba(24, 144, 255, 0.3);
- border-radius: 2px;
- }
-
- .alert-item-mini {
- display: flex;
- align-items: center;
- gap: 10px;
- padding: 12px 8px;
- border-bottom: 1px solid rgba(24, 144, 255, 0.1);
- transition: background-color 0.2s;
-
- &:hover {
- background: rgba(24, 144, 255, 0.08);
- }
-
- &:last-child {
- border-bottom: none;
- }
-
- .alert-icon-mini {
- width: 28px;
- height: 28px;
- border-radius: 6px;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 14px;
- color: white;
- flex-shrink: 0;
- }
-
- &.warning .alert-icon-mini {
- background: #faad14;
- }
-
- &.error .alert-icon-mini {
- background: #ff4d4f;
- }
-
- &.info .alert-icon-mini {
- background: #1890ff;
- }
-
- .alert-info {
- flex: 1;
- min-width: 0;
-
- .alert-title-mini {
- font-size: 12px;
- color: rgba(255, 255, 255, 0.85);
- font-weight: 500;
- margin-bottom: 2px;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
-
- .alert-time-mini {
- font-size: 10px;
- color: rgba(255, 255, 255, 0.45);
- }
- }
-
- .alert-status-mini {
- font-size: 10px;
- padding: 2px 6px;
- border-radius: 10px;
- font-weight: 500;
- flex-shrink: 0;
-
- &.pending {
- background: rgba(250, 173, 20, 0.2);
- color: #faad14;
- }
-
- &.processing {
- background: rgba(24, 144, 255, 0.2);
- color: #1890ff;
- }
-
- &.resolved {
- background: rgba(82, 196, 26, 0.2);
- color: #52c41a;
- }
- }
- }
- }
- .badge-mini {
- .badge-text {
- color: rgba(255, 255, 255, 0.65);
- font-size: 11px;
- }
- }
- // ============ 地图区域 ============
- .map-wrapper {
- height: 100%;
- display: flex;
- flex-direction: column;
- background: rgba(0, 33, 64, 0.6);
- border: 1px solid rgba(24, 144, 255, 0.3);
- border-radius: 8px;
- overflow: hidden;
- backdrop-filter: blur(10px);
-
- .map-header {
- background: rgba(24, 144, 255, 0.1);
- border-bottom: 1px solid rgba(24, 144, 255, 0.3);
- padding: 12px 16px;
-
- .map-title {
- font-size: 14px;
- font-weight: 600;
- color: #1890ff;
- margin: 0;
- text-shadow: 0 0 10px rgba(24, 144, 255, 0.5);
- }
- }
-
- .map-container-full {
- flex: 1;
- position: relative;
- overflow: hidden;
-
- #farmMap {
- width: 100%;
- height: 100%;
- background: #0a1929;
- }
- }
- }
- // ============ 底部汇总数据卡片 ============
- .dashboard-summary-bottom {
- position: absolute;
- bottom: 24px;
- left: 50%;
- transform: translateX(-50%);
- z-index: 2;
- display: flex;
- gap: 16px;
- max-width: calc(100% - 680px); // 左右各留出340px空间(面板320px + 间距20px)
- pointer-events: auto;
-
- .overview-card-mini {
- background: rgba(0, 33, 64, 0.85);
- backdrop-filter: blur(10px);
- border: 1px solid rgba(24, 144, 255, 0.4);
- border-radius: 10px;
- padding: 14px 18px;
- display: flex;
- align-items: center;
- gap: 12px;
- transition: all 0.3s ease;
- min-width: 160px;
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
-
- &:hover {
- background: rgba(0, 33, 64, 0.95);
- border-color: rgba(24, 144, 255, 0.6);
- box-shadow: 0 6px 20px rgba(24, 144, 255, 0.4);
- transform: translateY(-2px);
- }
-
- .card-icon-mini {
- width: 44px;
- height: 44px;
- border-radius: 10px;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 20px;
- color: #fff;
- flex-shrink: 0;
- }
-
- .card-info {
- flex: 1;
-
- .card-value-mini {
- font-size: 22px;
- font-weight: 700;
- color: #fff;
- line-height: 1;
- margin-bottom: 4px;
- }
-
- .card-label-mini {
- font-size: 12px;
- color: rgba(255, 255, 255, 0.75);
- white-space: nowrap;
- }
- }
- }
- }
- // 响应式:小屏幕下调整卡片布局
- @media (max-width: 1400px) {
- .dashboard-summary-bottom {
- max-width: calc(100% - 100px);
- flex-wrap: wrap;
- justify-content: center;
-
- .overview-card-mini {
- min-width: 140px;
- padding: 12px 14px;
-
- .card-icon-mini {
- width: 38px;
- height: 38px;
- font-size: 18px;
- }
-
- .card-value-mini {
- font-size: 18px !important;
- }
-
- .card-label-mini {
- font-size: 11px !important;
- }
- }
- }
- }
- // ============ 农事任务执行进度 ============
- .task-progress-wrapper {
- display: flex;
- flex-direction: column;
- gap: 12px;
- flex: 1;
- min-height: 0;
-
- .task-chart-container {
- flex: 1;
- min-height: 140px;
- width: 100%;
-
- #taskProgressChart {
- width: 100% !important;
- height: 100% !important;
- }
- }
-
- .task-stats-grid {
- display: grid;
- grid-template-columns: repeat(3, 1fr);
- gap: 8px;
- flex-shrink: 0;
-
- .task-stat-item {
- text-align: center;
- padding: 8px;
- background: rgba(24, 144, 255, 0.05);
- border: 1px solid rgba(24, 144, 255, 0.15);
- border-radius: 6px;
- transition: all 0.3s ease;
-
- &:hover {
- background: rgba(24, 144, 255, 0.1);
- border-color: rgba(24, 144, 255, 0.3);
- }
-
- .stat-value {
- font-size: 18px;
- font-weight: 700;
- line-height: 1;
- margin-bottom: 4px;
-
- &.total {
- color: #1890ff;
- }
-
- &.completed {
- color: #52c41a;
- }
-
- &.pending {
- color: #faad14;
- }
- }
-
- .stat-label {
- font-size: 11px;
- color: rgba(255, 255, 255, 0.65);
- }
- }
- }
- }
- </style>
|