Parcourir la source

feat:修改我的方案页面逻辑和样式

wangsisi il y a 2 semaines
Parent
commit
cc96f0ae39

+ 49 - 205
src/views/planting/components/MySchemePanel.vue

@@ -11,90 +11,27 @@
       </div>
     </div>
 
+    <div class="scheme-type-list">
+      <div
+        v-for="item in schemeTypeOptions"
+        :key="item.value"
+        class="scheme-type-tag"
+        :class="{ 'is-active': schemeType === item.value }"
+        @click="schemeType = item.value"
+      >
+        {{ item.label }}
+      </div>
+    </div>
+
     <!-- 表格 -->
     <div class="table-wrap">
-      <el-table :data="tableData" border class="scheme-table" :header-cell-style="headerCellStyle"
-        :cell-style="{ verticalAlign: 'top' }">
-        <el-table-column prop="name" label="农事名称" min-width="110" fixed />
-
-        <el-table-column label="农事类型" min-width="120">
-          <template #default="{ row }">
-            <div class="type-tags">
-              <span v-for="(item, idx) in row.types" :key="idx" class="type-tag">{{ item }}</span>
-            </div>
-          </template>
-        </el-table-column>
-
-        <el-table-column prop="trigger" label="触发条件" min-width="160" />
-
-        <el-table-column label="药肥处方" min-width="220">
-          <template #default="{ row }">
-            <div class="prescription">
-              <div class="prescription__title">{{ row.prescription.category }}</div>
-              <div class="prescription__desc">{{ row.prescription.desc }}</div>
-              <div class="prescription__freq">{{ row.prescription.freq }}</div>
-            </div>
-          </template>
-        </el-table-column>
-
-        <el-table-column label="执行窗口" align="center">
-          <el-table-column label="执行窗口" min-width="140" align="center">
-            <template #default="{ row }">
-              <div class="execute-window">{{ row.execute.window }}</div>
-            </template>
-          </el-table-column>
-          <el-table-column label="执行设备" min-width="140">
-            <template #default="{ row }">
-              <div class="device-groups">
-                <div class="device-group">
-                  <div class="device-group__label">主要设备:</div>
-                  <div class="device-group__tags">
-                    <span
-                      v-for="(item, idx) in row.execute.primaryDevices"
-                      :key="`primary-${idx}`"
-                      class="type-tag"
-                    >{{ item }}</span>
-                  </div>
-                </div>
-                <div class="device-group">
-                  <div class="device-group__label">备用设备:</div>
-                  <div class="device-group__tags">
-                    <span
-                      v-for="(item, idx) in row.execute.backupDevices"
-                      :key="`backup-${idx}`"
-                      class="type-tag"
-                    >{{ item }}</span>
-                  </div>
-                </div>
-              </div>
-            </template>
-          </el-table-column>
-          <el-table-column label="注意事项" min-width="160" prop="execute.notes" />
-        </el-table-column>
-
-        <el-table-column label="复核规程" align="center">
-          <el-table-column label="复核时间" min-width="120">
-            <template #default="{ row }">
-              <span class="review-time">
-                执行后 <em class="review-time__num">{{ row.review.days }}</em> 天
-              </span>
-            </template>
-          </el-table-column>
-          <el-table-column label="复核标准" prop="review.standard" min-width="160" />
-        </el-table-column>
-
-        <el-table-column label="操作" width="190" fixed="right">
-          <template #default="{ row }">
-            <div class="row-ops">
-              <el-button class="row-ops__btn" @click="onEditRow(row)">编辑</el-button>
-              <el-button class="row-ops__btn" @click="onDetailRow(row)">详情</el-button>
-              <el-button class="row-ops__btn row-ops__btn--danger" type="danger" @click="onDeleteRow(row)">
-                删除
-              </el-button>
-            </div>
-          </template>
-        </el-table-column>
-      </el-table>
+      <SchemeTable
+        :data="tableData"
+        show-ops
+        @edit="onEditRow"
+        @detail="onDetailRow"
+        @delete="onDeleteRow"
+      />
     </div>
 
     <!-- 底部操作 -->
@@ -118,15 +55,10 @@ import { Edit } from "@element-plus/icons-vue";
 import { ElMessage, ElMessageBox } from "element-plus";
 import FarmWorkEditDialog from "./FarmWorkEditDialog.vue";
 import FarmWorkDetailDialog from "./FarmWorkDetailDialog.vue";
