| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635 |
- <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>
- </div>
- <el-button class="btn-add" type="warning" @click="handleAdd">新增设备</el-button>
- </div>
- <el-table :data="pagedList" class="device-table" row-key="id" header-cell-class-name="device-table__header"
- @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="48" align="center" />
- <el-table-column prop="code" label="农机代码" min-width="140" show-overflow-tooltip>
- <template #default="{ row }">
- <span class="code-tag">{{ row.code }}</span>
- </template>
- </el-table-column>
- <el-table-column prop="name" label="农机名称" min-width="120" show-overflow-tooltip />
- <el-table-column label="农机类型" min-width="110">
- <template #default="{ row }">
- <span class="type-tag">{{ row.type }}</span>
- </template>
- </el-table-column>
- <el-table-column label="农事类别" min-width="160">
- <template #default="{ row }">
- <div class="category-grid">
- <span v-for="(item, idx) in row.categories" :key="idx" class="category-grid__item">
- {{ item }}
- </span>
- </div>
- </template>
- </el-table-column>
- <el-table-column label="存放点位" min-width="170">
- <template #default="{ row }">
- <div class="location-cell">
- <div class="location-cell__row">
- <el-icon class="location-cell__icon">
- <Location />
- </el-icon>
- <span class="location-cell__text" :title="row.location">{{ row.location }}</span>
- </div>
- <el-button link type="warning" class="link-btn" @click="handleViewLocation(row)">
- 查看点位
- </el-button>
- </div>
- </template>
- </el-table-column>
- <el-table-column label="执行区域" width="120" align="center">
- <template #default="{ row }">
- <div class="area-thumb">
- 一区,二区
- <el-button link type="warning" class="link-btn" @click="handleViewArea(row)">查看区域</el-button>
- </div>
- </template>
- </el-table-column>
- <el-table-column label="负责人" min-width="150">
- <template #default="{ row }">
- <div class="owner-cell">
- <div>{{ row.ownerName }}</div>
- <div class="owner-cell__phone">{{ row.ownerPhone }}</div>
- </div>
- </template>
- </el-table-column>
- <!-- <el-table-column label="服务记录" min-width="260">
- <template #default="{ row }">
- <div class="service-cell">
- <div v-for="(record, idx) in row.serviceRecords.slice(0, 3)" :key="idx" class="service-cell__line">
- {{ record.date }} | {{ record.name }} | 作业区域: {{ record.area }}
- </div>
- <el-button link type="warning" class="link-btn" @click="handleViewMore(row)">
- 查看更多
- </el-button>
- </div>
- </template>
- </el-table-column> -->
- <el-table-column label="操作" width="150" 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 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>
- <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 { Location } from "@element-plus/icons-vue";
- import DeviceFormDialog from "./DeviceFormDialog.vue";
- import DeviceDetailDialog from "./DeviceDetailDialog.vue";
- const tabs = ref([
- { key: "all", label: "全部设备", count: 158 },
- { key: "type-a", label: "某某类", count: 152 },
- { key: "type-b", label: "某某类", count: 158 },
- { key: "type-c", label: "某某类", count: 158 },
- ]);
- const activeTab = ref("type-a");
- const page = ref(1);
- const pageSize = ref(20);
- const selectedRows = ref([]);
- const deviceName = ref("");
- const appliedDeviceName = ref("");
- const DEVICE_NAMES = ["水肥一体机", "植保无人机", "收割机", "播种机"];
- const buildMockRows = (count = 101) => {
- const list = [];
- for (let i = 1; i <= count; i++) {
- list.push({
- id: i,
- code: "农场-类型-ID",
- name: DEVICE_NAMES[i % DEVICE_NAMES.length],
- type: "水肥一体",
- categories: ["类别一", "类别二", "类别三", "类别四", "类别五", "类别六"],
- location: "位置位置位置位置",
- areaLabel: "一区,二区",
- ownerName: "张扬",
- ownerPhone: "19871513658",
- serviceRecords: [
- { date: "2024-08-20", name: "农事名称", area: "3区" },
- { date: "2024-08-20", name: "农事名称", area: "3区" },
- { date: "2024-08-20", name: "农事名称", area: "3区" },
- { date: "2024-08-19", name: "农事名称", area: "2区" },
- ],
- categoryKey: i % 3 === 0 ? "type-b" : i % 2 === 0 ? "type-c" : "type-a",
- });
- }
- return list;
- };
- const allList = ref(buildMockRows());
- const deviceNameOptions = computed(() => {
- return [...new Set(allList.value.map((item) => item.name))];
- });
- const filteredList = computed(() => {
- let list = allList.value;
- if (activeTab.value !== "all") {
- list = list.filter((item) => item.categoryKey === activeTab.value);
- }
- if (appliedDeviceName.value) {
- list = list.filter((item) => item.name === appliedDeviceName.value);
- }
- return list;
- });
- const total = computed(() => filteredList.value.length);
- const pagedList = computed(() => {
- const start = (page.value - 1) * pageSize.value;
- return filteredList.value.slice(start, start + pageSize.value);
- });
- const handleTabChange = (key) => {
- activeTab.value = key;
- page.value = 1;
- };
- const handleSearch = () => {
- appliedDeviceName.value = deviceName.value || "";
- page.value = 1;
- };
- const handleReset = () => {
- deviceName.value = "";
- appliedDeviceName.value = "";
- page.value = 1;
- };
- const handleSelectionChange = (rows) => {
- selectedRows.value = rows;
- };
- 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) => {
- dialogMode.value = "edit";
- editingRow.value = { ...row };
- dialogVisible.value = true;
- };
- const handleDetail = (row) => {
- detailRow.value = { ...row };
- detailVisible.value = true;
- };
- const handleDetailEdit = () => {
- if (!detailRow.value) return;
- detailVisible.value = false;
- handleEdit(detailRow.value);
- };
- const handleDialogSubmit = ({ mode, data }) => {
- if (mode === "edit" && data.id != null) {
- const idx = allList.value.findIndex((item) => item.id === data.id);
- if (idx > -1) {
- allList.value[idx] = {
- ...allList.value[idx],
- ...data,
- };
- // 同步详情缓存
- if (detailRow.value?.id === data.id) {
- detailRow.value = { ...allList.value[idx] };
- }
- }
- return;
- }
- const nextId = allList.value.reduce((max, item) => Math.max(max, item.id), 0) + 1;
- allList.value.unshift({
- ...data,
- id: nextId,
- code: "农场-类型-ID",
- categoryKey: activeTab.value === "all" ? "type-a" : activeTab.value,
- serviceRecords: [],
- });
- };
- const handleViewLocation = () => ElMessage.info("查看存放点位");
- const handleViewArea = () => ElMessage.info("查看执行区域");
- const handleDelete = (row) => {
- ElMessageBox.confirm(`确认删除设备「${row.name}」吗?`, "提示", {
- type: "warning",
- confirmButtonText: "删除",
- cancelButtonText: "取消",
- })
- .then(() => {
- allList.value = allList.value.filter((item) => item.id !== row.id);
- ElMessage.success("已删除");
- })
- .catch(() => { });
- };
- </script>
- <style lang="scss" scoped>
- .device-page {
- box-sizing: border-box;
- min-height: 100%;
- padding: 25px;
- }
- .device-panel {
- min-height: calc(100% - 0px);
- display: flex;
- flex-direction: column;
- }
- .device-content {
- background: #fff;
- border-radius: 5px;
- padding: 0 10px;
- }
- .filter-bar {
- display: flex;
- align-items: center;
- gap: 30px;
- padding: 0 12px;
- border-radius: 5px;
- height: 72px;
- background: #fff;
- margin-bottom: 20px;
- }
- .filter-r {
- display: flex;
- align-items: center;
- gap: 12px;
- }
- .filter-bar__label {
- flex-shrink: 0;
- font-size: 14px;
- color: #333;
- padding-right: 8px;
- }
- .filter-bar__select {
- width: 220px;
- }
- .btn-reset {
- height: 32px;
- padding: 0 18px;
- color: $warning-color;
- background: #fff;
- border-color: $warning-color;
- border-radius: 4px;
- &:hover,
- &:focus {
- color: #fff;
- background: $warning-color;
- border-color: $warning-color;
- }
- }
- .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;
- border-radius: 4px;
- }
- .toolbar {
- display: flex;
- align-items: center;
- justify-content: space-between;
- height: 56px;
- border-bottom: 1px solid #f0f0f0;
- }
- .tabs {
- display: flex;
- align-items: stretch;
- height: 100%;
- gap: 28px;
- }
- .tabs__item {
- position: relative;
- display: flex;
- align-items: center;
- height: 100%;
- font-size: 14px;
- color: #666;
- cursor: pointer;
- user-select: none;
- padding: 0 16px;
- &:hover {
- color: $warning-color;
- }
- &.is-active {
- color: $warning-color;
- font-weight: 500;
- &::after {
- content: "";
- position: absolute;
- left: 0;
- right: 0;
- bottom: 0;
- height: 2px;
- background: $warning-color;
- }
- }
- }
- .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;
- padding: 0 18px;
- border-radius: 4px;
- }
- .device-table {
- flex: 1;
- width: 100%;
- margin-top: 20px;
- :deep(.device-table__header) {
- &:nth-child(2) {
- color: #818080;
- }
- background: #F5F5F5 !important;
- color: #535353;
- font-weight: 500;
- }
- :deep(.el-table__cell) {
- padding: 12px 0;
- vertical-align: middle;
- }
- :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;
- }
- }
- .type-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;
- }
- .category-grid {
- display: flex;
- flex-wrap: wrap;
- gap: 4px;
- color: #666;
- font-size: 14px;
- line-height: 20px;
- .category-grid__item {
- width: fit-content;
- background: #F2F2F2;
- border-radius: 2px;
- padding: 1px 6px;
- }
- }
- .code-tag {
- color: #818080;
- }
- .location-cell {
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- gap: 2px;
- }
- .location-cell__row {
- display: flex;
- align-items: center;
- gap: 4px;
- max-width: 100%;
- }
- .location-cell__icon {
- color: #999;
- flex-shrink: 0;
- }
- .location-cell__text {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: #535353;
- font-size: 14px;
- }
- .link-btn {
- padding: 0;
- height: auto;
- font-size: 14px;
- }
- .area-thumb {
- width: 88px;
- height: 56px;
- margin: 0 auto;
- border-radius: 2px;
- overflow: hidden;
- cursor: pointer;
- }
- .owner-cell {
- color: #535353;
- display: flex;
- align-items: center;
- gap: 4px;
- color: #666;
- font-size: 14px;
- line-height: 20px;
- }
- .owner-cell__phone {
- // color: #999;
- font-weight: 500;
- }
- .service-cell {
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- gap: 2px;
- }
- .service-cell__line {
- color: #666;
- font-size: 12px;
- line-height: 18px;
- white-space: nowrap;
- }
- .ops {
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 4px;
- }
- .ops__btn {
- margin: 0 !important;
- height: 28px;
- padding: 0 6px;
- font-size: 14px;
- color: #4C4C4C;
- background: #F2F2F2;
- border: 1px solid #D2D2D2;
- border-radius: 2px;
- &:hover {
- color: $warning-color;
- border-color: rgba($warning-color, 0.45);
- background: rgba($warning-color, 0.06);
- }
- }
- .ops__btn--danger {
- color: #fff !important;
- background: #F56B6B !important;
- border-color: #F56B6B !important;
- &:hover {
- color: #fff !important;
- // background: mix(#fff, #F56B6B, 12%) !important;
- // border-color: mix(#fff, #F56B6B, 12%) !important;
- }
- }
- .pager {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 16px 34px;
- }
- .pager__total {
- color: rgba(0, 0, 0, 0.6);
- font-size: 14px;
- }
- :deep(.el-pagination.is-background .el-pager li.is-active) {
- background-color: $warning-color !important;
- }
- :deep(.el-pagination.is-background .el-pager li:hover) {
- color: $warning-color;
- }
- :deep(.el-pagination__jump) {
- margin-left: 12px;
- }
- </style>
|