feat: add web application

This commit is contained in:
richjohnrambo
2026-10-10 20:55:59 +08:00
parent 3eb5d78875
commit 50fcfd2d3d
571 changed files with 73992 additions and 135 deletions
+8
View File
@@ -0,0 +1,8 @@
import useContext from './useContext';
import useBoolean from './useBoolean';
import useLoading from './useLoading';
import useLoadingEmpty from './useLoadingEmpty';
import useSendCode from './useSendCode';
import useSorter from './useSorter';
export { useContext, useBoolean, useLoading, useLoadingEmpty, useSendCode, useSorter };
+26
View File
@@ -0,0 +1,26 @@
import { ref } from 'vue';
export default function useBoolean(initValue = false) {
const bool = ref(initValue);
function setBool(value: boolean) {
bool.value = value;
}
function setTrue() {
setBool(true);
}
function setFalse() {
setBool(false);
}
function toggle() {
setBool(!bool.value);
}
return {
bool,
setBool,
setTrue,
setFalse,
toggle,
};
}
+20
View File
@@ -0,0 +1,20 @@
import { inject, provide } from 'vue';
import type { InjectionKey } from 'vue';
export default function useContext<T>(contextName = 'context') {
const injectKey: InjectionKey<T> = Symbol(contextName);
function useProvide(context: T) {
provide(injectKey, context);
return context;
}
function useInject() {
return inject(injectKey) as T;
}
return {
useProvide,
useInject,
};
}
+54
View File
@@ -0,0 +1,54 @@
import { computed, onScopeDispose, ref } from 'vue';
import useBoolean from './useBoolean';
/**
* 倒计时
* @param second - 倒计时的时间(s)
*/
export default function useCountDown(second: number) {
if (second <= 0 && second % 1 !== 0) {
throw new Error('倒计时的时间应该为一个正整数!');
}
const { bool: isComplete, setTrue, setFalse } = useBoolean(false);
const counts = ref(0);
const isCounting = computed(() => Boolean(counts.value));
let intervalId: any;
/**
* 开始计时
* @param updateSecond - 更改初时传入的倒计时时间
*/
function start(updateSecond: number = second) {
if (!counts.value) {
setFalse();
counts.value = updateSecond;
intervalId = setInterval(() => {
counts.value -= 1;
if (counts.value <= 0) {
clearInterval(intervalId);
setTrue();
}
}, 1000);
}
}
/**
* 停止计时
*/
function stop() {
intervalId = clearInterval(intervalId);
counts.value = 0;
}
onScopeDispose(stop);
return {
counts,
isCounting,
start,
stop,
isComplete,
};
}
+11
View File
@@ -0,0 +1,11 @@
import useBoolean from './useBoolean';
export default function useLoading(initValue = false) {
const { bool: loading, setTrue: startLoading, setFalse: endLoading } = useBoolean(initValue);
return {
loading,
startLoading,
endLoading,
};
}
+14
View File
@@ -0,0 +1,14 @@
import useBoolean from './useBoolean';
export default function useLoadingEmpty(initLoading = false, initEmpty = false) {
const { bool: loading, setTrue: startLoading, setFalse: endLoading } = useBoolean(initLoading);
const { bool: empty, setBool: setEmpty } = useBoolean(initEmpty);
return {
loading,
startLoading,
endLoading,
empty,
setEmpty,
};
}
+43
View File
@@ -0,0 +1,43 @@
import { computed } from 'vue';
import useLoading from './useLoading';
import useCountDown from './useCountDown';
export default function useSmsCode() {
const { loading, startLoading, endLoading } = useLoading();
const { counts, start, isCounting } = useCountDown(60);
const initLabel = '获取验证码';
const countingLabel = (second: number) => `重新获取(${second})`;
const sendLabel = computed(() => {
let text = initLabel;
if (loading.value) {
text = '';
}
if (isCounting.value) {
text = countingLabel(counts.value);
}
return text;
});
/**
* 激活发送
*/
function activateSend(request: Promise<any>) {
startLoading();
request
.then((_res) => {
window['$message']?.success('验证码发送成功!');
start();
})
.finally(() => {
endLoading();
});
}
return {
sendLabel,
start,
isCounting,
activateSend,
loading,
};
}
+40
View File
@@ -0,0 +1,40 @@
import { ref } from 'vue';
import { DataTableSortState } from 'naive-ui';
import { SorterMultiple } from 'naive-ui/es/data-table/src/interface';
export default function useSorter(callback: Function = function () {}) {
const sortStatesRef = ref<DataTableSortState[]>([]);
function updateSorter(sorter: DataTableSortState | DataTableSortState[] | null) {
if (sorter === null) {
// 默认排序
sortStatesRef.value = [];
} else if (Array.isArray(sorter)) {
// 多字段排序
sortStatesRef.value = filterMultipleSorters(sorter);
} else {
// 单字段排序
sortStatesRef.value = [];
sortStatesRef.value.push(sorter);
}
callback();
}
// 多字段排序,将不参与排序的字段过滤掉,再根据设置的优先级对排序器重新排列
function filterMultipleSorters(sorters: DataTableSortState[]): DataTableSortState[] {
const filter = sorters.filter((item) => item.order !== false);
return filter.sort((a, b) => {
if (typeof a.sorter === 'object' && typeof b.sorter === 'object') {
const aSorter = a.sorter as SorterMultiple;
const bSorter = b.sorter as SorterMultiple;
return bSorter.multiple - aSorter.multiple;
}
return 0;
});
}
return {
updateSorter,
sortStatesRef,
};
}