feat: 完成卡片分页

master
donghao 1 day ago
parent f8f5aec549
commit c5d9aabe0e

@ -1,3 +1,13 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2025-06-10 17:36:23
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-06-12 16:30:23
* @FilePath: \Web-Traffic-Police\src\components\CustomTable\index.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import baseTable from "./src/baseTable";
import basePagination from "./src/basePagination";
export const BaseTable = baseTable;
export const BasePagination = basePagination;

@ -0,0 +1,316 @@
import { ElLoading, ElPagination, ElTable, ElTableColumn } from "element-plus";
import BaseColumn from "./baseColumn.vue";
import { isUndefined } from "@/utils/is";
import {
computed,
defineComponent,
nextTick,
reactive,
type PropType,
} from "vue";
import "./baseTable.scss";
function getDefaultSort(attrs: Record<string, any>): any {
return attrs["default-sort"] || attrs.defaultSort;
}
export default defineComponent({
name: "XTable",
directives: {
loading: ElLoading.directive,
},
inheritAttrs: false,
props: {
/**
*
*/
showTable: {
type: Boolean,
default: true,
},
/**
*
*/
dataSource: {
type: Array as PropType<XTableData[]>,
required: true,
},
/**
* loading
*/
loading: {
type: Boolean,
default: false,
},
/**
*
*/
maxHeight: {
type: [Number, String] as PropType<number | "auto">,
default: "auto",
},
/**
*
* always
* false
* true
*/
pageable: {
type: [Boolean, String] as PropType<boolean | "always">,
default: true,
validator(value: boolean | "always") {
return ["always", true, false].includes(value);
},
},
/**
*
*/
pagerLayout: {
type: String,
default: "total, sizes, prev, pager, next, jumper",
validator(value: string) {
return value
.split(",")
.map((item) => item.trim())
.every((item) =>
["total", "sizes", "prev", "pager", "next", "jumper"].includes(item)
);
},
},
/**
*
*/
total: {
type: Number,
default: 0,
},
/**
*
*/
pageSize: {
type: Number,
default: 10,
},
/**
*
*/
page: {
type: Number,
default: 1,
},
/**
*
*/
pageSizes: {
type: Array as PropType<number[]>,
default() {
return [8, 12, 24, 48];
},
},
/**
* Key
*/
rowKey: {
type: [Function, String] as PropType<
(row: XTableData) => string | string
>,
default: "id",
},
/**
*
*/
visibleColumn: {
type: Boolean,
default: undefined,
},
/**
*
*/
isFixedPagination: {
type: Boolean,
default: true,
},
// handleDel: {
// type: Function,
// default: () => {}
// }
// customActions: {
// type: Function,
// default: () => {}
// }
},
emits: ["change", "columnChange", "update:visibleColumn", "actions"],
setup(props, { slots, attrs, emit }) {
const nonPropsAttrs = attrs;
const { prop: sortBy, order: sortOrder } = getDefaultSort(attrs) || {};
const tableState = reactive<XTableState>({
tid: 0,
sortBy,
sortOrder,
});
const showPagination = computed(() => {
if (props.pageable === "always") return true;
return props.pageable && props.dataSource.length > 0;
});
const mHeight = computed(() => {
if (props.maxHeight === "auto") {
return "auto";
}
return showPagination.value ? props.maxHeight - 44 : props.maxHeight;
});
/**
*
*/
function getSlot(column: XTableColumn, suffix?: string) {
const name = column.prop || column.type;
if (name) {
const key = suffix ? `${name}-${suffix}` : name;
return slots[key];
}
}
/**
*
*/
function onChange(data: XTableChangeData) {
emit("change", data);
}
/**
*
*/
function handlePageNumChange(page: number) {
const { sortBy, sortOrder } = tableState;
const { pageSize } = props;
onChange({
page,
pageSize,
prop: sortBy,
order: sortOrder,
type: "number",
});
}
/**
*
*/
function handlePageSizeChange(pageSize: number) {
const { sortBy, sortOrder } = tableState;
nextTick(() => {
// 下拉框溢出可能导致溢出 body 出现滚动条
// 加个延迟,等下拉隐藏
onChange({
page: 1,
pageSize,
prop: sortBy,
order: sortOrder,
type: "size",
});
});
}
/**
*
*/
function handleTableSortChange({ prop, order }: XTableSort) {
const { pageSize } = props;
onChange({ page: 1, pageSize, prop, order, type: "sort" });
}
/**
*
*/
function handleColumnChange(cols: XTableColumn[]) {
emit("columnChange", cols);
}
/**
*
*/
function handleVisibleChange(val: boolean) {
emit("update:visibleColumn", val);
}
/**
*
*/
function renderPagination() {
const paginationProps = {
size: "small",
background: false,
total: props.total,
layout: props.pagerLayout,
pageSize: props.pageSize,
pageSizes: props.pageSizes,
currentPage: props.page,
onSizeChange: handlePageSizeChange,
onCurrentChange: handlePageNumChange,
};
return (
<div
class={[
"x-table-pagination pagination_wrap",
props.isFixedPagination
? "fixed_pagination"
: "noneFixed_pagination",
]}
>
<ElPagination {...paginationProps} />
</div>
);
}
return () => {
const tableProps = {
ref: "elTableRef",
...nonPropsAttrs,
maxHeight: mHeight.value,
data: props.dataSource,
rowKey: props.rowKey,
onSortChange: handleTableSortChange,
};
const extraSlots: {
append?: () => any;
empty?: () => any;
} = {};
if (slots.append) {
extraSlots.append = () => slots.append?.();
}
if (slots.empty) {
extraSlots.empty = () => slots.empty?.();
}
return (
<div class="x-table baseTable_wrap">
{renderPagination()}
</div>
);
};
},
});

