20260729173317
This commit is contained in:
1 parent
f6b79ea09a
commit
1c839b707a
26 files changed
+1902
-29
No files matched your search
@@ -2,8 +2,8 @@
|
||||
import { computed, h, nextTick, reactive, ref, shallowRef, useSlots, watch } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import { message } from "antdv-next";
|
||||
import { Columns3, RefreshCw } from "@lucide/vue";
|
||||
import { loadDataApi, pageDataApi } from "@/services/api";
|
||||
import { Columns3, RefreshCw, Save } from "@lucide/vue";
|
||||
import { loadDataApi, pageDataApi, saveObjectApi } from "@/services/api";
|
||||
import { useAppStore } from "@/stores/app";
|
||||
import {
|
||||
identifierRe,
|
||||
@@ -18,6 +18,7 @@ import FmsQueryToolbar from "./FmsQueryToolbar.vue";
|
||||
|
||||
const props = defineProps({
|
||||
dataCode: { type: String, default: "" },
|
||||
fixedSearchCondition: { type: String, default: "" },
|
||||
columnExtensions: { type: Object, default: () => ({}) },
|
||||
rowActions: { type: Array, default: () => [] },
|
||||
rowSelection: { type: Object, default: null },
|
||||
@@ -44,6 +45,7 @@ const searchConditions = shallowRef([]);
|
||||
const keyField = ref("");
|
||||
const configLoading = ref(false);
|
||||
const dataLoading = ref(false);
|
||||
const columnSaving = ref(false);
|
||||
const configError = ref("");
|
||||
const dataError = ref("");
|
||||
const pagination = reactive({
|
||||
@@ -51,6 +53,7 @@ const pagination = reactive({
|
||||
pageSize: Number(props.pageSize) || 20,
|
||||
total: 0,
|
||||
});
|
||||
let dataRequestVersion = 0;
|
||||
|
||||
const loading = computed(() => configLoading.value || dataLoading.value);
|
||||
|
||||
@@ -63,9 +66,15 @@ const moreMenuItems = computed(() => [
|
||||
},
|
||||
{
|
||||
key: "reset-columns",
|
||||
label: appStore.t("common.resetColumns", "恢复配置列宽"),
|
||||
label: appStore.t("common.resetColumnSettings", "恢复栏位设置"),
|
||||
icon: h(Columns3, { size: 14 }),
|
||||
},
|
||||
{
|
||||
key: "save-column-settings",
|
||||
label: appStore.t("common.saveColumnSettings", "保存栏位设置"),
|
||||
icon: h(Save, { size: 14 }),
|
||||
disabled: columnSaving.value,
|
||||
},
|
||||
]);
|
||||
const cellSlotNames = computed(() => Object.keys(slots).filter((name) => name.startsWith("cell-")));
|
||||
|
||||
@@ -225,12 +234,17 @@ function resolveOrderBy() {
|
||||
}
|
||||
|
||||
async function fetchData() {
|
||||
if (!dataModule.value || !dataModule.value.b_viewtable || dataLoading.value) return;
|
||||
if (!dataModule.value || !dataModule.value.b_viewtable) return;
|
||||
|
||||
const currentModule = dataModule.value;
|
||||
const viewName = currentModule.b_viewtable;
|
||||
const currentCode = getDataCode();
|
||||
const currentPath = route.path;
|
||||
const requestVersion = ++dataRequestVersion;
|
||||
const conditions = [];
|
||||
const fixedCondition = String(props.fixedSearchCondition || "").trim();
|
||||
if (fixedCondition) conditions.push(`(${fixedCondition})`);
|
||||
conditions.push(...searchConditions.value);
|
||||
dataLoading.value = true;
|
||||
dataError.value = "";
|
||||
|
||||
@@ -239,17 +253,18 @@ async function fetchData() {
|
||||
viewName,
|
||||
orderBy: resolveOrderBy(),
|
||||
searchColumns: [],
|
||||
searchCondition: searchConditions.value.join(" AND "),
|
||||
searchCondition: conditions.join(" AND "),
|
||||
pageNo: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
});
|
||||
|
||||
if (dataModule.value !== currentModule) return;
|
||||
if (requestVersion !== dataRequestVersion || dataModule.value !== currentModule) return;
|
||||
if (getDataCode() !== currentCode || route.path !== currentPath) return;
|
||||
dataSource.value = res.data?.rows || [];
|
||||
pagination.total = Number(res.data?.total ?? res.data?.row_count) || 0;
|
||||
} catch (error) {
|
||||
if (
|
||||
requestVersion === dataRequestVersion &&
|
||||
dataModule.value === currentModule &&
|
||||
getDataCode() === currentCode &&
|
||||
route.path === currentPath
|
||||
@@ -260,6 +275,7 @@ async function fetchData() {
|
||||
}
|
||||
} finally {
|
||||
if (
|
||||
requestVersion === dataRequestVersion &&
|
||||
dataModule.value === currentModule &&
|
||||
getDataCode() === currentCode &&
|
||||
route.path === currentPath
|
||||
@@ -271,6 +287,7 @@ async function fetchData() {
|
||||
|
||||
// ── 公开方法 ──
|
||||
async function initialize() {
|
||||
dataRequestVersion++;
|
||||
dataModule.value = null;
|
||||
activeFields.value = [];
|
||||
activeFieldById.value = new Map();
|
||||
@@ -324,6 +341,56 @@ async function resetColumns() {
|
||||
if (tableRef.value) tableRef.value.resetColumns();
|
||||
}
|
||||
|
||||
async function saveColumnSettings() {
|
||||
if (loading.value || columnSaving.value || !tableRef.value) return;
|
||||
if (typeof tableRef.value.getColumnSettings !== "function") return;
|
||||
|
||||
const settings = tableRef.value.getColumnSettings();
|
||||
if (!settings.length) {
|
||||
message.info("当前没有可保存的栏位设置");
|
||||
return;
|
||||
}
|
||||
|
||||
const updates = [];
|
||||
for (const row of settings) {
|
||||
updates.push({
|
||||
b_id: row.b_id,
|
||||
b_xh: row.b_xh,
|
||||
b_width: row.b_width,
|
||||
});
|
||||
}
|
||||
|
||||
columnSaving.value = true;
|
||||
try {
|
||||
await saveObjectApi([
|
||||
{
|
||||
table: "s_module_field_list",
|
||||
key_field: "b_id",
|
||||
updates,
|
||||
},
|
||||
]);
|
||||
|
||||
const currentById = new Map();
|
||||
for (const row of listConfig.value) {
|
||||
currentById.set(String(row.b_id), row);
|
||||
}
|
||||
const savedListConfig = [];
|
||||
for (const saved of settings) {
|
||||
const current = currentById.get(String(saved.b_id));
|
||||
if (!current) continue;
|
||||
savedListConfig.push({ ...current, b_xh: saved.b_xh, b_width: saved.b_width });
|
||||
}
|
||||
listConfig.value = savedListConfig;
|
||||
message.success("栏位设置已保存");
|
||||
} catch (error) {
|
||||
let errorMessage = error;
|
||||
if (error && error.message) errorMessage = error.message;
|
||||
message.error("栏位设置保存失败:" + errorMessage);
|
||||
} finally {
|
||||
columnSaving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function resolveRowKey(row) {
|
||||
if (keyField.value) return row[keyField.value];
|
||||
return JSON.stringify(row);
|
||||
@@ -336,13 +403,26 @@ async function handleMoreAction({ key }) {
|
||||
}
|
||||
if (key === "reset-columns") {
|
||||
await resetColumns();
|
||||
message.success(appStore.t("common.columnsReset", "已恢复配置列宽"));
|
||||
message.success(appStore.t("common.columnSettingsReset", "已恢复栏位设置"));
|
||||
return;
|
||||
}
|
||||
if (key === "save-column-settings") {
|
||||
await saveColumnSettings();
|
||||
}
|
||||
}
|
||||
|
||||
// ── 生命周期 ──
|
||||
watch(() => [getDataCode(), route.path], initialize, { immediate: true });
|
||||
|
||||
watch(
|
||||
() => props.fixedSearchCondition,
|
||||
() => {
|
||||
if (!dataModule.value) return;
|
||||
pagination.current = 1;
|
||||
fetchData();
|
||||
},
|
||||
);
|
||||
|
||||
watch(
|
||||
() => dataSource.value,
|
||||
(rows) => {
|
||||
|
||||
@@ -37,7 +37,7 @@ const expansionOptions = computed(() =>
|
||||
const expandConfig = computed(() => ({ height: Number(expansionOptions.value.height) || 180 }));
|
||||
|
||||
function formatCellValue(value, field, optionInfo) {
|
||||
if (value === null || value === undefined || value === "") return "-";
|
||||
if (value === null || value === undefined || value === "") return "";
|
||||
if (field.b_type === "date") return formatDateValue(value, false);
|
||||
if (field.b_type === "datetime") return formatDateValue(value, true);
|
||||
if (field.b_type === "checkbox") {
|
||||
@@ -199,6 +199,35 @@ function resetColumns() {
|
||||
tableRef.value?.initVirtualScroll?.();
|
||||
}
|
||||
|
||||
function getColumnSettings() {
|
||||
const configByFieldId = new Map();
|
||||
for (const config of props.listConfig || []) {
|
||||
configByFieldId.set(String(config.b_field_id), config);
|
||||
}
|
||||
|
||||
const settings = [];
|
||||
let order = 10;
|
||||
for (const column of columns.value) {
|
||||
if (!column.dataIndex || String(column.dataIndex).startsWith("__")) continue;
|
||||
const field = props.fields.find((item) => item.b_field === column.dataIndex);
|
||||
if (!field) continue;
|
||||
const config = configByFieldId.get(String(field.b_id));
|
||||
if (!config) continue;
|
||||
const parsedWidth = Number.parseFloat(String(column.width));
|
||||
let columnWidth = config.b_width;
|
||||
if (Number.isFinite(parsedWidth) && parsedWidth > 0) {
|
||||
columnWidth = Math.round(parsedWidth);
|
||||
}
|
||||
settings.push({
|
||||
...config,
|
||||
b_xh: order,
|
||||
b_width: columnWidth,
|
||||
});
|
||||
order += 10;
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
|
||||
function handleCellClick(event, record, column, meta) {
|
||||
if (!column?.dataIndex || String(column.dataIndex).startsWith("__")) return;
|
||||
const field = props.fields.find((item) => item.b_field === column.dataIndex);
|
||||
@@ -251,7 +280,11 @@ watch(
|
||||
},
|
||||
);
|
||||
|
||||
defineExpose({ resetColumns, clearSelectedArea: () => tableRef.value?.clearSelectedArea?.() });
|
||||
defineExpose({
|
||||
resetColumns,
|
||||
getColumnSettings,
|
||||
clearSelectedArea: () => tableRef.value?.clearSelectedArea?.(),
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -226,7 +226,7 @@ watch(() => props.queryItems, initializeDrafts, { immediate: true });
|
||||
<Search :size="15" />
|
||||
{{ appStore.t("common.search", "查询") }}
|
||||
</a-button>
|
||||
<a-button :disabled="loading" @click="handleAdvancedReset">
|
||||
<a-button type="text" :disabled="loading" @click="handleAdvancedReset">
|
||||
<RotateCcw :size="15" />
|
||||
{{ appStore.t("common.reset", "重置") }}
|
||||
</a-button>
|
||||
|
||||
@@ -15,8 +15,10 @@ const props = defineProps({
|
||||
noDataFull: { type: Boolean, default: true },
|
||||
showOverflow: { type: Boolean, default: true },
|
||||
columns: { type: Array, default: () => [] },
|
||||
// 序号列:false=关闭;true=默认;{ title, width }=自定义
|
||||
seq: { type: [Boolean, Object], default: false },
|
||||
// 序号列默认显示;false=关闭;{ title, width }=自定义
|
||||
seq: { type: [Boolean, Object], default: true },
|
||||
// 列头拖拽默认开启;false=关闭;{ mode, disabled }=自定义
|
||||
columnDraggable: { type: [Boolean, Object], default: true },
|
||||
// 行多选:{ selectedRowKeys, onChange },提供时在最前列插入复选框列
|
||||
rowSelection: { type: Object, default: null },
|
||||
dataSource: { type: Array, default: () => [] },
|
||||
@@ -137,6 +139,27 @@ const seqConfig = computed(() => {
|
||||
width: Number(cfg.width ?? 50),
|
||||
};
|
||||
});
|
||||
const columnDragConfig = computed(() => {
|
||||
if (!props.columnDraggable) return false;
|
||||
const configured = props.columnDraggable === true ? {} : props.columnDraggable;
|
||||
return {
|
||||
...configured,
|
||||
disabled: (column) => {
|
||||
if (
|
||||
isSelectionColumn(column) ||
|
||||
column.type === "seq" ||
|
||||
column.type === "dragRow" ||
|
||||
column.type === "expand" ||
|
||||
column.dataIndex === "" ||
|
||||
column.dataIndex === "__actions__"
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
if (typeof configured.disabled === "function") return configured.disabled(column);
|
||||
return Boolean(configured.disabled);
|
||||
},
|
||||
};
|
||||
});
|
||||
const hasRowSelection = computed(() => Boolean(props.rowSelection));
|
||||
const dragRowColumn = {
|
||||
type: "dragRow",
|
||||
@@ -158,8 +181,6 @@ function getHeaderAlign(column) {
|
||||
|
||||
const displayColumns = computed(() => {
|
||||
const cols = props.columns.map((col) => resolveCustomCell(col, editingCtx));
|
||||
if (props.rowDraggable) cols.unshift(dragRowColumn);
|
||||
if (hasRowSelection.value) cols.unshift(selectionColumn);
|
||||
const seq = seqConfig.value;
|
||||
if (seq.enabled) {
|
||||
cols.unshift({
|
||||
@@ -170,6 +191,8 @@ const displayColumns = computed(() => {
|
||||
resizable: false,
|
||||
});
|
||||
}
|
||||
if (props.rowDraggable) cols.unshift(dragRowColumn);
|
||||
if (hasRowSelection.value) cols.unshift(selectionColumn);
|
||||
return cols.map((column) => ({
|
||||
...column,
|
||||
headerAlign: getHeaderAlign(column),
|
||||
@@ -435,6 +458,7 @@ defineExpose({
|
||||
:virtual-x="virtualX"
|
||||
:auto-resize="false"
|
||||
:col-resizable="colResizable"
|
||||
:header-drag="columnDragConfig"
|
||||
:columns="displayColumns"
|
||||
@update:columns="onColumnsUpdate"
|
||||
:data-source="dataSource"
|
||||
|
||||
Reference in new issue
Block a user