20260809223428

This commit is contained in:
oneao committed 2026-08-09 22:34:28 +08:00
1 parent d72ca4193d
commit c4891538a7
466 files changed
+21000 -3339

No files matched your search

@@ -0,0 +1,127 @@
import { onBeforeUnmount, ref, watch } from "vue";
import { useTimeoutFn } from "@vueuse/core";
import { pageDataApi } from "@/services/api";
function escapeSearchText(value) {
return String(value).replaceAll("'", "''");
}
function combineConditions(baseCondition, searchCondition) {
if (!baseCondition) return searchCondition;
if (!searchCondition) return baseCondition;
return `(${baseCondition}) AND (${searchCondition})`;
}
export function useLookupOptions(props) {
const rows = ref([]);
const loading = ref(false);
const pageNo = ref(0);
const total = ref(0);
const query = ref("");
let requestId = 0;
async function load(searchText = query.value, append = false) {
if (!props.viewName) return;
const currentRequestId = ++requestId;
const requestedPage = append ? pageNo.value + 1 : 1;
const normalizedSearchText = String(searchText ?? "").trim();
const searchFilter = normalizedSearchText
? `${props.labelKey} LIKE '%${escapeSearchText(normalizedSearchText)}%'`
: "";
loading.value = true;
try {
const response = await pageDataApi({
viewName: props.viewName,
orderBy: props.orderBy || props.labelKey,
searchColumns: props.searchColumns.length ? props.searchColumns : undefined,
searchCondition: combineConditions(props.searchCondition, searchFilter),
pageNo: requestedPage,
pageSize: props.pageSize,
});
if (currentRequestId !== requestId) return;
const result = response.data ?? {};
const nextRows = Array.isArray(result.rows) ? result.rows : [];
rows.value = append ? [...rows.value, ...nextRows] : nextRows;
pageNo.value = Number(result.page_no) || requestedPage;
total.value = Number(result.total ?? result.row_count) || 0;
query.value = normalizedSearchText;
} catch {
if (currentRequestId === requestId && !append) {
rows.value = [];
pageNo.value = 0;
total.value = 0;
}
} finally {
if (currentRequestId === requestId) loading.value = false;
}
}
const { start: startSearchTimer, stop: stopSearchTimer } = useTimeoutFn(
(searchText) => load(searchText),
() => props.searchDelay,
{ immediate: false },
);
const { start: startResetTimer, stop: stopResetTimer } = useTimeoutFn(reset, 200, {
immediate: false,
});
function search(value) {
stopResetTimer();
const searchText = String(value ?? "");
query.value = searchText;
requestId += 1;
loading.value = false;
startSearchTimer(searchText);
}
function open() {
stopResetTimer();
if (!rows.value.length && !loading.value) load(query.value);
}
function reset() {
stopSearchTimer();
stopResetTimer();
requestId += 1;
rows.value = [];
loading.value = false;
pageNo.value = 0;
total.value = 0;
query.value = "";
}
function resetAfterClose() {
startResetTimer();
}
function loadMore() {
if (loading.value || rows.value.length >= total.value) return;
load(query.value, true);
}
function onPopupScroll(event) {
const target = event.currentTarget || event.target;
if (target.scrollTop + target.clientHeight >= target.scrollHeight - 24) loadMore();
}
watch(
() => [
props.viewName,
props.labelKey,
props.valueKey,
props.orderBy,
props.searchCondition,
props.searchColumns,
],
reset,
);
onBeforeUnmount(reset);
return { rows, loading, query, load, search, open, resetAfterClose, onPopupScroll };
}