+import SchemeTable from "./SchemeTable.vue";
 
 const emit = defineEmits(["edit-scheme"]);
 
-const headerCellStyle = {
-  background: "#F5F5F5",
-  color: "#535353",
-  fontWeight: 400,
-};
-
 const schemeList = ref([
   { id: 1, name: "方案一" },
   { id: 2, name: "方案二" },
@@ -134,6 +66,12 @@ const schemeList = ref([
   { id: 4, name: "方案二" },
 ]);
 const activeSchemeId = ref(1);
+const schemeTypeOptions = [
+  { label: "标准化方案", value: "standard" },
+  { label: "气象类方案", value: "weather" },
+  { label: "异常类方案", value: "anomaly" },
+];
+const schemeType = ref("standard");
 const editVisible = ref(false);
 const detailVisible = ref(false);
 const currentRow = ref(null);
@@ -223,7 +161,7 @@ $text: rgba(0, 0, 0, 0.6);
     display: flex;
     flex-wrap: wrap;
     gap: 8px;
-    padding: 20px 0;
+    padding: 20px 0 0;
 
     .scheme-tab {
       display: flex;
@@ -254,129 +192,35 @@ $text: rgba(0, 0, 0, 0.6);
     }
   }
 
-  .table-wrap {
-    flex: 1;
-    min-height: 0;
-    overflow: auto;
-
-    .scheme-table {
-      color: #000;
-
-      .type-tags {
-        display: flex;
-        flex-direction: column;
-        align-items: flex-start;
-        gap: 4px;
-      }
-
-      .type-tag {
-        padding: 1px 6px;
-        border-radius: 4px;
-        font-size: 12px;
-        color: #2199f8;
-        background: rgba(33, 153, 248, 0.1);
-      }
-
-      .prescription {
-        &__title {
-          display: inline-block;
-          width: fit-content;
-          color: #4c4c4c;
-          margin-bottom: 2px;
-          background: rgba(125, 125, 125, 0.1);
-          padding: 0 6px;
-          border-radius: 2px;
-        }
-
-        &__desc {
-          font-size: 13px;
-          line-height: 1.6;
-        }
-
-        &__freq {
-          font-size: 12px;
-          color: #86909c;
-          line-height: 1.5;
-        }
-      }
-
-      .device-groups {
-        display: flex;
-        flex-direction: column;
-        gap: 8px;
-      }
-
-      .device-group {
-        display: flex;
-        flex-direction: column;
-        align-items: flex-start;
-        gap: 4px;
-
-        &__label {
-          font-size: 13px;
-          line-height: 1.4;
-          color: #86909c;
-        }
-
-        &__tags {
-          display: flex;
-          flex-direction: column;
-          align-items: flex-start;
-          gap: 4px;
-        }
-      }
-
-      .execute-window {
-        color: rgba(0, 0, 0, 0.4);
-      }
+  .scheme-type-list {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 8px;
+    padding: 10px 0 20px;
 
-      .review-time {
-        color: #000;
-        font-style: normal;
+    .scheme-type-tag {
+      padding: 6px 10px;
+      border-radius: 3px;
+      background: #f3f3f3;
+      color: $text;
+      cursor: pointer;
 
-        &__num {
-          color: $primary;
-          font-style: normal;
-          font-weight: 500;
-        }
+      &:hover {
+        color: $primary;
       }
 
-      .row-ops {
-        display: flex;
-        flex-wrap: wrap;
-        gap: 8px;
-
-        &__btn {
-          margin: 0;
-          height: 28px;
-          padding: 0 10px;
-          font-size: 13px;
-          color: #4c4c4c;
-          background: #fff;
-          border: 1px solid #d2d2d2;
-          border-radius: 2px;
-
-          &:hover {
-            color: $primary;
-            border-color: rgba($primary, 0.45);
-            background: rgba($primary, 0.06);
-          }
-
-          &--danger {
-            color: #fff;
-            background: #f56b6b;
-            border-color: #f56b6b;
-
-            &:hover {
-              color: #fff;
-              background: #f78989;
-              border-color: #f78989;
-            }
-          }
-        }
+      &.is-active {
+        background: $primary;
+        color: #fff;
       }
     }
   }
+
+  .table-wrap {
+    flex: 1;
+    min-height: 0;
+    overflow: auto;
+  }
 }
 
 .page-footer {

+ 192 - 0
src/views/planting/components/SchemeTable.vue

@@ -0,0 +1,192 @@
+<template>
+  <el-table
+    :data="data"
+    border
+    class="scheme-table"
+    :header-cell-style="headerCellStyle"
+    :cell-style="{ verticalAlign: 'top' }"
+  >
+    <el-table-column prop="code" label="农事编码" min-width="100" fixed header-align="center">
+      <template #default="{ row }">{{ row.code || "编码" }}</template>
+    </el-table-column>
+    <el-table-column prop="name" label="农事名称" min-width="110" header-align="center" />
+    <el-table-column prop="trigger" label="触发条件" min-width="180" header-align="center" />
+    <el-table-column label="农事研判" min-width="140" header-align="center">
+      <template #default="{ row }">
+        <div class="plain-text">{{ formatJudgment(row) }}</div>
+      </template>
+    </el-table-column>
+    <el-table-column label="农事处方" min-width="200" header-align="center">
+      <template #default="{ row }">
+        <div class="plain-text">{{ formatPrescription(row) }}</div>
+      </template>
+    </el-table-column>
+    <el-table-column label="执行参数" min-width="160" header-align="center">
+      <template #default="{ row }">
+        <div class="plain-text">{{ formatExecuteParams(row) }}</div>
+      </template>
+    </el-table-column>
+    <el-table-column label="注意事项" min-width="160" header-align="center">
+      <template #default="{ row }">{{ row.execute?.notes || row.notes || "注意事项" }}</template>
+    </el-table-column>
+    <el-table-column label="执行反馈要求" min-width="130" prop="feedback" header-align="center">
+      <template #default="{ row }">{{ row.feedback || "内容" }}</template>
+    </el-table-column>
+
+    <el-table-column label="土壤应对情况" align="center" header-align="center">
+      <el-table-column label="土壤偏酸" min-width="90" align="center" header-align="center">
+        <template #default="{ row }">{{ cellContent(row, "soil", "acid") }}</template>
+      </el-table-column>
+      <el-table-column label="土壤偏碱" min-width="90" align="center" header-align="center">
+        <template #default="{ row }">{{ cellContent(row, "soil", "alkaline") }}</template>
+      </el-table-column>
+      <el-table-column label="沙土/偏沙" min-width="100" align="center" header-align="center">
+        <template #default="{ row }">{{ cellContent(row, "soil", "sand") }}</template>
+      </el-table-column>
+      <el-table-column label="壤土" min-width="80" align="center" header-align="center">
+        <template #default="{ row }">{{ cellContent(row, "soil", "loam") }}</template>
+      </el-table-column>
+      <el-table-column label="壤偏黏/黏土" min-width="110" align="center" header-align="center">
+        <template #default="{ row }">{{ cellContent(row, "soil", "clay") }}</template>
+      </el-table-column>
+    </el-table-column>
+
+    <el-table-column label="长势应对情况" align="center" header-align="center">
+      <el-table-column label="长势偏旺" min-width="90" align="center" header-align="center">
+        <template #default="{ row }">{{ cellContent(row, "growth", "strong") }}</template>
+      </el-table-column>
+      <el-table-column label="长势偏弱" min-width="90" align="center" header-align="center">
+        <template #default="{ row }">{{ cellContent(row, "growth", "weak") }}</template>
+      </el-table-column>
+    </el-table-column>
+
+    <el-table-column label="气象应对情况" align="center" header-align="center">
+      <el-table-column label="高温" min-width="80" align="center" header-align="center">
+        <template #default="{ row }">{{ cellContent(row, "weather", "hot") }}</template>
+      </el-table-column>
+      <el-table-column label="降雨" min-width="80" align="center" header-align="center">
+        <template #default="{ row }">{{ cellContent(row, "weather", "rain") }}</template>
+      </el-table-column>
+      <el-table-column label="低温" min-width="80" align="center" header-align="center">
+        <template #default="{ row }">{{ cellContent(row, "weather", "cold") }}</template>
+      </el-table-column>
+      <el-table-column label="大风" min-width="80" align="center" header-align="center">
+        <template #default="{ row }">{{ cellContent(row, "weather", "wind") }}</template>
+      </el-table-column>
+    </el-table-column>
+
+    <el-table-column v-if="showOps" label="操作" width="190" fixed="right" align="center" header-align="center">
+      <template #default="{ row }">
+        <div class="row-ops">
+          <el-button class="row-ops__btn" @click="$emit('edit', row)">编辑</el-button>
+          <el-button class="row-ops__btn" @click="$emit('detail', row)">详情</el-button>
+          <el-button class="row-ops__btn row-ops__btn--danger" type="danger" @click="$emit('delete', row)">
+            删除
+          </el-button>
+        </div>
+      </template>
+    </el-table-column>
+  </el-table>
+</template>
+
+<script setup>
+defineProps({
+  data: {
+    type: Array,
+    default: () => [],
+  },
+  showOps: {
+    type: Boolean,
+    default: false,
+  },
+});
+
+defineEmits(["edit", "detail", "delete"]);
+
+const headerCellStyle = {
+  background: "#F5F5F5",
+  color: "#535353",
+  fontWeight: 400,
+};
+
+const formatJudgment = (row) => {
+  if (row.types?.length) return row.types.join("\n");
+  return row.judgment || "具体处方";
+};
+
+const formatPrescription = (row) => {
+  const item = row.prescription;
+  if (!item) return "处方";
+  const lines = [];
+  if (item.category) lines.push(item.category);
+  if (item.lines?.length) lines.push(...item.lines);
+  if (item.desc) lines.push(item.desc);
+  if (item.freq) lines.push(item.freq);
+  return lines.join("\n") || "处方";
+};
+
+const formatExecuteParams = (row) => {
+  const execute = row.execute;
+  if (!execute) return "参数";
+  const lines = [];
+  if (execute.window) lines.push(execute.window);
+  if (execute.devices?.length) lines.push(...execute.devices);
+  if (execute.primaryDevices?.length) {
+    lines.push(`主要设备: ${execute.primaryDevices.join("、")}`);
+  }
+  if (execute.backupDevices?.length) {
+    lines.push(`备用设备: ${execute.backupDevices.join("、")}`);
+  }
+  return lines.join("\n") || "参数";
+};
+
+const cellContent = (row, group, key) => row?.[group]?.[key] || "内容";
+</script>
+
+<style lang="scss" scoped>
+$primary: $warning-color;
+
+.scheme-table {
+  color: #000;
+
+  .plain-text {
+    white-space: pre-line;
+    line-height: 1.6;
+  }
+
+  .row-ops {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 8px;
+
+    &__btn {
+      margin: 0;
+      height: 28px;
+      padding: 0 10px;
+      font-size: 13px;
+      color: #4c4c4c;
+      background: #fff;
+      border: 1px solid #d2d2d2;
+      border-radius: 2px;
+
+      &:hover {
+        color: $primary;
+        border-color: rgba($primary, 0.45);
+        background: rgba($primary, 0.06);
+      }
+
+      &--danger {
+        color: #fff;
+        background: #f56b6b;
+        border-color: #f56b6b;
+
+        &:hover {
+          color: #fff;
+          background: #f78989;
+          border-color: #f78989;
+        }
+      }
+    }
+  }
+}
+</style>

+ 46 - 108
src/views/planting/index.vue

@@ -70,65 +70,24 @@
               </div>
             </div>
           </div>
+
+          <div class="filter-row">
+            <div class="filter-content scheme-type-list">
+              <div
+                v-for="item in schemeTypeOptions"
+                :key="item.value"
+                class="scheme-type-tag"
+                :class="{ 'is-active': filters.schemeType === item.value }"
+                @click="filters.schemeType = item.value"
+              >
+                {{ item.label }}
+              </div>
+            </div>
+          </div>
         </div>
 
         <div class="table-wrap">
-          <el-table
-            :data="tableData"
-            border
-            class="scheme-table"
-            :header-cell-style="headerCellStyle"
-            :cell-style="{ verticalAlign: 'top' }"
-          >
-            <el-table-column prop="name" label="农事名称" min-width="110" fixed />
-            <el-table-column label="农事类型" min-width="120">
-              <template #default="{ row }">
-                <div class="type-tags">
-                  <span v-for="(item, idx) in row.types" :key="idx" class="type-tag">{{ item }}</span>
-                </div>
-              </template>
-            </el-table-column>
-            <el-table-column prop="trigger" label="触发条件" min-width="160" />
-            <el-table-column label="药肥处方" min-width="260">
-              <template #default="{ row }">
-                <div class="prescription">
-                  <div class="prescription__title">{{ row.prescription.category }}</div>
-                  <div
-                    v-for="(line, idx) in row.prescription.lines"
-                    :key="idx"
-                    class="prescription__line"
-                  >
-                    {{ line }}
-                  </div>
-                </div>
-              </template>
-            </el-table-column>
-            <el-table-column label="执行规程" align="center">
-              <el-table-column label="执行窗口" min-width="140" prop="execute.window" />
-              <el-table-column label="执行设备" min-width="120">
-                <template #default="{ row }">
-                  <div class="type-tags">
-                    <span
-                      v-for="(item, idx) in row.execute.devices"
-                      :key="idx"
-                      class="type-tag"
-                    >{{ item }}</span>
-                  </div>
-                </template>
-              </el-table-column>
-              <el-table-column label="注意事项" min-width="160" prop="execute.notes" />
-            </el-table-column>
-            <el-table-column label="复核规程" align="center">
-              <el-table-column label="复核时间" min-width="120">
-                <template #default="{ row }">
-                  <span class="review-time">
-                    执行后 <em class="review-time__num">{{ row.review.days }}</em> 天
-                  </span>
-                </template>
-              </el-table-column>
-              <el-table-column label="复核标准" prop="review.standard" min-width="160" />
-            </el-table-column>
-          </el-table>
+          <SchemeTable :data="tableData" />
         </div>
 
         <div class="page-footer">
@@ -151,6 +110,7 @@ import { reactive, ref } from "vue";
 import { ElMessage } from "element-plus";
 import EditSchemeDialog from "./components/EditSchemeDialog.vue";
 import MySchemePanel from "./components/MySchemePanel.vue";
+import SchemeTable from "./components/SchemeTable.vue";
 
 const tabs = [
   { label: "种植方案", value: "scheme" },
@@ -164,6 +124,7 @@ const filters = reactive({
   city: "",
   categoryIndex: 0,
   varietyIndex: 0,
+  schemeType: "standard",
 });
 
 const provinceOptions = [
@@ -180,6 +141,11 @@ const cityOptions = [
 
 const categoryOptions = ["荔枝", "水稻", "水稻", "水稻", "水稻", "水稻", "水稻"];
 const varietyOptions = ["妃子笑", "桂味", "桂味", "桂味", "桂味", "桂味", "桂味", "桂味", "桂味", "桂味"];
+const schemeTypeOptions = [
+  { label: "标准化方案", value: "standard" },
+  { label: "气象类方案", value: "weather" },
+  { label: "异常类方案", value: "anomaly" },
+];
 
 const placeholderText =
   "触发条件触发条件触发条件触发条件触发条件触发条件触发条件触发条件触发条件触发条件";
@@ -253,12 +219,6 @@ const tableData = ref([
   },
 ]);
 
-const headerCellStyle = {
-  background: "#F5F5F5",
-  color: "#535353",
-  fontWeight: 400,
-};
-
 const onCopyScheme = () => {
   editDialogVisible.value = true;
 };
@@ -382,6 +342,30 @@ $border: #e7e7e7;
               }
             }
           }
+
+          &.scheme-type-list {
+            display: flex;
+            flex-wrap: wrap;
+            gap: 8px;
+
+            .scheme-type-tag {
+              padding: 6px 10px;
+              border-radius: 3px;
+              background: #f3f3f3;
+              color: rgba(0, 0, 0, 0.6);
+              margin-top: 10px;
+              cursor: pointer;
+
+              &:hover {
+                color: $primary;
+              }
+
+              &.is-active {
+                background: $primary;
+                color: #fff;
+              }
+            }
+          }
         }
       }
     }
@@ -390,52 +374,6 @@ $border: #e7e7e7;
       flex: 1;
       min-height: 0;
       overflow: auto;
-
-      .scheme-table {
-        color: #000;
-
-        .type-tags {
-          display: flex;
-          flex-direction: column;
-          align-items: flex-start;
-          gap: 4px;
-
-          .type-tag {
-            padding: 1px 6px;
-            border-radius: 4px;
-            font-size: 12px;
-            color: #2199f8;
-            background: rgba(33, 153, 248, 0.1);
-          }
-        }
-
-        .prescription {
-          &__title {
-            display: inline-block;
-            width: fit-content;
-            color: #4c4c4c;
-            margin-bottom: 2px;
-            background: rgba(125, 125, 125, 0.1);
-            padding: 0 6px;
-            border-radius: 2px;
-          }
-
-          &__line {
-            font-size: 13px;
-          }
-        }
-
-        .review-time {
-          color: #000;
-          font-style: normal;
-
-          &__num {
-            color: $primary;
-            font-style: normal;
-            font-weight: 500;
-          }
-        }
-      }
     }
 
     .page-footer {