Refactor code structure and remove redundant changes

This commit is contained in:
wangqiao
2025-08-15 16:45:15 +08:00
commit 99df1d1f81
220 changed files with 33086 additions and 0 deletions

133
utils/RefreshToken.ts Normal file
View File

@ -0,0 +1,133 @@
import axios, { AxiosRequestConfig, AxiosInstance, AxiosResponse } from 'axios'
import type { AppMemberUserInfoRespVO } from '@/api/common/types'
export type onRefreshTokenResponse = (data: AxiosResponse | boolean) => { token: string; refreshToken: string } | false
export type TRefreshTokenConstructorConfig = {
refreshTokenApiUrl: string
refreshTokenKey?: string
tokenKey?: string
axiosInstance: AxiosInstance
onRefreshTokenResponse: onRefreshTokenResponse
onRefreshTokenResquest?: () => {
config?: AxiosRequestConfig
data?: any
}
}
export default class RefreshToken {
static instance: RefreshToken
static SOTRAGE_REFRESH_TOKEN_KEY = 'kl-tk'
static SOTRAGE_TOKENKEY = 'kl-rfk'
static SOTRAGE_USERID = 'kl-userId'
static SOTRAGE_USERNAME = 'kl-userName'
static SOTRAGE_USERINFO = 'kl-userInfo'
private REFRESH_TOKEN_API_URL: string
public pending = false
private axios: AxiosInstance
public callbacks: any[] = []
private onRefreshTokenResponse: onRefreshTokenResponse
private onRefreshTokenResquest?: () => {
config?: AxiosRequestConfig
data?: any
}
protected constructor(config: TRefreshTokenConstructorConfig) {
RefreshToken.SOTRAGE_REFRESH_TOKEN_KEY = config?.refreshTokenKey || 'kl-tk'
RefreshToken.SOTRAGE_TOKENKEY = config?.refreshTokenKey || 'kl-rfk'
RefreshToken.SOTRAGE_USERID = config?.refreshTokenKey || 'kl-userId'
this.REFRESH_TOKEN_API_URL = config?.refreshTokenApiUrl || ''
this.axios = config.axiosInstance
this.onRefreshTokenResponse = config.onRefreshTokenResponse
this.onRefreshTokenResquest = config.onRefreshTokenResquest
}
static create(config: TRefreshTokenConstructorConfig) {
if (!RefreshToken.instance) {
RefreshToken.instance = new RefreshToken(config)
}
return RefreshToken.instance
}
// 设置token
setToken(token: string, refreshToken: string) {
window.localStorage.setItem(RefreshToken.SOTRAGE_TOKENKEY, token)
window.localStorage.setItem(RefreshToken.SOTRAGE_REFRESH_TOKEN_KEY, refreshToken)
}
// 清除token
removeToken() {
window.localStorage.removeItem(RefreshToken.SOTRAGE_TOKENKEY)
window.localStorage.removeItem(RefreshToken.SOTRAGE_REFRESH_TOKEN_KEY)
//清除token一起把userID也清除了
window.localStorage.removeItem(RefreshToken.SOTRAGE_USERID)
window.localStorage.removeItem(RefreshToken.SOTRAGE_USERNAME)
window.localStorage.removeItem(RefreshToken.SOTRAGE_USERINFO)
}
//设置userID
setUserId(userId: string) {
window.localStorage.setItem(RefreshToken.SOTRAGE_USERID, userId)
}
setUserName(userName: string) {
window.localStorage.setItem(RefreshToken.SOTRAGE_USERNAME, userName)
}
setUserInfo(userInfo: AppMemberUserInfoRespVO) {
window.localStorage.setItem(RefreshToken.SOTRAGE_USERINFO, JSON.stringify(userInfo))
}
// 获取token
getToken() {
const token = window.localStorage.getItem(RefreshToken.SOTRAGE_TOKENKEY) || ''
const refreshToken = window.localStorage.getItem(RefreshToken.SOTRAGE_REFRESH_TOKEN_KEY) || ''
const userId = window.localStorage.getItem(RefreshToken.SOTRAGE_USERID) || ''
const userName = window.localStorage.getItem(RefreshToken.SOTRAGE_USERNAME) || ''
const userInfo = window.localStorage.getItem(RefreshToken.SOTRAGE_USERINFO) || ''
return {
token,
refreshToken,
userId,
userName,
userInfo: userInfo ? JSON.parse(userInfo) : {},
}
}
// 刷新token
refresh() {
return new Promise<{ token: string; refreshToken: string } | boolean>((resolve) => {
this.pending = true
const config = (this.onRefreshTokenResquest && this.onRefreshTokenResquest()) || {}
axios
.post(this.REFRESH_TOKEN_API_URL, config.data || {}, config.config)
.then((res) => {
const ac = this.onRefreshTokenResponse(res)
if (ac) {
// 设置新的token
this.setToken(ac.token, ac.refreshToken)
resolve(ac)
return
}
resolve(false)
})
.catch((e) => {
console.log(e)
this.onRefreshTokenResponse(false)
resolve(false)
})
.finally(() => {
this.pending = false
})
})
}
// 推入刷新token成功 回调队列
pushCallbacks(config: AxiosRequestConfig) {
return new Promise((resolve) => {
this.callbacks.push(() => {
resolve(this.axios(config))
})
})
}
// 推出队列回调
releaseQueue() {
// const tokens = this.getToken()
this.callbacks.forEach((item) => {
item()
})
this.callbacks = []
}
}

