🧹 清理重复配置文件
- 删除根目录中重复的 NestJS 配置文件 - 删除 tsconfig.json, tsconfig.build.json, eslint.config.mjs, .prettierrc - 保留 wwjcloud-nest/ 目录中的完整配置 - 避免配置冲突,确保项目结构清晰
This commit is contained in:
402
admin-vben/src/utils/common.ts
Normal file
402
admin-vben/src/utils/common.ts
Normal file
@@ -0,0 +1,402 @@
|
||||
import type { App } from 'vue'
|
||||
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
||||
import { useCssVar, useTitle } from '@vueuse/core'
|
||||
import colorFunction from 'css-color-function'
|
||||
import storage from './storage'
|
||||
|
||||
/**
|
||||
* 全局注册element-icon
|
||||
* @param app
|
||||
*/
|
||||
export function useElementIcon(app: App): void {
|
||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||
app.component(key, component)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置主题色
|
||||
*/
|
||||
export function setThemeColor(color: string, mode: string = 'light'): void {
|
||||
useCssVar('--el-color-primary', null).value = color
|
||||
|
||||
const colors: any = {
|
||||
dark: {
|
||||
'light-3': 'shade(20%)',
|
||||
'light-5': 'shade(30%)',
|
||||
'light-7': 'shade(50%)',
|
||||
'light-8': 'shade(60%)',
|
||||
'light-9': 'shade(70%)',
|
||||
'dark-2': 'tint(20%)'
|
||||
},
|
||||
light: {
|
||||
'dark-2': 'shade(20%)',
|
||||
'light-3': 'tint(30%)',
|
||||
'light-5': 'tint(50%)',
|
||||
'light-7': 'tint(70%)',
|
||||
'light-8': 'tint(80%)',
|
||||
'light-9': 'tint(90%)'
|
||||
}
|
||||
}
|
||||
|
||||
Object.keys(colors[mode]).forEach((key) => {
|
||||
useCssVar('--el-color-primary' + '-' + key, null).value = colorFunction.convert(`color(${ color } ${ colors[mode][key] })`)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前访问应用类型
|
||||
*/
|
||||
export function getAppType() {
|
||||
const path = location.pathname.split('/').filter((val) => {
|
||||
return val
|
||||
})
|
||||
|
||||
if (!path.length) {
|
||||
return 'admin'
|
||||
} else {
|
||||
return path[0]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置网站 title
|
||||
* @param value
|
||||
*/
|
||||
export function setWindowTitle(value: string = ''): void {
|
||||
const title = useTitle()
|
||||
title.value = value ? value : import.meta.env.VITE_DETAULT_TITLE
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取token
|
||||
* @returns
|
||||
*/
|
||||
export function getToken(): null | string {
|
||||
return storage.get('token')
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置token
|
||||
* @param token
|
||||
* @returns
|
||||
*/
|
||||
export function setToken(token: string): void {
|
||||
storage.set({ key: 'token', data: token })
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除token
|
||||
* @returns
|
||||
*/
|
||||
export function removeToken(): void {
|
||||
storage.remove('token')
|
||||
}
|
||||
|
||||
/**
|
||||
* 防抖函数
|
||||
* @param fn
|
||||
* @param delay
|
||||
* @returns
|
||||
*/
|
||||
export function debounce(fn: (args?: any) => any, delay: number = 300) {
|
||||
let timer: null | number = null
|
||||
return function (...args) {
|
||||
if (timer != null) {
|
||||
clearTimeout(timer)
|
||||
timer = null
|
||||
}
|
||||
timer = setTimeout(() => {
|
||||
fn.call(this, ...args)
|
||||
}, delay);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是url
|
||||
* @param str
|
||||
* @returns
|
||||
*/
|
||||
export function isUrl(str: string): boolean {
|
||||
return str.indexOf('http://') != -1 || str.indexOf('https://') != -1
|
||||
}
|
||||
|
||||
/**
|
||||
* 图片输出
|
||||
* @param path
|
||||
* @returns
|
||||
*/
|
||||
export function img(path: string): string {
|
||||
let imgDomain = import.meta.env.VITE_IMG_DOMAIN || location.origin
|
||||
|
||||
if (typeof path == 'string' && path.startsWith('/')) path = path.replace(/^\//, '')
|
||||
if (typeof imgDomain == 'string' && imgDomain.endsWith('/')) imgDomain = imgDomain.slice(0, -1)
|
||||
|
||||
return isUrl(path) ? path : `${imgDomain}/${path}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出asset img
|
||||
* @param path
|
||||
* @returns
|
||||
*/
|
||||
export function assetImg(path: string) {
|
||||
return new URL('@/', import.meta.url) + path
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字符串字节长度
|
||||
* @param str
|
||||
* @returns
|
||||
*/
|
||||
export function strByteLength(str: string = ''): number {
|
||||
let len = 0;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
if (str.charCodeAt(i) > 127 || str.charCodeAt(i) == 94) {
|
||||
len += 2;
|
||||
} else {
|
||||
len++;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* url 转 route
|
||||
* @param url
|
||||
*/
|
||||
export function urlToRouteRaw(url: string) {
|
||||
const query: any = {}
|
||||
const [path, param] = url.split('?')
|
||||
|
||||
param && param.split('&').forEach((str: string) => {
|
||||
let [name, value] = str.split('=')
|
||||
query[name] = value
|
||||
})
|
||||
|
||||
return { path, query }
|
||||
}
|
||||
|
||||
const isArray = (value: any) => {
|
||||
if (typeof Array.isArray === 'function') {
|
||||
return Array.isArray(value)
|
||||
}
|
||||
return Object.prototype.toString.call(value) === '[object Array]'
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 深度克隆
|
||||
* @param {object} obj 需要深度克隆的对象
|
||||
* @returns {*} 克隆后的对象或者原值(不是对象)
|
||||
*/
|
||||
export function deepClone(obj: object) {
|
||||
// 对常见的“非”值,直接返回原来值
|
||||
if ([null, undefined, NaN, false].includes(obj)) return obj
|
||||
if (typeof obj !== 'object' && typeof obj !== 'function') {
|
||||
// 原始类型直接返回
|
||||
return obj
|
||||
}
|
||||
const o = isArray(obj) ? [] : {}
|
||||
for (const i in obj) {
|
||||
if (obj.hasOwnProperty(i)) {
|
||||
o[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i]
|
||||
}
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成唯一字符
|
||||
* @param {Number} len
|
||||
* @param {Boolean} firstU
|
||||
* @param {Number} radix
|
||||
*/
|
||||
export function guid(len = 10, firstU = true, radix: any = null) {
|
||||
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')
|
||||
const uuid = []
|
||||
radix = radix || chars.length
|
||||
|
||||
if (len) {
|
||||
// 如果指定uuid长度,只是取随机的字符,0|x为位运算,能去掉x的小数位,返回整数位
|
||||
for (let i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix]
|
||||
} else {
|
||||
let r
|
||||
// rfc4122标准要求返回的uuid中,某些位为固定的字符
|
||||
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'
|
||||
uuid[14] = '4'
|
||||
|
||||
for (let i = 0; i < 36; i++) {
|
||||
if (!uuid[i]) {
|
||||
r = 0 | Math.random() * 16
|
||||
uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]
|
||||
}
|
||||
}
|
||||
}
|
||||
// 移除第一个字符,并用u替代,因为第一个字符为数值时,该guuid不能用作id或者class
|
||||
if (firstU) {
|
||||
uuid.shift()
|
||||
return `u${ uuid.join('') }`
|
||||
}
|
||||
return uuid.join('')
|
||||
}
|
||||
|
||||
/**
|
||||
* 金额格式化
|
||||
*/
|
||||
export function moneyFormat(money: string): string {
|
||||
return isNaN(parseFloat(money)) ? money : parseFloat(money).toFixed(2)
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间戳转日期格式
|
||||
*/
|
||||
export function timeStampTurnTime(timeStamp: any, type = "") {
|
||||
if (timeStamp != undefined && timeStamp != "" && timeStamp > 0) {
|
||||
const date = new Date();
|
||||
date.setTime(timeStamp * 1000);
|
||||
const y: any = date.getFullYear();
|
||||
let m: any = date.getMonth() + 1;
|
||||
m = m < 10 ? ('0' + m) : m;
|
||||
let d: any = date.getDate();
|
||||
d = d < 10 ? ('0' + d) : d;
|
||||
let h: any = date.getHours();
|
||||
h = h < 10 ? ('0' + h) : h;
|
||||
let minute: any = date.getMinutes();
|
||||
let second: any = date.getSeconds();
|
||||
minute = minute < 10 ? ('0' + minute) : minute;
|
||||
second = second < 10 ? ('0' + second) : second;
|
||||
if (type) {
|
||||
if (type == 'yearMonthDay') {
|
||||
return y + '年' + m + '月' + d + '日';
|
||||
}
|
||||
return y + '-' + m + '-' + d;
|
||||
} else {
|
||||
return y + '-' + m + '-' + d + ' ' + h + ':' + minute + ':' + second;
|
||||
}
|
||||
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日期时间
|
||||
*/
|
||||
export function getCurrentDataTime(timeStamp: any) {
|
||||
const addZero = (t) => {
|
||||
return t < 10 ? '0' + t : t;
|
||||
}
|
||||
const time = new Date(timeStamp);
|
||||
let Y = time.getFullYear(), // 年
|
||||
M = time.getMonth() + 1, // 月
|
||||
D = time.getDate(), // 日
|
||||
h = time.getHours(), // 时
|
||||
m = time.getMinutes(), // 分
|
||||
s = time.getSeconds(); // 秒
|
||||
if (M > 12) {
|
||||
M = M - 12;
|
||||
}
|
||||
return `${Y}-${addZero(M)}-${addZero(D)} ${addZero(h)}:${addZero(m)}:${addZero(s)}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期格式转时间戳
|
||||
* @param {Object} date
|
||||
*/
|
||||
export function timeTurnTimeStamp(date: string) {
|
||||
const f = date.split(' ', 2);
|
||||
const d = (f[0] ? f[0] : '').split('-', 3);
|
||||
const t = (f[1] ? f[1] : '').split(':', 3);
|
||||
return (new Date(
|
||||
parseInt(d[0], 10) || null,
|
||||
(parseInt(d[1], 10) || 1) - 1,
|
||||
parseInt(d[2], 10) || null,
|
||||
parseInt(t[0], 10) || null,
|
||||
parseInt(t[1], 10) || null,
|
||||
parseInt(t[2], 10) || null
|
||||
)).getTime() / 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤小数点(保留两位)
|
||||
* @param event
|
||||
*/
|
||||
export function filterDigit(event: any) {
|
||||
event.target.value = event.target.value.replace(/[^\d\.]/g, '');
|
||||
event.target.value = event.target.value.replace(/^\./g, '');
|
||||
event.target.value = event.target.value.replace(/\.{2,}/g, '.');
|
||||
// 限制最多两位小数
|
||||
const decimalParts = event.target.value.split('.');
|
||||
if (decimalParts.length > 1 && decimalParts[1].length > 2) {
|
||||
// 如果有小数部分且超过两位,则截取前两位
|
||||
event.target.value = `${ decimalParts[0] }.${ decimalParts[1].slice(0, 2) }`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤整数
|
||||
* @param event
|
||||
*/
|
||||
export function filterNumber(event: any) {
|
||||
event.target.value = event.target.value.replace(/[^\d]/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤特殊字符
|
||||
* @param event
|
||||
*/
|
||||
export function filterSpecial(event: any) {
|
||||
event.target.value = event.target.value.replace(/[^\u4e00-\u9fa5a-zA-Z0-9]/g, '')
|
||||
event.target.value = event.target.value.replace(/[`~!@#$%^&*()_\-+=<>?:"{}|,.\/;'\\[\]·~!@#¥%……&*()——\-+={}|《》?:“”【】、;‘’,。、]/g, '')
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤空格
|
||||
* @param event
|
||||
*/
|
||||
export function filterBlank(event: any) {
|
||||
event.target.value = event.target.value.replace(/\s/g, '');
|
||||
}
|
||||
/**
|
||||
* 设置表格分页数据的本地存储
|
||||
* @param page
|
||||
* @param limit
|
||||
* @param where
|
||||
*/
|
||||
export function setTablePageStorage(page: any = 1, limit: any = 10, where: any = {}) {
|
||||
let data = storage.get('tablePageStorage');
|
||||
if (!data) {
|
||||
data = {};
|
||||
}
|
||||
|
||||
const key = location.pathname + JSON.stringify(where);
|
||||
data[key] = {
|
||||
page,
|
||||
limit
|
||||
};
|
||||
|
||||
const MAX_COUNT = 5; // 最多存储 5 个页面的分页缓存,超出则删除最开始的第一个页面
|
||||
if (Object.keys(data).length > MAX_COUNT) {
|
||||
delete data[Object.keys(data)[0]];
|
||||
}
|
||||
|
||||
storage.set({ key: 'tablePageStorage', data });
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取表格分页数据的本地存储
|
||||
* @param where
|
||||
*/
|
||||
export function getTablePageStorage(where: any = {}) {
|
||||
let data = storage.get('tablePageStorage');
|
||||
const key = location.pathname + JSON.stringify(where);
|
||||
if (!data || !data[key]) {
|
||||
data = {
|
||||
page: 1,
|
||||
limit: 10
|
||||
};
|
||||
} else {
|
||||
data = data[key];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
28
admin-vben/src/utils/directives.ts
Normal file
28
admin-vben/src/utils/directives.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
|
||||
const permission = {
|
||||
mounted(el: HTMLElement, binding: any) {
|
||||
const { value: permission } = binding;
|
||||
const userStore = useUserStore()
|
||||
const rules = userStore.rules
|
||||
let isHavePermission = true
|
||||
|
||||
if (typeof permission == 'string') {
|
||||
isHavePermission = rules.includes(permission)
|
||||
} else if (Array.isArray(permission)) {
|
||||
isHavePermission = permission.every(element => rules.includes(element))
|
||||
}
|
||||
|
||||
// 如果没有权限,则隐藏按钮
|
||||
if (!isHavePermission) el.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册自定义指令
|
||||
*/
|
||||
export default {
|
||||
install(app: any) {
|
||||
app.directive('permission', permission)
|
||||
}
|
||||
};
|
||||
224
admin-vben/src/utils/lodop.ts
Normal file
224
admin-vben/src/utils/lodop.ts
Normal file
@@ -0,0 +1,224 @@
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { ref } from 'vue'
|
||||
|
||||
// Web打印服务CLodop/Lodop7
|
||||
|
||||
// 用双端口加载主JS文件Lodop.js(或CLodopfuncs.js兼容老版本)以防其中某端口被占:
|
||||
const MainJS = "CLodopfuncs.js";
|
||||
const URL_WS1: any = ref("ws://localhost:{port}/" + MainJS); // ws用8000/18000
|
||||
const URL_WS2: any = ref("ws://localhost:{port}/" + MainJS);
|
||||
const URL_HTTP1: any = ref("http://localhost:{port}/" + MainJS); // http用8000/18000
|
||||
const URL_HTTP2: any = ref("http://localhost:{port}/" + MainJS);
|
||||
const URL_HTTP3: any = ref("https://localhost.lodop.net:{port}/" + MainJS); // https用8000/8443
|
||||
|
||||
const CreatedOKLodopObject: any = ref(null);
|
||||
const CLodopIsLocal: any = ref(null);
|
||||
const LoadJsState: any = ref('');
|
||||
|
||||
const initPort = (paramas: any) => {
|
||||
if (!paramas) {
|
||||
paramas = {
|
||||
server_port1: 8000,
|
||||
server_port2: 18000,
|
||||
https_port: 8443
|
||||
};
|
||||
}
|
||||
URL_WS1.value = URL_WS1.value.replace('{port}', paramas.server_port1);
|
||||
URL_WS2.value = URL_WS2.value.replace('{port}', paramas.server_port2);
|
||||
|
||||
URL_HTTP1.value = URL_HTTP1.value.replace('{port}', paramas.server_port1);
|
||||
URL_HTTP2.value = URL_HTTP2.value.replace('{port}', paramas.server_port2);
|
||||
|
||||
URL_HTTP3.value = URL_HTTP2.value.replace('{port}', paramas.https_port);
|
||||
|
||||
}
|
||||
|
||||
//==判断是否需要CLodop(那些不支持插件的浏览器):==
|
||||
const needCLodop = () => {
|
||||
try {
|
||||
let ua = navigator.userAgent;
|
||||
if (ua.match(/Windows\sPhone/i) ||
|
||||
ua.match(/iPhone|iPod|iPad/i) ||
|
||||
ua.match(/Android/i) ||
|
||||
ua.match(/Edge\D?\d+/i))
|
||||
return true;
|
||||
let verTrident = ua.match(/Trident\D?\d+/i);
|
||||
let verIE = ua.match(/MSIE\D?\d+/i);
|
||||
let verOPR: any = ua.match(/OPR\D?\d+/i);
|
||||
let verFF: any = ua.match(/Firefox\D?\d+/i);
|
||||
let x64 = ua.match(/x64/i);
|
||||
if ((!verTrident) && (!verIE) && (x64)) return true;
|
||||
else if (verFF) {
|
||||
verFF = verFF[0].match(/\d+/);
|
||||
if ((verFF[0] >= 41) || (x64)) return true;
|
||||
} else if (verOPR) {
|
||||
verOPR = verOPR[0].match(/\d+/);
|
||||
if (verOPR[0] >= 32) return true;
|
||||
} else if ((!verTrident) && (!verIE)) {
|
||||
let verChrome: any = ua.match(/Chrome\D?\d+/i);
|
||||
if (verChrome) {
|
||||
verChrome = verChrome[0].match(/\d+/);
|
||||
if (verChrome[0] >= 41) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch (err) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// ==检查加载成功与否,如没成功则用http(s)再试==
|
||||
// ==低版本CLODOP6.561/Lodop7.043及前)用本方法==
|
||||
function checkOrTryHttp() {
|
||||
if (window.getCLodop) {
|
||||
LoadJsState.value = "complete";
|
||||
return true;
|
||||
}
|
||||
if (LoadJsState.value == "loadingB" || LoadJsState.value == "complete") return;
|
||||
LoadJsState.value = "loadingB";
|
||||
let head = document.head || document.getElementsByTagName("head")[0] || document.documentElement;
|
||||
let JS1 = document.createElement("script")
|
||||
, JS2 = document.createElement("script")
|
||||
, JS3 = document.createElement("script");
|
||||
JS1.src = URL_HTTP1.value;
|
||||
JS2.src = URL_HTTP2.value;
|
||||
JS3.src = URL_HTTP3.value;
|
||||
JS1.onload = JS2.onload = JS3.onload = JS2.onerror = JS3.onerror = function () {
|
||||
LoadJsState.value = "complete";
|
||||
};
|
||||
JS1.onerror = function (e) {
|
||||
if (window.location.protocol !== 'https:') {
|
||||
head.insertBefore(JS2, head.firstChild);
|
||||
} else {
|
||||
head.insertBefore(JS3, head.firstChild);
|
||||
}
|
||||
};
|
||||
head.insertBefore(JS1, head.firstChild);
|
||||
}
|
||||
|
||||
// ==加载Lodop对象的主过程:==
|
||||
const loadCLodop = (paramas: any = null) => {
|
||||
if (!needCLodop()) return;
|
||||
|
||||
initPort(paramas);
|
||||
|
||||
CLodopIsLocal.value = !!((URL_WS1.value + URL_WS2.value).match(/\/\/localho|\/\/127.0.0./i));
|
||||
LoadJsState.value = "loadingA";
|
||||
if (!window.WebSocket && window.MozWebSocket) window.WebSocket = window.MozWebSocket;
|
||||
//ws方式速度快(小于200ms)且可避免CORS错误,但要求Lodop版本足够新:
|
||||
try {
|
||||
let WSK1 = new WebSocket(URL_WS1.value);
|
||||
WSK1.onopen = function (e) {
|
||||
setTimeout(checkOrTryHttp, 200);
|
||||
};
|
||||
WSK1.onmessage = function (e) {
|
||||
if (!window.getCLodop) eval(e.data);
|
||||
};
|
||||
WSK1.onerror = function (e) {
|
||||
let WSK2 = new WebSocket(URL_WS2.value);
|
||||
WSK2.onopen = function (e) {
|
||||
setTimeout(checkOrTryHttp, 200);
|
||||
};
|
||||
WSK2.onmessage = function (e) {
|
||||
if (!window.getCLodop) eval(e.data);
|
||||
};
|
||||
WSK2.onerror = function (e) {
|
||||
checkOrTryHttp();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
checkOrTryHttp();
|
||||
}
|
||||
};
|
||||
|
||||
//==获取LODOP对象主过程,判断是否安装、需否升级:==
|
||||
const getLodop = (oOBJECT = null, oEMBED = null) => {
|
||||
let strFontTag = "<br>打印控件";
|
||||
let strLodopInstall = strFontTag + "未安装!点击这里<a href='http://www.lodop.net/download.html' target='_blank' class='text-primary'>执行安装</a>";
|
||||
let strLodopUpdate = strFontTag + "需要升级!点击这里<a href='http://www.lodop.net/download.html' target='_blank' class='text-primary'>执行升级</a>";
|
||||
let strCLodopInstallA = "<br>Web打印服务CLodop未安装启动,点击这里<a href='http://www.lodop.net/download.html' target='_blank' class='text-primary'>下载执行安装</a>";
|
||||
let strCLodopInstallB = "<br>(若此前已安装过,可<a href='CLodop.protocol:setup' target='_blank' class='text-primary'>点这里直接再次启动</a>)";
|
||||
let strCLodopUpdate = "<br>Web打印服务CLodop需升级!点击这里<a href='http://www.lodop.net/download.html' target='_blank' class='text-primary'>执行升级</a>";
|
||||
let strLodop7FontTag = "<br>Web打印服务Lodop7";
|
||||
let strLodop7HrefX86 = "点击这里<a href='http://www.lodop.net/download.html' target='_blank' class='text-primary'>下载安装</a>(下载后解压,点击lodop文件开始执行)";
|
||||
let strLodop7Install_X86 = strLodop7FontTag + "未安装启动," + strLodop7HrefX86;
|
||||
let strLodop7Update_X86 = strLodop7FontTag + "需升级," + strLodop7HrefX86;
|
||||
let strInstallOK = ",成功后请刷新本页面或重启浏览器。";
|
||||
let LODOP;
|
||||
try {
|
||||
let isWinIE = (/MSIE/i.test(navigator.userAgent)) || (/Trident/i.test(navigator.userAgent));
|
||||
let isLinuxX86 = (/Linux/i.test(navigator.platform)) && (/x86/i.test(navigator.platform));
|
||||
let isLinuxARM = (/Linux/i.test(navigator.platform)) && (/aarch/i.test(navigator.platform));
|
||||
|
||||
if (needCLodop() || isLinuxX86 || isLinuxARM) {
|
||||
try {
|
||||
LODOP = window.getCLodop();
|
||||
} catch (err) {
|
||||
}
|
||||
if (!LODOP && LoadJsState.value !== "complete") {
|
||||
if (!LoadJsState.value) {
|
||||
ElMessageBox.alert('未曾加载Lodop主JS文件,请先调用loadCLodop过程', '提示', { dangerouslyUseHTMLString: true, })
|
||||
} else {
|
||||
ElMessageBox.alert('网页还没下载完毕,请稍等一下再操作', '提示', { dangerouslyUseHTMLString: true, })
|
||||
}
|
||||
return;
|
||||
}
|
||||
let strAlertMessage;
|
||||
if (!LODOP) {
|
||||
if (isLinuxX86 || isLinuxARM)
|
||||
strAlertMessage = strLodop7Install_X86;
|
||||
else
|
||||
strAlertMessage = strCLodopInstallA + (CLodopIsLocal.value ? strCLodopInstallB : "");
|
||||
|
||||
ElMessageBox.alert(strAlertMessage + strInstallOK, '提示', { dangerouslyUseHTMLString: true, })
|
||||
return;
|
||||
} else {
|
||||
if ((isLinuxX86 || isLinuxARM) && LODOP.CVERSION < "7.0.7.5")
|
||||
strAlertMessage = strLodop7Update_X86;
|
||||
else if (CLODOP.CVERSION < "6.5.9.8")
|
||||
strAlertMessage = strCLodopUpdate;
|
||||
|
||||
if (strAlertMessage) {
|
||||
ElMessageBox.alert(strAlertMessage + strInstallOK, '提示', { dangerouslyUseHTMLString: true, })
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//==如果页面有Lodop插件就直接使用,否则新建:==
|
||||
if (oOBJECT || oEMBED) {
|
||||
if (isWinIE) LODOP = oOBJECT;
|
||||
else LODOP = oEMBED;
|
||||
} else if (!CreatedOKLodopObject.value) {
|
||||
LODOP = document.createElement("object");
|
||||
LODOP.setAttribute("width", 0);
|
||||
LODOP.setAttribute("height", 0);
|
||||
LODOP.setAttribute("style", "position:absolute;left:0px;top:-100px;width:0px;height:0px;");
|
||||
if (isWinIE) LODOP.setAttribute("classid", "clsid:2105C259-1E0C-4534-8141-A753534CB4CA");
|
||||
else LODOP.setAttribute("type", "application/x-print-lodop");
|
||||
document.documentElement.appendChild(LODOP);
|
||||
CreatedOKLodopObject.value = LODOP;
|
||||
} else
|
||||
LODOP = CreatedOKLodopObject.value;
|
||||
//==Lodop插件未安装时提示下载地址:==
|
||||
if ((!LODOP) || (!LODOP.VERSION)) {
|
||||
ElMessageBox.alert(strLodopInstall + strInstallOK, '提示', { dangerouslyUseHTMLString: true, })
|
||||
return LODOP;
|
||||
}
|
||||
if (LODOP.VERSION < "6.2.2.6") {
|
||||
ElMessageBox.alert(strLodopUpdate + strInstallOK, '提示', { dangerouslyUseHTMLString: true, })
|
||||
}
|
||||
}
|
||||
|
||||
//===如下空白位置适合调用统一功能(如注册语句、语言选择等):=======================
|
||||
|
||||
//===============================================================================
|
||||
return LODOP;
|
||||
} catch (err) {
|
||||
ElMessage({
|
||||
message: "getLodop出错:" + err,
|
||||
type: 'error',
|
||||
duration: 5000
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
export { loadCLodop, getLodop }
|
||||
182
admin-vben/src/utils/qqmap.ts
Normal file
182
admin-vben/src/utils/qqmap.ts
Normal file
@@ -0,0 +1,182 @@
|
||||
import { jsonp } from 'vue-jsonp'
|
||||
|
||||
const geometry: any = {}
|
||||
|
||||
/**
|
||||
* 在地图上创建一个圆形
|
||||
*/
|
||||
export const createCircle = (map: any, geometriesData: any) => {
|
||||
const TMap = (window as any).TMap
|
||||
const LatLng = TMap.LatLng
|
||||
|
||||
geometriesData.radius = geometriesData.radius ?? 1000
|
||||
geometriesData.center = geometriesData.center ?? { lat: map.getCenter().lat, lng: map.getCenter().lng }
|
||||
|
||||
const color = [
|
||||
Math.floor(Math.random() * 255),
|
||||
Math.floor(Math.random() * 255),
|
||||
Math.floor(Math.random() * 255)
|
||||
]
|
||||
|
||||
// 创建图形
|
||||
const multiCircle = new TMap.MultiCircle({
|
||||
map,
|
||||
styles: { // 设置圆形样式
|
||||
circle: new TMap.CircleStyle({
|
||||
color: `rgba(${color.toString()}, .4)`,
|
||||
showBorder: true,
|
||||
borderColor: `rgb(${color.toString()})`,
|
||||
borderWidth: 2
|
||||
})
|
||||
},
|
||||
geometries: [
|
||||
{
|
||||
styleId: 'circle',
|
||||
center: new LatLng(geometriesData.center.lat, geometriesData.center.lng),
|
||||
radius: parseInt(geometriesData.radius),
|
||||
id: geometriesData.key
|
||||
}
|
||||
]
|
||||
})
|
||||
geometry[geometriesData.key] = { graphical: multiCircle }
|
||||
|
||||
// 创建图形编辑器
|
||||
const editor = new TMap.tools.GeometryEditor({
|
||||
map: map,
|
||||
overlayList: [
|
||||
{
|
||||
overlay: multiCircle,
|
||||
id: geometriesData.key,
|
||||
}
|
||||
],
|
||||
actionMode: TMap.tools.constants.EDITOR_ACTION.INTERACT,
|
||||
activeOverlayId: geometriesData.key, // 激活图层
|
||||
selectable: true // 开启点选功能
|
||||
})
|
||||
|
||||
editor.on('adjust_complete', (data: any) => {
|
||||
geometriesData.center = { lat: data.center.lat, lng: data.center.lng }
|
||||
geometriesData.radius = parseInt(data.radius)
|
||||
})
|
||||
|
||||
geometry[geometriesData.key] = { graphical: multiCircle, editor }
|
||||
}
|
||||
|
||||
/**
|
||||
* 在地图上创建一个多边形
|
||||
* @param map
|
||||
* @param geometriesData
|
||||
*/
|
||||
export const createPolygon = (map: any, geometriesData: any) => {
|
||||
const TMap = (window as any).TMap
|
||||
const LatLng = TMap.LatLng
|
||||
|
||||
const { lat, lng } = map.getCenter();
|
||||
|
||||
geometriesData.paths = geometriesData.paths ?? [
|
||||
{ lat: lat + 0.01, lng: lng + 0.01 },
|
||||
{ lat: lat - 0.01, lng: lng + 0.01 },
|
||||
{ lat: lat - 0.01, lng: lng - 0.01 },
|
||||
{ lat: lat + 0.01, lng: lng - 0.01 }
|
||||
]
|
||||
|
||||
const color = [
|
||||
Math.floor(Math.random() * 255),
|
||||
Math.floor(Math.random() * 255),
|
||||
Math.floor(Math.random() * 255)
|
||||
]
|
||||
|
||||
const multiPolygon = new TMap.MultiPolygon({
|
||||
map: map,
|
||||
styles: {
|
||||
polygon: new TMap.PolygonStyle({
|
||||
color: `rgba(${color.toString()}, .4)`,
|
||||
showBorder: true,
|
||||
borderColor: `rgb(${color.toString()})`,
|
||||
borderWidth: 2
|
||||
})
|
||||
},
|
||||
geometries: [
|
||||
{
|
||||
id: geometriesData.key,
|
||||
styleId: 'polygon',
|
||||
paths: geometriesData.paths.map((item: any) => {
|
||||
return new LatLng(item.lat, item.lng)
|
||||
})
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const editor = new TMap.tools.GeometryEditor({
|
||||
map: map,
|
||||
overlayList: [
|
||||
{
|
||||
overlay: multiPolygon,
|
||||
id: geometriesData.key,
|
||||
}
|
||||
],
|
||||
actionMode: TMap.tools.constants.EDITOR_ACTION.INTERACT,
|
||||
activeOverlayId: geometriesData.key, // 激活图层
|
||||
selectable: true, // 开启点选功能
|
||||
})
|
||||
|
||||
editor.on('adjust_complete', (data: any) => {
|
||||
geometriesData.paths = data.paths.map(item => {
|
||||
return { lat: item.lat, lng: item.lng}
|
||||
})
|
||||
})
|
||||
|
||||
geometry[geometriesData.key] = { graphical: multiPolygon, editor }
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除图形
|
||||
* @param key
|
||||
*/
|
||||
export const deleteGeometry = (key: string) => {
|
||||
geometry[key].graphical.remove(key)
|
||||
geometry[key].editor.delete()
|
||||
}
|
||||
|
||||
/**
|
||||
* 选中图形
|
||||
* @param key
|
||||
*/
|
||||
export const selectGeometry = (key: string) => {
|
||||
geometry[key].editor.select([key])
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建点标记
|
||||
* @param map
|
||||
* @returns
|
||||
*/
|
||||
export const createMarker = (map: any) => {
|
||||
const TMap = (window as any).TMap
|
||||
const LatLng = TMap.LatLng
|
||||
|
||||
return new TMap.MultiMarker({
|
||||
map,
|
||||
geometries: [
|
||||
{
|
||||
id: 'center',
|
||||
position: map.getCenter(),
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 逆地址解析
|
||||
* @param params
|
||||
*/
|
||||
export const latLngToAddress = (params: any) => {
|
||||
return jsonp(`https://apis.map.qq.com/ws/geocoder/v1/?key=${params.mapKey}&location=${params.lat},${params.lng}&output=jsonp&callback=latLngToAddress`, { callbackName: 'latLngToAddress' })
|
||||
}
|
||||
|
||||
/**
|
||||
* 地址解析
|
||||
*/
|
||||
export const addressToLatLng = (params: any) => {
|
||||
return jsonp(`https://apis.map.qq.com/ws/geocoder/v1/?key=${params.mapKey}&address=${params.address}&output=jsonp&callback=addressToLatLng`, { callbackName: 'addressToLatLng' })
|
||||
}
|
||||
198
admin-vben/src/utils/request.ts
Normal file
198
admin-vben/src/utils/request.ts
Normal file
@@ -0,0 +1,198 @@
|
||||
import axios, { HttpStatusCode } from 'axios'
|
||||
import type { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse, AxiosRequestConfig } from 'axios'
|
||||
import { getToken, isUrl } from './common';
|
||||
import { ElMessage } from 'element-plus'
|
||||
import type { MessageParams } from 'element-plus'
|
||||
import { t } from '@/lang'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import storage from '@/utils/storage'
|
||||
|
||||
interface RequestConfig extends AxiosRequestConfig {
|
||||
showErrorMessage?: boolean
|
||||
showSuccessMessage?: boolean
|
||||
}
|
||||
|
||||
interface InternalRequestConfig extends InternalAxiosRequestConfig {
|
||||
showErrorMessage?: boolean
|
||||
showSuccessMessage?: boolean
|
||||
}
|
||||
|
||||
interface requestResponse extends AxiosResponse {
|
||||
config: InternalRequestConfig
|
||||
}
|
||||
|
||||
class Request {
|
||||
private instance: AxiosInstance;
|
||||
|
||||
constructor() {
|
||||
this.instance = axios.create({
|
||||
baseURL: import.meta.env.VITE_APP_BASE_URL.substr(-1) == '/' ? import.meta.env.VITE_APP_BASE_URL : `${import.meta.env.VITE_APP_BASE_URL}/`,
|
||||
timeout: 0,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'lang': storage.get('lang') ?? 'zh-cn'
|
||||
}
|
||||
});
|
||||
|
||||
// 全局请求拦截器
|
||||
this.instance.interceptors.request.use(
|
||||
(config: InternalRequestConfig) => {
|
||||
// 携带token site-id
|
||||
if (getToken()) {
|
||||
config.headers[import.meta.env.VITE_REQUEST_HEADER_TOKEN_KEY] = getToken()
|
||||
}
|
||||
config.headers[import.meta.env.VITE_REQUEST_HEADER_SITEID_KEY] = storage.get('siteId') || 0
|
||||
return config
|
||||
},
|
||||
(err: any) => {
|
||||
return Promise.reject(err)
|
||||
}
|
||||
)
|
||||
|
||||
// 全局响应拦截器
|
||||
this.instance.interceptors.response.use(
|
||||
(response: requestResponse) => {
|
||||
if (response.request.responseType != 'blob') {
|
||||
const res = response.data
|
||||
if (res.code != 1) {
|
||||
this.handleAuthError(res.code)
|
||||
if (res.code != 401 && response.config.showErrorMessage !== false) this.showElMessage({ message: res.msg, type: 'error', dangerouslyUseHTMLString: true, duration: 5000 })
|
||||
return Promise.reject(new Error(res.msg || 'Error'))
|
||||
} else {
|
||||
if (response.config.showSuccessMessage) ElMessage({ message: res.msg, type: 'success' })
|
||||
return res
|
||||
}
|
||||
}
|
||||
return response.data
|
||||
},
|
||||
(err: any) => {
|
||||
this.handleNetworkError(err)
|
||||
return Promise.reject(err)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送get请求
|
||||
* @param url
|
||||
* @param config
|
||||
* @returns
|
||||
*/
|
||||
public get<T = any, R = AxiosResponse<T>>(url: string, config?: RequestConfig): Promise<R> {
|
||||
return this.instance.get(url, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送post请求
|
||||
* @param url
|
||||
* @param data
|
||||
* @param config
|
||||
* @returns
|
||||
*/
|
||||
public post<T = any, R = AxiosResponse<T>, D = any>(url: string, data?: D, config?: RequestConfig): Promise<R> {
|
||||
return this.instance.post(url, data, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送put请求
|
||||
* @param url
|
||||
* @param data
|
||||
* @param config
|
||||
* @returns
|
||||
*/
|
||||
public put<T = any, R = AxiosResponse<T>, D = any>(url: string, data?: D, config?: RequestConfig): Promise<R> {
|
||||
return this.instance.put(url, data, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送delete请求
|
||||
* @param url
|
||||
* @param config
|
||||
* @returns
|
||||
*/
|
||||
public delete<T = any, R = AxiosResponse<T>>(url: string, config?: RequestConfig): Promise<R> {
|
||||
return this.instance.delete(url, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理网络请求错误
|
||||
* @param err
|
||||
*/
|
||||
private handleNetworkError(err: any) {
|
||||
let errMessage = ''
|
||||
|
||||
if (err.response && err.response.status) {
|
||||
const errStatus = err.response.status
|
||||
switch (errStatus) {
|
||||
case 400:
|
||||
errMessage = t('axios.400')
|
||||
break
|
||||
case 401:
|
||||
errMessage = t('axios.401')
|
||||
break
|
||||
case 403:
|
||||
errMessage = t('axios.403')
|
||||
break
|
||||
case 404:
|
||||
const baseURL = isUrl(err.response.config.baseURL) ? err.response.config.baseURL : `${location.origin}${err.response.config.baseURL}`
|
||||
errMessage = baseURL + t('axios.baseUrlError')
|
||||
break
|
||||
case 405:
|
||||
errMessage = t('axios.405')
|
||||
break
|
||||
case 408:
|
||||
errMessage = t('axios.408')
|
||||
break
|
||||
case 409:
|
||||
errMessage = t('axios.409')
|
||||
break
|
||||
case 500:
|
||||
errMessage = t('axios.500')
|
||||
break
|
||||
case 501:
|
||||
errMessage = t('axios.501')
|
||||
break
|
||||
case 502:
|
||||
errMessage = t('axios.502')
|
||||
break
|
||||
case 503:
|
||||
errMessage = t('axios.503')
|
||||
break
|
||||
case 504:
|
||||
errMessage = t('axios.504')
|
||||
break
|
||||
case 505:
|
||||
errMessage = t('axios.505')
|
||||
break
|
||||
}
|
||||
}
|
||||
err.message.includes('timeout') && (errMessage = t('axios.timeout'))
|
||||
if (err.code == 'ERR_NETWORK') {
|
||||
const baseURL = isUrl(err.config.baseURL) ? err.config.baseURL : `${location.origin}${err.config.baseURL}`
|
||||
errMessage = baseURL + t('axios.baseUrlError')
|
||||
}
|
||||
errMessage && this.showElMessage({ dangerouslyUseHTMLString: true, duration: 5000, message: errMessage, type: 'error' })
|
||||
}
|
||||
|
||||
private handleAuthError(code: number) {
|
||||
switch (code) {
|
||||
case 401:
|
||||
useUserStore().logout()
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private messageCache = new Map();
|
||||
|
||||
private showElMessage(options: MessageParams) {
|
||||
const cacheKey = options.message
|
||||
const cachedMessage = this.messageCache.get(cacheKey);
|
||||
|
||||
if (!cachedMessage || Date.now() - cachedMessage.timestamp > 5000) { // 5秒内重复内容不再弹出,可自定义过期时间
|
||||
this.messageCache.set(cacheKey, { timestamp: Date.now() });
|
||||
ElMessage(options)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new Request()
|
||||
66
admin-vben/src/utils/storage.ts
Normal file
66
admin-vben/src/utils/storage.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { getAppType } from './common'
|
||||
|
||||
interface setParam {
|
||||
key: string,
|
||||
data: any,
|
||||
success?: () => {},
|
||||
fail?: (err: any) => {}
|
||||
}
|
||||
|
||||
class Storage {
|
||||
private prefix = ''
|
||||
|
||||
public constructor() {
|
||||
this.prefix = getAppType() == 'admin' ? 'admin' : 'site'
|
||||
}
|
||||
|
||||
public setPrefix(prefix: string) {
|
||||
this.prefix = prefix
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置缓存
|
||||
* @param param
|
||||
*/
|
||||
public set(param: setParam) {
|
||||
try {
|
||||
window.localStorage.setItem(`${this.prefix}.${param.key}`, JSON.stringify(param.data))
|
||||
typeof param.success == 'function' && param.success()
|
||||
} catch (error) {
|
||||
typeof param.fail == 'function' && param.fail(error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存
|
||||
* @param key
|
||||
* @returns
|
||||
*/
|
||||
public get(key: string) {
|
||||
try {
|
||||
const json: any = window.localStorage.getItem(`${this.prefix}.${key}`)
|
||||
return JSON.parse(json)
|
||||
} catch (error) {
|
||||
return window.localStorage.getItem(`${this.prefix}.${key}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除指定缓存
|
||||
* @param key
|
||||
*/
|
||||
public remove(key: string | string[]) {
|
||||
if (typeof key == 'string') window.localStorage.removeItem(`${this.prefix}.${key}`)
|
||||
else key.forEach(item => { window.localStorage.removeItem(`${this.prefix}.${item}`) })
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理缓存
|
||||
*/
|
||||
public clear() {
|
||||
window.localStorage.clear()
|
||||
}
|
||||
}
|
||||
|
||||
const storage = new Storage()
|
||||
export default storage
|
||||
246
admin-vben/src/utils/test.ts
Normal file
246
admin-vben/src/utils/test.ts
Normal file
@@ -0,0 +1,246 @@
|
||||
const test = {
|
||||
/**
|
||||
* 验证电子邮箱格式
|
||||
*/
|
||||
email(value: string) {
|
||||
return /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/.test(value)
|
||||
},
|
||||
/**
|
||||
* 验证手机格式
|
||||
*/
|
||||
mobile(value: string) {
|
||||
return /^1[23456789]\d{9}$/.test(value)
|
||||
},
|
||||
/**
|
||||
* 验证URL格式
|
||||
*/
|
||||
url(value: string) {
|
||||
return /^((https|http|ftp|rtsp|mms):\/\/)(([0-9a-zA-Z_!~*'().&=+$%-]+: )?[0-9a-zA-Z_!~*'().&=+$%-]+@)?(([0-9]{1,3}.){3}[0-9]{1,3}|([0-9a-zA-Z_!~*'()-]+.)*([0-9a-zA-Z][0-9a-zA-Z-]{0,61})?[0-9a-zA-Z].[a-zA-Z]{2,6})(:[0-9]{1,4})?((\/?)|(\/[0-9a-zA-Z_!~*'().;?:@&=+$,%#-]+)+\/?)$/
|
||||
.test(value)
|
||||
},
|
||||
/**
|
||||
* 验证日期格式
|
||||
*/
|
||||
date(value: any) {
|
||||
if (!value) return false
|
||||
// 判断是否数值或者字符串数值(意味着为时间戳),转为数值,否则new Date无法识别字符串时间戳
|
||||
if (this.number(value)) value = +value
|
||||
return !/Invalid|NaN/.test(new Date(value).toString())
|
||||
},
|
||||
/**
|
||||
* 验证ISO类型的日期格式
|
||||
*/
|
||||
dateISO(value: string) {
|
||||
return /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(value)
|
||||
},
|
||||
/**
|
||||
* 验证十进制数字
|
||||
*/
|
||||
number(value: string) {
|
||||
return /^[\+-]?(\d+\.?\d*|\.\d+|\d\.\d+e\+\d+)$/.test(value)
|
||||
},
|
||||
/**
|
||||
* 验证字符串
|
||||
*/
|
||||
string(value: string) {
|
||||
return typeof value === 'string'
|
||||
},
|
||||
/**
|
||||
* 验证整数
|
||||
*/
|
||||
digits(value: string) {
|
||||
return /^\d+$/.test(value)
|
||||
},
|
||||
/**
|
||||
* 验证身份证号码
|
||||
*/
|
||||
idCard(value: string) {
|
||||
return /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(
|
||||
value
|
||||
)
|
||||
},
|
||||
/**
|
||||
* 是否车牌号
|
||||
*/
|
||||
carNo(value: string) {
|
||||
// 新能源车牌
|
||||
const xreg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}(([0-9]{5}[DF]$)|([DF][A-HJ-NP-Z0-9][0-9]{4}$))/
|
||||
// 旧车牌
|
||||
const creg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1}$/
|
||||
if (value.length === 7) {
|
||||
return creg.test(value)
|
||||
}
|
||||
if (value.length === 8) {
|
||||
return xreg.test(value)
|
||||
}
|
||||
return false
|
||||
},
|
||||
/**
|
||||
* 金额,只允许2位小数
|
||||
*/
|
||||
amount(value: string) {
|
||||
// 金额,只允许保留两位小数
|
||||
return /^[1-9]\d*(,\d{3})*(\.\d{1,2})?$|^0\.\d{1,2}$/.test(value)
|
||||
},
|
||||
/**
|
||||
* 验证小数
|
||||
*/
|
||||
decimal(value: string, digit: number) {
|
||||
const regexPattern = `^\\d+(?:\\.\\d{1,${ digit }})?$`
|
||||
// 金额,只允许保留两位小数
|
||||
return new RegExp(regexPattern).test(value)
|
||||
},
|
||||
/**
|
||||
* 中文
|
||||
*/
|
||||
chinese(value: string) {
|
||||
const reg = /^[\u4e00-\u9fa5]+$/gi
|
||||
return reg.test(value)
|
||||
},
|
||||
/**
|
||||
* 只能输入字母
|
||||
*/
|
||||
letter(value: string) {
|
||||
return /^[a-zA-Z]*$/.test(value)
|
||||
},
|
||||
/**
|
||||
* 只能是字母或者数字
|
||||
*/
|
||||
enOrNum(value: string) {
|
||||
// 英文或者数字
|
||||
const reg = /^[0-9a-zA-Z]*$/g
|
||||
return reg.test(value)
|
||||
},
|
||||
/**
|
||||
* 验证是否包含某个值
|
||||
*/
|
||||
contains(value: string, param: string) {
|
||||
return value.indexOf(param) >= 0
|
||||
},
|
||||
/**
|
||||
* 验证一个值范围[min, max]
|
||||
*/
|
||||
range(value: number, param: number[]) {
|
||||
return value >= param[0] && value <= param[1]
|
||||
},
|
||||
/**
|
||||
* 验证一个长度范围[min, max]
|
||||
*/
|
||||
rangeLength(value: string, param: number[]) {
|
||||
return value.length >= param[0] && value.length <= param[1]
|
||||
},
|
||||
/**
|
||||
* 是否固定电话
|
||||
*/
|
||||
landline(value: string) {
|
||||
const reg = /^\d{3,4}-\d{7,8}(-\d{3,4})?$/
|
||||
return reg.test(value)
|
||||
},
|
||||
/**
|
||||
* 判断是否为空
|
||||
*/
|
||||
empty(value: any) {
|
||||
switch (typeof value) {
|
||||
case 'undefined':
|
||||
return true
|
||||
case 'string':
|
||||
if (value.replace(/(^[ \t\n\r]*)|([ \t\n\r]*$)/g, '').length == 0) return true
|
||||
break
|
||||
case 'boolean':
|
||||
if (!value) return true
|
||||
break
|
||||
case 'number':
|
||||
if (value === 0 || isNaN(value)) return true
|
||||
break
|
||||
case 'object':
|
||||
if (value === null || value.length === 0) return true
|
||||
for (const i in value) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
/**
|
||||
* 是否json字符串
|
||||
*/
|
||||
jsonString(value: object) {
|
||||
if (typeof value === 'string') {
|
||||
try {
|
||||
const obj = JSON.parse(value)
|
||||
if (typeof obj === 'object' && obj) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
/**
|
||||
* 是否数组
|
||||
*/
|
||||
array(value: []) {
|
||||
if (typeof Array.isArray === 'function') {
|
||||
return Array.isArray(value)
|
||||
}
|
||||
return Object.prototype.toString.call(value) === '[object Array]'
|
||||
},
|
||||
/**
|
||||
* 是否对象
|
||||
*/
|
||||
object(value: object) {
|
||||
return Object.prototype.toString.call(value) === '[object Object]'
|
||||
},
|
||||
/**
|
||||
* 是否短信验证码
|
||||
*/
|
||||
code(value: string, len = 6) {
|
||||
return new RegExp(`^\\d{${ len }}$`).test(value)
|
||||
},
|
||||
/**
|
||||
* 是否函数方法
|
||||
* @param {Object} value
|
||||
*/
|
||||
func(value: string) {
|
||||
return typeof value === 'function'
|
||||
},
|
||||
/**
|
||||
* 是否promise对象
|
||||
* @param {Object} value
|
||||
*/
|
||||
promise(value: Promise<any>) {
|
||||
return this.object(value) && this.func(value.then) && this.func(value.catch)
|
||||
},
|
||||
/** 是否图片格式
|
||||
* @param {Object} value
|
||||
*/
|
||||
image(value: string) {
|
||||
const newValue = value.split('?')[0]
|
||||
const IMAGE_REGEXP = /\.(jpeg|jpg|gif|png|svg|jfif|bmp|dpg)/i // todo 暂不支持webp格式
|
||||
return IMAGE_REGEXP.test(newValue)
|
||||
},
|
||||
/**
|
||||
* 是否视频格式
|
||||
* @param {Object} value
|
||||
*/
|
||||
video(value: string) {
|
||||
const VIDEO_REGEXP = /\.(mp4|mpg|mpeg|dat|asf|avi|rm|rmvb|mov|wmv|flv|mkv|m3u8)/i
|
||||
return VIDEO_REGEXP.test(value)
|
||||
},
|
||||
/**
|
||||
* 是否为正则对象
|
||||
*/
|
||||
regExp(o) {
|
||||
return o && Object.prototype.toString.call(o) === '[object RegExp]'
|
||||
},
|
||||
/**
|
||||
* 验证必填
|
||||
*/
|
||||
require(value: string) {
|
||||
return /^\s*$/.test(value)
|
||||
}
|
||||
}
|
||||
|
||||
export default test
|
||||
Reference in New Issue
Block a user