|
@@ -0,0 +1,477 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <div class="agri-record-detail">
|
|
|
|
|
+ <custom-header name="农事详情"></custom-header>
|
|
|
|
|
+ <div class="content">
|
|
|
|
|
+ <div class="status-banner" :class="`status-banner--${statusInfo.theme}`">
|
|
|
|
|
+ <div class="status-banner__title">{{ statusInfo.title }}</div>
|
|
|
|
|
+ <div class="status-banner__deadline">截止到 {{ statusInfo.deadline }}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="box-wrap execution-area-card">
|
|
|
|
|
+ <div class="execution-area-card__header">
|
|
|
|
|
+ <span class="title">执行区域</span>
|
|
|
|
|
+ <span class="code">{{ executionArea.zoneCode }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="map-container" ref="mapContainer"></div>
|
|
|
|
|
+ <div class="execution-area-card__footer">
|
|
|
|
|
+ <div class="address">
|
|
|
|
|
+ <div class="address-title">{{ executionArea.addressTitle }}</div>
|
|
|
|
|
+ <div class="address-detail">{{ executionArea.addressDetail }}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="nav-btn" @click="handleNavigate">导航到这里</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="box-wrap work-summary-card">
|
|
|
|
|
+ <div class="header">
|
|
|
|
|
+ <div class="icon">
|
|
|
|
|
+ <el-icon color="#fff" :size="14">
|
|
|
|
|
+ <School />
|
|
|
|
|
+ </el-icon>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <span class="title">{{ workSummary.workName }}</span>
|
|
|
|
|
+ <div class="tags">
|
|
|
|
|
+ <span
|
|
|
|
|
+ v-for="(tag, index) in workSummary.tags"
|
|
|
|
|
+ :key="index"
|
|
|
|
|
+ class="work-tag"
|
|
|
|
|
+ :class="`work-tag--${tag.theme}`"
|
|
|
|
|
+ >{{ tag.label }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="body">
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-for="(row, index) in workSummary.detailRows"
|
|
|
|
|
+ :key="index"
|
|
|
|
|
+ class="detail-row"
|
|
|
|
|
+ :class="{ 'detail-row--field': isFieldRow(row) }"
|
|
|
|
|
+ >
|
|
|
|
|
+ <span class="detail-row__label">{{ row.label }}</span>
|
|
|
|
|
+ <span v-if="isTextRow(row)" class="detail-row__value">{{ formatRowValue(row) }}</span>
|
|
|
|
|
+ <el-date-picker
|
|
|
|
|
+ v-else-if="getEffectiveRowType(row) === 'date'"
|
|
|
|
|
+ v-model="row.value"
|
|
|
|
|
+ class="detail-row__control"
|
|
|
|
|
+ type="date"
|
|
|
|
|
+ format="YYYY.MM.DD"
|
|
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
|
|
+ placeholder="请选择日期"
|
|
|
|
|
+ :editable="false"
|
|
|
|
|
+ style="width: 100%"
|
|
|
|
|
+ />
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-else-if="getEffectiveRowType(row) === 'input'"
|
|
|
|
|
+ v-model="row.value"
|
|
|
|
|
+ class="detail-row__control"
|
|
|
|
|
+ placeholder="请输入"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="box-wrap">
|
|
|
|
|
+ <div class="info-item">
|
|
|
|
|
+ <div class="info-title"><span class="title-block"></span>农事目的</div>
|
|
|
|
|
+ <div class="info-value">农事目的农事目的农事目的农事目的农事目的农事目</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="info-item">
|
|
|
|
|
+ <div class="info-title"><span class="title-block"></span>药物处方</div>
|
|
|
|
|
+ <div class="info-value">农事目的农事目的农事目的农事目的农事目的农事目</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="info-item">
|
|
|
|
|
+ <div class="info-title"><span class="title-block"></span>执行参数</div>
|
|
|
|
|
+ <div class="info-value">农事目的农事目的农事目的农事目的农事目的农事目</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="info-item">
|
|
|
|
|
+ <div class="info-title"><span class="title-block"></span>注意事项</div>
|
|
|
|
|
+ <div class="info-value">农事目的农事目的农事目的农事目的农事目的农事目</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="custom-bottom-fixed-btns">
|
|
|
|
|
+ <div class="bottom-btn secondary-btn" @click="handleToggleEdit">
|
|
|
|
|
+ {{ isEditing ? '取消修改' : '修改信息' }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="bottom-btn primary-btn" :class="{ 'orange-btn': !isEditing }" @click="handleAccept">{{ isEditing ? '保存信息' : '我要接受' }}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script setup>
|
|
|
|
|
+import { ref, onActivated, nextTick } from 'vue';
|
|
|
|
|
+import { School } from '@element-plus/icons-vue';
|
|
|
|
|
+import * as util from '@/common/ol_common.js';
|
|
|
|
|
+import customHeader from '@/components/customHeader.vue';
|
|
|
|
|
+import { useI18n } from '@/i18n';
|
|
|
|
|
+import IndexMap from './map/index.js';
|
|
|
|
|
+
|
|
|
|
|
+const { t } = useI18n();
|
|
|
|
|
+
|
|
|
|
|
+const DEFAULT_FARM_POINT = 'POINT(113.6142086995688 23.585836479509055)';
|
|
|
|
|
+const mapContainer = ref(null);
|
|
|
|
|
+const recordDetailMap = new IndexMap();
|
|
|
|
|
+
|
|
|
|
|
+const syncExecutionAreaMap = async () => {
|
|
|
|
|
+ const location = DEFAULT_FARM_POINT;
|
|
|
|
|
+ await nextTick();
|
|
|
|
|
+ if (!mapContainer.value) return;
|
|
|
|
|
+ if (recordDetailMap.kmap) {
|
|
|
|
|
+ const coordinate = util.wktCastGeom(location).getFirstCoordinate();
|
|
|
|
|
+ recordDetailMap.setMapPosition(coordinate);
|
|
|
|
|
+ recordDetailMap.kmap?.map?.updateSize?.();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ recordDetailMap.initMap(location, mapContainer.value);
|
|
|
|
|
+ recordDetailMap.kmap?.map?.updateSize?.();
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+onActivated(async () => {
|
|
|
|
|
+ isEditing.value = false;
|
|
|
|
|
+ detailRowsSnapshot = null;
|
|
|
|
|
+ await syncExecutionAreaMap();
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+const EDITABLE_FIELD_MAP = {
|
|
|
|
|
+ 执行时间: 'date',
|
|
|
|
|
+ 执行农机: 'input',
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const isEditing = ref(false);
|
|
|
|
|
+let detailRowsSnapshot = null;
|
|
|
|
|
+
|
|
|
|
|
+const getEffectiveRowType = (row) => {
|
|
|
|
|
+ if (!isEditing.value) return undefined;
|
|
|
|
|
+ return EDITABLE_FIELD_MAP[row.label] || undefined;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const isTextRow = (row) => !getEffectiveRowType(row);
|
|
|
|
|
+const isFieldRow = (row) => !!getEffectiveRowType(row);
|
|
|
|
|
+
|
|
|
|
|
+const formatRowValue = (row) => {
|
|
|
|
|
+ if (!row?.value) return row?.value ?? '';
|
|
|
|
|
+ if (row.type === 'date' || row.label === '执行时间') {
|
|
|
|
|
+ return String(row.value).replace(/-/g, '.');
|
|
|
|
|
+ }
|
|
|
|
|
+ return row.value;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const normalizeDateValue = (value) => {
|
|
|
|
|
+ if (!value) return value;
|
|
|
|
|
+ return String(value).replace(/\./g, '-');
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const normalizeDetailRows = (rows = []) =>
|
|
|
|
|
+ rows.map((row) => {
|
|
|
|
|
+ if (row.type === 'date' && row.value) {
|
|
|
|
|
+ return { ...row, value: normalizeDateValue(row.value) };
|
|
|
|
|
+ }
|
|
|
|
|
+ return row;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+const workSummary = ref({
|
|
|
|
|
+ workName: '农事名称',
|
|
|
|
|
+ tags: [
|
|
|
|
|
+ { label: '感知类', theme: 'orange' },
|
|
|
|
|
+ { label: '标准类', theme: 'blue' },
|
|
|
|
|
+ { label: '复核类', theme: 'green' },
|
|
|
|
|
+ ],
|
|
|
|
|
+ detailRows: normalizeDetailRows([
|
|
|
|
|
+ { label: '负责人', value: '张扬洋' },
|
|
|
|
|
+ { label: '农事详情', value: '解释解释解释解释' },
|
|
|
|
|
+ { label: '农情研判', value: '原因原因原因原因原因原因原因原因' },
|
|
|
|
|
+ { label: '执行时间', value: '2025.05.06' },
|
|
|
|
|
+ { label: '执行农机', value: 'D-260602-1455-01-01' },
|
|
|
|
|
+ ]),
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+const statusInfo = ref({
|
|
|
|
|
+ title: '待接收',
|
|
|
|
|
+ deadline: '2025.05.06',
|
|
|
|
|
+ theme: 'orange',
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+const executionArea = ref({
|
|
|
|
|
+ zoneCode: 'ws0gefwg9tdn',
|
|
|
|
|
+ addressTitle: '具体地址具体地址具体地',
|
|
|
|
|
+ addressDetail: '广东省广州市从化区富江道',
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+const handleNavigate = () => {};
|
|
|
|
|
+
|
|
|
|
|
+const handleToggleEdit = () => {
|
|
|
|
|
+ if (!isEditing.value) {
|
|
|
|
|
+ detailRowsSnapshot = JSON.parse(JSON.stringify(workSummary.value.detailRows));
|
|
|
|
|
+ workSummary.value.detailRows = workSummary.value.detailRows.map((row) => {
|
|
|
|
|
+ if (row.label === '执行时间' && row.value) {
|
|
|
|
|
+ return { ...row, value: normalizeDateValue(row.value) };
|
|
|
|
|
+ }
|
|
|
|
|
+ return row;
|
|
|
|
|
+ });
|
|
|
|
|
+ isEditing.value = true;
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (detailRowsSnapshot) {
|
|
|
|
|
+ workSummary.value.detailRows = detailRowsSnapshot;
|
|
|
|
|
+ detailRowsSnapshot = null;
|
|
|
|
|
+ }
|
|
|
|
|
+ isEditing.value = false;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const handleAccept = () => {
|
|
|
|
|
+ // TODO: 提交接受农事接口
|
|
|
|
|
+ isEditing.value = false;
|
|
|
|
|
+ detailRowsSnapshot = null;
|
|
|
|
|
+};
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style scoped lang="scss">
|
|
|
|
|
+.agri-record-detail {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100vh;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ background: #f2f3f5;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+
|
|
|
|
|
+ .content {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ min-height: 0;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ overflow-y: auto;
|
|
|
|
|
+ -webkit-overflow-scrolling: touch;
|
|
|
|
|
+ padding-bottom: 90px;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+
|
|
|
|
|
+ .status-banner {
|
|
|
|
|
+ padding: 20px 12px 72px;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+
|
|
|
|
|
+ &--orange {
|
|
|
|
|
+ background: #FF9838;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &--blue {
|
|
|
|
|
+ background: #2199F8;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &--red {
|
|
|
|
|
+ background: #FF6A6A;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &__title {
|
|
|
|
|
+ font-size: 22px;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .box-wrap {
|
|
|
|
|
+ background: #ffffff;
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ padding: 10px;
|
|
|
|
|
+ margin: 10px 12px 0 12px;
|
|
|
|
|
+
|
|
|
|
|
+ &.execution-area-card {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ z-index: 1;
|
|
|
|
|
+ margin-top: -52px;
|
|
|
|
|
+
|
|
|
|
|
+ .execution-area-card__header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ .title {
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ }
|
|
|
|
|
+ .code {
|
|
|
|
|
+ color: #565656;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .map-container {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 166px;
|
|
|
|
|
+ margin: 12px 0;
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .execution-area-card__footer {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ .address {
|
|
|
|
|
+ .address-title {
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ color: #1D2129;
|
|
|
|
|
+ // overflow: hidden;
|
|
|
|
|
+ // text-overflow: ellipsis;
|
|
|
|
|
+ // white-space: nowrap;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .address-detail {
|
|
|
|
|
+ margin-top: 2px;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: rgba(29, 33, 41, 0.6);
|
|
|
|
|
+ // overflow: hidden;
|
|
|
|
|
+ // text-overflow: ellipsis;
|
|
|
|
|
+ // white-space: nowrap;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .nav-btn {
|
|
|
|
|
+ padding: 6px 10px;
|
|
|
|
|
+ border: 1px solid #2199F8;
|
|
|
|
|
+ border-radius: 25px;
|
|
|
|
|
+ color: #2199F8;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &.work-summary-card {
|
|
|
|
|
+ padding: 12px 10px 10px;
|
|
|
|
|
+
|
|
|
|
|
+ .header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 8px;
|
|
|
|
|
+ border-bottom: 1px solid rgba(245, 245, 245, 0.99);
|
|
|
|
|
+ padding-bottom: 8px;
|
|
|
|
|
+ margin-bottom: 8px;
|
|
|
|
|
+ .icon {
|
|
|
|
|
+ width: 22px;
|
|
|
|
|
+ height: 22px;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+ background: #2199F8;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .title {
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .tags {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 4px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .work-tag {
|
|
|
|
|
+ padding: 0 6px;
|
|
|
|
|
+ border-radius: 2px;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+
|
|
|
|
|
+ &--orange {
|
|
|
|
|
+ background: rgba(255, 179, 47, 0.1);
|
|
|
|
|
+ color: #FFB32F;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &--blue {
|
|
|
|
|
+ background: rgba(33, 153, 248, 0.1);
|
|
|
|
|
+ color: #2199F8;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &--green {
|
|
|
|
|
+ background: rgba(58, 173, 148, 0.1);
|
|
|
|
|
+ color: #3AAD94;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .body {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ gap: 6px;
|
|
|
|
|
+ .detail-row {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 8px;
|
|
|
|
|
+
|
|
|
|
|
+ &__label {
|
|
|
|
|
+ width: 56px;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ color: rgba(111, 114, 116, 0.6);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &__value {
|
|
|
|
|
+ color: #565656;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &__control {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ min-width: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &--field {
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+
|
|
|
|
|
+ :deep(.el-input__wrapper) {
|
|
|
|
|
+ border: 1px solid rgba(33, 153, 248, 0.5);
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+ box-shadow: none;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ :deep(.el-input__inner) {
|
|
|
|
|
+ color: #2199F8;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ :deep(.el-input__prefix),
|
|
|
|
|
+ :deep(.el-input__suffix) {
|
|
|
|
|
+ color: #2199F8;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .info-item {
|
|
|
|
|
+ .info-title {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 4px;
|
|
|
|
|
+ color: #2199F8;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+
|
|
|
|
|
+ .title-block {
|
|
|
|
|
+ width: 6px;
|
|
|
|
|
+ height: 6px;
|
|
|
|
|
+ background: #2199F8;
|
|
|
|
|
+ border-radius: 1px;
|
|
|
|
|
+ transform: rotate(45deg);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .info-value {
|
|
|
|
|
+ padding-top: 4px;
|
|
|
|
|
+ color: #ACACAC;
|
|
|
|
|
+ line-height: 21px;
|
|
|
|
|
+ white-space: pre-line;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .blod-text {
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .info-item+.info-item {
|
|
|
|
|
+ margin-top: 10px;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .custom-bottom-fixed-btns {
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ .secondary-btn{
|
|
|
|
|
+ background: #F6F6F6;
|
|
|
|
|
+ border: none;
|
|
|
|
|
+ }
|
|
|
|
|
+ .primary-btn{
|
|
|
|
|
+ background: #2199F8;
|
|
|
|
|
+ border: none;
|
|
|
|
|
+ }
|
|
|
|
|
+ .orange-btn{
|
|
|
|
|
+ background: #FF953D;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|