View File

@ -0,0 +1,126 @@
export default class WebSocketWithHeartbeatAndReconnect {
private url: string
private socket: WebSocket | null
private heartbeatInterval: number
private pingMessage: string
private pongMessage: string
private reconnectInterval: number
private maxReconnectAttempts: number
private reconnectAttempts: number
private heartbeatTimer: any
private reconnectTimer: any
constructor(url: string, options = {} as any) {
this.url = url
this.socket = null
this.heartbeatInterval = options.heartbeatInterval || 30000 // 默认每 30 秒发送一次心跳
this.pingMessage = options.pingMessage || 'ping' // 默认 ping 消息
this.pongMessage = options.pongMessage || 'pong' // 默认 pong 消息
this.reconnectInterval = options.reconnectInterval || 5000 // 默认每 5 秒尝试重连
this.maxReconnectAttempts = options.maxReconnectAttempts || 5 // 最大重连次数
this.reconnectAttempts = 0 // 当前已尝试的重连次数
this.heartbeatTimer = null // 存储心跳定时器
this.reconnectTimer = null // 存储重连定时器
}
// 初始化 WebSocket 连接
connect() {
if (this.socket) {
this.socket.close() // 关闭现有连接
}
this.socket = new WebSocket(this.url)
// 连接成功时启动心跳
this.socket.onopen = () => {
console.log('WebSocket connected')
this.reconnectAttempts = 0 // 重置重连次数
this.startHeartbeat() // 启动心跳机制
}
// 接收到消息时
this.socket.onmessage = (event) => {
console.log('Received message:', event.data)
// 如果接收到 pong 消息,说明服务器回应了心跳
if (event.data === this.pongMessage) {
console.log('Pong received')
this.resetHeartbeat() // 重置心跳定时器
} else {
this.getMsg(event.data)
}
}
// 连接关闭时
this.socket.onclose = (event) => {
console.log('WebSocket closed:', event)
this.stopHeartbeat() // 停止心跳机制
this.handleReconnect() // 尝试重连
}
// 错误处理
this.socket.onerror = (error) => {
console.error('WebSocket error:', error)
this.socket?.close() // 在发生错误时关闭连接
}
}
// 启动心跳机制,定时发送 ping 消息
startHeartbeat() {
this.heartbeatTimer = setInterval(() => {
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
console.log('Sending ping...')
this.socket.send(this.pingMessage) // 发送 ping 消息
}
}, this.heartbeatInterval)
}
// 重置心跳机制
resetHeartbeat() {
clearInterval(this.heartbeatTimer) // 清除之前的心跳定时器
this.startHeartbeat() // 重新启动心跳定时器
}
// 停止心跳机制
stopHeartbeat() {
clearInterval(this.heartbeatTimer) // 清除心跳定时器
clearTimeout(this.reconnectTimer) // 清除重连定时器
}
// 处理重连机制
handleReconnect() {
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++
console.log(`Attempting to reconnect... (${this.reconnectAttempts}/${this.maxReconnectAttempts})`)
// 重连时延
this.reconnectTimer = setTimeout(() => {
this.connect() // 尝试重新连接
}, this.reconnectInterval)
} else {
console.log('Max reconnect attempts reached. Giving up.')
}
}
// 发送数据
send(message: string) {
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
this.socket.send(message)
console.log('Message sent:', message)
} else {
console.log('WebSocket is not open. Cannot send message.')
}
}
// 关闭连接
close() {
if (this.socket) {
this.socket.close()
console.log('WebSocket closed manually.')
}
}
// 接受到的数据
getMsg(val: string) {
console.log(val)
}
}

