feat(common): ✨ 添加工具
This commit is contained in:
@@ -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,
|
||||
};
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user