|
|
@@ -1,145 +1,253 @@
|
|
|
<template>
|
|
|
<div class="device-page">
|
|
|
- <div class="device-panel">
|
|
|
-
|
|
|
- <!-- 筛选 -->
|
|
|
- <div class="filter-bar">
|
|
|
- <div class="filter-l">
|
|
|
- <span class="filter-bar__label">搜索姓名</span>
|
|
|
- <el-select
|
|
|
- v-model="deviceName"
|
|
|
- class="filter-bar__select"
|
|
|
- clearable
|
|
|
- filterable
|
|
|
- placeholder="请选择姓名"
|
|
|
- >
|
|
|
- <el-option
|
|
|
- v-for="item in deviceNameOptions"
|
|
|
- :key="item"
|
|
|
- :label="item"
|
|
|
- :value="item"
|
|
|
- />
|
|
|
- </el-select>
|
|
|
- </div>
|
|
|
- <div class="filter-r">
|
|
|
- <el-button class="btn-reset" @click="handleReset">重置</el-button>
|
|
|
- <el-button class="btn-search" type="warning" @click="handleSearch">搜索</el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="device-content">
|
|
|
- <div class="toolbar">
|
|
|
- <div class="tabs">
|
|
|
- <div v-for="tab in tabs" :key="tab.key" class="tabs__item" :class="{ 'is-active': activeTab === tab.key }"
|
|
|
- @click="handleTabChange(tab.key)">
|
|
|
- {{ tab.label }}({{ tab.count }})
|
|
|
+ <div class="device-layout">
|
|
|
+ <!-- 左侧 -->
|
|
|
+ <div class="device-main">
|
|
|
+ <!-- 上:统计卡片 -->
|
|
|
+ <div class="stat-row">
|
|
|
+ <div v-for="item in statCards" :key="item.key" class="stat-card">
|
|
|
+ <div class="stat-card__body">
|
|
|
+ <div class="stat-card__title">{{ item.title }}</div>
|
|
|
+ <div class="stat-card__value">{{ item.value }}</div>
|
|
|
+ <div class="stat-card__extra">
|
|
|
+ {{ item.extra }}
|
|
|
+ <span class="extra-value">{{ item.extraValue }}</span>
|
|
|
+ <span class="extra-unit">人</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="stat-card__icon">
|
|
|
+ <img class="icon-img" src="@/assets/page/person.png" alt="">
|
|
|
</div>
|
|
|
</div>
|
|
|
- <el-button class="btn-add" type="warning" @click="handleAdd">新增设备</el-button>
|
|
|
</div>
|
|
|
|
|
|
- <el-table
|
|
|
- :data="tableData"
|
|
|
- :span-method="objectSpanMethod"
|
|
|
- class="device-table"
|
|
|
- row-key="rowKey"
|
|
|
- border
|
|
|
- header-cell-class-name="device-table__header"
|
|
|
- >
|
|
|
- <el-table-column label="姓名/手机号" min-width="120">
|
|
|
- <template #default="{ row }">
|
|
|
- <div class="person-cell">
|
|
|
- <div class="person-cell__name">{{ row.name }}</div>
|
|
|
- <div class="person-cell__phone">{{ row.phone }}</div>
|
|
|
+ <!-- 下:列表区(原筛选+表格) -->
|
|
|
+ <div class="device-content">
|
|
|
+ <div class="toolbar">
|
|
|
+ <div class="tabs">
|
|
|
+ <div v-for="tab in tabs" :key="tab.key" class="tabs__item" :class="{ 'is-active': activeTab === tab.key }"
|
|
|
+ @click="handleTabChange(tab.key)">
|
|
|
+ {{ tab.label }}({{ tab.count }})
|
|
|
</div>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
+ </div>
|
|
|
+ <div class="toolbar__search">
|
|
|
+ <el-input v-model="deviceName" class="search-input" clearable placeholder="请输入农户姓名/农服姓名"
|
|
|
+ @keyup.enter="handleSearch" />
|
|
|
+ <el-button class="btn-search" type="warning" @click="handleSearch">搜索</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="table-wrap">
|
|
|
+ <el-table
|
|
|
+ :data="tableData"
|
|
|
+ :span-method="objectSpanMethod"
|
|
|
+ class="device-table"
|
|
|
+ height="100%"
|
|
|
+ row-key="rowKey"
|
|
|
+ border
|
|
|
+ header-cell-class-name="device-table__header"
|
|
|
+ >
|
|
|
+ <el-table-column label="个人信息" min-width="120">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <div class="person-cell">
|
|
|
+ <div class="person-cell__name">{{ row.name }}</div>
|
|
|
+ <div class="person-cell__phone">{{ row.phone }}</div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ <el-table-column prop="cropCategory" label="种植品类" min-width="100" show-overflow-tooltip />
|
|
|
+
|
|
|
+ <el-table-column label="种植品种" min-width="110">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <span class="variety-tag">{{ row.variety }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ <el-table-column prop="phenology" label="物候期" min-width="110" />
|
|
|
+
|
|
|
+ <el-table-column prop="area" label="种植面积" min-width="100" />
|
|
|
+
|
|
|
+ <el-table-column label="起种点" min-width="170">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <div class="start-point-cell">
|
|
|
+ <span class="start-point-tag">{{ row.startPoint }}</span>
|
|
|
+ <span class="start-point-date">{{ row.startDate }}</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ <el-table-column label="种植点位" min-width="160">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <div class="location-cell">
|
|
|
+ <span class="location-cell__text" :title="row.plantLocation">{{ row.plantLocation }}</span>
|
|
|
+ <el-button link type="warning" class="link-btn" @click="handleViewPlantLocation(row)">
|
|
|
+ 查看点位
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ <el-table-column label="农机设备" min-width="120">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <div class="tag-list">
|
|
|
+ <span
|
|
|
+ v-for="(equip, idx) in row.equipments || []"
|
|
|
+ :key="idx"
|
|
|
+ class="equip-tag"
|
|
|
+ >
|
|
|
+ {{ equip }}
|
|
|
+ </span>
|
|
|
+ <span v-if="!(row.equipments && row.equipments.length)">-</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ <el-table-column label="外包农事" min-width="120">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <div class="tag-list">
|
|
|
+ <span
|
|
|
+ v-for="(farm, idx) in row.outsourceFarmWorks || []"
|
|
|
+ :key="idx"
|
|
|
+ class="farm-tag"
|
|
|
+ >
|
|
|
+ {{ farm }}
|
|
|
+ </span>
|
|
|
+ <span v-if="!(row.outsourceFarmWorks && row.outsourceFarmWorks.length)">-</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ <el-table-column label="常驻点位" min-width="160">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <div class="location-cell">
|
|
|
+ <span class="location-cell__text" :title="row.residentLocation">{{ row.residentLocation }}</span>
|
|
|
+ <el-button link type="warning" class="link-btn" @click="handleViewResidentLocation(row)">
|
|
|
+ 查看点位
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ <el-table-column label="邀请人" min-width="130">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <div v-if="row.inviterName" class="inviter-cell">
|
|
|
+ <el-avatar :size="28" class="inviter-cell__avatar">
|
|
|
+ {{ row.inviterName.slice(0, 1) }}
|
|
|
+ </el-avatar>
|
|
|
+ <span class="inviter-cell__name">{{ row.inviterName }}</span>
|
|
|
+ </div>
|
|
|
+ <span v-else>-</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ <el-table-column label="操作" width="168" fixed="right" align="center">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <div class="ops">
|
|
|
+ <el-button class="ops__btn" @click="handleEdit(row)">编辑</el-button>
|
|
|
+ <el-button class="ops__btn" @click="handleDetail(row)">详情</el-button>
|
|
|
+ <el-button class="ops__btn ops__btn--danger" type="danger" @click="handleDelete(row)">
|
|
|
+ 删除
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
|
|
|
- <el-table-column prop="cropCategory" label="种植品类" min-width="100" show-overflow-tooltip />
|
|
|
+ <div class="pager">
|
|
|
+ <span class="pager__total">共 {{ total }} 项数据</span>
|
|
|
+ <el-pagination v-model:current-page="page" v-model:page-size="pageSize" background
|
|
|
+ layout="sizes, prev, pager, next, jumper" :page-sizes="[10, 20, 50]" :total="total" :pager-count="7" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
|
|
|
- <el-table-column label="种植品种" min-width="110">
|
|
|
- <template #default="{ row }">
|
|
|
- <span class="variety-tag">{{ row.variety }}</span>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
+ <!-- 右侧:排行榜 -->
|
|
|
+ <aside class="rank-panel">
|
|
|
+ <div class="rank-panel__head">
|
|
|
+ <span class="rank-panel__title">排行榜</span>
|
|
|
+ <el-button link type="warning" class="rank-more" @click="handleRankMore">更多 ></el-button>
|
|
|
+ </div>
|
|
|
|
|
|
- <el-table-column prop="phenology" label="物候期" min-width="110" />
|
|
|
+ <div class="rank-tabs">
|
|
|
+ <div v-for="tab in rankTabs" :key="tab.key" class="rank-tabs__item"
|
|
|
+ :class="{ 'is-active': activeRankTab === tab.key }" @click="activeRankTab = tab.key">
|
|
|
+ {{ tab.label }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
|
|
|
- <el-table-column prop="area" label="种植面积" min-width="100" />
|
|
|
+ <div class="rank-list">
|
|
|
+ <div
|
|
|
+ v-for="item in currentRankList"
|
|
|
+ :key="item.rank"
|
|
|
+ class="rank-item"
|
|
|
+ :class="[`is-top-${Math.min(item.rank, 4)}`, { 'is-top': item.rank <= 3 }]"
|
|
|
+ >
|
|
|
+ <div class="rank-item__head">
|
|
|
+ <span class="rank-item__rank" :class="`rank-item__rank--${item.rank}`">
|
|
|
+ <img
|
|
|
+ v-if="item.rank <= 3"
|
|
|
+ class="rank-item__rank-img"
|
|
|
+ :src="rankIcons[item.rank]"
|
|
|
+ :alt="`第${item.rank}名`"
|
|
|
+ />
|
|
|
+ <template v-else>{{ item.rank }}</template>
|
|
|
+ </span>
|
|
|
+ <el-avatar :size="40" class="rank-item__avatar">
|
|
|
+ {{ item.name.slice(0, 1) }}
|
|
|
+ </el-avatar>
|
|
|
+ <span class="rank-item__name">{{ item.name }}</span>
|
|
|
+ </div>
|
|
|
|
|
|
- <el-table-column label="起种点" min-width="170">
|
|
|
- <template #default="{ row }">
|
|
|
- <div class="start-point-cell">
|
|
|
- <span class="start-point-tag">{{ row.startPoint }}</span>
|
|
|
- <span class="start-point-date">{{ row.startDate }}</span>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
-
|
|
|
- <el-table-column label="种植点位" min-width="160">
|
|
|
- <template #default="{ row }">
|
|
|
- <div class="location-cell">
|
|
|
- <span class="location-cell__text" :title="row.plantLocation">{{ row.plantLocation }}</span>
|
|
|
- <el-button link type="warning" class="link-btn" @click="handleViewPlantLocation(row)">
|
|
|
- 查看点位
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
-
|
|
|
- <el-table-column label="常驻点位" min-width="160">
|
|
|
- <template #default="{ row }">
|
|
|
- <div class="location-cell">
|
|
|
- <span class="location-cell__text" :title="row.residentLocation">{{ row.residentLocation }}</span>
|
|
|
- <el-button link type="warning" class="link-btn" @click="handleViewResidentLocation(row)">
|
|
|
- 查看点位
|
|
|
- </el-button>
|
|
|
+ <div class="rank-item__stats">
|
|
|
+ <div class="rank-stat-card">
|
|
|
+ <div class="rank-stat">
|
|
|
+ <div class="rank-stat__value">{{ item.metricA }}</div>
|
|
|
+ <div class="rank-stat__label">{{ item.metricALabel }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="rank-stat">
|
|
|
+ <div class="rank-stat__value">{{ item.metricB }}</div>
|
|
|
+ <div class="rank-stat__label">{{ item.metricBLabel }}</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
-
|
|
|
- <el-table-column label="操作" width="168" fixed="right" align="center">
|
|
|
- <template #default="{ row }">
|
|
|
- <div class="ops">
|
|
|
- <el-button class="ops__btn" @click="handleEdit(row)">编辑</el-button>
|
|
|
- <el-button class="ops__btn" @click="handleDetail(row)">详情</el-button>
|
|
|
- <el-button class="ops__btn ops__btn--danger" type="danger" @click="handleDelete(row)">
|
|
|
- 删除
|
|
|
- </el-button>
|
|
|
+ <div class="rank-stat-card">
|
|
|
+ <div class="rank-stat">
|
|
|
+ <div class="rank-stat__value">{{ item.metricC }}</div>
|
|
|
+ <div class="rank-stat__label">{{ item.metricCLabel }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="rank-stat">
|
|
|
+ <div class="rank-stat__value">{{ item.metricD }}</div>
|
|
|
+ <div class="rank-stat__label">{{ item.metricDLabel }}</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- </el-table>
|
|
|
-
|
|
|
- <div class="pager">
|
|
|
- <span class="pager__total">共 {{ total }} 项数据</span>
|
|
|
- <el-pagination v-model:current-page="page" v-model:page-size="pageSize" background
|
|
|
- layout="sizes, prev, pager, next, jumper" :page-sizes="[10, 20, 50]" :total="total" :pager-count="7" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
-
|
|
|
+ </aside>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
- <DeviceFormDialog
|
|
|
- v-model="dialogVisible"
|
|
|
- :mode="dialogMode"
|
|
|
- :data="editingRow"
|
|
|
- @submit="handleDialogSubmit"
|
|
|
- />
|
|
|
-
|
|
|
- <DeviceDetailDialog
|
|
|
- v-model="detailVisible"
|
|
|
- :data="detailRow"
|
|
|
- @edit="handleDetailEdit"
|
|
|
- />
|
|
|
+ <DeviceFormDialog v-model="dialogVisible" :mode="dialogMode" :data="editingRow" @submit="handleDialogSubmit" />
|
|
|
+
|
|
|
+ <DeviceDetailDialog v-model="detailVisible" :data="detailRow" @edit="handleDetailEdit" />
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
import { computed, ref } from "vue";
|
|
|
import { ElMessage, ElMessageBox } from "element-plus";
|
|
|
+import { UserFilled } from "@element-plus/icons-vue";
|
|
|
import DeviceFormDialog from "./DeviceFormDialog.vue";
|
|
|
import DeviceDetailDialog from "./DeviceDetailDialog.vue";
|
|
|
+import rank1Icon from "@/assets/page/rank-1.png";
|
|
|
+import rank2Icon from "@/assets/page/rank-2.png";
|
|
|
+import rank3Icon from "@/assets/page/rank-3.png";
|
|
|
+
|
|
|
+const rankIcons = {
|
|
|
+ 1: rank1Icon,
|
|
|
+ 2: rank2Icon,
|
|
|
+ 3: rank3Icon,
|
|
|
+};
|
|
|
|
|
|
const NAMES = ["张洋", "李明", "王芳", "赵强", "陈丽"];
|
|
|
const VARIETIES = [
|
|
|
@@ -152,7 +260,6 @@ const VARIETIES = [
|
|
|
const buildMockRows = (count = 40) => {
|
|
|
const list = [];
|
|
|
for (let i = 1; i <= count; i++) {
|
|
|
- // 保证首条与设计图一致:一人 + 一品类 + 多品种
|
|
|
const varieties = i === 1 ? ["妃子笑", "桂味"] : VARIETIES[i % VARIETIES.length];
|
|
|
list.push({
|
|
|
id: i,
|
|
|
@@ -160,6 +267,9 @@ const buildMockRows = (count = 40) => {
|
|
|
phone: i === 1 ? "19871533168" : `1987153${String(3160 + (i % 40)).padStart(4, "0")}`,
|
|
|
cropCategory: "荔枝",
|
|
|
residentLocation: "位置位置位置位置",
|
|
|
+ equipments: ["农机设备"],
|
|
|
+ outsourceFarmWorks: ["农事类别一"],
|
|
|
+ inviterName: "张扬",
|
|
|
tabKey: i % 2 === 0 ? "service" : "owner",
|
|
|
plantings: varieties.map((variety) => ({
|
|
|
variety,
|
|
|
@@ -189,28 +299,65 @@ const tabs = computed(() => [
|
|
|
},
|
|
|
]);
|
|
|
|
|
|
+const ownerCount = computed(() => allList.value.filter((i) => i.tabKey === "owner").length);
|
|
|
+const serviceCount = computed(() => allList.value.filter((i) => i.tabKey === "service").length);
|
|
|
+
|
|
|
+const statCards = computed(() => [
|
|
|
+ {
|
|
|
+ key: "farmer",
|
|
|
+ title: "农户总数",
|
|
|
+ value: ownerCount.value,
|
|
|
+ extra: "昨日新增",
|
|
|
+ extraValue: "8",
|
|
|
+ iconBg: "rgba(251, 142, 51, 0.12)",
|
|
|
+ iconColor: "#FB8E33",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: "service",
|
|
|
+ title: "农服人员总数",
|
|
|
+ value: serviceCount.value,
|
|
|
+ extra: "昨日新增",
|
|
|
+ extraValue: "5",
|
|
|
+ iconBg: "rgba(251, 142, 51, 0.12)",
|
|
|
+ iconColor: "#FB8E33",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: "owner",
|
|
|
+ title: "权属人员总数",
|
|
|
+ value: ownerCount.value,
|
|
|
+ extra: "本月新增",
|
|
|
+ extraValue: "12",
|
|
|
+ iconBg: "rgba(251, 142, 51, 0.12)",
|
|
|
+ iconColor: "#FB8E33",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: "area",
|
|
|
+ title: "种植总面积(亩)",
|
|
|
+ value: 12580,
|
|
|
+ extra: "本月增加",
|
|
|
+ extraValue: "120",
|
|
|
+ iconBg: "rgba(251, 142, 51, 0.12)",
|
|
|
+ iconColor: "#FB8E33",
|
|
|
+ },
|
|
|
+]);
|
|
|
+
|
|
|
const activeTab = ref("owner");
|
|
|
const page = ref(1);
|
|
|
const pageSize = ref(20);
|
|
|
const deviceName = ref("");
|
|
|
const appliedDeviceName = ref("");
|
|
|
|
|
|
-const deviceNameOptions = computed(() => {
|
|
|
- return [...new Set(allList.value.map((item) => item.name))];
|
|
|
-});
|
|
|
-
|
|
|
-/** 人员维度过滤 */
|
|
|
const filteredPersons = computed(() => {
|
|
|
let list = allList.value.filter((item) => item.tabKey === activeTab.value);
|
|
|
- if (appliedDeviceName.value) {
|
|
|
- list = list.filter((item) => item.name === appliedDeviceName.value);
|
|
|
+ const keyword = appliedDeviceName.value.trim();
|
|
|
+ if (keyword) {
|
|
|
+ list = list.filter((item) => item.name.includes(keyword));
|
|
|
}
|
|
|
return list;
|
|
|
});
|
|
|
|
|
|
const total = computed(() => filteredPersons.value.length);
|
|
|
|
|
|
-/** 人员维度分页后,按种植记录展开为表格行 */
|
|
|
const tableData = computed(() => {
|
|
|
const start = (page.value - 1) * pageSize.value;
|
|
|
const persons = filteredPersons.value.slice(start, start + pageSize.value);
|
|
|
@@ -228,7 +375,6 @@ const tableData = computed(() => {
|
|
|
rowKey: `${person.id}-${idx}`,
|
|
|
plantIndex: idx,
|
|
|
plantCount: plantings.length,
|
|
|
- // 兼容原弹窗字段
|
|
|
code: person.code || "农场-类型-ID",
|
|
|
type: person.cropCategory,
|
|
|
location: person.residentLocation,
|
|
|
@@ -243,18 +389,16 @@ const tableData = computed(() => {
|
|
|
return rows;
|
|
|
});
|
|
|
|
|
|
-/** 需合并的列:姓名/手机号、种植品类、常驻点位、操作 */
|
|
|
-const MERGE_COLUMN_INDEXES = new Set([0, 1, 7, 8]);
|
|
|
+/** 需合并的列:个人信息、种植品类、农机设备、外包农事、常驻点位、邀请人、操作 */
|
|
|
+const MERGE_COLUMN_INDEXES = new Set([0, 1, 7, 8, 9, 10, 11]);
|
|
|
|
|
|
const objectSpanMethod = ({ row, columnIndex }) => {
|
|
|
if (!MERGE_COLUMN_INDEXES.has(columnIndex)) {
|
|
|
return { rowspan: 1, colspan: 1 };
|
|
|
}
|
|
|
-
|
|
|
if (row.plantIndex === 0) {
|
|
|
return { rowspan: row.plantCount, colspan: 1 };
|
|
|
}
|
|
|
-
|
|
|
return { rowspan: 0, colspan: 0 };
|
|
|
};
|
|
|
|
|
|
@@ -268,24 +412,77 @@ const handleSearch = () => {
|
|
|
page.value = 1;
|
|
|
};
|
|
|
|
|
|
-const handleReset = () => {
|
|
|
- deviceName.value = "";
|
|
|
- appliedDeviceName.value = "";
|
|
|
- page.value = 1;
|
|
|
+/** 排行榜 */
|
|
|
+const rankTabs = [
|
|
|
+ { key: "manage", label: "管理业绩排行" },
|
|
|
+ { key: "area", label: "农户种植面积排行" },
|
|
|
+ { key: "order", label: "农服服务订单排行" },
|
|
|
+];
|
|
|
+const activeRankTab = ref("manage");
|
|
|
+
|
|
|
+const buildRankList = (type) => {
|
|
|
+ const names = ["郑以轩", "李明轩", "王晓彤", "赵子涵", "陈思远", "周雨桐"];
|
|
|
+ return names.map((name, idx) => {
|
|
|
+ const base = {
|
|
|
+ rank: idx + 1,
|
|
|
+ name,
|
|
|
+ };
|
|
|
+ if (type === "area") {
|
|
|
+ return {
|
|
|
+ ...base,
|
|
|
+ metricALabel: "种植面积",
|
|
|
+ metricA: `${320 - idx * 28}亩`,
|
|
|
+ metricBLabel: "品种数",
|
|
|
+ metricB: 6 - (idx % 3),
|
|
|
+ metricCLabel: "地块数",
|
|
|
+ metricC: 12 - idx,
|
|
|
+ metricDLabel: "本月新增",
|
|
|
+ metricD: `${8 - idx}亩`,
|
|
|
+ };
|
|
|
+ }
|
|
|
+ if (type === "order") {
|
|
|
+ return {
|
|
|
+ ...base,
|
|
|
+ metricALabel: "服务订单",
|
|
|
+ metricA: 86 - idx * 7,
|
|
|
+ metricBLabel: "本月完成",
|
|
|
+ metricB: 18 - idx,
|
|
|
+ metricCLabel: "好评率",
|
|
|
+ metricC: `${98 - idx}%`,
|
|
|
+ metricDLabel: "服务农户",
|
|
|
+ metricD: 40 - idx * 3,
|
|
|
+ };
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ ...base,
|
|
|
+ metricALabel: "农户总数",
|
|
|
+ metricA: 128 - idx * 9,
|
|
|
+ metricBLabel: "本月邀请",
|
|
|
+ metricB: 16 - idx,
|
|
|
+ metricCLabel: "农服总数",
|
|
|
+ metricC: 56 - idx * 4,
|
|
|
+ metricDLabel: "本月邀请",
|
|
|
+ metricD: 9 - idx,
|
|
|
+ };
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const rankMap = {
|
|
|
+ manage: buildRankList("manage"),
|
|
|
+ area: buildRankList("area"),
|
|
|
+ order: buildRankList("order"),
|
|
|
};
|
|
|
|
|
|
+const currentRankList = computed(() => rankMap[activeRankTab.value] || rankMap.manage);
|
|
|
+
|
|
|
+const handleRankMore = () => ElMessage.info("查看更多排行");
|
|
|
+
|
|
|
const dialogVisible = ref(false);
|
|
|
const dialogMode = ref("add");
|
|
|
const editingRow = ref(null);
|
|
|
const detailVisible = ref(false);
|
|
|
const detailRow = ref(null);
|
|
|
|
|
|
-const handleAdd = () => {
|
|
|
- dialogMode.value = "add";
|
|
|
- editingRow.value = null;
|
|
|
- dialogVisible.value = true;
|
|
|
-};
|
|
|
-
|
|
|
const handleEdit = (row) => {
|
|
|
const person = allList.value.find((item) => item.id === row.id) || row;
|
|
|
dialogMode.value = "edit";
|
|
|
@@ -302,7 +499,6 @@ const handleDetail = (row) => {
|
|
|
const person = allList.value.find((item) => item.id === row.id) || row;
|
|
|
detailRow.value = {
|
|
|
...person,
|
|
|
- // 兼容弹窗字段
|
|
|
code: person.code || "农场-类型-ID",
|
|
|
type: person.cropCategory,
|
|
|
location: person.residentLocation,
|
|
|
@@ -371,20 +567,23 @@ const handleDialogSubmit = ({ mode, data }) => {
|
|
|
cropCategory: data.cropCategory || categories[0]?.category || "荔枝",
|
|
|
residentLocation: data.residentLocation || data.location || "位置位置位置位置",
|
|
|
locationWkt: data.locationWkt || "",
|
|
|
+ equipments: data.equipments || ["农机设备"],
|
|
|
+ outsourceFarmWorks: data.outsourceFarmWorks || ["农事类别一"],
|
|
|
+ inviterName: data.inviterName || "张扬",
|
|
|
tabKey: activeTab.value,
|
|
|
categories,
|
|
|
plantings: plantings.length
|
|
|
? plantings
|
|
|
: [
|
|
|
- {
|
|
|
- variety: "妃子笑",
|
|
|
- phenology: "生育期一",
|
|
|
- area: "158亩",
|
|
|
- startPoint: "来白点",
|
|
|
- startDate: "2025.05.08",
|
|
|
- plantLocation: "位置位置位置位置",
|
|
|
- },
|
|
|
- ],
|
|
|
+ {
|
|
|
+ variety: "妃子笑",
|
|
|
+ phenology: "生育期一",
|
|
|
+ area: "158亩",
|
|
|
+ startPoint: "来白点",
|
|
|
+ startDate: "2025.05.08",
|
|
|
+ plantLocation: "位置位置位置位置",
|
|
|
+ },
|
|
|
+ ],
|
|
|
});
|
|
|
};
|
|
|
|
|
|
@@ -401,98 +600,126 @@ const handleDelete = (row) => {
|
|
|
allList.value = allList.value.filter((item) => item.id !== row.id);
|
|
|
ElMessage.success("已删除");
|
|
|
})
|
|
|
- .catch(() => {});
|
|
|
+ .catch(() => { });
|
|
|
};
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
.device-page {
|
|
|
box-sizing: border-box;
|
|
|
- min-height: 100%;
|
|
|
- padding: 25px;
|
|
|
+ height: 100%;
|
|
|
+ overflow: hidden;
|
|
|
+ padding: 20px 24px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
}
|
|
|
|
|
|
-.device-panel {
|
|
|
- min-height: calc(100% - 0px);
|
|
|
+.device-layout {
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
display: flex;
|
|
|
- flex-direction: column;
|
|
|
+ align-items: stretch;
|
|
|
+ gap: 16px;
|
|
|
}
|
|
|
|
|
|
-.device-content {
|
|
|
- background: #fff;
|
|
|
- border-radius: 5px;
|
|
|
- padding: 0 10px;
|
|
|
+.device-main {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+ min-height: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 16px;
|
|
|
+}
|
|
|
|
|
|
+/* 统计卡片 */
|
|
|
+.stat-row {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
|
+ gap: 12px;
|
|
|
+ flex-shrink: 0;
|
|
|
}
|
|
|
|
|
|
-.filter-bar {
|
|
|
+.stat-card {
|
|
|
display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 30px;
|
|
|
- padding: 0 12px;
|
|
|
- border-radius: 5px;
|
|
|
- height: 72px;
|
|
|
+ align-items: flex-start;
|
|
|
+ justify-content: space-between;
|
|
|
+ gap: 10px;
|
|
|
+ padding: 10px 16px;
|
|
|
background: #fff;
|
|
|
- margin-bottom: 20px;
|
|
|
-}
|
|
|
-.filter-r {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 12px;
|
|
|
+ box-sizing: border-box;
|
|
|
}
|
|
|
|
|
|
-.filter-bar__label {
|
|
|
- flex-shrink: 0;
|
|
|
+.stat-card__title {
|
|
|
font-size: 14px;
|
|
|
- color: #333;
|
|
|
- padding-right: 8px;
|
|
|
+ color: #1D2129;
|
|
|
+ line-height: 22px;
|
|
|
}
|
|
|
|
|
|
-.filter-bar__select {
|
|
|
- width: 220px;
|
|
|
+.stat-card__value {
|
|
|
+ margin-top: 12px;
|
|
|
+ font-size: 24px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #1D2129;
|
|
|
+ line-height: 32px;
|
|
|
}
|
|
|
|
|
|
-.btn-reset {
|
|
|
- height: 32px;
|
|
|
- padding: 0 18px;
|
|
|
- color: $warning-color;
|
|
|
- background: #fff;
|
|
|
- border-color: $warning-color;
|
|
|
- border-radius: 4px;
|
|
|
+.stat-card__extra {
|
|
|
+ margin-top: 4px;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #4E5969;
|
|
|
+ line-height: 22px;
|
|
|
|
|
|
- &:hover,
|
|
|
- &:focus {
|
|
|
- color: #fff;
|
|
|
- background: $warning-color;
|
|
|
- border-color: $warning-color;
|
|
|
+ .extra-value {
|
|
|
+ font-weight: 500;
|
|
|
+ font-size: 14px;
|
|
|
+ padding: 0 4px;
|
|
|
+ color: #23C343;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-.btn-search {
|
|
|
- // --el-button-bg-color: #{$warning-color};
|
|
|
- // --el-button-border-color: #{$warning-color};
|
|
|
- // --el-button-hover-bg-color: #{mix(#fff, $warning-color, 12%)};
|
|
|
- // --el-button-hover-border-color: #{mix(#fff, $warning-color, 12%)};
|
|
|
- // --el-button-active-bg-color: #{mix(#000, $warning-color, 8%)};
|
|
|
- // --el-button-active-border-color: #{mix(#000, $warning-color, 8%)};
|
|
|
- height: 32px;
|
|
|
- padding: 0 18px;
|
|
|
+.stat-card__icon {
|
|
|
+ width: 44px;
|
|
|
+ height: 44px;
|
|
|
border-radius: 4px;
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ flex-shrink: 0;
|
|
|
+ background: rgba(251, 142, 51, 0.1);
|
|
|
+
|
|
|
+ .icon-img {
|
|
|
+ width: 24px;
|
|
|
+ object-fit: contain;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 列表区 */
|
|
|
+.device-content {
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 0 12px 8px;
|
|
|
+ overflow: hidden;
|
|
|
}
|
|
|
|
|
|
.toolbar {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: space-between;
|
|
|
+ gap: 16px;
|
|
|
height: 56px;
|
|
|
border-bottom: 1px solid #f0f0f0;
|
|
|
+ flex-shrink: 0;
|
|
|
}
|
|
|
|
|
|
.tabs {
|
|
|
display: flex;
|
|
|
align-items: stretch;
|
|
|
height: 100%;
|
|
|
- gap: 28px;
|
|
|
+ gap: 8px;
|
|
|
}
|
|
|
|
|
|
.tabs__item {
|
|
|
@@ -504,7 +731,7 @@ const handleDelete = (row) => {
|
|
|
color: #666;
|
|
|
cursor: pointer;
|
|
|
user-select: none;
|
|
|
- padding: 0 16px;
|
|
|
+ padding: 0 14px;
|
|
|
|
|
|
&:hover {
|
|
|
color: $warning-color;
|
|
|
@@ -526,28 +753,33 @@ const handleDelete = (row) => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-.btn-add {
|
|
|
- // --el-button-bg-color: #{$warning-color};
|
|
|
- // --el-button-border-color: #{$warning-color};
|
|
|
- // --el-button-hover-bg-color: #{mix(#fff, $warning-color, 12%)};
|
|
|
- // --el-button-hover-border-color: #{mix(#fff, $warning-color, 12%)};
|
|
|
- // --el-button-active-bg-color: #{mix(#000, $warning-color, 8%)};
|
|
|
- // --el-button-active-border-color: #{mix(#000, $warning-color, 8%)};
|
|
|
- height: 36px;
|
|
|
+.toolbar__search {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.search-input {
|
|
|
+ width: 240px;
|
|
|
+}
|
|
|
+
|
|
|
+.btn-search {
|
|
|
+ height: 32px;
|
|
|
padding: 0 18px;
|
|
|
border-radius: 4px;
|
|
|
}
|
|
|
|
|
|
-.device-table {
|
|
|
+.table-wrap {
|
|
|
flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ margin-top: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.device-table {
|
|
|
width: 100%;
|
|
|
- margin-top: 20px;
|
|
|
|
|
|
:deep(.device-table__header) {
|
|
|
- &:nth-child(2) {
|
|
|
- color: #818080;
|
|
|
- }
|
|
|
- background: #F5F5F5 !important;
|
|
|
+ background: #f5f5f5 !important;
|
|
|
color: #535353;
|
|
|
font-weight: 500;
|
|
|
}
|
|
|
@@ -560,12 +792,6 @@ const handleDelete = (row) => {
|
|
|
:deep(.el-table__body .cell) {
|
|
|
padding: 0 12px;
|
|
|
}
|
|
|
-
|
|
|
- :deep(.el-checkbox__input.is-checked .el-checkbox__inner),
|
|
|
- :deep(.el-checkbox__input.is-indeterminate .el-checkbox__inner) {
|
|
|
- background-color: $warning-color;
|
|
|
- border-color: $warning-color;
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
.person-cell {
|
|
|
@@ -593,6 +819,32 @@ const handleDelete = (row) => {
|
|
|
line-height: 22px;
|
|
|
}
|
|
|
|
|
|
+.tag-list {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 6px;
|
|
|
+}
|
|
|
+
|
|
|
+.equip-tag {
|
|
|
+ display: inline-block;
|
|
|
+ padding: 2px 10px;
|
|
|
+ border-radius: 4px;
|
|
|
+ background: rgba($warning-color, 0.12);
|
|
|
+ color: $warning-color;
|
|
|
+ font-size: 12px;
|
|
|
+ line-height: 22px;
|
|
|
+}
|
|
|
+
|
|
|
+.farm-tag {
|
|
|
+ display: inline-block;
|
|
|
+ padding: 2px 10px;
|
|
|
+ border-radius: 4px;
|
|
|
+ background: rgba(64, 158, 255, 0.12);
|
|
|
+ color: #409eff;
|
|
|
+ font-size: 12px;
|
|
|
+ line-height: 22px;
|
|
|
+}
|
|
|
+
|
|
|
.start-point-cell {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
@@ -631,6 +883,28 @@ const handleDelete = (row) => {
|
|
|
font-size: 14px;
|
|
|
}
|
|
|
|
|
|
+.inviter-cell {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ min-width: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.inviter-cell__avatar {
|
|
|
+ flex-shrink: 0;
|
|
|
+ background: #ffe4c4;
|
|
|
+ color: #c07020;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.inviter-cell__name {
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ color: #535353;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
.link-btn {
|
|
|
padding: 0;
|
|
|
height: auto;
|
|
|
@@ -675,7 +949,8 @@ const handleDelete = (row) => {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: space-between;
|
|
|
- padding: 16px 34px;
|
|
|
+ padding: 12px 16px;
|
|
|
+ flex-shrink: 0;
|
|
|
}
|
|
|
|
|
|
.pager__total {
|
|
|
@@ -694,4 +969,196 @@ const handleDelete = (row) => {
|
|
|
:deep(.el-pagination__jump) {
|
|
|
margin-left: 12px;
|
|
|
}
|
|
|
+
|
|
|
+/* 右侧排行榜 */
|
|
|
+.rank-panel {
|
|
|
+ width: 450px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ min-height: 0;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 6px;
|
|
|
+ padding: 16px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ box-sizing: border-box;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.rank-panel__head {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ margin-bottom: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.rank-panel__title {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #1D2129;
|
|
|
+}
|
|
|
+
|
|
|
+.rank-more {
|
|
|
+ padding: 0;
|
|
|
+ height: auto;
|
|
|
+ font-size: 13px;
|
|
|
+}
|
|
|
+
|
|
|
+.rank-tabs {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 8px;
|
|
|
+ margin-bottom: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.rank-tabs__item {
|
|
|
+ padding: 4px 10px;
|
|
|
+ border-radius: 4px;
|
|
|
+ background: #F3F3F3;
|
|
|
+ color: rgba(0, 0, 0, 0.6);
|
|
|
+ font-size: 12px;
|
|
|
+ line-height: 20px;
|
|
|
+ border: 1px solid transparent;
|
|
|
+ cursor: pointer;
|
|
|
+ user-select: none;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ color: $warning-color;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.is-active {
|
|
|
+ color: $warning-color;
|
|
|
+ background: rgba($warning-color, 0.12);
|
|
|
+ font-weight: 500;
|
|
|
+ border-color: $warning-color;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.rank-list {
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ overflow: auto;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.rank-item {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 10px;
|
|
|
+ padding: 12px;
|
|
|
+ border-radius: 10px;
|
|
|
+ background: rgba(209, 209, 209, 0.13);
|
|
|
+ border: 1px solid transparent;
|
|
|
+ box-sizing: border-box;
|
|
|
+
|
|
|
+ &.is-top-1 {
|
|
|
+ background: linear-gradient(90deg, #fff0d2 0%, rgba(255, 240, 210, 0) 100%);
|
|
|
+ border-color: #ffe6b8;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.is-top-2 {
|
|
|
+ background: linear-gradient(90deg, #ebeff3 0%, rgba(235, 239, 243, 0) 100%);
|
|
|
+ border-color: #dde3ea;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.is-top-3 {
|
|
|
+ background: linear-gradient(90deg, #ffede5 0%, rgba(255, 237, 229, 0) 100%);
|
|
|
+ border-color: #ffe1d2;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.rank-item__head {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+ min-width: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.rank-item__rank {
|
|
|
+ width: 28px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ text-align: center;
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 600;
|
|
|
+ line-height: 1;
|
|
|
+ color: #4e5969;
|
|
|
+}
|
|
|
+
|
|
|
+.rank-item__rank-img {
|
|
|
+ display: block;
|
|
|
+ width: 30px;
|
|
|
+ height: 30px;
|
|
|
+ object-fit: contain;
|
|
|
+}
|
|
|
+
|
|
|
+.rank-item__avatar {
|
|
|
+ flex-shrink: 0;
|
|
|
+ background: #ffe4c4;
|
|
|
+ color: #c07020;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.rank-item__name {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #1d2129;
|
|
|
+}
|
|
|
+
|
|
|
+.rank-item__stats {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
|
+ gap: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.rank-stat-card {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
|
+ gap: 4px;
|
|
|
+ padding: 10px 6px;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 8px;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+.rank-stat {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ text-align: center;
|
|
|
+ min-width: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.rank-stat__value {
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 700;
|
|
|
+ line-height: 24px;
|
|
|
+ color: #1d2129;
|
|
|
+}
|
|
|
+
|
|
|
+.rank-stat__label {
|
|
|
+ margin-top: 2px;
|
|
|
+ font-size: 12px;
|
|
|
+ line-height: 18px;
|
|
|
+ color: #86909c;
|
|
|
+}
|
|
|
+
|
|
|
+@media (max-width: 1400px) {
|
|
|
+ .rank-panel {
|
|
|
+ width: 320px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-row {
|
|
|
+ grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|