151
utils/axios.ts Normal file
View File

@ -0,0 +1,151 @@
import axios, { AxiosInstance, InternalAxiosRequestConfig, AxiosRequestConfig, AxiosResponse } from 'axios'
import qs from 'qs'
import useUserStore from '@/store/user'
import isPlainObject from 'lodash/isPlainObject'
import RefreshToken from './RefreshToken'
// 允许跨域
axios.defaults.headers.post['Access-Control-Allow-Origin-Type'] = '*'
const axiosInstance: AxiosInstance = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API,
timeout: 1200000,
})
// 自动刷新 token 实现
export const refreshToken = RefreshToken.create({
axiosInstance,
refreshTokenApiUrl: '',
onRefreshTokenResponse: (res: any) => {
if (res.data && (res?.data?.code === 0 || res?.data?.statusCode === '00000') && res.data.data) {
return {
token: res?.data?.data?.access_token || '',
refreshToken: res?.data?.data?.refresh_token || '',
}
}
const userStore = useUserStore()
userStore.logout()
return false
},
onRefreshTokenResquest() {
const tokens = refreshToken.getToken()
return {
data: {
refreshToken: tokens.refreshToken,
},
config: {
headers: {
refreshToken: tokens.refreshToken,
},
data: {
refreshToken: tokens.refreshToken,
},
},
}
},
})
// axios实例拦截响应
axiosInstance.interceptors.response.use(
(response: AxiosResponse) => {
//因为后端的有些接口没有statusCode这个状态码先这样判断吧
if (response.data.statusCode === '00000' || response.data.code === 0) {
return response.data
} else {
ElMessage.error(response.data.msg)
return response.data
}
},
(error) => {
let message = '系统异常'
const { status, config } = error.response
if (status === 401) {
if (refreshToken.pending) {
return refreshToken.pushCallbacks(config)
} else {
// 刷新token
refreshToken.refresh().then((refreshSuccess) => {
// 刷新成功 回调错误队列
if (refreshSuccess) {
refreshToken.releaseQueue()
} else {
return Promise.reject(error)
}
})
// 推入第一个401请求
return refreshToken.pushCallbacks(config)
}
} else if (status === 404) {
message = '接口地址有误'
} else if (status === 400) {
message = '参数有误,请确认参数是否正确'
}
ElMessage.error(message)
return Promise.reject(error)
}
)
// axios实例拦截请求
axiosInstance.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
config.headers['Accept-Language'] = 'zh-CN'
const tokens = refreshToken.getToken()
if (tokens !== null) {
config.headers['authorization'] = `Bearer ${tokens.token}`
config.headers['Refreshtoken'] = tokens.refreshToken
}
// 防止get请求缓存
if (config.method === 'get') {
config.params = {
...config.params,
...{ _t: new Date().getTime() },
}
}
if (isPlainObject(config.data)) {
// eslint-disable-next-line no-param-reassign
config.data = {
...config.data,
}
if (config.headers?.['content-type']) {
const contentType: string = config.headers['content-type'] + ''
if (/^application\/x-www-form-urlencoded/.test(contentType)) {
// form形式编码
config.data = qs.stringify(config.data)
}
}
}
return config
},
(error) => {
return Promise.reject(error)
}
)
const request = <T = any>(config: AxiosRequestConfig): Promise<T> => {
const conf = config
return new Promise((resolve, reject) => {
axiosInstance
.request<any, AxiosResponse<IResponse>>(conf)
.then((res: AxiosResponse<IResponse>) => {
const data: any = res
resolve(data as T)
})
.catch((error) => reject(error))
})
}
// 封装get
export function get<T = any>(config: AxiosRequestConfig): Promise<T> {
return request({ ...config, method: 'GET' })
}
// 封装delete
export function Delete<T = any>(config: AxiosRequestConfig): Promise<T> {
return request({ ...config, method: 'delete' })
}
// 封装put
export function put<T = any>(config: AxiosRequestConfig): Promise<T> {
return request({ ...config, method: 'put' })
}
// 封装post
export function post<T = any>(config: AxiosRequestConfig): Promise<T> {
return request({ ...config, method: 'POST' })
}
export default axiosInstance
export type { AxiosInstance, AxiosResponse }

