20260725172954

This commit is contained in:
oneao committed 2026-07-25 17:29:54 +08:00
1 parent 1b86e0043a
commit e3c7c6f8da
16 files changed
+714 -796

No files matched your search

@@ -97,6 +97,49 @@ function batchDelete() {
});
}
// ── 编辑状态管理 ──
// 通过 row._editing = { mode: "cell", col: dataIndex } 控制单元格编辑。
// area-selection-change 统一响应鼠标点击和键盘方向键,无需额外 row-click 处理。
// 编辑状态变更后需触发表格重渲染。
function handleEditEnd() {
let hasEditing = false;
localPowers.value.forEach((r) => {
if (r._editing) {
delete r._editing;
hasEditing = true;
}
});
if (hasEditing) localPowers.value = [...localPowers.value];
}
function handleAreaSelectionChange(ranges) {
if (!ranges?.length) {
handleEditEnd();
return;
}
const begin = ranges[0].index.begin;
const row = localPowers.value[begin.row];
const area = tableRef.value?.getSelectedArea();
if (!row || !area) return;
const col = area.cols[begin.col];
if (!col || col.type !== "input") {
handleEditEnd();
return;
}
const rowId = String(row.b_id);
// 目标未变则跳过,避免方向键连续触发全表重渲染
const cur = row._editing;
if (cur && cur.mode === "cell" && cur.col === col.dataIndex && cur.rowId === rowId) return;
localPowers.value.forEach((r) => {
if (r._editing) delete r._editing;
});
row._editing = { mode: "cell", col: col.dataIndex, rowId };
localPowers.value = [...localPowers.value];
}
// ── 快速设置多语言 ──
const i18nModalRef = ref(null);
@@ -153,71 +196,16 @@ const I18nKeyCell = ({ row, cellValue }) =>
],
);
// 启用状态单元格:原生 checkbox + 自定义 CSS 模拟 antdv-next 外观,不创建组件实例
const CanUseCell = ({ row, cellValue }) => {
const checked = cellValue === 1;
return h(
"label",
{
class: "pw-checkbox",
onClick: (e) => e.stopPropagation(),
},
[
h("input", {
type: "checkbox",
checked: checked,
onChange: (e) => {
e.stopPropagation();
row.b_canuse = e.target.checked ? 1 : 0;
emitUpdate();
},
}),
h("span", {
class: ["pw-checkbox-box", checked ? "checked" : null].filter(Boolean).join(" "),
}),
],
);
};
// 操作列单元格:普通文字「删除」按钮(原生 button,避免每行一个组件实例开销)
const ActionsCell = ({ row }) =>
h(
"button",
{
type: "button",
title: "删除",
onMousedown: (e) => e.stopPropagation(),
style: {
border: "none",
background: "transparent",
cursor: "pointer",
padding: "2px 4px",
color: "#ff4d4f",
fontSize: "12px",
lineHeight: "20px",
},
onClick: (e) => {
e.stopPropagation();
Modal.confirm({
title: "确定删除该记录?",
okText: "删除",
okType: "danger",
cancelText: "取消",
onOk: () => deleteRow(row),
});
},
},
"删除",
);
const columns = [
{ dataIndex: "b_code", title: "操作编码", width: 160, editor: { onChange: () => emitUpdate() } },
{ dataIndex: "b_name", title: "操作名称", width: 160, editor: { onChange: () => emitUpdate() } },
const columns = ref([
{ dataIndex: "b_code", title: "操作编码", width: 160, type: "input", onChange: () => emitUpdate(), _onEditEnd: handleEditEnd },
{ dataIndex: "b_name", title: "操作名称", width: 160, type: "input", onChange: () => emitUpdate(), _onEditEnd: handleEditEnd },
{ dataIndex: "b_i18n", title: "多语言键", width: 160, customCell: I18nKeyCell },
{ dataIndex: "b_xh", title: "排序", width: 80, editor: { onChange: () => emitUpdate() } },
{ dataIndex: "b_canuse", title: "启用", width: 70, align: "center", customCell: CanUseCell },
{ dataIndex: "actions", title: "操作", width: 60, align: "center", customCell: ActionsCell },
];
{ dataIndex: "b_xh", title: "排序", width: 80, type: "input", onChange: () => emitUpdate(), _onEditEnd: handleEditEnd },
{ dataIndex: "b_canuse", title: "启用", width: 70, type: "checkbox", onChange: () => emitUpdate() },
{ dataIndex: "actions", title: "操作", width: 60, type: "actions", actions: [
{ type: "delete", label: "删除", confirm: "确定删除该记录?", onClick: (row) => deleteRow(row) },
] },
]);
</script>
<template>
@@ -234,12 +222,14 @@ const columns = [
<FpsMonitor />
<FmsTable
ref="tableRef"
:columns="columns"
v-model:columns="columns"
:data-source="localPowers"
row-key="b_id"
:active-row-key="activeKey"
:row-selection="rowSelection"
:area-selection="true"
@row-click="(_, row) => (activeKey = String(row.b_id))"
@area-selection-change="handleAreaSelectionChange"
/>
</div>
<I18nQuickSetModal ref="i18nModalRef" />
@@ -273,57 +263,22 @@ const columns = [
min-height: 0;
width: 100%;
}
</style>
<!-- 非 scoped 全局样式:customCell 通过 h() 渲染的元素不带 data-v 属性,
scoped 的 :deep() 可能不生效,用全局 style 确保 checkbox 样式注入。
基于 antdv-next Checkbox 源码(checkbox/style/index.js)精确模拟外观。 -->
<style lang="scss">
.pw-checkbox {
display: flex;
align-items: center;
justify-content: center;
// 编辑态 input 样式
:deep(.fms-editable-input) {
width: 100%;
cursor: pointer;
line-height: 1;
margin: 0;
height: 100%;
border: 1px solid #1677ff;
border-radius: 4px;
padding: 0 8px;
font-size: 13px;
outline: none;
box-sizing: border-box;
background: #fff;
input {
position: absolute;
width: 0;
height: 0;
opacity: 0;
margin: 0;
}
.pw-checkbox-box {
display: block;
position: relative;
width: 16px;
height: 16px;
border: 1px solid #d9d9d9;
border-radius: 4px;
background: #fff;
transition: all 0.2s;
box-sizing: border-box;
flex: none;
&.checked {
background: #1677ff;
border-color: #1677ff;
&::after {
content: "";
position: absolute;
left: 5px;
top: 2px;
width: 4px;
height: 8px;
border: solid #fff;
border-width: 0 2px 2px 0;
transform: rotate(45deg);
}
}
&:focus {
border-color: #1677ff;
box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.12);
}
}
</style>