This commit is contained in:
2026-07-20 11:50:47 +08:00
parent 95d43746f6
commit 019ed28d37
401 changed files with 61622 additions and 23869 deletions
+311
View File
@@ -0,0 +1,311 @@
import { ref } from 'vue';
import { listDictData } from '@/api/system/dict-data';
import { listCollege } from '@/api/gxmu/college';
import { listClassInfo } from '@/api/gxmu/class';
import type { ClassInfo } from '@/api/gxmu/class/model';
export interface SelectOption {
label: string;
value: string;
}
export interface ClassCascaderOption {
label: string;
value: string;
children?: ClassCascaderOption[];
}
export interface ClassCascadeSelection {
classId?: number;
className: string;
collegeId?: number;
collegeName: string;
path: string[];
combinedLabel: string;
}
const NATION_DICT_ID = 173;
const POLITICS_DICT_ID = 172;
const genderOptions: SelectOption[] = [
{ label: '男', value: '男' },
{ label: '女', value: '女' }
];
let nationCache: SelectOption[] | null = null;
let politicsCache: SelectOption[] | null = null;
let collegeCache: SelectOption[] | null = null;
let classCache: SelectOption[] | null = null;
let classCascaderCache: ClassCascaderOption[] | null = null;
let classCascadeSelectionCache: ClassCascadeSelection[] | null = null;
const normalizeOptions = (values: string[]) =>
values
.map((item) => item.trim())
.filter((item, index, arr) => !!item && arr.indexOf(item) === index)
.map((item) => ({
label: item,
value: item
}));
const normalizeText = (value?: string) =>
String(value || '')
.trim()
.replace(/[\/|,,、]+/g, ' ')
.replace(/\s+/g, ' ');
const compactText = (value?: string) =>
normalizeText(value).replace(/\s+/g, '').toLowerCase();
const buildCombinedLabel = (collegeName?: string, className?: string) =>
[String(collegeName || '').trim(), String(className || '').trim()]
.filter(Boolean)
.join(' ');
const buildClassCascadeData = (list: ClassInfo[]) => {
const collegeMap = new Map<string, ClassCascaderOption>();
const classSelections: ClassCascadeSelection[] = [];
list.forEach((item, index) => {
const className = String(item.className || '').trim();
const collegeName = String(item.collegeName || '').trim();
if (!className || !collegeName) {
return;
}
const collegeValue = `college:${
item.collegeId ?? `${collegeName}:${index}`
}`;
const classValue = `class:${
item.id ?? `${collegeValue}:${className}:${index}`
}`;
let collegeOption = collegeMap.get(collegeValue);
if (!collegeOption) {
collegeOption = {
label: collegeName,
value: collegeValue,
children: []
};
collegeMap.set(collegeValue, collegeOption);
}
if (
!collegeOption.children?.some(
(child) => child.label === className && child.value === classValue
)
) {
collegeOption.children?.push({
label: className,
value: classValue
});
}
classSelections.push({
classId: item.id,
className,
collegeId: item.collegeId,
collegeName,
path: [collegeValue, classValue],
combinedLabel: buildCombinedLabel(collegeName, className)
});
});
return {
classOptions: normalizeOptions(
classSelections.map((item) => item.className)
),
cascaderOptions: Array.from(collegeMap.values()).filter(
(item) => item.children?.length
),
classSelections
};
};
const ensureClassDataLoaded = async () => {
if (classCache && classCascaderCache && classCascadeSelectionCache) {
return;
}
const list = await listClassInfo({ status: 1, limit: 1000 });
const { classOptions, cascaderOptions, classSelections } =
buildClassCascadeData(list);
classCache = classOptions;
classCascaderCache = cascaderOptions;
classCascadeSelectionCache = classSelections;
};
export const filterSelectOption = (input: string, option: SelectOption) => {
return String(option?.label || '')
.toLowerCase()
.includes(input.toLowerCase());
};
export const useGxmuFormSelectOptions = () => {
const loading = ref(false);
const loaded = ref(false);
const nationOptions = ref<SelectOption[]>(nationCache ?? []);
const politicsOptions = ref<SelectOption[]>(politicsCache ?? []);
const collegeOptions = ref<SelectOption[]>(collegeCache ?? []);
const classOptions = ref<SelectOption[]>(classCache ?? []);
const classCascaderOptions = ref<ClassCascaderOption[]>(
classCascaderCache ?? []
);
const loadNationOptions = async () => {
if (nationCache) {
nationOptions.value = nationCache;
return nationCache;
}
const result = await listDictData({ dictId: NATION_DICT_ID });
nationCache = result
.filter((item) => !!item.dictDataName)
.map((item) => ({
label: String(item.dictDataName),
value: String(item.dictDataName)
}));
nationOptions.value = nationCache;
return nationCache;
};
const loadCollegeOptions = async () => {
if (collegeCache) {
collegeOptions.value = collegeCache;
return collegeCache;
}
const list = await listCollege({ status: 1, limit: 500 });
collegeCache = normalizeOptions(
list.map((item) => item.collegeName || item.shortName || '')
);
collegeOptions.value = collegeCache;
return collegeCache;
};
const loadPoliticsOptions = async () => {
if (politicsCache) {
politicsOptions.value = politicsCache;
return politicsCache;
}
const result = await listDictData({ dictId: POLITICS_DICT_ID });
politicsCache = result
.filter((item) => !!item.dictDataName)
.map((item) => ({
label: String(item.dictDataName),
value: String(item.dictDataName)
}));
politicsOptions.value = politicsCache;
return politicsCache;
};
const loadClassOptions = async () => {
if (classCache) {
classOptions.value = classCache;
return classCache;
}
await ensureClassDataLoaded();
classOptions.value = classCache;
return classCache;
};
const loadClassCascaderOptions = async () => {
if (classCascaderCache) {
classCascaderOptions.value = classCascaderCache;
return classCascaderCache;
}
await ensureClassDataLoaded();
classCascaderOptions.value = classCascaderCache;
return classCascaderCache;
};
const findClassCascadeSelection = (
value?: string,
mode: 'class' | 'collegeClass' = 'class'
) => {
const source = classCascadeSelectionCache ?? [];
const normalizedValue = normalizeText(value);
const compactValue = compactText(value);
if (!normalizedValue) {
return void 0;
}
if (mode === 'collegeClass') {
return (
source.find(
(item) => normalizeText(item.combinedLabel) === normalizedValue
) ??
source.find(
(item) => compactText(item.combinedLabel) === compactValue
) ??
source.find((item) => {
return (
compactValue.includes(compactText(item.collegeName)) &&
compactValue.includes(compactText(item.className))
);
})
);
}
return (
source.find(
(item) => normalizeText(item.className) === normalizedValue
) ??
source.find((item) => compactText(item.className) === compactValue) ??
source.find(
(item) => normalizeText(item.combinedLabel) === normalizedValue
) ??
source.find((item) => compactText(item.combinedLabel) === compactValue)
);
};
const getClassCascadeSelectionByPath = (path?: string[]) => {
if (!path?.length) {
return void 0;
}
const key = path.join('>');
return (classCascadeSelectionCache ?? []).find(
(item) => item.path.join('>') === key
);
};
const loadAll = async () => {
if (loaded.value) {
return;
}
loading.value = true;
try {
await Promise.all([
loadNationOptions(),
loadPoliticsOptions(),
loadCollegeOptions(),
loadClassOptions(),
loadClassCascaderOptions()
]);
loaded.value = true;
} finally {
loading.value = false;
}
};
return {
loading,
loaded,
genderOptions,
nationOptions,
politicsOptions,
collegeOptions,
classOptions,
classCascaderOptions,
loadAll,
loadNationOptions,
loadPoliticsOptions,
loadCollegeOptions,
loadClassOptions,
loadClassCascaderOptions,
findClassCascadeSelection,
getClassCascadeSelectionByPath,
buildCombinedLabel
};
};