24
utils/className.ts Normal file
View File

@ -0,0 +1,24 @@
/**
* 检查元素是否存在cls这个名字的class
* @private
*/
export function hasClass(obj: HTMLElement, cls: string) {
return obj.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
}
/**
* 为元素添加class
* @private
*/
export function addClass(obj: HTMLElement, cls: string) {
if (!hasClass(obj, cls)) obj.className += ' ' + cls
}
/**
* 删除元素中的class
* @private
*/
export function removeClass(obj: HTMLElement, cls: string) {
if (hasClass(obj, cls)) {
const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
obj.className = obj.className.replace(reg, ' ')
}
}

31
utils/login.ts Normal file
View File

@ -0,0 +1,31 @@
export const QQ_APP_ID = '102796005' // QQ appid
export const WECHAT_APP_ID = 'wxc2fa7aafa1649f7a' // 微信 appid
// 生成随机字符串
export const generateRandomString = (length: number) => {
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
let result = ''
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length))
}
return result
}
// QQ登录
export const handleLoginQQ = () => {
const appId = QQ_APP_ID // APP ID
const redirectUri = encodeURIComponent('https://tuxixi.net/index?type=35') // 回调地址
const state = generateRandomString(16) // 生成随机state
// 存储state用于后续验证
localStorage.setItem('qq_login_state', state)
window.location.href = `https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=${appId}&redirect_uri=${redirectUri}&state=${state}`
}
export const handleLoginWechat = () => {
const appId = WECHAT_APP_ID // APP ID
const redirectUri = encodeURIComponent('https://tuxixi.net?type=32') // 回调地址
const state = generateRandomString(16) // 生成随机state
// 存储state用于后续验证
localStorage.setItem('wechat_login_state', state)
window.location.href = `https://open.weixin.qq.com/connect/qrconnect?appid=${appId}&redirect_uri=${redirectUri}&response_type=code&scope=snsapi_login&state=${state}`
}

101
utils/mqttClient.ts Normal file
View File

@ -0,0 +1,101 @@
import mqtt, { MqttClient, IClientOptions } from 'mqtt'
// MQTT 配置
const defaultOptions: IClientOptions = {
clean: true,
connectTimeout: 4000,
clientId: 'vue3-client-' + Math.random().toString(16).substr(2, 8),
username: 'zbjk',
password: 'zbjk@123456',
// 移除 port 配置
// port: 8083,
reconnectPeriod: 1000, // 添加重连间隔
}
// MQTT 代理地址(示例使用公共测试服务器)
const brokerUrl = 'wss://www.tuxixi.net/mqtt'
export default class MQTTClient {
private client: MqttClient | null = null
private url: string
private options: IClientOptions
constructor(url: string, options = {} as any) {
this.client = null
this.url = url || brokerUrl
this.options = { ...defaultOptions, ...options }
}
connect(): void {
this.client = mqtt.connect(this.url, this.options)
// 连接成功
this.client.on('connect', () => {
console.log('MQTT Connected successfully')
})
// 连接关闭
this.client.on('close', () => {
console.log('MQTT Connection closed')
})
// 重连
this.client.on('reconnect', () => {
console.log('MQTT Attempting to reconnect...')
})
// 错误处理
this.client.on('error', (error: Error) => {
console.error('MQTT Error:', error)
console.error('Error details:', {
message: error.message,
stack: error.stack,
url: this.url,
options: this.options,
})
})
// 连接结束
this.client.on('end', () => {
console.log('MQTT Connection ended')
})
}
subscribe(topic: string): void {
if (!this.client) return
this.client.subscribe(topic, { qos: 0 }, (err?: any) => {
if (!err) console.log(`Subscribed to ${topic}`)
})
}
unsubscribe(topic: string): void {
if (!this.client) return
this.client.unsubscribe(topic, (err?: any) => {
if (!err) console.log(`Unsubscribed from ${topic}`)
})
}
// 接收消息处理
onMessage(callback: (topic: string, message: string) => void): void {
if (!this.client) return
this.client.on('message', (topic: string, message: Buffer) => {
console.log('接收消息---------', topic, message.toString())
callback(topic, message.toString())
})
}
// 发送消息
publish(topic: string, message: string): void {
if (!this.client) return
console.log('发送消息---------', topic, message)
this.client.publish(topic, message, { qos: 0 })
}
disconnect(): void {
this.client?.end()
}
}

