20260802220544

This commit is contained in:
oneao committed 2026-08-02 22:05:44 +08:00
1 parent c00329b5a4
commit 4fc9040a8a
60 files changed
+6273 -908

No files matched your search

@@ -9,8 +9,6 @@ import { loadDataApi, nextIdApi, pageDataApi, saveObjectApi } from "@/services/a
import { buildTree, sortTree } from "@/utils/tree";
const ALL_CATEGORIES_KEY = "__fms_tree_root__";
const CATEGORY_COLUMNS = ["b_id", "b_parent_id", "b_name", "b_level", "b_path", "b_xh", "b_canuse"];
const categories = ref([]);
const categoryLoading = ref(false);
const selectedCategoryKey = ref(ALL_CATEGORIES_KEY);
@@ -22,14 +20,20 @@ const categoryById = computed(
const categoryTree = computed(() => {
const roots = buildTree(categories.value, {
mapNode: (item) => ({
key: String(item.b_id),
title: Number(item.b_canuse) === 1 ? item.b_name : `${item.b_name}(停用)`,
b_id: String(item.b_id),
b_parent_id: item.b_parent_id == null ? null : String(item.b_parent_id),
b_xh: item.b_xh,
children: [],
}),
mapNode: (item) => {
let title = item.b_name;
if (Number(item.b_canuse) !== 1) {
title = `${title}(停用)`;
}
return {
key: String(item.b_id),
title,
b_id: String(item.b_id),
b_parent_id: item.b_parent_id == null ? null : String(item.b_parent_id),
b_xh: item.b_xh,
children: [],
};
},
});
sortTree(roots);
return roots;
@@ -44,7 +48,11 @@ const categoryFilterCondition = computed(() => {
const columnExtensions = computed(() => ({
b_cate_id: {
formatter: ({ value }) => categoryById.value.get(String(value || ""))?.b_name || value || "",
formatter: ({ value }) => {
const cat = categoryById.value.get(String(value || ""));
if (!cat) return value || "";
return cat.b_name || value || "";
},
},
}));
@@ -72,12 +80,7 @@ function collectDescendantIds(rootId) {
async function loadCategories() {
categoryLoading.value = true;
try {
const response = await loadDataApi(
"b_othercompany_bmfl",
"",
"b_path ASC, b_xh ASC, b_id ASC",
CATEGORY_COLUMNS,
);
const response = await loadDataApi("b_othercompany_bmfl", "", "b_path ASC, b_xh ASC, b_id ASC");
categories.value = response.data || [];
const existingKeys = new Set(categories.value.map((item) => String(item.b_id)));
@@ -187,6 +190,7 @@ function openEditCategoryModal(node) {
addModalParentId.value = parentId;
addModalParentName.value = parent?.b_name || "";
addForm.b_name = category.b_name || "";
addModalVisible.value = true;
}
@@ -364,7 +368,9 @@ async function confirmDeleteCategory(node) {
});
}
onMounted(loadCategories);
onMounted(() => {
loadCategories();
});
</script>
<template>
@@ -413,6 +419,7 @@ onMounted(loadCategories);
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
@@ -472,4 +479,5 @@ onMounted(loadCategories);
border: 0;
border-radius: 0;
}
</style>
@@ -1,7 +1,7 @@
<script setup>
import { computed, h, onMounted, reactive, ref } from "vue";
import { computed, h, onMounted, reactive, ref, watch } from "vue";
import { message, Modal } from "antdv-next";
import { Pencil, Plus, RefreshCw, Trash2 } from "@lucide/vue";
import { Pencil, Plus, RefreshCw, Save, Trash2 } from "@lucide/vue";
import FmsModuleListPage from "@/components/fms-module-list/FmsModuleListPage.vue";
import FmsTree from "@/components/FmsTree.vue";
import { loadDataApi, nextIdApi, pageDataApi, saveObjectApi } from "@/services/api";
@@ -32,9 +32,28 @@ const categoryById = computed(
);
const tableKey = computed(() => selectedModuleCode.value);
const shouldLoadData = computed(() => Boolean(selectedModuleCode.value));
// 编辑表格:当前模块列表实例、选中行、保存/删除状态
const moduleListRef = ref(null);
const selectedRowKeys = ref([]);
const editableSaving = ref(false);
const dirtyCount = ref(0);
const rowSelection = computed(() => ({
selectedRowKeys: selectedRowKeys.value,
onChange: (keys) => {
selectedRowKeys.value = keys;
},
}));
const selectedCategoryKeys = computed(() =>
selectedCategoryKey.value ? [selectedCategoryKey.value] : [],
);
// 切换数据模块时清空编辑状态,避免残留脏标记与选中项。
watch(selectedModuleCode, () => {
selectedRowKeys.value = [];
dirtyCount.value = 0;
});
const modalTitle = computed(() => {
if (editingCategoryId.value) return modalType.value === "node" ? "修改节点" : "修改分类";
return modalType.value === "node" ? "添加节点" : "添加分类";
@@ -82,7 +101,7 @@ function buildCategoryTreeNode(item) {
const module = moduleByCode.value.get(String(moduleCode));
title = appStore.t(module?.b_i18n, module?.b_name || item.b_name || moduleCode);
} else {
title = appStore.t(item.b_i18n, item.b_name);
title = item.b_name;
}
if (Number(item.b_canuse) !== 1) {
title = `${title}(${appStore.t("common.disabled", "停用")})`;
@@ -92,7 +111,6 @@ function buildCategoryTreeNode(item) {
title,
b_id: String(item.b_id),
b_parent_id: item.b_parent_id == null ? null : String(item.b_parent_id),
b_i18n: item.b_i18n || "",
b_node_type: nodeType,
b_module_code: moduleCode,
b_xh: item.b_xh,
@@ -108,10 +126,6 @@ function getNodeType(item) {
return "category";
}
function buildCategoryI18nKey(id) {
return `category.base_otherdata.${id}`;
}
function updateSelectedModule(key) {
selectedCategoryKey.value = key;
@@ -280,7 +294,7 @@ function openAddModal(node, type) {
modalParentId.value = node?.isFmsRoot ? null : String(node?.b_id || node?.key || "");
modalParentName.value = node?.isFmsRoot ? "" : node?.title || "";
form.b_name = "";
form.b_module_code = "";
form.b_module_code = "";
modalVisible.value = true;
}
@@ -300,6 +314,7 @@ function openEditModal(node) {
modalParentName.value = parentId ? categoryById.value.get(parentId)?.b_name || "" : "";
form.b_name = category.b_name || "";
form.b_module_code = category.b_module_code || "";
modalVisible.value = true;
}
@@ -320,7 +335,6 @@ function buildNewCategory(id, name, moduleCode, nodeType) {
b_id: id,
b_parent_id: parentId || null,
b_name: name,
b_i18n: nodeType === "category" ? buildCategoryI18nKey(id) : null,
b_node_type: nodeType,
b_xh: nextSort(parentId),
b_canuse: 1,
@@ -364,7 +378,7 @@ async function saveCategory() {
saving.value = true;
try {
if (editingCategoryId.value) {
await saveObjectApi([
const saves = [
{
table: "b_other_bmfl",
key_field: "b_id",
@@ -372,24 +386,25 @@ async function saveCategory() {
{
b_id: editingCategoryId.value,
b_name: name,
b_i18n:
nodeType === "category" ? buildCategoryI18nKey(editingCategoryId.value) : null,
b_node_type: nodeType,
b_module_code: moduleCode,
},
],
},
]);
];
await saveObjectApi(saves);
message.success(isNodeModal.value ? "节点已修改" : "分类已修改");
} else {
const idRes = await nextIdApi();
await saveObjectApi([
const newId = String(idRes.data);
const saves = [
{
table: "b_other_bmfl",
key_field: "b_id",
inserts: [buildNewCategory(String(idRes.data), name, moduleCode, nodeType)],
inserts: [buildNewCategory(newId, name, moduleCode, nodeType)],
},
]);
];
await saveObjectApi(saves);
message.success(isNodeModal.value ? "节点已添加" : "分类已添加");
}
@@ -470,6 +485,50 @@ function confirmDeleteCategory(node) {
});
}
// ---- 编辑表格:新增行 / 保存 / 批量删除 ----
async function addNewRow() {
await moduleListRef.value?.addRow?.();
}
async function saveEditableChanges() {
if (editableSaving.value) return;
if (dirtyCount.value <= 0) {
message.info("没有需要保存的修改");
return;
}
editableSaving.value = true;
try {
await moduleListRef.value?.saveChanges?.();
dirtyCount.value = 0;
} finally {
editableSaving.value = false;
}
}
function confirmBatchDelete() {
if (!selectedRowKeys.value.length) {
message.warning("请先选择要删除的记录");
return;
}
Modal.confirm({
title: `确定删除选中的 ${selectedRowKeys.value.length} 条记录?`,
content: "此操作不可恢复",
okText: "删除",
cancelText: "取消",
okButtonProps: { danger: true },
onOk: async () => {
editableSaving.value = true;
try {
await moduleListRef.value?.deleteSelected?.(selectedRowKeys.value);
selectedRowKeys.value = [];
dirtyCount.value = 0;
} finally {
editableSaving.value = false;
}
},
});
}
onMounted(() => {
loadCategories();
loadDataModules();
@@ -502,9 +561,40 @@ onMounted(() => {
<main class="data-panel">
<FmsModuleListPage
v-if="shouldLoadData"
ref="moduleListRef"
:key="tableKey"
:data-code="selectedModuleCode"
/>
:editable="true"
:row-draggable="true"
:row-selection="rowSelection"
@dirty-change="({ count }) => (dirtyCount = count)"
>
<template #actions>
<a-space>
<a-button
type="primary"
ghost
:disabled="!shouldLoadData"
@click="addNewRow"
>
<Plus :size="15" />
新增行
</a-button>
<a-button type="primary" :loading="editableSaving" @click="saveEditableChanges">
<Save :size="15" />
保存
</a-button>
<a-button
danger
:disabled="!selectedRowKeys.length"
@click="confirmBatchDelete"
>
<Trash2 :size="15" />
批量删除
</a-button>
</a-space>
</template>
</FmsModuleListPage>
<div v-else class="data-empty">
<a-empty description="暂无数据" />
</div>
@@ -537,6 +627,7 @@ onMounted(() => {
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
@@ -604,4 +695,5 @@ onMounted(() => {
align-items: center;
justify-content: center;
}
</style>
File diff suppressed because it is too large. Load diff