@ -1,151 +0,0 @@
.baseTable_wrap {
/* 去掉表格整体边框 */
.el-table {
border: none !important;
background-color: transparent;
}
/* 去掉表头下边框 */
.el-table__header-wrapper thead th {
border-bottom: none !important;
border: none !important;
}
/* 去掉单元格边框 */
.el-table td,
.el-table th.is-leaf {
border-bottom: none !important;
border: none !important;
}
/* 去掉纵向分割线 */
.el-table--border::after,
.el-table--group::after,
.el-table::before {
display: none;
}
.el-table--border,
.el-table--group {
border-right: none !important;
border-bottom: none !important;
border: none !important;
}
.el-table td,
.el-table th {
border-right: none !important;
border: none !important;
border-collapse: collapse !important;
}
.el-scrollbar__view {
background: transparent !important;
}
.el-table--large .el-table__cell {
padding: 8.5px 0;
}
.baseTable_box {
cursor: pointer;
.el-table__body {
background: transparent;
border-collapse: collapse !important;
border: none !important;
tr {
color: #fff;
background: transparent;
&:hover td {
background: transparent !important;
}
&:hover {
color: #37dbff;
background: linear-gradient(
90deg,
rgba(30, 54, 88, 0) 0%,
#0c4fad 53%,
rgba(65, 117, 190, 0) 100%
);
}
&.selected-row {
color: #37dbff;
background: linear-gradient(
90deg,
rgba(30, 54, 88, 0) 0%,
#0c4fad 53%,
rgba(65, 117, 190, 0) 100%
);
// border-top: 1px solid;
// border-bottom: 1px solid;
// border-image: linear-gradient(90deg, rgba(12, 24, 64, 0), rgba(69, 174, 250, 1), rgba(102, 102, 102, 0));
}
}
}
.el-table__header > thead {
color: #9fb5d7;
background-color: #104284 !important;
tr {
background-color: #104284 !important;
}
th {
background-color: #104284 !important;
}
}
}
.fixed_pagination {
padding: 12px 20px 0;
}
/* full_table */
&.full_table {
.el-table--large .el-table__cell {
padding: 4px 0;
}
.baseTable_box {
cursor: default;
.el-table__body {
border: none !important;
background: linear-gradient(90deg, #082050 0%, #02102a 100%);
tr {
color: #fff;
background: linear-gradient(90deg, #082050 0%, #02102a 100%);
&:nth-child(odd) {
background: linear-gradient(90deg, #082050 0%, #02102a 100%);
}
&:nth-child(even) {
background: linear-gradient(90deg, #102d65 0%, #081736 100%);
}
&:hover {
border: none !important;
}
&:hover td {
background-color: transparent;
}
}
}
.el-table__header > thead {
color: #9fb5d7;
background-color: #104284 !important;
tr {
background-color: #104284 !important;
}
th {
background-color: #104284 !important;
}
}
}
.fixed_pagination {
padding: 28px 20px;
}
}
}
.pagination_box {
margin-top: 50px;
width: 100%;
// position: fixed;
// bottom: 100px;
// right: 40px;
background-color: white;
z-index: 9;
}

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2025-03-11 11:09:39
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-03-11 11:11:22
* @LastEditTime: 2025-06-12 17:16:05
* @FilePath: \5G-Loading-Bay-Web\src\plugins\zhCn.ts
* @Description: element-plus
*/
@ -10,10 +10,11 @@ import zhCn from "element-plus/es/locale/lang/zh-cn";
// 自定义分页器文案
zhCn.el.pagination = {
goto: "前往",
goto: "跳至",
pageClassifier: "页",
pagesize: "条/页",
total: "共 {total} 条",
// total: ""
total: "共 {total} 条"
};
export default zhCn;

@ -6,7 +6,7 @@
@forward "element-plus/theme-chalk/src/common/var.scss" with (
$colors: (
"primary": (
"base": #2de6ff,
"base": #154ddd,
),
),
$select-dropdown: (
@ -61,12 +61,12 @@
}
.el-pagination {
button {
background-color: transparent;
// background-color: transparent;
color: #333333;
}
button:disabled,
button.is-disabled {
background-color: transparent;
// background-color: transparent;
}
.el-pagination--small .btn-prev,
@ -92,7 +92,7 @@
height: 28px;
}
.el-input__wrapper {
background-color: transparent;
// background-color: transparent;
.el-input__inner {
color: #333333;
@ -101,9 +101,18 @@
}
}
}
.el-pager li {
background-color: transparent;
color: #333333;
.el-pager {
margin-inline: 4px;
& > li {
margin-inline: 4px;
// background-color: transparent;
color: #333333;
&.is-active {
background-color: #154ddd;
color: white;
}
}
}
/* 下拉选择 */
@ -160,19 +169,19 @@
}
/* 修改下拉菜单背景色 */
.el-select-dropdown {
background-color: #032b5c; /* 下拉菜单背景 */
border: none; /* 可选:去掉下拉框边框 */
border: 1px solid #032b5c;
box-shadow: none; /* 可选:去掉阴影 */
}
// .el-select-dropdown {
// background-color: #032b5c; /* 下拉菜单背景 */
// border: none; /* 可选:去掉下拉框边框 */
// border: 1px solid #032b5c;
// box-shadow: none; /* 可选:去掉阴影 */
// }
/* 修改普通选项文字颜色 */
.el-select-dropdown__item {
color: #333333; /* 下拉选项文字颜色 */
}
.el-select-dropdown__item.is-hovering {
background-color: #0c4eac;
// background-color: #0c4eac;
color: #333333;
}
@ -195,13 +204,13 @@
.el-pagination__total {
color: #333333;
}
.el-select {
background-color: transparent; /* 自定义背景色 */
border: none; /* 可选:去掉边框 */
}
.el-select__wrapper {
background-color: transparent;
}
// .el-select {
// background-color: transparent; /* 自定义背景色 */
// border: none; /* 可选:去掉边框 */
// }
// .el-select__wrapper {
// background-color: transparent;
// }
}
/* 按钮 */

@ -2,97 +2,199 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2025-06-12 10:27:06
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-06-12 10:38:27
* @LastEditTime: 2025-06-12 17:21:17
* @FilePath: \Web-Traffic-Police\src\views\dataView\components\Type2LicensePlateRecog.vue
* @Description: 车牌识别
-->
<template>
<div class="type-second">
<div class="type-second-top">
<span></span> <span>车牌识别</span>
<div class="type-second">
<div class="type-second-mid">
<div class="type-second-mid-video">
<!-- //TODO -->
<video
class="w-[100%] h-[100%]"
:src="info[0].video_url"
controls
></video>
<!-- <img src="https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg" class="w-[100%] h-[100%]"/> -->
</div>
<div
class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4 type-second-mid-box"
>
<div
class="type-second-mid-crad"
v-for="(item, index) in currentInfoList.slice(
(pagination.page - 1) * pagination.pageSize,
pagination.page * pagination.pageSize
)"
:key="index"
>
<div class="type-second-mid-crad-image">
<img :src="item['车牌图片']" class="w-[100%] h-[100%]" />
</div>
<div class="type-second-mid-crad-text">
<!-- 车辆识别 -->
<p>
<span>牌照颜色</span><span>{{ item["车牌颜色"] }}</span>
</p>
<p>
<span>车牌号</span><span>{{ item["车牌号"] }}</span>
</p>
</div>
</div>
<div class="type-second-mid">
<div class="type-second-mid-video">
<img src="https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg" class="w-[100%] h-[100%]"/>
</div>
<div class="type-second-mid-box">
<div class="type-second-mid-crad" v-for="(item, index) in 8">
<div class="type-second-mid-crad-image">
<img src="https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg" class="w-[100%] h-[100%]"/>
</div>
<div class="type-second-mid-crad-text">
123123
</div>
</div>
</div>
</div>
<div class="type-second-bottom"></div>
</div>
</div>
<div class="type-second-bottom mt-[87px]">
<BasePagination
class="bg-transparent"
:showTable="false"
:total="currentInfoList?.length"
:pageSize="pagination.pageSize"
:dataSource="currentInfoList"
:isFixedPagination="true"
:page="pagination.page"
@change="changePage"
>
</BasePagination>
</div>
</div>
</template>
<script setup>
<script lang="ts" setup>
import { BasePagination } from "@/components/CustomTable";
defineOptions({
name: "Type2LicensePlateRecogWarp"
name: "Type2LicensePlateRecogWarp",
});
interface Props {
typeKey: String;
info: Record<string, any>;
title: String;
}
const props = withDefaults(defineProps<Props>(), {
typeKey: "4",
info: {},
title: String,
});
const pagination = ref({ page: 1, pageSize: 8 });
const currentIndex = ref<number>(0); //
const currentInfo = ref<Record<string, any> | null>(null);
const currentInfoList = ref<Record<string, any>[]>([]);
//
function convertLPRArrToObjects() {
const result = [];
for (let i = 0; i < currentInfo.value?.["车牌图片"].length; i++) {
result.push({
["车牌图片"]: currentInfo.value?.["车牌图片"][i],
["车牌号"]: currentInfo.value?.["车牌号"][i],
["车牌颜色"]: currentInfo.value?.["车牌颜色"][i],
});
}
return result;
}
//
function changePage({ page, pageSize }) {
// console.log(record, "changePage_record");
pagination.value = { page, pageSize };
// currentInfoList.value = convertLPRArrToObjects().slice(
// (page - 1) * pagination.value.pageSize,
// page * pagination.value.pageSize
// );
}
watch(
props.info,
() => {
currentInfo.value = props.info[0];
},
{
immediate: true,
deep: true,
}
);
watch(
currentInfo.value,
() => {
console.log(currentInfo.value, props.title);
switch (props.title) {
case "车牌识别":
currentInfoList.value = convertLPRArrToObjects();
default:
break;
}
},
{
immediate: true,
deep: true,
}
);
/**人脸检测 */
</script>
<style lang="scss" scoped>
.type-second {
.type-second-top {
cursor: pointer;
margin-bottom: 16px;
font-family: PingFang SC, PingFang SC;
font-weight: bold;
font-size: 20px;
color: #1D2129;
.type-second-top {
cursor: pointer;
margin-bottom: 16px;
font-family: PingFang SC, PingFang SC;
font-weight: bold;
font-size: 20px;
color: #1d2129;
}
.type-second-mid {
.type-second-mid-video {
box-sizing: border-box;
margin-bottom: 24px;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 324px;
border-radius: 4px;
video {
width: 720px;
height: 100%;
border-radius: 4px;
}
}
.type-second-mid {
.type-second-mid-video {
box-sizing: border-box;
margin-bottom: 24px;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 324px;
border-radius: 4px;
img {
width: 720px;
height: 100%;
border-radius: 4px;
}
.type-second-mid-box {
// display: flex;
// // justify-content: space-between;
// align-content: space-between;
// flex-direction: row;
// flex-wrap: wrap;
// height: 480px;
min-height: 480px;
max-height: 480px;
overflow-y: auto;
.type-second-mid-crad {
box-sizing: border-box;
width: 348px;
height: 232px;
background: #fff;
border-radius: 4px;
.type-second-mid-crad-image {
box-sizing: border-box;
width: 100%;
height: 148px;
img {
border-radius: 4px 4px 0 0;
}
}
.type-second-mid-box {
display: flex;
justify-content: space-between;
align-content: space-between;
flex-direction: row;
flex-wrap: wrap;
height: 480px;
.type-second-mid-crad {
box-sizing: border-box;
width: 348px;
height: 232px;
background: #fff;
border-radius: 4px;
.type-second-mid-crad-image {
box-sizing: border-box;
width: 100%;
height: 148px;
img {
border-radius: 4px 4px 0 0;
}
}
.type-second-mid-crad-text {
box-sizing: border-box;
width: 100%;
height: 84px;
padding: 16px;
font-family: PingFang SC, PingFang SC;
font-weight: bold;
font-size: 14px;
color: #1D2129;
}
}
.type-second-mid-crad-text {
box-sizing: border-box;
width: 100%;
height: 84px;
padding: 16px;
font-family: PingFang SC, PingFang SC;
font-weight: bold;
font-size: 14px;
color: #1d2129;
}
}
}
}
}
</style>
</style>

@ -17,9 +17,7 @@ export const useAllData = () => {
}
const typeMap = {
"1": ["目标检测"],
"2": ["车牌识别", "人脸检测"],
"3": [
"1": [
"递钱",
"递烟",
"遮挡",
@ -32,6 +30,8 @@ export const useAllData = () => {
"语音角色",
"多次吹气",
],
"3": ["目标检测"],
"2": ["车牌识别", "人脸检测"],
"4": ["音频检测"],
};

Loading…
Cancel
Save