11
utils/rem.ts Normal file
View File

@ -0,0 +1,11 @@
// 设置 rem 函数
function setRem() {
// 1920 默认大小16px; 1920px = 120rem ;每个元素px基础上/16
const screenWidth = 1920
const scale = screenWidth / 16
const htmlWidth = window.screen.width
// 得到html的Dom元素
const htmlDom = document.getElementsByTagName('html')[0]
// 设置根元素字体大小
htmlDom.style.fontSize = htmlWidth / scale + 'px'
}

81
utils/useMessage.ts Normal file
View File

@ -0,0 +1,81 @@
import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
export const useMessage = () => {
return {
// 消息提示
info(content: string) {
ElMessage.info(content)
},
// 错误消息
error(content: string) {
ElMessage.error(content)
},
// 成功消息
success(content: string) {
ElMessage.success(content)
},
// 警告消息
warning(content: string) {
ElMessage.warning(content)
},
// 弹出提示
alert(content: string, title: string) {
ElMessageBox.alert(content, title)
},
// 错误提示
alertError(content: string, title: string) {
ElMessageBox.alert(content, title, { type: 'error' })
},
// 成功提示
alertSuccess(content: string, title: string) {
ElMessageBox.alert(content, title, { type: 'success' })
},
// 警告提示
alertWarning(content: string, title: string) {
ElMessageBox.alert(content, title, { type: 'warning' })
},
// 通知提示
notify(content: string) {
ElNotification.info(content)
},
// 错误通知
notifyError(content: string) {
ElNotification.error(content)
},
// 成功通知
notifySuccess(content: string) {
ElNotification.success(content)
},
// 警告通知
notifyWarning(content: string) {
ElNotification.warning(content)
},
// 确认窗体
confirm(content: string, title?: string, options?: any) {
return ElMessageBox.confirm(content, title, {
type: 'warning',
...options,
})
},
// 删除窗体
delConfirm(content?: string, title?: string, options?: any) {
return ElMessageBox.confirm(content, title, {
type: 'warning',
...options,
})
},
// 导出窗体
exportConfirm(content?: string, title?: string, options?: any) {
return ElMessageBox.confirm(content, title, {
type: 'warning',
...options,
})
},
// 提交内容
prompt(content: string, title: string, options?: any) {
return ElMessageBox.prompt(content, title, {
type: 'warning',
...options,
})
},
}
}

98
utils/utils.ts Normal file
View File

