feat(common): 添加工具

This commit is contained in:
2026-04-20 17:54:26 +08:00
parent 7ff223fa32
commit b10d613987
64 changed files with 8342 additions and 16243 deletions
+120
View File
@@ -0,0 +1,120 @@
/*
* @file /src/hooks/list.ts
* @description
* @author tsl (randy1924@163.com)
* @date 2026-03-19 11:11:11
* @lastModified 2026-03-20 10:43:38
* @lastModifiedBy tsl (randy1924@163.com)
*/
import { ref, computed } from "vue";
/**
* 列表加载状态类型
*/
export type LoadStatus = "loadmore" | "loading" | "nomore";
/**
* 列表加载更多Hook
* @param fetchFunction 获取数据的函数
* @param options 配置选项
* @returns 列表相关数据和方法
*/
export function useLoadMore(
fetchFunction: (
pageNum: number,
pageSize: number,
) => Promise<{ total: number; list: unknown[] }>,
options = {
pageSize: 10,
},
) {
// 数据列表 - 确保初始化为空数组而不是undefined
const list = ref<unknown[]>([]);
// 分页和加载状态
const pageNum = ref(1);
const pageSize = ref(options.pageSize);
const status = ref<LoadStatus>("loadmore");
const total = ref(0);
const isLoading = computed(() => status.value === "loading");
const isFinished = computed(() => status.value === "nomore");
const isEmpty = computed(() => total.value === 0);
/**
* 初始化列表,重置数据并加载第一页
*/
const initList = async () => {
list.value = []; // 重置为空数组
pageNum.value = 1;
status.value = "loadmore";
return loadMore();
};
/**
* 加载更多数据
*/
const loadMore = async () => {
// 如果当前不是可加载状态,则直接返回
if (status.value !== "loadmore") {
return;
}
try {
// 先设置状态,再请求数据
status.value = "loading";
// 调用传入的获取数据函数
const response = await fetchFunction(pageNum.value, pageSize.value);
// 确保response.list是数组
const responseList = response.list || [];
// 更新数据,确保list.value总是数组
if (pageNum.value === 1) {
list.value = [...responseList];
} else {
// 确保数据正确合并
list.value = [...list.value, ...responseList];
}
total.value = response.total || 0;
pageNum.value++;
// 只有当列表长度确实达到或超过总数,或者当前页返回空数据时,才设置为nomore
if (
list.value.length >= (response.total || 0) ||
responseList.length === 0
) {
status.value = "nomore";
} else {
status.value = "loadmore";
}
} catch (err) {
console.error("加载数据失败:", err);
// 出错时立即恢复为可加载状态
status.value = "loadmore";
}
};
/**
* 刷新列表
*/
const refresh = () => {
return initList();
};
return {
list,
total,
pageNum,
pageSize,
status,
isLoading,
isFinished,
isEmpty,
loadMore,
initList,
refresh,
};
}
+115
View File
@@ -0,0 +1,115 @@
import { getValueOfRule } from "@r-utils/common";
import { ref, computed, toRef } from "vue";
import type { InputOptions, InputValue } from "@r-utils/common";
import type { Ref } from "vue";
/**
* 倒计时工具
* @param initTime 初始时间,秒
*/
export function useTimer(initTime = 0) {
const time = ref(initTime);
const timeInterval = ref();
const start = () => {
timeInterval.value = setInterval(() => {
if (time.value <= 0) {
clearInterval(timeInterval.value);
return;
}
time.value--;
}, 1000);
};
const restart = () => {
time.value = initTime;
start();
};
const stop = () => {
time.value = 0;
clearInterval(timeInterval.value);
};
return { time, start, restart, timeInterval, stop };
}
type UseNumberSetFn = (v: string | number) => string | number;
const defaultUseNumberSetFn: UseNumberSetFn = (v: string | number) => String(v);
/**
* 把响应式变量转为数字输出
* @param value 要监听的值
* @param setFn 在监听值改变时,处理函数
*/
export function useNumber(
value: Ref<string | number>,
setFn: UseNumberSetFn = defaultUseNumberSetFn,
) {
const int = computed<number>({
// 总是返回整数
get: () => Number.parseInt(String(value.value)),
set: (v) => {
value.value = setFn(v);
},
});
const float = computed<number>({
// 总是返回 float
get: () => Number.parseFloat(String(value.value)),
set: (v) => {
value.value = setFn(v);
},
});
const number = computed<number>({
// 总是返回 Number
get: () => Number(value.value),
set: (v) => {
value.value = setFn(v);
},
});
return { number, int, float };
}
/**
* 监听一个响应式变量,转为字符串输出
* @param value 要监听的值
*/
export function useString(value: Ref<string | number>) {
const string = computed<string>({
get: () => String(value.value),
set: (v) => {
value.value = v;
},
});
return { string };
}
interface UseValueOfRuleOptions {
value: InputValue | Ref<InputValue>;
rule: InputOptions;
}
/**
* 按自定义规则转换数字或文本
* @param options
*/
export function useValueOfRule(options: UseValueOfRuleOptions) {
const value = toRef(options.value);
const rule = toRef(options.rule);
function handleChange() {
const newValue = getValueOfRule(value.value, rule.value);
value.value = newValue;
}
return {
value,
rule,
handleChange,
};
}