prodInputFlux.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986
  1. <template>
  2. <div class="agricultural-input-management">
  3. <!-- 计算页面 -->
  4. <div v-if="showInputForm" class="page-container">
  5. <el-card class="gradient-card">
  6. <div class="calculation-content">
  7. <h2 class="page-title">农业投入品输入通量计算</h2>
  8. <div class="scrollable-content">
  9. <el-form label-position="left">
  10. <div class="input-section">
  11. <!-- 第一行:氮肥的两个输入栏 -->
  12. <div class="input-row">
  13. <div class="input-item">
  14. <div class="input-title">氮肥镉含量平均值 (mg/kg)</div>
  15. <el-input
  16. v-model="formData.f3_nitrogen_cd_content"
  17. placeholder="0.12"
  18. size="large"
  19. class="fixed-width-input"
  20. />
  21. </div>
  22. <div class="input-item">
  23. <div class="input-title">氮肥单位面积使用量 (t/ha/a)</div>
  24. <el-input
  25. v-model="formData.nf_nitrogen_usage"
  26. placeholder="0.25"
  27. size="large"
  28. class="fixed-width-input"
  29. />
  30. </div>
  31. </div>
  32. <!-- 第二行:磷肥的两个输入栏 -->
  33. <div class="input-row">
  34. <div class="input-item">
  35. <div class="input-title">磷肥镉含量平均值 (mg/kg)</div>
  36. <el-input
  37. v-model="formData.f4_phosphorus_cd_content"
  38. placeholder="0.85"
  39. size="large"
  40. class="fixed-width-input"
  41. />
  42. </div>
  43. <div class="input-item">
  44. <div class="input-title">磷肥单位面积使用量 (t/ha/a)</div>
  45. <el-input
  46. v-model="formData.pf_phosphorus_usage"
  47. placeholder="0.15"
  48. size="large"
  49. class="fixed-width-input"
  50. />
  51. </div>
  52. </div>
  53. <!-- 第三行:钾肥的两个输入栏 -->
  54. <div class="input-row">
  55. <div class="input-item">
  56. <div class="input-title">钾肥镉含量平均值 (mg/kg)</div>
  57. <el-input
  58. v-model="formData.f5_potassium_cd_content"
  59. placeholder="0.05"
  60. size="large"
  61. class="fixed-width-input"
  62. />
  63. </div>
  64. <div class="input-item">
  65. <div class="input-title">钾肥单位面积使用量 (t/ha/a)</div>
  66. <el-input
  67. v-model="formData.kf_potassium_usage"
  68. placeholder="0.12"
  69. size="large"
  70. class="fixed-width-input"
  71. />
  72. </div>
  73. </div>
  74. <!-- 第四行:复合肥的两个输入栏 -->
  75. <div class="input-row">
  76. <div class="input-item">
  77. <div class="input-title">复合肥镉含量平均值 (mg/kg)</div>
  78. <el-input
  79. v-model="formData.f6_compound_cd_content"
  80. placeholder="0.45"
  81. size="large"
  82. class="fixed-width-input"
  83. />
  84. </div>
  85. <div class="input-item">
  86. <div class="input-title">复合肥单位面积使用量 (t/ha/a)</div>
  87. <el-input
  88. v-model="formData.cf_compound_usage"
  89. placeholder="0.30"
  90. size="large"
  91. class="fixed-width-input"
  92. />
  93. </div>
  94. </div>
  95. <!-- 第五行:有机肥的两个输入栏 -->
  96. <div class="input-row">
  97. <div class="input-item">
  98. <div class="input-title">有机肥镉含量平均值 (mg/kg)</div>
  99. <el-input
  100. v-model="formData.f7_organic_cd_content"
  101. placeholder="0.22"
  102. size="large"
  103. class="fixed-width-input"
  104. />
  105. </div>
  106. <div class="input-item">
  107. <div class="input-title">有机肥单位面积使用量 (t/ha/a)</div>
  108. <el-input
  109. v-model="formData.of_organic_usage"
  110. placeholder="2.50"
  111. size="large"
  112. class="fixed-width-input"
  113. />
  114. </div>
  115. </div>
  116. <!-- 第六行:农药的两个输入栏 -->
  117. <div class="input-row">
  118. <div class="input-item">
  119. <div class="input-title">农药镉含量 (mg/kg)</div>
  120. <el-input
  121. v-model="formData.f8_pesticide_cd_content"
  122. placeholder="0.08"
  123. size="large"
  124. class="fixed-width-input"
  125. />
  126. </div>
  127. <div class="input-item">
  128. <div class="input-title">农药单位面积使用量 (t/ha/a)</div>
  129. <el-input
  130. v-model="formData.p_pesticide_usage"
  131. placeholder="0.02"
  132. size="large"
  133. class="fixed-width-input"
  134. />
  135. </div>
  136. </div>
  137. <!-- 第七行:农家肥的两个输入栏 -->
  138. <div class="input-row">
  139. <div class="input-item">
  140. <div class="input-title">农家肥镉含量 (mg/kg)</div>
  141. <el-input
  142. v-model="formData.f9_farmyard_cd_content"
  143. placeholder="0.15"
  144. size="large"
  145. class="fixed-width-input"
  146. />
  147. </div>
  148. <div class="input-item">
  149. <div class="input-title">农家肥单位面积使用量 (t/ha/a)</div>
  150. <el-input
  151. v-model="formData.ff_farmyard_usage"
  152. placeholder="1.80"
  153. size="large"
  154. class="fixed-width-input"
  155. />
  156. </div>
  157. </div>
  158. <!-- 第八行:农膜的两个输入栏 -->
  159. <div class="input-row">
  160. <div class="input-item">
  161. <div class="input-title">农膜镉含量 (mg/kg)</div>
  162. <el-input
  163. v-model="formData.f10_film_cd_content"
  164. placeholder="0.03"
  165. size="large"
  166. class="fixed-width-input"
  167. />
  168. </div>
  169. <div class="input-item">
  170. <div class="input-title">农膜单位面积使用量 (t/ha/a)</div>
  171. <el-input
  172. v-model="formData.af_film_usage"
  173. placeholder="0.05"
  174. size="large"
  175. class="fixed-width-input"
  176. />
  177. </div>
  178. </div>
  179. </div>
  180. </el-form>
  181. </div>
  182. <div class="button-container">
  183. <el-button
  184. class="calculate-btn"
  185. @click="calculateAndVisualize"
  186. :loading="loading"
  187. size="large"
  188. >
  189. 计算农业投入品输入通量
  190. </el-button>
  191. </div>
  192. </div>
  193. </el-card>
  194. </div>
  195. <!-- 结果页面 -->
  196. <div v-if="!showInputForm" class="page-container">
  197. <div class="toolbar">
  198. <el-button class="custom-button back-button" @click="showInputForm = true">
  199. 返回计算
  200. </el-button>
  201. </div>
  202. <el-card class="results-card">
  203. <div class="results-content">
  204. <!-- 地图区域 -->
  205. <div class="map-section">
  206. <h3>农业投入品Cd通量分布图</h3>
  207. <div v-if="loadingMap" class="loading-container">
  208. <el-icon class="loading-icon"><Loading /></el-icon>
  209. <span>地图加载中...</span>
  210. </div>
  211. <div class="image-container">
  212. <img v-if="mapImageUrl" :src=mapImageUrl class="result-image"></img>
  213. <div v-if="!mapImageUrl && !loadingMap" class="no-data">
  214. <el-icon><Picture /></el-icon>
  215. <p>暂无地图数据</p>
  216. </div>
  217. </div>
  218. </div>
  219. <!-- 统计图表区域 -->
  220. <div class="stats-area">
  221. <h3>农业投入品Cd通量统计信息</h3>
  222. <div class="model-info">
  223. <el-tag type="info">农业投入品Cd通量模型</el-tag>
  224. <span class="update-time">
  225. 最后更新: {{ updateTime ? new Date(updateTime).toLocaleString() : '未知' }}
  226. </span>
  227. </div>
  228. <div v-if="loadingStats" class="loading-container">
  229. <el-icon class="loading-icon"><Loading /></el-icon>
  230. <span>统计数据加载中...</span>
  231. </div>
  232. <div v-if="!loadingStats && customResult.data" class="stats-container">
  233. <div class="total-flux">
  234. 总通量: {{ customResult.data.total_cd_flux }} g/ha/a
  235. </div>
  236. <el-table
  237. :data="customResultDetails"
  238. style="width: 100%; margin-bottom: 15px;"
  239. border
  240. stripe
  241. >
  242. <el-table-column prop="type" label="投入类型" align="center" min-width="120" />
  243. <el-table-column prop="flux" label="Cd通量(g/ha/a)" align="center" :formatter="formatNumber" min-width="120" />
  244. </el-table>
  245. </div>
  246. <div v-if="!loadingStats && !customResult.data" class="no-data">
  247. <el-icon><DataAnalysis /></el-icon>
  248. <p>暂无统计数据</p>
  249. </div>
  250. </div>
  251. <!-- 饼图区域 -->
  252. <div class="chart-section">
  253. <h3>农业投入品Cd通量占比</h3>
  254. <div class="image-container">
  255. <div ref="pieChart" style="width: 100%; height: 350px;"></div>
  256. </div>
  257. </div>
  258. </div>
  259. </el-card>
  260. </div>
  261. </div>
  262. </template>
  263. <script>
  264. import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue';
  265. import {
  266. ElInput,
  267. ElButton,
  268. ElMessage,
  269. ElCard,
  270. ElTable,
  271. ElTableColumn,
  272. ElTag,
  273. ElIcon,
  274. ElForm
  275. } from 'element-plus';
  276. import {
  277. Loading,
  278. Picture,
  279. DataAnalysis
  280. } from '@element-plus/icons-vue';
  281. import * as echarts from 'echarts';
  282. import { api8000 } from '@/utils/request';
  283. export default {
  284. components: {
  285. ElInput,
  286. ElButton,
  287. ElCard,
  288. ElTable,
  289. ElTableColumn,
  290. ElTag,
  291. ElIcon,
  292. ElForm,
  293. Loading,
  294. Picture,
  295. DataAnalysis
  296. },
  297. setup() {
  298. // 计算页面数据
  299. const showInputForm = ref(true);
  300. const formData = ref({
  301. f3_nitrogen_cd_content: "0.12",
  302. f4_phosphorus_cd_content: "0.85",
  303. f5_potassium_cd_content: "0.05",
  304. f6_compound_cd_content: "0.45",
  305. f7_organic_cd_content: "0.22",
  306. f8_pesticide_cd_content: "0.08",
  307. f9_farmyard_cd_content: "0.15",
  308. f10_film_cd_content: "0.03",
  309. nf_nitrogen_usage: "0.25",
  310. pf_phosphorus_usage: "0.15",
  311. kf_potassium_usage: "0.12",
  312. cf_compound_usage: "0.30",
  313. of_organic_usage: "2.50",
  314. p_pesticide_usage: "0.02",
  315. ff_farmyard_usage: "1.80",
  316. af_film_usage: "0.05"
  317. });
  318. const loading = ref(false);
  319. // 结果页面数据
  320. const mapImageUrl = ref('');
  321. const customResult = ref({});
  322. const updateTime = ref(new Date().toISOString());
  323. const loadingMap = ref(false);
  324. const loadingStats = ref(false);
  325. const pieChart = ref(null);
  326. // 格式化数字显示(保留4位小数)
  327. const formatNumber = (row, column, cellValue) => {
  328. if (typeof cellValue === 'number') {
  329. return cellValue.toFixed(4);
  330. }
  331. return cellValue;
  332. };
  333. // 获取类型名称
  334. const getTypeName = (type) => {
  335. const typeNames = {
  336. 'nitrogen_fertilizer': '氮肥',
  337. 'phosphorus_fertilizer': '磷肥',
  338. 'potassium_fertilizer': '钾肥',
  339. 'compound_fertilizer': '复合肥',
  340. 'organic_fertilizer': '有机肥',
  341. 'pesticide': '农药',
  342. 'farmyard_manure': '农家肥',
  343. 'agricultural_film': '农膜'
  344. };
  345. return typeNames[type] || type;
  346. };
  347. // 计算详情数据
  348. const customResultDetails = ref([]);
  349. // 计算并可视化
  350. const calculateAndVisualize = async () => {
  351. try {
  352. loading.value = true;
  353. loadingMap.value = true;
  354. loadingStats.value = true;
  355. mapImageUrl.value = '';
  356. // 准备请求数据
  357. const requestBody = {
  358. ...formData.value,
  359. // 将字符串值转换为数字
  360. f3_nitrogen_cd_content: parseFloat(formData.value.f3_nitrogen_cd_content),
  361. f4_phosphorus_cd_content: parseFloat(formData.value.f4_phosphorus_cd_content),
  362. f5_potassium_cd_content: parseFloat(formData.value.f5_potassium_cd_content),
  363. f6_compound_cd_content: parseFloat(formData.value.f6_compound_cd_content),
  364. f7_organic_cd_content: parseFloat(formData.value.f7_organic_cd_content),
  365. f8_pesticide_cd_content: parseFloat(formData.value.f8_pesticide_cd_content),
  366. f9_farmyard_cd_content: parseFloat(formData.value.f9_farmyard_cd_content),
  367. f10_film_cd_content: parseFloat(formData.value.f10_film_cd_content),
  368. nf_nitrogen_usage: parseFloat(formData.value.nf_nitrogen_usage),
  369. pf_phosphorus_usage: parseFloat(formData.value.pf_phosphorus_usage),
  370. kf_potassium_usage: parseFloat(formData.value.kf_potassium_usage),
  371. cf_compound_usage: parseFloat(formData.value.cf_compound_usage),
  372. of_organic_usage: parseFloat(formData.value.of_organic_usage),
  373. p_pesticide_usage: parseFloat(formData.value.p_pesticide_usage),
  374. ff_farmyard_usage: parseFloat(formData.value.ff_farmyard_usage),
  375. af_film_usage: parseFloat(formData.value.af_film_usage)
  376. };
  377. // 调用计算并可视化接口
  378. const [mapResponse, calcResponse] = await Promise.all([
  379. api8000.post(
  380. '/api/agricultural-input/calculate-and-visualize-file',
  381. requestBody,
  382. {
  383. params: {
  384. area: '乐昌市',
  385. level: 'county',
  386. colormap: 'green_yellow_red_purple',
  387. resolution_factor: 4.0,
  388. enable_interpolation: false,
  389. cleanup_intermediate: true
  390. },
  391. responseType: 'blob'
  392. }
  393. ),
  394. api8000.post(
  395. '/api/agricultural-input/calculate-with-custom-data',
  396. requestBody
  397. )
  398. ]);
  399. // 处理地图响应
  400. const blob = new Blob([mapResponse.data], { type: 'image/jpeg' });
  401. mapImageUrl.value = URL.createObjectURL(blob);
  402. // 处理计算结果
  403. if (calcResponse.data.success) {
  404. customResult.value = {
  405. success: true,
  406. data: calcResponse.data.data
  407. };
  408. // 更新详情数据
  409. customResultDetails.value = Object.entries(customResult.value.data.details).map(([type, flux]) => ({
  410. type: getTypeName(type),
  411. flux: flux
  412. }));
  413. showInputForm.value = false;
  414. updateTime.value = new Date().toISOString();
  415. // 初始化图表
  416. initPieChart();
  417. ElMessage.success('计算完成,结果已展示');
  418. } else {
  419. throw new Error(calcResponse.data.message);
  420. }
  421. } catch (error) {
  422. console.error('API调用错误:', error);
  423. ElMessage.error('计算失败: ' + (error.message || '请检查网络连接'));
  424. } finally {
  425. loading.value = false;
  426. loadingMap.value = false;
  427. loadingStats.value = false;
  428. }
  429. };
  430. // 初始化饼图
  431. const initPieChart = () => {
  432. if (!customResult.value.data || !customResult.value.data.details) return;
  433. nextTick(() => {
  434. const chartContainer = document.querySelector('.chart-section .image-container');
  435. if (!chartContainer) {
  436. console.error('图表容器未找到');
  437. return;
  438. }
  439. // 处理图表数据
  440. const chartData = Object.entries(customResult.value.data.details)
  441. .filter(([_, value]) => value > 0)
  442. .map(([type, value]) => ({
  443. name: getTypeName(type),
  444. value: parseFloat(value.toFixed(4))
  445. }));
  446. // 销毁旧图表实例
  447. if (pieChart.value) {
  448. pieChart.value.dispose();
  449. }
  450. // 初始化新图表
  451. pieChart.value = echarts.init(chartContainer);
  452. // 设置图表选项
  453. const option = {
  454. tooltip: {
  455. trigger: 'item',
  456. formatter: '{a} <br/>{b}: {c} g/ha/a ({d}%)'
  457. },
  458. legend: {
  459. orient: 'vertical',
  460. right: 10,
  461. top: 'center',
  462. data: chartData.map(item => item.name)
  463. },
  464. series: [
  465. {
  466. name: '农业投入品Cd通量占比',
  467. type: 'pie',
  468. radius: ['40%', '70%'],
  469. center: ['40%', '50%'],
  470. avoidLabelOverlap: false,
  471. itemStyle: {
  472. borderRadius: 10,
  473. borderColor: '#fff',
  474. borderWidth: 2
  475. },
  476. label: {
  477. show: false,
  478. position: 'center'
  479. },
  480. emphasis: {
  481. label: {
  482. show: true,
  483. fontSize: '16',
  484. fontWeight: 'bold',
  485. formatter: '{b}\n{c} g/ha/a\n({d}%)'
  486. }
  487. },
  488. labelLine: {
  489. show: false
  490. },
  491. data: chartData
  492. }
  493. ],
  494. responsive: true,
  495. animation: true,
  496. animationDuration: 1000,
  497. animationEasing: 'cubicOut'
  498. };
  499. // 设置图表选项
  500. pieChart.value.setOption(option);
  501. // 添加窗口大小变化监听
  502. window.addEventListener('resize', function() {
  503. pieChart.value.resize();
  504. });
  505. });
  506. };
  507. // 响应式调整
  508. const handleResize = () => {
  509. if (pieChart.value) {
  510. pieChart.value.resize();
  511. }
  512. };
  513. onMounted(() => {
  514. window.addEventListener('resize', handleResize);
  515. });
  516. onBeforeUnmount(() => {
  517. window.removeEventListener('resize', handleResize);
  518. if (pieChart.value) {
  519. pieChart.value.dispose();
  520. }
  521. if (mapImageUrl.value) {
  522. URL.revokeObjectURL(mapImageUrl.value);
  523. }
  524. });
  525. return {
  526. showInputForm,
  527. formData,
  528. loading,
  529. mapImageUrl,
  530. customResult,
  531. updateTime,
  532. loadingMap,
  533. loadingStats,
  534. customResultDetails,
  535. formatNumber,
  536. calculateAndVisualize
  537. };
  538. }
  539. };
  540. </script>
  541. <style scoped>
  542. /* 整体布局优化 - 紧凑版 */
  543. .agricultural-input-management {
  544. padding: 15px;
  545. background: linear-gradient(
  546. 135deg,
  547. rgba(230, 247, 255, 0.7) 0%,
  548. rgba(240, 248, 255, 0.7) 100%
  549. );
  550. box-sizing: border-box;
  551. }
  552. .page-container {
  553. width: 100%;
  554. height: 100%;
  555. display: flex;
  556. flex-direction: column;
  557. }
  558. .gradient-card, .results-card {
  559. background-color: rgba(255, 255, 255, 0.8);
  560. border-radius: 6px;
  561. padding: 15px;
  562. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  563. backdrop-filter: blur(5px);
  564. flex: 1;
  565. display: flex;
  566. flex-direction: column;
  567. }
  568. /* 计算内容区域 */
  569. .calculation-content {
  570. display: flex;
  571. flex-direction: column;
  572. height: 100%;
  573. }
  574. .page-title {
  575. text-align: center;
  576. margin-bottom: 5px;
  577. color: #333;
  578. font-size: 20px;
  579. font-weight: 600;
  580. }
  581. .scrollable-content {
  582. flex: 1;
  583. overflow-y: auto;
  584. padding: 8px;
  585. margin-bottom: 10px;
  586. }
  587. /* 输入区域样式 - 响应式布局 */
  588. .input-section {
  589. width: 100%;
  590. padding: 8px 0;
  591. }
  592. .input-row {
  593. display: flex;
  594. flex-wrap: wrap;
  595. margin-bottom: 12px;
  596. gap: 12px;
  597. }
  598. .input-item {
  599. flex: 1;
  600. display: flex;
  601. align-items: center;
  602. min-width: 300px; /* 最小宽度确保在小屏幕上也能正常显示 */
  603. gap: 12px; /* 增加标题和输入框之间的间距 */
  604. }
  605. .input-title {
  606. font-size: 16px;
  607. color: #666;
  608. text-align: left;
  609. font-weight: 500;
  610. width: 220px;
  611. white-space: nowrap;
  612. flex-shrink: 0;
  613. margin-right: 15px; /* 增加标题右侧间距 */
  614. margin-left: 20px;
  615. padding: 8px 0; /* 增加标题上下内边距 */
  616. }
  617. /* 固定输入栏宽度 */
  618. .fixed-width-input {
  619. flex: 1;
  620. min-width: 150px; /* 确保输入框有最小宽度 */
  621. }
  622. /* 按钮容器 */
  623. .button-container {
  624. padding: 10px 0;
  625. display: flex;
  626. justify-content: center;
  627. margin-top: auto;
  628. }
  629. .calculate-btn {
  630. width: 280px;
  631. background-color: #47C3B9 !important;
  632. color: white !important;
  633. font-weight: bold;
  634. height: 40px;
  635. border-radius: 6px;
  636. font-size: 15px;
  637. }
  638. .results-card {
  639. background-color: rgba(255, 255, 255, 0.8);
  640. border-radius: 8px;
  641. padding: 20px;
  642. box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
  643. backdrop-filter: blur(5px);
  644. height: 100%;
  645. box-sizing: border-box;
  646. }
  647. .results-content {
  648. height: 100%;
  649. display: flex;
  650. flex-direction: column;
  651. }
  652. .map-section, .stats-area, .chart-section {
  653. background-color: rgba(255, 255, 255, 0.8);
  654. border-radius: 6px;
  655. padding: 15px;
  656. margin-bottom: 15px;
  657. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  658. }
  659. h3 {
  660. margin-bottom: 12px;
  661. color: #333;
  662. font-size: 16px;
  663. font-weight: 600;
  664. }
  665. .model-info {
  666. display: flex;
  667. align-items: center;
  668. gap: 12px;
  669. margin-bottom: 12px;
  670. }
  671. .update-time {
  672. color: #666;
  673. font-size: 13px;
  674. }
  675. .total-flux {
  676. text-align: center;
  677. font-size: 16px;
  678. font-weight: bold;
  679. margin-bottom: 15px;
  680. }
  681. /* 图片容器限定大小 */
  682. .image-container {
  683. width: 100%;
  684. height: 500px;
  685. display: flex;
  686. justify-content: center;
  687. align-items: center;
  688. background-color: #f9f9f9;
  689. border-radius: 6px;
  690. overflow: hidden;
  691. }
  692. .result-image {
  693. max-width: 100%;
  694. max-height: 100%;
  695. object-fit: contain;
  696. }
  697. .loading-container {
  698. display: flex;
  699. flex-direction: column;
  700. align-items: center;
  701. justify-content: center;
  702. height: 250px;
  703. color: #47C3B9;
  704. }
  705. .no-data {
  706. display: flex;
  707. flex-direction: column;
  708. align-items: center;
  709. justify-content: center;
  710. height: 250px;
  711. color: #999;
  712. font-size: 14px;
  713. }
  714. .no-data .el-icon {
  715. font-size: 40px;
  716. margin-bottom: 8px;
  717. }
  718. .loading-icon {
  719. font-size: 32px;
  720. margin-bottom: 8px;
  721. animation: rotate 2s linear infinite;
  722. }
  723. @keyframes rotate {
  724. from { transform: rotate(0deg); }
  725. to { transform: rotate(360deg); }
  726. }
  727. /* 响应式设计 - 增强版 */
  728. @media (max-width: 1200px) {
  729. .input-item {
  730. min-width: 280px;
  731. }
  732. .input-title {
  733. margin-right: 12px; /* 中等屏幕调整间距 */
  734. margin-left: 12px;
  735. }
  736. }
  737. @media (max-width: 992px) {
  738. .input-row {
  739. gap: 10px;
  740. }
  741. .input-item {
  742. min-width: 100%;
  743. flex-direction: row; /* 保持水平布局 */
  744. align-items: center;
  745. gap: 10px; /* 调整间距 */
  746. }
  747. .input-title {
  748. width: 220px;
  749. min-width: 220px; /* 固定标题宽度 */
  750. margin-right: 10px;
  751. font-size: 15px;
  752. }
  753. .fixed-width-input {
  754. width: 100%;
  755. }
  756. .page-title {
  757. font-size: 18px;
  758. margin-bottom: 15px;
  759. }
  760. }
  761. @media (max-width: 768px) {
  762. .toolbar {
  763. flex-direction: column;
  764. align-items: stretch;
  765. gap: 8px;
  766. }
  767. .input-item {
  768. gap: 8px;
  769. }
  770. .input-title {
  771. width: 180px;
  772. min-width: 180px;
  773. font-size: 14px;
  774. margin-right: 8px;
  775. margin-left: 8px;
  776. }
  777. .image-container {
  778. height: 280px;
  779. }
  780. :deep(.el-input__inner) {
  781. height: 34px;
  782. line-height: 34px;
  783. font-size: 13px;
  784. }
  785. }
  786. @media (max-width: 600px) {
  787. .input-item {
  788. flex-direction: column;
  789. align-items: flex-start;
  790. gap: 6px;
  791. }
  792. .input-title {
  793. width: 100%;
  794. min-width: 100%;
  795. margin-right: 0;
  796. text-align: left;
  797. padding: 4px 0;
  798. }
  799. .fixed-width-input {
  800. width: 100%;
  801. margin-left: 0;
  802. }
  803. }
  804. @media (max-width: 480px) {
  805. .agricultural-input-management {
  806. padding: 10px;
  807. }
  808. .gradient-card, .results-card {
  809. padding: 12px;
  810. }
  811. .page-title {
  812. font-size: 16px;
  813. margin-bottom: 12px;
  814. }
  815. .input-item {
  816. min-width: 100%;
  817. gap: 5px;
  818. }
  819. .input-title {
  820. font-size: 13px;
  821. padding: 3px 0;
  822. }
  823. .calculate-btn {
  824. width: 100%;
  825. max-width: 280px;
  826. height: 38px;
  827. font-size: 14px;
  828. }
  829. .image-container {
  830. height: 220px;
  831. }
  832. .total-flux {
  833. font-size: 15px;
  834. }
  835. .input-row {
  836. margin-bottom: 10px;
  837. gap: 8px;
  838. }
  839. }
  840. /* 工具栏样式 */
  841. .toolbar {
  842. display: flex;
  843. justify-content: flex-start;
  844. gap: 15px;
  845. margin-bottom: 20px;
  846. padding: 15px;
  847. background-color: rgba(255, 255, 255, 0.8);
  848. border-radius: 8px;
  849. box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
  850. backdrop-filter: blur(5px);
  851. }
  852. .custom-button {
  853. background-color: #47C3B9 !important;
  854. color: #DCFFFA !important;
  855. border: none;
  856. border-radius: 155px;
  857. padding: 10px 20px;
  858. font-weight: bold;
  859. display: flex;
  860. align-items: center;
  861. }
  862. /* 特殊小屏幕适配 */
  863. @media (max-width: 360px) {
  864. .input-title {
  865. font-size: 12px;
  866. padding: 2px 0;
  867. }
  868. .calculate-btn {
  869. font-size: 13px;
  870. padding: 0 10px;
  871. }
  872. .input-item {
  873. gap: 4px;
  874. }
  875. }
  876. /* 为输入项添加悬停效果,提升用户体验 */
  877. .input-item:hover .input-title {
  878. color: #47C3B9;
  879. transition: color 0.3s ease;
  880. }
  881. .input-item:hover :deep(.el-input__inner) {
  882. border-color: #47C3B9;
  883. transition: border-color 0.3s ease;
  884. }
  885. </style>