feat: 🚀 表格Bar未完成,剩余一些bug
This commit is contained in:
parent
ef51ae18ce
commit
7ab9f084ed
|
@ -12,7 +12,7 @@ export default {
|
|||
"subject-empty": [2, "never"],
|
||||
"type-empty": [2, "never"],
|
||||
"subject-case": [0],
|
||||
"type-enum": [2, "always", ["feat", "fix", "media", "docs", "style", "refactor", "perf", "test", "build", "ci", "chore", "revert", "wip", "workflow", "types", "release"]]
|
||||
"type-enum": [2, "always", ["init", "optimize", "feat", "fix", "media", "docs", "style", "refactor", "perf", "test", "build", "ci", "chore", "revert", "wip", "workflow", "types", "release"]]
|
||||
},
|
||||
prompt: {
|
||||
messages: {
|
||||
|
@ -28,6 +28,8 @@ export default {
|
|||
confirmCommit: "是否提交或修改commit ?"
|
||||
},
|
||||
types: [
|
||||
{ value: "init", name: "初始化: ⏳ 初始化项目", emoji: "⏳" },
|
||||
{ value: "optimize", name: "优化代码: ♻️ 优化项目代码", emoji: "♻️" },
|
||||
{ value: "feat", name: "特性: 🚀 新增功能", emoji: "🚀" },
|
||||
{ value: "media", name: "媒体: 🎁 新增媒体资源", emoji: "🎁" },
|
||||
{ value: "fix", name: "修复: 🧩 修复缺陷", emoji: "🧩" },
|
||||
|
|
|
@ -180,10 +180,7 @@ menus:
|
|||
pureMindMap: Mind Map
|
||||
pureMenuOverflow: Menu Overflow Show Tooltip Text
|
||||
pureChildMenuOverflow: Child Menu Overflow Show Tooltip Text
|
||||
bills: Ledger management
|
||||
billRecord: Billing record
|
||||
billHistory: Billing History
|
||||
billCount: Billing Count
|
||||
systemctlTest: Systemctl lTest
|
||||
status:
|
||||
pureLoad: Loading...
|
||||
pureMessage: Message
|
||||
|
@ -234,3 +231,5 @@ login:
|
|||
purePassWordSureReg: Please enter confirm password
|
||||
purePassWordDifferentReg: The two passwords do not match!
|
||||
purePassWordUpdateReg: Password has been updated
|
||||
table:
|
||||
tableNumber: Table Number
|
||||
|
|
|
@ -180,10 +180,7 @@ menus:
|
|||
pureMindMap: 思维导图
|
||||
pureMenuOverflow: 目录超出显示 Tooltip 文字提示
|
||||
pureChildMenuOverflow: 菜单超出显示 Tooltip 文字提示
|
||||
bills: 台账管理
|
||||
billRecord: 账单记录
|
||||
billHistory: 历史账单
|
||||
billCount: 账单统计
|
||||
systemctlTest: 系统测试
|
||||
status:
|
||||
pureLoad: 加载中...
|
||||
pureMessage: 消息
|
||||
|
@ -234,3 +231,5 @@ login:
|
|||
purePassWordSureReg: 请输入确认密码
|
||||
purePassWordDifferentReg: 两次密码不一致!
|
||||
purePassWordUpdateReg: 修改密码成功
|
||||
table:
|
||||
tableNumber: 序号
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 模拟后端动态生成路由
|
||||
import { defineFakeRoute } from "vite-plugin-fake-server/client";
|
||||
import { bills, frame, monitor, permission, system, tabs } from "@/router/enums";
|
||||
import { frame, monitor, permission, system } from "@/router/enums";
|
||||
|
||||
/**
|
||||
* roles:页面级别权限,这里模拟二种 "admin"、"common"
|
||||
|
@ -102,6 +102,16 @@ const systemMonitorRouter = {
|
|||
title: "menus.pureSystemLog",
|
||||
roles: ["admin"]
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/monitor/system-test",
|
||||
component: "monitor/test/index",
|
||||
name: "SystemTest",
|
||||
meta: {
|
||||
icon: "ri:file-search-line",
|
||||
title: "menus.systemctlTest",
|
||||
roles: ["admin"]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
@ -257,48 +267,6 @@ const frameRouter = {
|
|||
]
|
||||
};
|
||||
|
||||
const tabsRouter = {
|
||||
path: "/tabs",
|
||||
meta: {
|
||||
icon: "ri:bookmark-2-line",
|
||||
title: "menus.pureTabs",
|
||||
rank: tabs
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/tabs/index",
|
||||
name: "Tabs",
|
||||
meta: {
|
||||
title: "menus.pureTabs",
|
||||
roles: ["admin", "common"]
|
||||
}
|
||||
},
|
||||
// query 传参模式
|
||||
{
|
||||
path: "/tabs/query-detail",
|
||||
name: "TabQueryDetail",
|
||||
meta: {
|
||||
// 不在menu菜单中显示
|
||||
showLink: false,
|
||||
activePath: "/tabs/index",
|
||||
roles: ["admin", "common"]
|
||||
}
|
||||
},
|
||||
// params 传参模式
|
||||
{
|
||||
path: "/tabs/params-detail/:id",
|
||||
component: "params-detail",
|
||||
name: "TabParamsDetail",
|
||||
meta: {
|
||||
// 不在menu菜单中显示
|
||||
showLink: false,
|
||||
activePath: "/tabs/index",
|
||||
roles: ["admin", "common"]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const about = {
|
||||
path: "/about",
|
||||
meta: {
|
||||
|
@ -324,7 +292,7 @@ export default defineFakeRoute([
|
|||
response: () => {
|
||||
return {
|
||||
success: true,
|
||||
data: [systemManagementRouter, systemMonitorRouter, permissionRouter, frameRouter, about, /*tabsRouter*/]
|
||||
data: [systemManagementRouter, systemMonitorRouter, permissionRouter, frameRouter, about]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
import vxeTableBar from "./src/bar";
|
||||
import { withInstall } from "@pureadmin/utils";
|
||||
|
||||
/** 配合 `vxe-table` 实现快速便捷的表格操作 */
|
||||
export const VxeTableBar = withInstall(vxeTableBar);
|
|
@ -1,251 +0,0 @@
|
|||
import Sortable from "sortablejs";
|
||||
import { transformI18n } from "@/plugins/i18n";
|
||||
import { useEpThemeStoreHook } from "@/store/modules/epTheme";
|
||||
import { cloneDeep, delay, getKeyList } from "@pureadmin/utils";
|
||||
import { computed, defineComponent, getCurrentInstance, nextTick, type PropType, ref, unref } from "vue";
|
||||
|
||||
import DragIcon from "@/assets/table-bar/drag.svg?component";
|
||||
import ExpandIcon from "@/assets/table-bar/expand.svg?component";
|
||||
import RefreshIcon from "@/assets/table-bar/refresh.svg?component";
|
||||
import SettingIcon from "@/assets/table-bar/settings.svg?component";
|
||||
import CollapseIcon from "@/assets/table-bar/collapse.svg?component";
|
||||
|
||||
const props = {
|
||||
/** 头部最左边的标题 */
|
||||
title: {
|
||||
type: String,
|
||||
default: "列表"
|
||||
},
|
||||
vxeTableRef: {
|
||||
type: Object as PropType<any>
|
||||
},
|
||||
/** 需要展示的列 */
|
||||
columns: {
|
||||
type: Array as PropType<any>,
|
||||
default: () => []
|
||||
},
|
||||
/** 是否为树列表 */
|
||||
tree: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isExpandAll: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
tableKey: {
|
||||
type: [String, Number] as PropType<string | number>,
|
||||
default: "0"
|
||||
}
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
name: "VxeTableBar",
|
||||
props,
|
||||
emits: ["refresh"],
|
||||
setup(props, { emit, slots, attrs }) {
|
||||
const size = ref("small");
|
||||
const loading = ref(false);
|
||||
const checkAll = ref(true);
|
||||
const isIndeterminate = ref(false);
|
||||
const instance = getCurrentInstance()!;
|
||||
const isExpandAll = ref(props.isExpandAll);
|
||||
let checkColumnList = getKeyList(cloneDeep(props?.columns), "title");
|
||||
const checkedColumns = ref(getKeyList(cloneDeep(props?.columns), "title"));
|
||||
const dynamicColumns = ref(cloneDeep(props?.columns));
|
||||
|
||||
const getDropdownItemStyle = computed(() => {
|
||||
return s => {
|
||||
return {
|
||||
background: s === size.value ? useEpThemeStoreHook().epThemeColor : "",
|
||||
color: s === size.value ? "#fff" : "var(--el-text-color-primary)"
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
const iconClass = computed(() => {
|
||||
return ["text-black", "dark:text-white", "duration-100", "hover:!text-primary", "cursor-pointer", "outline-none"];
|
||||
});
|
||||
|
||||
const topClass = computed(() => {
|
||||
return ["flex", "justify-between", "pt-[3px]", "px-[11px]", "border-b-[1px]", "border-solid", "border-[#dcdfe6]", "dark:border-[#303030]"];
|
||||
});
|
||||
|
||||
function onReFresh() {
|
||||
loading.value = true;
|
||||
emit("refresh");
|
||||
delay(500).then(() => (loading.value = false));
|
||||
}
|
||||
|
||||
function onExpand() {
|
||||
isExpandAll.value = !isExpandAll.value;
|
||||
isExpandAll.value ? props.vxeTableRef.setAllTreeExpand(true) : props.vxeTableRef.clearTreeExpand();
|
||||
props.vxeTableRef.refreshColumn();
|
||||
}
|
||||
|
||||
function reloadColumn() {
|
||||
const curCheckedColumns = cloneDeep(dynamicColumns.value).filter(item => checkedColumns.value.includes(item.title));
|
||||
props.vxeTableRef.reloadColumn(curCheckedColumns);
|
||||
}
|
||||
|
||||
function handleCheckAllChange(val: boolean) {
|
||||
checkedColumns.value = val ? checkColumnList : [];
|
||||
isIndeterminate.value = false;
|
||||
reloadColumn();
|
||||
}
|
||||
|
||||
function handleCheckedColumnsChange(value: string[]) {
|
||||
checkedColumns.value = value;
|
||||
const checkedCount = value.length;
|
||||
checkAll.value = checkedCount === checkColumnList.length;
|
||||
isIndeterminate.value = checkedCount > 0 && checkedCount < checkColumnList.length;
|
||||
}
|
||||
|
||||
async function onReset() {
|
||||
checkAll.value = true;
|
||||
isIndeterminate.value = false;
|
||||
dynamicColumns.value = cloneDeep(props?.columns);
|
||||
checkColumnList = [];
|
||||
checkColumnList = await getKeyList(cloneDeep(props?.columns), "title");
|
||||
checkedColumns.value = getKeyList(cloneDeep(props?.columns), "title");
|
||||
props.vxeTableRef.refreshColumn();
|
||||
}
|
||||
|
||||
function changeSize(curSize: string) {
|
||||
size.value = curSize;
|
||||
props.vxeTableRef.refreshColumn();
|
||||
}
|
||||
|
||||
const dropdown = {
|
||||
dropdown: () => (
|
||||
<el-dropdown-menu class="translation">
|
||||
<el-dropdown-item style={getDropdownItemStyle.value("medium")} onClick={() => changeSize("medium")}>
|
||||
宽松
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item style={getDropdownItemStyle.value("small")} onClick={() => changeSize("small")}>
|
||||
默认
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item style={getDropdownItemStyle.value("mini")} onClick={() => changeSize("mini")}>
|
||||
紧凑
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
)
|
||||
};
|
||||
|
||||
/** 列展示拖拽排序 */
|
||||
const rowDrop = (event: { preventDefault: () => void }) => {
|
||||
event.preventDefault();
|
||||
nextTick(() => {
|
||||
const wrapper: HTMLElement = (instance?.proxy?.$refs[`VxeGroupRef${unref(props.tableKey)}`] as any).$el.firstElementChild;
|
||||
Sortable.create(wrapper, {
|
||||
animation: 300,
|
||||
handle: ".drag-btn",
|
||||
onEnd: ({ newIndex, oldIndex, item }) => {
|
||||
const targetThElem = item;
|
||||
const wrapperElem = targetThElem.parentNode as HTMLElement;
|
||||
const oldColumn = dynamicColumns.value[oldIndex];
|
||||
const newColumn = dynamicColumns.value[newIndex];
|
||||
if (oldColumn?.fixed || newColumn?.fixed) {
|
||||
// 当前列存在fixed属性 则不可拖拽
|
||||
const oldThElem = wrapperElem.children[oldIndex] as HTMLElement;
|
||||
if (newIndex > oldIndex) {
|
||||
wrapperElem.insertBefore(targetThElem, oldThElem);
|
||||
} else {
|
||||
wrapperElem.insertBefore(targetThElem, oldThElem ? oldThElem.nextElementSibling : oldThElem);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const currentRow = dynamicColumns.value.splice(oldIndex, 1)[0];
|
||||
dynamicColumns.value.splice(newIndex, 0, currentRow);
|
||||
reloadColumn();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const isFixedColumn = (title: string) => {
|
||||
return dynamicColumns.value.filter(item => transformI18n(item.title) === transformI18n(title))[0].fixed ? true : false;
|
||||
};
|
||||
|
||||
const rendTippyProps = (content: string) => {
|
||||
// https://vue-tippy.netlify.app/props
|
||||
return {
|
||||
content,
|
||||
offset: [0, 18],
|
||||
duration: [300, 0],
|
||||
followCursor: true,
|
||||
hideOnClick: "toggle"
|
||||
};
|
||||
};
|
||||
|
||||
const reference = {
|
||||
reference: () => <SettingIcon class={["w-[16px]", iconClass.value]} v-tippy={rendTippyProps("列设置")} />
|
||||
};
|
||||
|
||||
return () => (
|
||||
<>
|
||||
<div {...attrs} class="w-[99/100] mt-2 px-2 pb-2 bg-bg_color">
|
||||
<div class="flex justify-between w-full h-[60px] p-4">
|
||||
{slots?.title ? slots.title() : <p class="font-bold truncate">{props.title}</p>}
|
||||
<div class="flex items-center justify-around">
|
||||
{slots?.buttons ? <div class="flex mr-4">{slots.buttons()}</div> : null}
|
||||
{props.tree ? (
|
||||
<>
|
||||
<ExpandIcon
|
||||
class={["w-[16px]", iconClass.value]}
|
||||
style={{
|
||||
transform: isExpandAll.value ? "none" : "rotate(-90deg)"
|
||||
}}
|
||||
v-tippy={rendTippyProps(isExpandAll.value ? "折叠" : "展开")}
|
||||
onClick={() => onExpand()}
|
||||
/>
|
||||
<el-divider direction="vertical" />
|
||||
</>
|
||||
) : null}
|
||||
<RefreshIcon class={["w-[16px]", iconClass.value, loading.value ? "animate-spin" : ""]} v-tippy={rendTippyProps("刷新")} onClick={() => onReFresh()} />
|
||||
<el-divider direction="vertical" />
|
||||
<el-dropdown v-slots={dropdown} trigger="click" v-tippy={rendTippyProps("密度")}>
|
||||
<CollapseIcon class={["w-[16px]", iconClass.value]} />
|
||||
</el-dropdown>
|
||||
<el-divider direction="vertical" />
|
||||
|
||||
<el-popover v-slots={reference} placement="bottom-start" popper-style={{ padding: 0 }} width="200" trigger="click">
|
||||
<div class={[topClass.value]}>
|
||||
<el-checkbox class="!-mr-1" label="列展示" v-model={checkAll.value} indeterminate={isIndeterminate.value} onChange={value => handleCheckAllChange(value)} />
|
||||
<el-button type="primary" link onClick={() => onReset()}>
|
||||
重置
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div class="pt-[6px] pl-[11px]">
|
||||
<el-scrollbar max-height="36vh">
|
||||
<el-checkbox-group ref={`VxeGroupRef${unref(props.tableKey)}`} modelValue={checkedColumns.value} onChange={value => handleCheckedColumnsChange(value)}>
|
||||
<el-space direction="vertical" alignment="flex-start" size={0}>
|
||||
{checkColumnList.map((item, index) => {
|
||||
return (
|
||||
<div class="flex items-center">
|
||||
<DragIcon class={["drag-btn w-[16px] mr-2", isFixedColumn(item) ? "!cursor-no-drop" : "!cursor-grab"]} onMouseenter={(event: { preventDefault: () => void }) => rowDrop(event)} />
|
||||
<el-checkbox key={index} label={item} value={item} onChange={reloadColumn}>
|
||||
<span title={transformI18n(item)} class="inline-block w-[120px] truncate hover:text-text_color_primary">
|
||||
{transformI18n(item)}
|
||||
</span>
|
||||
</el-checkbox>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</el-space>
|
||||
</el-checkbox-group>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</el-popover>
|
||||
</div>
|
||||
</div>
|
||||
{slots.default({
|
||||
size: size.value,
|
||||
dynamicColumns: dynamicColumns.value
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
});
|
|
@ -0,0 +1,48 @@
|
|||
<template>
|
||||
<div class="main">
|
||||
<pure-table
|
||||
ref="tableRef"
|
||||
:adaptiveConfig="{ offsetBottom: 108 }"
|
||||
:columns="column"
|
||||
:data="dataList"
|
||||
:header-cell-style="cellHeaderStyle"
|
||||
:loading="loading"
|
||||
:size="size"
|
||||
adaptive
|
||||
align-whole="center"
|
||||
border
|
||||
row-key="id"
|
||||
table-layout="auto"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { cellHeaderStyle } from "@/components/TableBar/utils/tableStyle";
|
||||
import PureTable from "@pureadmin/table";
|
||||
import type { PropType } from "vue";
|
||||
|
||||
// * 传入数据
|
||||
defineProps({
|
||||
// 表格数据
|
||||
dataList: {
|
||||
type: Array<any>,
|
||||
default: []
|
||||
},
|
||||
// 表格列字段
|
||||
column: {
|
||||
type: Array<any>,
|
||||
default: []
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
size: {
|
||||
type: String as PropType<any>,
|
||||
default: "default"
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
|
@ -0,0 +1,282 @@
|
|||
<template>
|
||||
<div class="main main-content">
|
||||
<!-- 表单设置,外加插槽 -->
|
||||
<el-form ref="formRef" :inline="true" :model="form" class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto">
|
||||
<slot name="tableForm" />
|
||||
</el-form>
|
||||
|
||||
<!-- 表格头部设置 -->
|
||||
<div class="w-[99/100] mt-2 px-2 pb-2 bg-bg_color">
|
||||
<div class="flex justify-between w-full h-[60px] p-4">
|
||||
<!-- 自定义左边头部内容 -->
|
||||
<slot name="tableTitle">
|
||||
<p class="font-bold truncate">{{ tableTitle ? tableTitle : t(route.meta.title) }}</p>
|
||||
</slot>
|
||||
|
||||
<!-- 自定义表格操作内容 -->
|
||||
<slot name="tableOperation">
|
||||
<div class="flex items-center justify-around">
|
||||
<!-- 插槽内容 -->
|
||||
<div class="mr-4">
|
||||
<slot name="tableButtons" />
|
||||
</div>
|
||||
|
||||
<!-- 右边操作按钮 -->
|
||||
<RefreshIcon v-tippy="rendTipProps('刷新')" :class="`w-[16px] ${iconClass()}} ${loading ? 'animate-spin' : ''}`" @click="onReFresh" />
|
||||
<el-divider direction="vertical" />
|
||||
|
||||
<el-dropdown trigger="click">
|
||||
<CollapseIcon :class="`w-[16px] ${iconClass()}`" />
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu class="translation">
|
||||
<el-dropdown-item :style="getDropdownItemStyle(size, 'large')" @click="handleTableSizeClick('large')"> 宽松 </el-dropdown-item>
|
||||
<el-dropdown-item :style="getDropdownItemStyle(size, 'default')" @click="handleTableSizeClick('default')"> 默认 </el-dropdown-item>
|
||||
<el-dropdown-item :style="getDropdownItemStyle(size, 'small')" @click="handleTableSizeClick('small')"> 紧凑 </el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<el-divider direction="vertical" />
|
||||
|
||||
<el-popover :popper-style="{ padding: 0 }" placement="bottom-start" trigger="click" width="200">
|
||||
<template #reference>
|
||||
<SettingIcon v-tippy="rendTipProps('列设置')" :class="`w-[16px] ${iconClass()}`" />
|
||||
</template>
|
||||
|
||||
<div :class="topClass()">
|
||||
<el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" class="!-mr-1" label="列展示" @change="handleCheckAllChange" />
|
||||
<el-button link type="primary" @click="onReset"> 重置</el-button>
|
||||
</div>
|
||||
|
||||
<div class="pt-[6px] pl-[11px]">
|
||||
<el-scrollbar max-height="36vh">
|
||||
<el-checkbox-group :ref="`GroupRef${unref(props.tableKey)}`" :modelValue="checkedColumns" @change="handleCheckedColumnsChange">
|
||||
<el-space :alignment="'flex-start'" :size="0" direction="vertical">
|
||||
<div v-for="(item, index) in checkColumnList" :key="index" class="flex items-center">
|
||||
<DragIcon :class="`drag-btn w-[16px] mr-2 ${isFixedColumn(item) ? '!cursor-no-drop' : '!cursor-grab'}`" @mouseenter="rowDrop" />
|
||||
<el-checkbox :key="index" :label="item" :value="item" @change="handleCheckColumnListChange(true, item)">
|
||||
<span class="inline-block w-[120px] truncate hover:text-text_color_primary" title="{transformI18n(item)}"> {{ transformI18n(item) }} </span>
|
||||
</el-checkbox>
|
||||
</div>
|
||||
</el-space>
|
||||
</el-checkbox-group>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</el-popover>
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
<slot name="tableSelect" />
|
||||
<pure-table
|
||||
ref="tableRef"
|
||||
:adaptiveConfig="{ offsetBottom: 108 }"
|
||||
:columns="column"
|
||||
:data="dataList"
|
||||
:header-cell-style="cellHeaderStyle"
|
||||
:loading="loading"
|
||||
:pagination="pagination"
|
||||
:paginationSmall="size === 'small'"
|
||||
:size="size"
|
||||
adaptive
|
||||
align-whole="center"
|
||||
border
|
||||
table-layout="auto"
|
||||
v-bind="$attrs"
|
||||
@selection-change="handleSelectionChange"
|
||||
@page-size-change="handleSizeChange"
|
||||
@page-current-change="handleCurrentChange"
|
||||
>
|
||||
<template v-for="(item, index) in column" :key="index" v-slot:[item.slot]="slotProps">
|
||||
<slot :name="item.slot" v-bind="slotProps" />
|
||||
</template>
|
||||
</pure-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, getCurrentInstance, nextTick, onMounted, PropType, ref, unref, watch } from "vue";
|
||||
import { rendTipProps } from "@/components/TableBar/utils/tableConfig";
|
||||
import { cellHeaderStyle, iconClass, topClass } from "@/components/TableBar/utils/tableStyle";
|
||||
import PureTable from "@pureadmin/table";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import RefreshIcon from "@/assets/table-bar/refresh.svg?component";
|
||||
import CollapseIcon from "@/assets/table-bar/collapse.svg?component";
|
||||
import { useEpThemeStoreHook } from "@/store/modules/epTheme";
|
||||
import SettingIcon from "@/assets/table-bar/settings.svg?component";
|
||||
import { cloneDeep, getKeyList, isBoolean, isFunction } from "@pureadmin/utils";
|
||||
import { transformI18n } from "@/plugins/i18n";
|
||||
import DragIcon from "@/assets/table-bar/drag.svg?component";
|
||||
import Sortable from "sortablejs";
|
||||
|
||||
// * 传入数据
|
||||
const props = defineProps({
|
||||
// 表格数据
|
||||
dataList: { type: Array<any>, default: [] },
|
||||
// 表格列字段
|
||||
column: { type: Array<any>, default: [] },
|
||||
// 是否加载
|
||||
loading: { type: Boolean, default: false },
|
||||
// 页面字体大小,small | default | large
|
||||
size: { type: String as PropType<any>, default: "default" },
|
||||
// 分页器参数
|
||||
pagination: { type: Object, default: Object },
|
||||
// 一页大小变化
|
||||
handleSelectionChange: {
|
||||
type: Function as PropType<Function>,
|
||||
default: () => {}
|
||||
},
|
||||
// 分页大小变化
|
||||
handleSizeChange: {
|
||||
type: Function as PropType<Function>,
|
||||
default: () => {}
|
||||
},
|
||||
// 当前页变化
|
||||
handleCurrentChange: {
|
||||
type: Function as PropType<Function>,
|
||||
default: () => {}
|
||||
},
|
||||
// 表单参数
|
||||
form: {
|
||||
type: Object as PropType<any>,
|
||||
default: Object
|
||||
},
|
||||
onReFresh: {
|
||||
type: Function as PropType<Function>,
|
||||
default: () => {}
|
||||
},
|
||||
tableKey: {
|
||||
type: [String, Number] as PropType<string | number>,
|
||||
default: "0"
|
||||
},
|
||||
tableTitle: { type: String, default: "" },
|
||||
class: { type: String, default: "" }
|
||||
});
|
||||
|
||||
const emit = defineEmits(["changeColumn"]);
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const checkAll = ref(true);
|
||||
const size = ref(props.size);
|
||||
const isIndeterminate = ref(false);
|
||||
const dynamicColumns = ref(props.column);
|
||||
const filterColumns = cloneDeep(props.column).filter(column => (isBoolean(column?.hide) ? !column.hide : !(isFunction(column?.hide) && column?.hide())));
|
||||
const checkedColumns = ref(getKeyList(cloneDeep(filterColumns), "label"));
|
||||
let checkColumnList = getKeyList(cloneDeep(props.column), "label");
|
||||
const instance = getCurrentInstance()!;
|
||||
|
||||
const getDropdownItemStyle = computed(() => {
|
||||
return (size: string, s: string) => {
|
||||
return {
|
||||
background: s === size ? useEpThemeStoreHook().epThemeColor : "",
|
||||
color: s === size ? "#fff" : "var(--el-text-color-primary)"
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* * 修改表格样式大小
|
||||
* @param value 修改样式大小 larger | default | small
|
||||
*/
|
||||
const handleTableSizeClick = (value: string) => {
|
||||
size.value = value;
|
||||
};
|
||||
|
||||
/**
|
||||
* 设置表格列是否全部显示
|
||||
* @param val 是否全部显示
|
||||
*/
|
||||
const handleCheckAllChange = (val: boolean) => {
|
||||
checkedColumns.value = val ? checkColumnList : [];
|
||||
isIndeterminate.value = false;
|
||||
dynamicColumns.value.map(column => (val ? (column.hide = false) : (column.hide = true)));
|
||||
};
|
||||
|
||||
const handleCheckedColumnsChange = (value: string[]) => {
|
||||
checkedColumns.value = value;
|
||||
const checkedCount = value.length;
|
||||
checkAll.value = checkedCount === checkColumnList.length;
|
||||
isIndeterminate.value = checkedCount > 0 && checkedCount < checkColumnList.length;
|
||||
};
|
||||
const handleCheckColumnListChange = (val: boolean, label: string) => {
|
||||
dynamicColumns.value.filter(item => transformI18n(item.label) === transformI18n(label))[0].hide = !val;
|
||||
};
|
||||
const isFixedColumn = (label: string) => {
|
||||
return dynamicColumns.value.filter(item => transformI18n(item.label) === transformI18n(label))[0].fixed;
|
||||
};
|
||||
const onReset = () => {
|
||||
checkAll.value = true;
|
||||
isIndeterminate.value = false;
|
||||
// dynamicColumns.value = cloneDeep(props.column);
|
||||
// checkColumnList = [];
|
||||
// checkColumnList = getKeyList(cloneDeep(props?.column), "label");
|
||||
checkedColumns.value = getKeyList(cloneDeep(filterColumns), "label");
|
||||
|
||||
const list = [];
|
||||
checkedColumns.value.forEach(item => {
|
||||
dynamicColumns.value.forEach(column => {
|
||||
if (column.label == item) {
|
||||
list.push(column);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
emit("changeColumn", list);
|
||||
};
|
||||
|
||||
/** 列展示拖拽排序 */
|
||||
const rowDrop = (event: any) => {
|
||||
event.preventDefault();
|
||||
nextTick(() => {
|
||||
const wrapper: HTMLElement = (instance?.proxy?.$refs[`GroupRef${unref(props.tableKey)}`] as any).$el.firstElementChild;
|
||||
Sortable.create(wrapper, {
|
||||
animation: 300,
|
||||
handle: ".drag-btn",
|
||||
onEnd: ({ newIndex, oldIndex, item }) => {
|
||||
const targetThElem = item;
|
||||
const wrapperElem = targetThElem.parentNode as HTMLElement;
|
||||
const oldColumn = dynamicColumns.value[oldIndex];
|
||||
const newColumn = dynamicColumns.value[newIndex];
|
||||
if (oldColumn?.fixed || newColumn?.fixed) {
|
||||
// 当前列存在fixed属性 则不可拖拽
|
||||
const oldThElem = wrapperElem.children[oldIndex] as HTMLElement;
|
||||
if (newIndex > oldIndex) {
|
||||
wrapperElem.insertBefore(targetThElem, oldThElem);
|
||||
} else {
|
||||
wrapperElem.insertBefore(targetThElem, oldThElem ? oldThElem.nextElementSibling : oldThElem);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const currentRow = dynamicColumns.value.splice(oldIndex, 1)[0];
|
||||
dynamicColumns.value.splice(newIndex, 0, currentRow);
|
||||
|
||||
emit("changeColumn", props.column);
|
||||
}
|
||||
});
|
||||
}).then();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
watch([() => props.column], () => {
|
||||
dynamicColumns.value = props.column;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-dropdown-menu__item i) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
margin: 24px 24px 0 !important;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,75 @@
|
|||
<template>
|
||||
<div class="main mt-2 p-2 bg-bg_color">
|
||||
<pure-table
|
||||
ref="tableRef"
|
||||
:adaptiveConfig="{ offsetBottom: 108 }"
|
||||
:columns="column"
|
||||
:data="dataList"
|
||||
:header-cell-style="cellHeaderStyle"
|
||||
:loading="loading"
|
||||
:pagination="pagination"
|
||||
:paginationSmall="size === 'small'"
|
||||
:size="size"
|
||||
adaptive
|
||||
align-whole="center"
|
||||
border
|
||||
row-key="id"
|
||||
table-layout="auto"
|
||||
@selection-change="handleSelectionChange"
|
||||
@page-size-change="handleSizeChange"
|
||||
@page-current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { cellHeaderStyle } from "@/components/TableBar/utils/tableStyle";
|
||||
import PureTable from "@pureadmin/table";
|
||||
import type { PropType } from "vue";
|
||||
|
||||
// * 传入数据
|
||||
defineProps({
|
||||
// 表格数据
|
||||
dataList: {
|
||||
type: Array<any>,
|
||||
default: []
|
||||
},
|
||||
// 表格列字段
|
||||
column: {
|
||||
type: Array<any>,
|
||||
default: []
|
||||
},
|
||||
// 是否加载
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 页面字体大小,small | default | large
|
||||
size: {
|
||||
type: String as PropType<any>,
|
||||
default: "default"
|
||||
},
|
||||
// 分页器参数
|
||||
pagination: {
|
||||
type: Object,
|
||||
default: Object
|
||||
},
|
||||
// 一页大小变化
|
||||
handleSelectionChange: {
|
||||
type: Function as PropType<Function>,
|
||||
default: () => {}
|
||||
},
|
||||
// 分页大小变化
|
||||
handleSizeChange: {
|
||||
type: Function as PropType<Function>,
|
||||
default: () => {}
|
||||
},
|
||||
// 当前页变化
|
||||
handleCurrentChange: {
|
||||
type: Function as PropType<Function>,
|
||||
default: () => {}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
|
@ -0,0 +1,100 @@
|
|||
<template>
|
||||
<div class="main">
|
||||
<el-form ref="formRef" :inline="true" :model="form" class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto">
|
||||
<slot name="tableForm" />
|
||||
</el-form>
|
||||
|
||||
<div class="mt-2 p-2 bg-bg_color">
|
||||
<pure-table
|
||||
ref="tableRef"
|
||||
:adaptiveConfig="{ offsetBottom: 108 }"
|
||||
:columns="column"
|
||||
:data="dataList"
|
||||
:header-cell-style="cellHeaderStyle"
|
||||
:loading="loading"
|
||||
:pagination="pagination"
|
||||
:paginationSmall="size === 'small'"
|
||||
:size="size"
|
||||
adaptive
|
||||
align-whole="center"
|
||||
border
|
||||
row-key="id"
|
||||
table-layout="auto"
|
||||
@selection-change="handleSelectionChange"
|
||||
@page-size-change="handleSizeChange"
|
||||
@page-current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { PropType } from "vue";
|
||||
import { cellHeaderStyle } from "@/components/TableBar/utils/tableStyle";
|
||||
import PureTable from "@pureadmin/table";
|
||||
|
||||
// * 传入数据
|
||||
defineProps({
|
||||
// 表格数据
|
||||
dataList: {
|
||||
type: Array<any>,
|
||||
default: []
|
||||
},
|
||||
// 表格列字段
|
||||
column: {
|
||||
type: Array<any>,
|
||||
default: []
|
||||
},
|
||||
// 是否加载
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 页面字体大小,small | default | large
|
||||
size: {
|
||||
type: String as PropType<any>,
|
||||
default: "default"
|
||||
},
|
||||
// 分页器参数
|
||||
pagination: {
|
||||
type: Object,
|
||||
default: Object
|
||||
},
|
||||
// 一页大小变化
|
||||
handleSelectionChange: {
|
||||
type: Function as PropType<Function>,
|
||||
default: () => {}
|
||||
},
|
||||
// 分页大小变化
|
||||
handleSizeChange: {
|
||||
type: Function as PropType<Function>,
|
||||
default: () => {}
|
||||
},
|
||||
// 当前页变化
|
||||
handleCurrentChange: {
|
||||
type: Function as PropType<Function>,
|
||||
default: () => {}
|
||||
},
|
||||
// 表单参数
|
||||
form: {
|
||||
type: Object as PropType<any>,
|
||||
default: Object
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-dropdown-menu__item i) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
margin: 24px 24px 0 !important;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -188,7 +188,7 @@ export default defineComponent({
|
|||
};
|
||||
|
||||
const isFixedColumn = (label: string) => {
|
||||
return !!dynamicColumns.value.filter(item => transformI18n(item.label) === transformI18n(label))[0].fixed;
|
||||
return dynamicColumns.value.filter(item => transformI18n(item.label) === transformI18n(label))[0].fixed;
|
||||
};
|
||||
|
||||
const rendTippyProps = (content: string) => {
|
||||
|
@ -244,7 +244,7 @@ export default defineComponent({
|
|||
<div class="pt-[6px] pl-[11px]">
|
||||
<el-scrollbar max-height="36vh">
|
||||
<el-checkbox-group ref={`GroupRef${unref(props.tableKey)}`} modelValue={checkedColumns.value} onChange={value => handleCheckedColumnsChange(value)}>
|
||||
<el-space direction="vertical" alignment="flex-start" size={0}>
|
||||
<el-space direction="vertical" alignment={"flex-start"} size={0}>
|
||||
{checkColumnList.map((item, index) => {
|
||||
return (
|
||||
<div class="flex items-center">
|
||||
|
@ -271,24 +271,6 @@ export default defineComponent({
|
|||
size: size.value,
|
||||
dynamicColumns: dynamicColumns.value
|
||||
})}
|
||||
{/*<PureTable*/}
|
||||
{/* ref="tableRef"*/}
|
||||
{/* columns={dynamicColumns.value}*/}
|
||||
{/* adaptiveConfig={{ offsetBottom: 108 }}*/}
|
||||
{/* headerCellStyle={{*/}
|
||||
{/* background: "var(--el-fill-color-light)",*/}
|
||||
{/* color: "var(--el-text-color-primary)"*/}
|
||||
{/* }}*/}
|
||||
{/* adaptive*/}
|
||||
{/* align-whole="center"*/}
|
||||
{/* row-key="id"*/}
|
||||
{/* table-layout="auto"*/}
|
||||
{/* data={props.dataList}*/}
|
||||
{/* loading={props.loading}*/}
|
||||
{/* pagination={props.pagination}*/}
|
||||
{/* paginationSmall={props.size == "small"}*/}
|
||||
{/* {...props}*/}
|
||||
{/*/>*/}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
export const rendTipProps = (content: string) => ({
|
||||
content,
|
||||
offset: [0, 18],
|
||||
duration: [300, 0],
|
||||
followCursor: true,
|
||||
hideOnClick: "toggle"
|
||||
});
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* * 表格头部样式
|
||||
*/
|
||||
export const cellHeaderStyle = () => ({
|
||||
background: "var(--el-fill-color-light)",
|
||||
color: "var(--el-text-color-primary)"
|
||||
});
|
||||
|
||||
export const iconClass = () => "text-black dark:text-white duration-100 hover:!text-primary cursor-pointer outline-none";
|
||||
|
||||
export const topClass = () => "flex justify-between pt-[3px] px-[11px] border-b-[1px] border-solid border-[#dcdfe6] dark:border-[#303030]";
|
|
@ -1,6 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { ref, computed } from "vue";
|
||||
import { computed, ref } from "vue";
|
||||
import { noticesData } from "./data";
|
||||
import NoticeList from "./components/NoticeList.vue";
|
||||
import BellIcon from "@iconify-icons/ep/bell";
|
||||
|
@ -12,23 +12,13 @@ const activeKey = ref(noticesData[0]?.key);
|
|||
|
||||
notices.value.map(v => (noticesNum.value += v.list.length));
|
||||
|
||||
const getLabel = computed(
|
||||
() => item =>
|
||||
t(item.name) + (item.list.length > 0 ? `(${item.list.length})` : "")
|
||||
);
|
||||
const getLabel = computed(() => item => t(item.name) + (item.list.length > 0 ? `(${item.list.length})` : ""));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-dropdown trigger="click" placement="bottom-end">
|
||||
<span
|
||||
:class="[
|
||||
'dropdown-badge',
|
||||
'navbar-bg-hover',
|
||||
'select-none',
|
||||
Number(noticesNum) !== 0 && 'mr-[10px]'
|
||||
]"
|
||||
>
|
||||
<el-badge :value="Number(noticesNum) === 0 ? '' : noticesNum" :max="99">
|
||||
<el-dropdown placement="bottom-end" trigger="click">
|
||||
<span :class="['dropdown-badge', 'navbar-bg-hover', 'select-none', Number(noticesNum) !== 0 && 'mr-[10px]']">
|
||||
<el-badge :max="99" :value="Number(noticesNum) === 0 ? '' : noticesNum">
|
||||
<span class="header-notice-icon">
|
||||
<IconifyIconOffline :icon="BellIcon" />
|
||||
</span>
|
||||
|
@ -36,23 +26,14 @@ const getLabel = computed(
|
|||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-tabs
|
||||
v-model="activeKey"
|
||||
:stretch="true"
|
||||
class="dropdown-tabs"
|
||||
:style="{ width: notices.length === 0 ? '200px' : '330px' }"
|
||||
>
|
||||
<el-empty
|
||||
v-if="notices.length === 0"
|
||||
:description="t('status.pureNoMessage')"
|
||||
:image-size="60"
|
||||
/>
|
||||
<el-tabs v-model="activeKey" :stretch="true" :style="{ width: notices.length === 0 ? '200px' : '330px' }" class="dropdown-tabs">
|
||||
<el-empty v-if="notices.length === 0" :description="t('status.pureNoMessage')" :image-size="60" />
|
||||
<span v-else>
|
||||
<template v-for="item in notices" :key="item.key">
|
||||
<el-tab-pane :label="getLabel(item)" :name="`${item.key}`">
|
||||
<el-scrollbar max-height="330px">
|
||||
<div class="noticeList-container">
|
||||
<NoticeList :list="item.list" :emptyText="item.emptyText" />
|
||||
<NoticeList :emptyText="item.emptyText" :list="item.list" />
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</el-tab-pane>
|
||||
|
|
|
@ -13,7 +13,6 @@ import { injectResponsiveStorage } from "@/utils/responsive";
|
|||
import { FontIcon, IconifyIconOffline, IconifyIconOnline } from "./components/ReIcon";
|
||||
import Table from "@pureadmin/table";
|
||||
import PureDescriptions from "@pureadmin/descriptions";
|
||||
|
||||
// 引入重置样式
|
||||
import "./style/reset.scss";
|
||||
// 导入公共样式
|
||||
|
@ -42,7 +41,6 @@ Object.keys(directives).forEach(key => {
|
|||
app.component("IconifyIconOffline", IconifyIconOffline);
|
||||
app.component("IconifyIconOnline", IconifyIconOnline);
|
||||
app.component("FontIcon", FontIcon);
|
||||
|
||||
app.component("Auth", Auth);
|
||||
|
||||
app.use(VueTippy);
|
||||
|
|
|
@ -82,7 +82,7 @@ const {
|
|||
}"
|
||||
:loading="loading"
|
||||
:pagination="pagination"
|
||||
:paginationSmall="size === 'small' ? true : false"
|
||||
:paginationSmall="size === 'small'"
|
||||
:size="size"
|
||||
adaptive
|
||||
align-whole="center"
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
<script lang="ts" setup>
|
||||
import { onMounted, reactive, ref } from "vue";
|
||||
import { PaginationProps } from "@pureadmin/table";
|
||||
import TablePlusBar from "@/components/TableBar/src/TablePlusBar.vue";
|
||||
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
|
||||
import Refresh from "@iconify-icons/ep/refresh";
|
||||
import { getPickerShortcuts } from "@/views/monitor/utils";
|
||||
import { delay } from "@pureadmin/utils";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
const loading = ref(true);
|
||||
const form = reactive({});
|
||||
const selectedNum = ref(0);
|
||||
const pagination = reactive<PaginationProps>({
|
||||
total: 0,
|
||||
pageSize: 10,
|
||||
currentPage: 1,
|
||||
background: true
|
||||
});
|
||||
let columns = ref([
|
||||
{ label: t("table.tableNumber"), prop: "id", minWidth: 60 },
|
||||
{ label: "用户名", prop: "username", minWidth: 100 },
|
||||
{ label: "登录 IP", prop: "ip", minWidth: 140 },
|
||||
{ label: "登录地点", prop: "address", minWidth: 140 },
|
||||
{ label: "操作系统", prop: "system", minWidth: 100 },
|
||||
{ label: "浏览器类型", prop: "browser", minWidth: 100 },
|
||||
{ label: "登录时间", prop: "loginTime", minWidth: 180 },
|
||||
{ label: "操作", fixed: "right", slot: "operation" }
|
||||
]);
|
||||
|
||||
const dataList = [
|
||||
{
|
||||
id: 1,
|
||||
username: "admin",
|
||||
ip: "163.108.28.226",
|
||||
address: "中国河南省信阳市",
|
||||
system: "macOS",
|
||||
browser: "Chrome",
|
||||
loginTime: "2024-05-12T07:33:12.080Z"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
username: "common",
|
||||
ip: "106.62.252.181",
|
||||
address: "中国广东省深圳市",
|
||||
system: "Windows",
|
||||
browser: "Firefox",
|
||||
loginTime: "2024-05-12T07:33:12.080Z"
|
||||
}
|
||||
];
|
||||
|
||||
const onSearch = () => {
|
||||
console.log(form);
|
||||
console.log("搜索。。。");
|
||||
};
|
||||
|
||||
const resetForm = formEl => {
|
||||
if (!formEl) return;
|
||||
formEl.resetFields();
|
||||
onSearch();
|
||||
};
|
||||
|
||||
function handleSizeChange(val: number) {
|
||||
console.log(`${val} items per page`);
|
||||
}
|
||||
|
||||
function handleCurrentChange(val: number) {
|
||||
console.log(`current page: ${val}`);
|
||||
}
|
||||
|
||||
function handleSelectionChange(val) {
|
||||
console.log("handleSelectionChange", val);
|
||||
}
|
||||
|
||||
function onReFresh() {
|
||||
loading.value = true;
|
||||
delay(500).then(() => (loading.value = false));
|
||||
}
|
||||
|
||||
function handleChangeColumn(value: Object[]) {
|
||||
columns.value = value;
|
||||
}
|
||||
|
||||
const onSelectionCancel = () => {};
|
||||
|
||||
const onbatchDel = () => {};
|
||||
const handleCellDblclick = val => {
|
||||
console.log(val);
|
||||
};
|
||||
onMounted(() => {
|
||||
setTimeout(() => (loading.value = false), 1000);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TablePlusBar
|
||||
:column="columns"
|
||||
:data-list="dataList"
|
||||
:form="form"
|
||||
:handle-current-change="handleCurrentChange"
|
||||
:handle-selection-change="handleSelectionChange"
|
||||
:handle-size-change="handleSizeChange"
|
||||
:loading="loading"
|
||||
:onReFresh="onReFresh"
|
||||
:pagination="pagination"
|
||||
row-key="id"
|
||||
tableTitle="系统测试(仅演示,操作后不生效)"
|
||||
@changeColumn="handleChangeColumn"
|
||||
@cell-dblclick="handleCellDblclick"
|
||||
>
|
||||
<template #tableForm>
|
||||
<el-form-item label="用户名" prop="username">
|
||||
<el-input v-model="form.username" class="!w-[150px]" clearable placeholder="请输入用户名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="登录状态" prop="status">
|
||||
<el-select v-model="form.status" class="!w-[150px]" clearable placeholder="请选择">
|
||||
<el-option label="成功" value="1" />
|
||||
<el-option label="失败" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="登录时间" prop="loginTime">
|
||||
<el-date-picker v-model="form.loginTime" :shortcuts="getPickerShortcuts()" end-placeholder="结束日期时间" range-separator="至" start-placeholder="开始日期时间" type="datetimerange" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button :icon="useRenderIcon('ri:search-line')" :loading="loading" type="primary" @click="onSearch"> 搜索 </el-button>
|
||||
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)"> 重置</el-button>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<template #tableButtons>
|
||||
<el-button type="danger">按钮</el-button>
|
||||
</template>
|
||||
|
||||
<template #tableSelect>
|
||||
<div v-if="selectedNum > 0" v-motion-fade class="bg-[var(--el-fill-color-light)] w-full h-[46px] mb-2 pl-4 flex items-center">
|
||||
<div class="flex-auto">
|
||||
<span class="text-[rgba(42,46,54,0.5)] dark:text-[rgba(220,220,242,0.5)]" style="font-size: var(--el-font-size-base)"> 已选 {{ selectedNum }} 项 </span>
|
||||
<el-button text type="primary" @click="onSelectionCancel"> 取消选择</el-button>
|
||||
</div>
|
||||
<el-popconfirm title="是否确认删除?" @confirm="onbatchDel">
|
||||
<template #reference>
|
||||
<el-button class="mr-1" text type="danger"> 批量删除</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #operation> 111</template>
|
||||
</TablePlusBar>
|
||||
</template>
|
Loading…
Reference in New Issue