20260724173425

This commit is contained in:
oneao committed 2026-07-24 17:34:26 +08:00
1 parent 4f40ad9f11
commit b33c743236
27 files changed
+1310 -437

No files matched your search

@@ -1,7 +1,11 @@
<script setup>
import { nextTick, ref, watch } from "vue";
import { h, nextTick, ref, watch } from "vue";
import { message, Modal } from "antdv-next";
import { Languages } from "@lucide/vue";
import FmsTable from "@/components/fms-table/FmsTable.vue";
import FpsMonitor from "@/components/FpsMonitor.vue";
import { createTempId } from "@/utils/tempId";
import I18nQuickSetModal from "./I18nQuickSetModal.vue";
const props = defineProps({
moduleId: { type: String, required: true },
@@ -23,16 +27,17 @@ watch(
localPowers.value = (val || []).map((r) => ({
...r,
b_i18n:
r.b_code && props.moduleCode
? `power.${props.moduleCode}.${r.b_code}`
: (r.b_i18n ?? null),
r.b_code && props.moduleCode ? `power.${props.moduleCode}.${r.b_code}` : (r.b_i18n ?? null),
}));
},
{ immediate: true },
);
function emitUpdate() {
emit("update", localPowers.value.map((r) => ({ ...r })));
emit(
"update",
localPowers.value.map((r) => ({ ...r })),
);
}
async function addRow() {
@@ -58,25 +63,125 @@ function deleteRow(record) {
emitUpdate();
}
// ── 快速设置多语言 ──
const i18nModalRef = ref(null);
function openI18n(row) {
const key =
row.b_code && props.moduleCode ? `power.${props.moduleCode}.${row.b_code}` : row.b_i18n;
if (!key) {
message.warning("请先填写操作编码");
return;
}
i18nModalRef.value?.open(key, row.b_name || "");
}
// 多语言键单元格:值 + 右侧翻译 icon 按钮(原生 button,避免 antdv Button 组件开销)
const I18nKeyCell = ({ row, cellValue }) =>
h(
"span",
{
style: {
display: "flex",
alignItems: "center",
justifyContent: "space-between",
gap: "4px",
width: "100%",
},
},
[
h(
"span",
{ style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } },
cellValue ?? "",
),
h(
"button",
{
type: "button",
title: "设置多语言",
style: {
flex: "none",
border: "none",
background: "transparent",
cursor: "pointer",
padding: "2px",
display: "inline-flex",
alignItems: "center",
},
onClick: (e) => {
e.stopPropagation();
openI18n(row);
},
},
[h(Languages, { size: 14 })],
),
],
);
// 启用状态单元格:原生 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 + Modal.confirm,避免每行一个 Popconfirm 实例的开销
const ActionsCell = ({ row }) =>
h(
"button",
{
type: "button",
title: "删除",
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() } },
{ dataIndex: "b_i18n", title: "多语言键", width: 160 },
{ 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",
editor: { type: "checkbox", onChange: () => emitUpdate() },
},
{
dataIndex: "actions",
title: "操作",
width: 60,
align: "center",
actions: [{ type: "danger", label: "删除", confirm: { title: "确定删除该记录?", okText: "删除" }, onClick: (row) => deleteRow(row) }],
},
{ dataIndex: "b_canuse", title: "启用", width: 70, align: "center", customCell: CanUseCell },
{ dataIndex: "actions", title: "操作", width: 60, align: "center", customCell: ActionsCell },
];
</script>
@@ -88,8 +193,17 @@ const columns = [
</a-space>
</div>
<div class="panel-body">
<FmsTable ref="tableRef" :columns="columns" :data-source="localPowers" row-key="b_id" :active-row-key="activeKey" @row-click="(_, row) => (activeKey = String(row.b_id))" />
<FpsMonitor />
<FmsTable
ref="tableRef"
:columns="columns"
:data-source="localPowers"
row-key="b_id"
:active-row-key="activeKey"
@row-click="(_, row) => (activeKey = String(row.b_id))"
/>
</div>
<I18nQuickSetModal ref="i18nModalRef" />
</div>
</template>
@@ -121,3 +235,54 @@ const columns = [
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: inline-flex;
align-items: center;
cursor: pointer;
line-height: 1;
margin: 0;
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);
}
}
}
}
</style>