@ -0,0 +1,98 @@
import Decimal from 'decimal.js'
/**
* 加法计算
* @param param1 当前值number或string
* @param param2 当前值number或string
* @param num 保留小数位数默认小数2位
* @param mode 舍入模式1 向上取2 向下取3 四舍五入默认3
* @returns 返回处理后的数据
*/
export function accAdd(param1: number | string, param2: number | string, num = 2, mode = 3) {
if (param1 === null || param1 === undefined || param1 === '') return param1
if (param2 === null || param2 === undefined || param2 === '') return param2
const temp = new Decimal(param1).add(new Decimal(param2))
if (mode === 1) return temp.toFixed(num, Decimal.ROUND_UP)
else if (mode === 2) return temp.toFixed(num, Decimal.ROUND_DOWN)
else return temp.toFixed(num, Decimal.ROUND_HALF_UP)
}
/**
* 减法计算
* @param param1 当前值number或string
* @param param2 当前值number或string
* @param num 保留小数位数默认小数2位
* @param mode 舍入模式1 向上取2 向下取3 四舍五入默认3
* @returns 返回处理后的数据
*/
export function accSub(param1: number | string, param2: number | string, num = 2, mode = 3) {
if (param1 === null || param1 === undefined || param1 === '') return param1
if (param2 === null || param2 === undefined || param2 === '') return param2
const temp = new Decimal(param1).sub(new Decimal(param2))
if (mode === 1) return temp.toFixed(num, Decimal.ROUND_UP)
else if (mode === 2) return temp.toFixed(num, Decimal.ROUND_DOWN)
else return temp.toFixed(num, Decimal.ROUND_HALF_UP)
}
/**
* 乘法计算
* @param param1 当前值number或string
* @param param2 当前值number或string
* @param num 保留小数位数默认小数2位
* @param mode 舍入模式1 向上取2 向下取3 四舍五入默认3
* @returns 返回处理后的数据
*/
export function accMul(param1: number | string, param2: number | string, num = 2, mode = 3) {
if (param1 === null || param1 === undefined || param1 === '') return param1
if (param2 === null || param2 === undefined || param2 === '') return param2
const temp = new Decimal(param1).mul(new Decimal(param2))
if (mode === 1) return temp.toFixed(num, Decimal.ROUND_UP)
else if (mode === 2) return temp.toFixed(num, Decimal.ROUND_DOWN)
else return temp.toFixed(num, Decimal.ROUND_HALF_UP)
}
/**
* 除法计算
* @param param1 当前值number或string
* @param param2 当前值number或string
* @param num 保留小数位数默认小数2位
* @param mode 舍入模式1 向上取2 向下取3 四舍五入默认3
* @returns 返回处理后的数据
*/
export function accDiv(param1: number | string, param2: number | string, num = 2, mode = 3) {
if (param1 === null || param1 === undefined || param1 === '') return param1
if (param2 === null || param2 === undefined || param2 === '' || param2.toString() === '0') return param2
const temp = new Decimal(param1).div(new Decimal(param2))
if (mode === 1) return temp.toFixed(num, Decimal.ROUND_UP)
else if (mode === 2) return temp.toFixed(num, Decimal.ROUND_DOWN)
else return temp.toFixed(num, Decimal.ROUND_HALF_UP)
}
/**
* 数字格式化千分位显示
* @param decimals 保留小数位数, 传-1则表示 原数字有小数则保留两位小数,原数字没小数则为整数
* @returns 返回处理后的数据字符串
*/
export const formatNumber = (value?: number, decimals = 0) => {
if (!value) return 0
if (decimals === -1) {
decimals = value % 1 === 0 ? 0 : 2
}
return new Intl.NumberFormat('zh-CN', {
minimumFractionDigits: decimals,
maximumFractionDigits: decimals,
}).format(value)
}
/***
* 下载文件
* @param url 文件地址
* @param filename 文件名
*/
export const downloadFile = (url: string, filename: string) => {
const a = document.createElement('a')
a.href = url
a.download = filename || 'download' // 设置下载的文件名
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
}

58
utils/validate.ts Normal file
View File

@ -0,0 +1,58 @@
/**
* 只能输入汉字或字母或数字
* @param {} arg
* @returns {Boolean}
*/
export function textInputValidate(value?: string) {
if (!value) return ''
return value.replace(/[^\u4E00-\u9FA5A-Za-z0-9]/gi, '')
}
/**
* 只能输入小数或整数(不可以负数)
* @param val 当前值number或string
* @returns 返回处理后的
*/
export function verifyNumberIntegerAndFloat<T = string>(val?: number | string) {
if (!val) {
if (typeof val === 'string') return val as T
else return undefined
}
// 匹配空格
let v = val.toString().replace(/(^\s*)|(\s*$)/g, '')
// 只能是数字和小数点,不能是其他输入
v = v.replace(/[^\d.]/g, '')
// 以0开始只能输入一个
v = v.replace(/^0{2}$/g, '0')
// 保证第一位只能是数字,不能是点
v = v.replace(/^\./g, '')
// 小数只能出现1位
v = v.replace('.', '$#$').replace(/\./g, '').replace('$#$', '.')
// 小数点后面保留2位
v = v.replace(/^(-)*(\d+)\.(\d\d).*$/, '$1$2.$3')
// 返回结果
return v as T
}
/**
* 只能输入正整数
* @param val 当前值number或string
* @returns 返回处理后的
*/
export function verifiyNumberInteger<T = string>(val?: number | string) {
if (!val) {
if (typeof val === 'string') return val as T
else return undefined
}
// 匹配空格
let v = val.toString().replace(/(^\s*)|(\s*$)/g, '')
// 去掉 '.' , 防止贴贴的时候出现问题 如 0.1.12.12
v = v.replace(/[.]*/g, '')
// 去掉以 0 开始后面的数, 防止贴贴的时候出现问题 如 00121323
v = v.replace(/(^0[\d]*)$/g, '0')
// 首位是0,只能出现一次
v = v.replace(/^0\d$/g, '0')
// 只匹配数字
v = v.replace(/[^\d]/g, '')
// 返回结果
return v as T
}