260720
This commit is contained in:
@@ -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
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user