first commit

This commit is contained in:
2026-05-08 03:06:24 +08:00
commit 8da6567178
146 changed files with 82014 additions and 0 deletions
+28
View File
@@ -0,0 +1,28 @@
import { ref } from 'vue'
export function useModal() {
const isVisible = ref(false)
const modalData = ref(null)
const open = (data = null) => {
modalData.value = data
isVisible.value = true
}
const close = () => {
isVisible.value = false
modalData.value = null
}
const toggle = () => {
isVisible.value = !isVisible.value
}
return {
isVisible,
modalData,
open,
close,
toggle
}
}
+47
View File
@@ -0,0 +1,47 @@
import { ref, computed } from 'vue'
export function usePagination(items, pageSize = 10) {
const currentPage = ref(1)
const itemsPerPage = ref(pageSize)
const totalPages = computed(() => Math.ceil(items.value.length / itemsPerPage.value))
const paginatedItems = computed(() => {
const start = (currentPage.value - 1) * itemsPerPage.value
const end = start + itemsPerPage.value
return items.value.slice(start, end)
})
const goToPage = (page) => {
if (page >= 1 && page <= totalPages.value) {
currentPage.value = page
}
}
const nextPage = () => {
if (currentPage.value < totalPages.value) {
currentPage.value++
}
}
const prevPage = () => {
if (currentPage.value > 1) {
currentPage.value--
}
}
const resetPage = () => {
currentPage.value = 1
}
return {
currentPage,
itemsPerPage,
totalPages,
paginatedItems,
goToPage,
nextPage,
prevPage,
resetPage
}
}
+53
View File
@@ -0,0 +1,53 @@
import { ref, computed } from 'vue'
export function useSearch(items, searchFields = []) {
const searchQuery = ref('')
const statusFilter = ref('')
const sourceFilter = ref('')
const filteredItems = computed(() => {
let result = items.value
// 文本搜索
if (searchQuery.value.trim()) {
const query = searchQuery.value.toLowerCase()
result = result.filter(item => {
if (searchFields.length === 0) {
// 默认搜索所有字符串字段
return Object.values(item).some(val =>
String(val).toLowerCase().includes(query)
)
}
return searchFields.some(field =>
String(item[field]).toLowerCase().includes(query)
)
})
}
// 状态过滤
if (statusFilter.value) {
result = result.filter(item => item.status === statusFilter.value)
}
// 来源过滤
if (sourceFilter.value) {
result = result.filter(item => item.source === sourceFilter.value)
}
return result
})
const resetFilters = () => {
searchQuery.value = ''
statusFilter.value = ''
sourceFilter.value = ''
}
return {
searchQuery,
statusFilter,
sourceFilter,
filteredItems,
resetFilters
}
}
+31
View File
@@ -0,0 +1,31 @@
import { ref, readonly } from 'vue'
const toastMsg = ref('')
const toastClass = ref('')
let timer = null
export function useToast() {
function showToast(msg, type = 'info') {
if (timer) clearTimeout(timer)
toastMsg.value = msg
toastClass.value = 'show ' + type
timer = setTimeout(() => {
toastClass.value = ''
}, 3000)
}
function toastSuccess(msg) { showToast(msg, 'success') }
function toastError(msg) { showToast(msg, 'error') }
function toastInfo(msg) { showToast(msg, 'info') }
function toastWarning(msg) { showToast(msg, 'warning') }
return {
toastMsg: readonly(toastMsg),
toastClass: readonly(toastClass),
showToast,
toastSuccess,
toastError,
toastInfo,
toastWarning
}
}