Initial commit: gmTouringMiniApp project

This commit is contained in:
周瑞哲
2026-07-30 16:04:34 +08:00
commit ebcae02d35
201 changed files with 49545 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
import { isNumber } from '@pmun/utils'
import dayjs from 'dayjs'
import customParseFormat from 'dayjs/plugin/customParseFormat'
// 导入本地化语言
import 'dayjs/locale/zh-cn'
dayjs.locale('zh-cn')
dayjs.extend(customParseFormat)
export type dayJsDate = string | number | Date
// 判断时间戳是否毫秒
export function isMillisecondTimestamp(value: dayJsDate) {
if (typeof value !== 'number' || value.toString().length !== 13)
return false
const date = new Date(value)
return !Number.isNaN(date.getTime())
}
// 转换为 dayjs 接收参数
export function convertToDayjsParam(value: dayJsDate) {
if (!isMillisecondTimestamp(value) && isNumber(value))
return value * 1000
return value
}
export function stringFormat(date: string, format: string) {
return dayjs(date, format)
}
export function formatCalendar(date: dayJsDate) {
return formatTime(date, 'MM-DD')
}
export function formatTime(date?: dayJsDate, format = 'YYYY-MM-DD') {
if (!date)
return ''
return dayjs(convertToDayjsParam(date)).format(format)
}
// 将时间戳格式化成完整的时间字符串
export function formatFullTime(date?: dayJsDate) {
return formatTime(date, 'YYYY年MM月DD日 HH:mm:ss')
}
export function diffDate(start: dayJsDate, end: dayJsDate, unit: dayjs.OpUnitType = 'day') {
return dayjs(convertToDayjsParam(start)).diff(dayjs(convertToDayjsParam(end)), unit)
}
// 获取今天和明天的日期
export function getTodayAndTomorrow(template = 'YYYY-MM-DD') {
const today = dayjs().format(template)
const tomorrow = dayjs().add(1, 'day').format(template)
return { today, tomorrow }
}
+39
View File
@@ -0,0 +1,39 @@
/**
* @description: Development mode
*/
export const devMode = 'development'
/**
* @description: Production mode
*/
export const prodMode = 'production'
/**
* @description: Get environment variables
* @returns:
* @example:
*/
export function getEnv(): string {
return import.meta.env.MODE
}
export function getHttpUrl(): string {
return import.meta.env.VITE_HTTP_URL
}
/**
* @description: Is it a development mode
* @returns:
* @example:
*/
export function isDevMode(): boolean {
return getEnv() === 'development'
}
/**
* @description: Is it a production mode
* @returns:
* @example:
*/
export function isProdMode(): boolean {
return getEnv() === 'production'
}
+26
View File
@@ -0,0 +1,26 @@
// 防抖函数(debounce)。优化处理频繁触发的事件(如键盘输入、窗口大小调整等)时。与节流函数类似,防抖函数通过延迟执行来减少函数调用的频率,但它的工作方式略有不同:防抖函数会在事件停止触发后的一段时间才执行函数,如果在这段时间内事件再次被触发,则重新计时。
export function debounce<T extends (...args: any[]) => void>(
func: T,
wait: number = 500,
immediate: boolean = false,
): (...args: Parameters<T>) => void {
let timeoutId: ReturnType<typeof setTimeout> | null = null
return function (this: ThisParameterType<T>, ...args: Parameters<T>) {
const later = () => {
timeoutId = null
if (!immediate)
func.apply(this as ThisParameterType<T>, args)
}
const shouldCallNow = immediate && timeoutId === null
if (timeoutId !== null)
clearTimeout(timeoutId)
timeoutId = setTimeout(later, wait)
if (shouldCallNow)
func.apply(this, args)
}
}
+2
View File
@@ -0,0 +1,2 @@
export * from './debounce'
export * from './throttle'
+29
View File
@@ -0,0 +1,29 @@
// throttle(节流)。优化处理频繁触发的事件(例如窗口的 resize、scroll 事件或者是键盘事件等)。其核心思想是在一定时间内,不管你触发了多少次回调,我都只执行一次。
export function throttle<T extends (...args: any[]) => any>(
func: T,
wait: number = 500,
immediate: boolean = true,
): (...args: Parameters<T>) => void {
let timeout: ReturnType<typeof setTimeout> | null = null
let initialCall = true
return function (this: ThisParameterType<T>, ...args: Parameters<T>) {
const callNow = immediate && initialCall
const next = () => {
func.apply(this as ThisParameterType<T>, args)
timeout = null
}
if (callNow) {
initialCall = false
next()
}
if (!timeout) {
timeout = setTimeout(() => {
initialCall = true // Reset initial call for the next debounce delay
next()
}, wait)
}
}
}
+5
View File
@@ -0,0 +1,5 @@
export * from './dayjs'
export * from './env'
export * from './functions'
export * from './uniTools'
export * from './validate'
+1
View File
@@ -0,0 +1 @@
export * from './ui'
+34
View File
@@ -0,0 +1,34 @@
import { isString } from '@pmun/utils'
export function showToast(options: UniNamespace.ShowToastOptions | string) {
let {
title = '',
icon = 'none',
duration = 2000,
} = options as UniNamespace.ShowToastOptions
if (isString(options))
title = options
uni.showToast({
title,
icon,
duration,
})
}
export function showModal({ title = '提示', content, showCancel = true, cancelColor, confirmColor }: UniNamespace.ShowModalOptions = {}): Promise<void> {
return new Promise((resolve, reject) => {
uni.showModal({
title,
content,
showCancel,
cancelColor,
confirmColor,
success(res) {
if (res.confirm)
resolve()
else if (res.cancel)
reject(new Error('用户取消弹窗'))
},
})
})
}
+44
View File
@@ -0,0 +1,44 @@
import type { ComputedRef, Ref } from 'vue'
import { showToast } from '@/utils/uniTools'
interface Rule {
required?: boolean | Ref<boolean> | ComputedRef<boolean>
min?: number
max?: number
pattern?: string
message: string
}
interface ValidateCb {
(bool: boolean, value?: any): void
}
// 表单校验
export function validate(form: Record<string, any>, rules: Record<string, Rule[]>, cb: ValidateCb) {
// 循环 form
for (const key in form) {
const value = form[key]
const rule = rules[key]
// 如果有校验规则
if (rule) {
for (const r of rule) {
if (
(unref(r.required) && !value)
|| (r.min && value.length < r.min)
|| (r.max && value.length > r.max)
|| (r.pattern && !new RegExp(r.pattern).test(value))
) {
return failValidate(r.message, cb, value, key)
}
}
}
}
return cb(true)
}
export function failValidate(msg: string, cb: ValidateCb, value?: any, key?: string) {
const content = msg || `${key}验证不通过`
console.error(content)
showToast(content)
cb(false, value)
}