fixbug: 🐛 表格拖拽排序列,重置和点击不显示无反应

This commit is contained in:
bunny 2024-05-13 14:18:07 +08:00
parent 7ab9f084ed
commit f097ab32b6
6 changed files with 153 additions and 101 deletions

View File

@ -12,7 +12,11 @@ export default {
"subject-empty": [2, "never"], "subject-empty": [2, "never"],
"type-empty": [2, "never"], "type-empty": [2, "never"],
"subject-case": [0], "subject-case": [0],
"type-enum": [2, "always", ["init", "optimize", "feat", "fix", "media", "docs", "style", "refactor", "perf", "test", "build", "ci", "chore", "revert", "wip", "workflow", "types", "release"]] "type-enum": [
2,
"always",
["init", "optimize", "feat", "fix", "fixbug", "media", "docs", "style", "refactor", "perf", "test", "build", "ci", "chore", "revert", "wip", "workflow", "types", "release"]
]
}, },
prompt: { prompt: {
messages: { messages: {
@ -35,6 +39,7 @@ export default {
{ value: "fix", name: "修复: 🧩 修复缺陷", emoji: "🧩" }, { value: "fix", name: "修复: 🧩 修复缺陷", emoji: "🧩" },
{ value: "docs", name: "文档: 📚 文档变更", emoji: "📚" }, { value: "docs", name: "文档: 📚 文档变更", emoji: "📚" },
{ value: "style", name: "格式: 🎨 代码格式(不影响功能,例如空格、分号等格式修正)", emoji: "🎨" }, { value: "style", name: "格式: 🎨 代码格式(不影响功能,例如空格、分号等格式修正)", emoji: "🎨" },
{ value: "fixbug", name: "bug: 🐛 修改bug", emoji: "🐛" },
{ value: "refactor", name: "重构: ♻️ 代码重构(不包括 bug 修复、功能新增)", emoji: "♻️" }, { value: "refactor", name: "重构: ♻️ 代码重构(不包括 bug 修复、功能新增)", emoji: "♻️" },
{ value: "perf", name: "性能: ⚡️ 性能优化", emoji: "⚡️" }, { value: "perf", name: "性能: ⚡️ 性能优化", emoji: "⚡️" },
{ value: "test", name: "测试: ✅ 添加疏漏测试或已有测试改动", emoji: "✅" }, { value: "test", name: "测试: ✅ 添加疏漏测试或已有测试改动", emoji: "✅" },

View File

@ -19,6 +19,7 @@ buttons:
pureBackTop: BackTop pureBackTop: BackTop
pureOpenText: Open pureOpenText: Open
pureCloseText: Close pureCloseText: Close
rest: Rest
search: search:
pureTotal: Total pureTotal: Total
pureHistory: History pureHistory: History
@ -233,3 +234,7 @@ login:
purePassWordUpdateReg: Password has been updated purePassWordUpdateReg: Password has been updated
table: table:
tableNumber: Table Number tableNumber: Table Number
style:
larger: Larger
default: Default
small: Small

View File

@ -19,6 +19,7 @@ buttons:
pureBackTop: 回到顶部 pureBackTop: 回到顶部
pureOpenText: pureOpenText:
pureCloseText: pureCloseText:
rest: 重置
search: search:
pureTotal: pureTotal:
pureHistory: 搜索历史 pureHistory: 搜索历史
@ -233,3 +234,7 @@ login:
purePassWordUpdateReg: 修改密码成功 purePassWordUpdateReg: 修改密码成功
table: table:
tableNumber: 序号 tableNumber: 序号
style:
larger: 宽松
default: 默认
small: 紧凑

View File

@ -1,10 +1,9 @@
<template> <template>
<div class="main main-content"> <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"> <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" /> <slot name="tableForm" />
</el-form> </el-form>
<!-- 表格头部设置 --> <!-- 表格头部设置 -->
<div class="w-[99/100] mt-2 px-2 pb-2 bg-bg_color"> <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"> <div class="flex justify-between w-full h-[60px] p-4">
@ -21,22 +20,28 @@
<slot name="tableButtons" /> <slot name="tableButtons" />
</div> </div>
<!-- 右边操作按钮 --> <!-- 表格刷新按钮 -->
<RefreshIcon v-tippy="rendTipProps('刷新')" :class="`w-[16px] ${iconClass()}} ${loading ? 'animate-spin' : ''}`" @click="onReFresh" /> <RefreshIcon v-tippy="rendTipProps('刷新')" :class="`w-[16px] ${iconClass()}} ${loading ? 'animate-spin' : ''}`" @click="onReFresh" />
<el-divider direction="vertical" /> <el-divider direction="vertical" />
<!-- 选择表格大小 -->
<el-dropdown trigger="click"> <el-dropdown trigger="click">
<CollapseIcon :class="`w-[16px] ${iconClass()}`" /> <CollapseIcon :class="`w-[16px] ${iconClass()}`" />
<template #dropdown> <template #dropdown>
<el-dropdown-menu class="translation"> <el-dropdown-menu class="translation">
<el-dropdown-item :style="getDropdownItemStyle(size, 'large')" @click="handleTableSizeClick('large')"> 宽松 </el-dropdown-item> <el-dropdown-item :style="getDropdownItemStyle(size, 'large')" @click="handleTableSizeClick('large')">
<el-dropdown-item :style="getDropdownItemStyle(size, 'default')" @click="handleTableSizeClick('default')"> 默认 </el-dropdown-item> {{ $t("style.larger") }}
<el-dropdown-item :style="getDropdownItemStyle(size, 'small')" @click="handleTableSizeClick('small')"> 紧凑 </el-dropdown-item> </el-dropdown-item>
<el-dropdown-item :style="getDropdownItemStyle(size, 'default')" @click="handleTableSizeClick('default')"> {{ t("style.default") }} </el-dropdown-item>
<el-dropdown-item :style="getDropdownItemStyle(size, 'small')" @click="handleTableSizeClick('small')">
{{ t("style.small") }}
</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>
<el-divider direction="vertical" /> <el-divider direction="vertical" />
<!-- 表格列设置 -->
<el-popover :popper-style="{ padding: 0 }" placement="bottom-start" trigger="click" width="200"> <el-popover :popper-style="{ padding: 0 }" placement="bottom-start" trigger="click" width="200">
<template #reference> <template #reference>
<SettingIcon v-tippy="rendTipProps('列设置')" :class="`w-[16px] ${iconClass()}`" /> <SettingIcon v-tippy="rendTipProps('列设置')" :class="`w-[16px] ${iconClass()}`" />
@ -44,7 +49,7 @@
<div :class="topClass()"> <div :class="topClass()">
<el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" class="!-mr-1" label="列展示" @change="handleCheckAllChange" /> <el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" class="!-mr-1" label="列展示" @change="handleCheckAllChange" />
<el-button link type="primary" @click="onReset"> 重置</el-button> <el-button link type="primary" @click="onReset"> {{ t("buttons.rest") }}</el-button>
</div> </div>
<div class="pt-[6px] pl-[11px]"> <div class="pt-[6px] pl-[11px]">
@ -53,8 +58,8 @@
<el-space :alignment="'flex-start'" :size="0" direction="vertical"> <el-space :alignment="'flex-start'" :size="0" direction="vertical">
<div v-for="(item, index) in checkColumnList" :key="index" class="flex items-center"> <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" /> <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)"> <el-checkbox :key="index" :label="item" :value="item" @change="handleCheckColumnListChange(item)">
<span class="inline-block w-[120px] truncate hover:text-text_color_primary" title="{transformI18n(item)}"> {{ transformI18n(item) }} </span> <span :title="transformI18n(item)" class="inline-block w-[120px] truncate hover:text-text_color_primary"> {{ transformI18n(item) }} </span>
</el-checkbox> </el-checkbox>
</div> </div>
</el-space> </el-space>
@ -80,7 +85,7 @@
adaptive adaptive
align-whole="center" align-whole="center"
border border
table-layout="auto" table-layout="fixed"
v-bind="$attrs" v-bind="$attrs"
@selection-change="handleSelectionChange" @selection-change="handleSelectionChange"
@page-size-change="handleSizeChange" @page-size-change="handleSizeChange"
@ -95,15 +100,14 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, getCurrentInstance, nextTick, onMounted, PropType, ref, unref, watch } from "vue"; import { getCurrentInstance, nextTick, onMounted, PropType, ref, unref, watch } from "vue";
import { rendTipProps } from "@/components/TableBar/utils/tableConfig"; import { rendTipProps } from "@/components/TableBar/utils/tableConfig";
import { cellHeaderStyle, iconClass, topClass } from "@/components/TableBar/utils/tableStyle"; import { cellHeaderStyle, getDropdownItemStyle, iconClass, topClass } from "@/components/TableBar/utils/tableStyle";
import PureTable from "@pureadmin/table"; import PureTable from "@pureadmin/table";
import { useRoute, useRouter } from "vue-router"; import { useRoute } from "vue-router";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import RefreshIcon from "@/assets/table-bar/refresh.svg?component"; import RefreshIcon from "@/assets/table-bar/refresh.svg?component";
import CollapseIcon from "@/assets/table-bar/collapse.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 SettingIcon from "@/assets/table-bar/settings.svg?component";
import { cloneDeep, getKeyList, isBoolean, isFunction } from "@pureadmin/utils"; import { cloneDeep, getKeyList, isBoolean, isFunction } from "@pureadmin/utils";
import { transformI18n } from "@/plugins/i18n"; import { transformI18n } from "@/plugins/i18n";
@ -142,40 +146,37 @@ const props = defineProps({
type: Object as PropType<any>, type: Object as PropType<any>,
default: Object default: Object
}, },
//
onReFresh: { onReFresh: {
type: Function as PropType<Function>, type: Function as PropType<Function>,
default: () => {} default: () => {}
}, },
// key
tableKey: { tableKey: {
type: [String, Number] as PropType<string | number>, type: [String, Number] as PropType<string | number>,
default: "0" default: "0"
}, },
tableTitle: { type: String, default: "" }, //
class: { type: String, default: "" } tableTitle: { type: String, default: "" }
}); });
const emit = defineEmits(["changeColumn"]); const emit = defineEmits(["changeColumn"]);
const { t } = useI18n(); const { t } = useI18n();
const router = useRouter();
const route = useRoute(); const route = useRoute();
//
const checkAll = ref(true); const checkAll = ref(true);
//
const size = ref(props.size); const size = ref(props.size);
const isIndeterminate = ref(false); const isIndeterminate = ref(false);
//
const dynamicColumns = ref(props.column); const dynamicColumns = ref(props.column);
//
const filterColumns = cloneDeep(props.column).filter(column => (isBoolean(column?.hide) ? !column.hide : !(isFunction(column?.hide) && column?.hide()))); const filterColumns = cloneDeep(props.column).filter(column => (isBoolean(column?.hide) ? !column.hide : !(isFunction(column?.hide) && column?.hide())));
//
const checkedColumns = ref(getKeyList(cloneDeep(filterColumns), "label")); const checkedColumns = ref(getKeyList(cloneDeep(filterColumns), "label"));
let checkColumnList = getKeyList(cloneDeep(props.column), "label"); const checkColumnList = ref(getKeyList(cloneDeep(dynamicColumns.value), "label"));
const instance = getCurrentInstance()!; 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 * @param value 修改样式大小 larger | default | small
@ -189,32 +190,57 @@ const handleTableSizeClick = (value: string) => {
* @param val 是否全部显示 * @param val 是否全部显示
*/ */
const handleCheckAllChange = (val: boolean) => { const handleCheckAllChange = (val: boolean) => {
checkedColumns.value = val ? checkColumnList : []; checkedColumns.value = val ? checkColumnList.value : [];
isIndeterminate.value = false; isIndeterminate.value = false;
dynamicColumns.value.map(column => (val ? (column.hide = false) : (column.hide = true))); dynamicColumns.value.map(column => (val ? (column.hide = false) : (column.hide = true)));
}; };
/**
* * 选中的表格列---是否显示
* @param value
*/
const handleCheckedColumnsChange = (value: string[]) => { const handleCheckedColumnsChange = (value: string[]) => {
checkedColumns.value = value; checkedColumns.value = value;
const checkedCount = value.length; const checkedCount = value.length;
checkAll.value = checkedCount === checkColumnList.length; checkAll.value = checkedCount === checkColumnList.value.length;
isIndeterminate.value = checkedCount > 0 && checkedCount < checkColumnList.length; isIndeterminate.value = checkedCount > 0 && checkedCount < checkColumnList.value.length;
}; };
const handleCheckColumnListChange = (val: boolean, label: string) => {
dynamicColumns.value.filter(item => transformI18n(item.label) === transformI18n(label))[0].hide = !val; /**
* * 点击是否显示列
* @param label
*/
const handleCheckColumnListChange = (label: string) => {
dynamicColumns.value.filter(item => transformI18n(item.label) === transformI18n(label))[0].hide = !(event.target as any).checked;
}; };
/**
* * 是否为固定列
* @param label
*/
const isFixedColumn = (label: string) => { 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 onReset = () => {
/**
* * 重置自定义表格列字段
*/
const onReset = async () => {
//
const list = [];
// true
checkAll.value = true; checkAll.value = true;
isIndeterminate.value = false; isIndeterminate.value = false;
// dynamicColumns.value = cloneDeep(props.column); //
// checkColumnList = [];
// checkColumnList = getKeyList(cloneDeep(props?.column), "label");
checkedColumns.value = getKeyList(cloneDeep(filterColumns), "label"); checkedColumns.value = getKeyList(cloneDeep(filterColumns), "label");
// ? ref reactive
// ? Proxy 访使
checkColumnList.value = [];
await nextTick(() => {
checkColumnList.value = getKeyList(filterColumns, "label");
});
const list = []; // checkedColumns list
checkedColumns.value.forEach(item => { checkedColumns.value.forEach(item => {
dynamicColumns.value.forEach(column => { dynamicColumns.value.forEach(column => {
if (column.label == item) { if (column.label == item) {
@ -251,8 +277,7 @@ const rowDrop = (event: any) => {
} }
const currentRow = dynamicColumns.value.splice(oldIndex, 1)[0]; const currentRow = dynamicColumns.value.splice(oldIndex, 1)[0];
dynamicColumns.value.splice(newIndex, 0, currentRow); dynamicColumns.value.splice(newIndex, 0, currentRow);
emit("changeColumn", dynamicColumns.value);
emit("changeColumn", props.column);
} }
}); });
}).then(); }).then();
@ -270,10 +295,6 @@ onMounted(() => {
margin: 0; margin: 0;
} }
.main-content {
margin: 24px 24px 0 !important;
}
.search-form { .search-form {
:deep(.el-form-item) { :deep(.el-form-item) {
margin-bottom: 12px; margin-bottom: 12px;

View File

@ -1,3 +1,6 @@
import { computed } from "vue";
import { useEpThemeStoreHook } from "@/store/modules/epTheme";
/** /**
* * * *
*/ */
@ -6,6 +9,20 @@ export const cellHeaderStyle = () => ({
color: "var(--el-text-color-primary)" color: "var(--el-text-color-primary)"
}); });
// * icon 样式
export const iconClass = () => "text-black dark:text-white duration-100 hover:!text-primary cursor-pointer outline-none"; 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]"; export const topClass = () => "flex justify-between pt-[3px] px-[11px] border-b-[1px] border-solid border-[#dcdfe6] dark:border-[#303030]";
/**
* *
*/
export const getDropdownItemStyle = computed(() => {
return (size: string, s: string) => {
return {
background: s === size ? useEpThemeStoreHook().epThemeColor : "",
color: s === size ? "#fff" : "var(--el-text-color-primary)"
};
};
});

View File

@ -1,3 +1,59 @@
<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>
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, reactive, ref } from "vue"; import { onMounted, reactive, ref } from "vue";
import { PaginationProps } from "@pureadmin/table"; import { PaginationProps } from "@pureadmin/table";
@ -92,60 +148,3 @@ onMounted(() => {
setTimeout(() => (loading.value = false), 1000); setTimeout(() => (loading.value = false), 1000);
}); });
</script> </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>