Просмотр исходного кода

feat:添加种植方案页面

wangsisi 1 неделя назад
Родитель
Сommit
90ca8f6f65
3 измененных файлов с 519 добавлено и 13 удалено
  1. 10 0
      src/styles/common.scss
  2. 1 0
      src/styles/variables.scss.js
  3. 508 13
      src/views/planting/index.vue

+ 10 - 0
src/styles/common.scss

@@ -1,3 +1,13 @@
+:root {
+  --el-color-warning: #{$warning-color};
+  --el-color-warning-light-3: #{mix(#fff, $warning-color, 30%)};
+  --el-color-warning-light-5: #{mix(#fff, $warning-color, 50%)};
+  --el-color-warning-light-7: #{mix(#fff, $warning-color, 70%)};
+  --el-color-warning-light-8: #{mix(#fff, $warning-color, 80%)};
+  --el-color-warning-light-9: #{mix(#fff, $warning-color, 90%)};
+  --el-color-warning-dark-2: #{mix(#000, $warning-color, 20%)};
+}
+
 html,
 html,
 body,
 body,
 #app {
 #app {

+ 1 - 0
src/styles/variables.scss.js

@@ -1,6 +1,7 @@
 const variables = {
 const variables = {
   main_bg_color: "#f5f5f5",
   main_bg_color: "#f5f5f5",
   base_color: "#d4af37",
   base_color: "#d4af37",
+  warning_color: "#FB8E33",
   nav_height: "64px",
   nav_height: "64px",
   side_close_width: "64px",
   side_close_width: "64px",
   side_open_width: "220px",
   side_open_width: "220px",

+ 508 - 13
src/views/planting/index.vue

@@ -1,29 +1,524 @@
 <template>
 <template>
-  <div class="page-placeholder">
-    <h2>种植方案</h2>
-    <p>页面内容区域,后续在此完善业务。</p>
+  <div class="planting-page">
+    <div class="page-card">
+      <!-- 顶部:Tab + 操作 -->
+      <div class="page-header">
+        <div class="page-tabs">
+          <div
+            v-for="tab in tabs"
+            :key="tab.value"
+            class="page-tabs__item"
+            :class="{ 'is-active': activeTab === tab.value }"
+            @click="activeTab = tab.value"
+          >
+            {{ tab.label }}
+          </div>
+        </div>
+        <el-button type="warning" class="btn-add" @click="onAddDevice">
+          新增设备
+        </el-button>
+      </div>
+
+      <!-- 筛选区 -->
+      <div class="filter-panel">
+        <div class="filter-row">
+          <span class="filter-label">区域:</span>
+          <div class="filter-content region-selects">
+            <el-select
+              v-model="filters.province"
+              placeholder="选择省份"
+              clearable
+              class="region-select"
+            >
+              <el-option
+                v-for="item in provinceOptions"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              />
+            </el-select>
+            <el-select
+              v-model="filters.city"
+              placeholder="选择城市"
+              clearable
+              class="region-select"
+            >
+              <el-option
+                v-for="item in cityOptions"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              />
+            </el-select>
+          </div>
+        </div>
+
+        <div class="filter-row">
+          <span class="filter-label">品类:</span>
+          <div class="filter-content tag-list">
+            <button
+              v-for="(item, idx) in categoryOptions"
+              :key="`category-${idx}`"
+              type="button"
+              class="filter-tag"
+              :class="{ 'is-active': filters.categoryIndex === idx }"
+              @click="filters.categoryIndex = idx"
+            >
+              {{ item }}
+            </button>
+          </div>
+        </div>
+
+        <div class="filter-row">
+          <span class="filter-label">品种:</span>
+          <div class="filter-content tag-list">
+            <button
+              v-for="(item, idx) in varietyOptions"
+              :key="`variety-${idx}`"
+              type="button"
+              class="filter-tag"
+              :class="{ 'is-active': filters.varietyIndex === idx }"
+              @click="filters.varietyIndex = idx"
+            >
+              {{ item }}
+            </button>
+          </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>
+            <template #default="{ row }">
+              <span class="cell-name">{{ row.name }}</span>
+            </template>
+          </el-table-column>
+
+          <el-table-column label="农事类型" min-width="200">
+            <template #default="{ row }">
+              <div class="link-group">
+                <a
+                  v-for="(item, idx) in row.types"
+                  :key="idx"
+                  class="cell-link"
+                  href="javascript:;"
+                >{{ item }}</a>
+              </div>
+            </template>
+          </el-table-column>
+
+          <el-table-column prop="trigger" label="触发条件" min-width="160">
+            <template #default="{ row }">
+              <p class="cell-text">{{ row.trigger }}</p>
+            </template>
+          </el-table-column>
+
+          <el-table-column label="药肥处方" min-width="280">
+            <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">
+              <template #default="{ row }">
+                <p class="cell-text">{{ row.execute.window }}</p>
+              </template>
+            </el-table-column>
+            <el-table-column label="执行设备" min-width="120">
+              <template #default="{ row }">
+                <div class="link-group link-group--col">
+                  <a
+                    v-for="(item, idx) in row.execute.devices"
+                    :key="idx"
+                    class="cell-link"
+                    href="javascript:;"
+                  >{{ item }}</a>
+                </div>
+              </template>
+            </el-table-column>
+            <el-table-column label="注意事项" min-width="160">
+              <template #default="{ row }">
+                <p class="cell-text">{{ row.execute.notes }}</p>
+              </template>
+            </el-table-column>
+          </el-table-column>
+
+          <el-table-column label="复核规程" align="center">
+            <el-table-column label="复核时间" min-width="110">
+              <template #default="{ row }">
+                <p class="cell-text">{{ row.review.time }}</p>
+              </template>
+            </el-table-column>
+            <el-table-column label="复核标准" min-width="160">
+              <template #default="{ row }">
+                <p class="cell-text">{{ row.review.standard }}</p>
+              </template>
+            </el-table-column>
+          </el-table-column>
+        </el-table>
+      </div>
+
+      <!-- 底部操作 -->
+      <div class="page-footer">
+        <el-button type="warning" plain class="btn-copy" @click="onCopyScheme">
+          复制为我的方案
+        </el-button>
+      </div>
+    </div>
   </div>
   </div>
 </template>
 </template>
 
 
 <script setup>
 <script setup>
+import { reactive, ref } from "vue";
+import { ElMessage } from "element-plus";
+
+const tabs = [
+  { label: "种植方案", value: "scheme" },
+  { label: "我的方案", value: "mine" },
+];
+const activeTab = ref("scheme");
+
+const filters = reactive({
+  province: "",
+  city: "",
+  categoryIndex: 0,
+  varietyIndex: 0,
+});
+
+const provinceOptions = [
+  { label: "广东省", value: "guangdong" },
+  { label: "广西壮族自治区", value: "guangxi" },
+  { label: "海南省", value: "hainan" },
+];
+
+const cityOptions = [
+  { label: "广州市", value: "guangzhou" },
+  { label: "深圳市", value: "shenzhen" },
+  { label: "茂名市", value: "maoming" },
+];
+
+const categoryOptions = ["荔枝", "水稻", "水稻", "水稻", "水稻", "水稻", "水稻"];
+const varietyOptions = ["妃子笑", "桂味", "桂味", "桂味", "桂味", "桂味", "桂味", "桂味", "桂味", "桂味"];
+
+const placeholderText =
+  "触发条件触发条件触发条件触发条件触发条件触发条件触发条件触发条件触发条件触发条件";
+
+const tableData = ref([
+  {
+    name: "播前基肥",
+    types: ["标准农事", "日常营养", "水肥类"],
+    trigger: placeholderText,
+    prescription: {
+      category: "营养类",
+      lines: [
+        "砂土: 产品名称/用量/亩 使用次数",
+        "粘土: 产品名称/用量/亩 使用次数",
+        "壤土: 产品名称/用量/亩 使用次数",
+      ],
+    },
+    execute: {
+      window: "生育期起始-生育期结束",
+      devices: ["农机设备一", "农机设备二", "农机设备三"],
+      notes: placeholderText,
+    },
+    review: {
+      time: "执行后 7 天",
+      standard: placeholderText,
+    },
+  },
+  {
+    name: "播前基肥",
+    types: ["标准农事", "日常营养", "水肥类"],
+    trigger: placeholderText,
+    prescription: {
+      category: "营养类",
+      lines: [
+        "砂土: 产品名称/用量/亩 使用次数",
+        "粘土: 产品名称/用量/亩 使用次数",
+        "壤土: 产品名称/用量/亩 使用次数",
+      ],
+    },
+    execute: {
+      window: "生育期起始-生育期结束",
+      devices: ["农机设备一", "农机设备二", "农机设备三"],
+      notes: placeholderText,
+    },
+    review: {
+      time: "执行后 7 天",
+      standard: placeholderText,
+    },
+  },
+  {
+    name: "播前基肥",
+    types: ["标准农事", "日常营养", "水肥类"],
+    trigger: placeholderText,
+    prescription: {
+      category: "营养类",
+      lines: [
+        "砂土: 产品名称/用量/亩 使用次数",
+        "粘土: 产品名称/用量/亩 使用次数",
+        "壤土: 产品名称/用量/亩 使用次数",
+      ],
+    },
+    execute: {
+      window: "生育期起始-生育期结束",
+      devices: ["农机设备一", "农机设备二", "农机设备三"],
+      notes: placeholderText,
+    },
+    review: {
+      time: "执行后 7 天",
+      standard: placeholderText,
+    },
+  },
+]);
+
+const headerCellStyle = {
+  background: "#f5f7fa",
+  color: "#606266",
+  fontWeight: 500,
+  textAlign: "center",
+};
+
+const onAddDevice = () => {
+  ElMessage.info("新增设备功能待接入");
+};
+
+const onCopyScheme = () => {
+  ElMessage.success("已复制为我的方案");
+};
 </script>
 </script>
 
 
 <style lang="scss" scoped>
 <style lang="scss" scoped>
-.page-placeholder {
+$primary: $warning-color;
+$primary-light: mix(#fff, $warning-color, 90%);
+$link: #409eff;
+$text: #303133;
+$text-secondary: #606266;
+$border: #E7E7E7;
+
+.planting-page {
   box-sizing: border-box;
   box-sizing: border-box;
   min-height: 100%;
   min-height: 100%;
-  padding: 24px;
-  background: #fff;
+  padding: 25px;
+  .page-card {
+    background: #fff;
+    padding: 10px;
+    .page-header {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      border-bottom: 1px solid $border;
+    }
+  }
+}
+
+.page-tabs {
+  display: flex;
+  gap: 32px;
+
+  &__item {
+    position: relative;
+    padding: 16px 0 14px;
+    font-size: 15px;
+    color: $text-secondary;
+    cursor: pointer;
+    transition: color 0.2s;
+    user-select: none;
 
 
-  h2 {
-    margin: 0 0 8px;
-    font-size: 20px;
-    color: #303133;
+    &:hover {
+      color: $primary;
+    }
+
+    &.is-active {
+      color: $primary;
+      font-weight: 500;
+
+      &::after {
+        content: "";
+        position: absolute;
+        left: 0;
+        right: 0;
+        bottom: 0;
+        height: 3px;
+        background: $primary;
+        border-radius: 2px 2px 0 0;
+      }
+    }
   }
   }
+}
+
+.btn-add {
+  height: 32px;
+  padding: 0 16px;
+  font-size: 13px;
+}
+
+.filter-panel {
+  padding: 20px 0 8px;
+  display: flex;
+  flex-direction: column;
+  gap: 16px;
+}
+
+.filter-row {
+  display: flex;
+  align-items: flex-start;
+  gap: 12px;
+}
+
+.filter-label {
+  flex-shrink: 0;
+  width: 42px;
+  line-height: 32px;
+  font-size: 14px;
+  color: $text;
+  text-align: right;
+}
+
+.filter-content {
+  flex: 1;
+  min-width: 0;
+}
+
+.region-selects {
+  display: flex;
+  gap: 12px;
+}
 
 
-  p {
-    margin: 0;
-    color: #909399;
+.region-select {
+  width: 160px;
+}
+
+.tag-list {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+}
+
+.filter-tag {
+  appearance: none;
+  border: 1px solid #dcdfe6;
+  background: #f5f7fa;
+  color: $text-secondary;
+  height: 32px;
+  padding: 0 16px;
+  border-radius: 4px;
+  font-size: 13px;
+  line-height: 30px;
+  cursor: pointer;
+  transition: all 0.2s;
+
+  &:hover {
+    border-color: $primary;
+    color: $primary;
+  }
+
+  &.is-active {
+    background: $primary-light;
+    border-color: $primary;
+    color: $primary;
+  }
+}
+
+.table-wrap {
+  flex: 1;
+  min-height: 0;
+  overflow: auto;
+}
+
+.scheme-table {
+  width: 100%;
+
+  :deep(.el-table__header th) {
+    font-size: 13px;
+  }
+
+  :deep(.el-table__body td) {
+    padding: 14px 0;
   }
   }
+
+  :deep(.el-table__cell) {
+    vertical-align: top;
+  }
+}
+
+.cell-name {
+  font-weight: 600;
+  color: $text;
+  font-size: 14px;
+}
+
+.cell-text {
+  margin: 0;
+  font-size: 13px;
+  line-height: 1.6;
+  color: $text-secondary;
+  word-break: break-all;
+}
+
+.link-group {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px 12px;
+
+  &--col {
+    flex-direction: column;
+    gap: 6px;
+  }
+}
+
+.cell-link {
+  color: $link;
+  font-size: 13px;
+  text-decoration: none;
+  line-height: 1.5;
+
+  &:hover {
+    text-decoration: underline;
+  }
+}
+
+.prescription {
+  font-size: 13px;
+  line-height: 1.7;
+  color: $text-secondary;
+
+  &__title {
+    color: $text;
+    margin-bottom: 2px;
+  }
+
+  &__line {
+    word-break: break-all;
+  }
+}
+
+.page-footer {
+  display: flex;
+  justify-content: flex-end;
+  padding-top: 20px;
+}
+
+.btn-copy {
+  height: 36px;
+  padding: 0 20px;
+  font-size: 14px;
 }
 }
 </style>
 </style>