33 changed files with 902 additions and 163 deletions
@ -0,0 +1,4 @@ |
|||||||
|
export * from './tag'; |
||||||
|
export * from './list-table'; |
||||||
|
export * from './search-row'; |
||||||
|
export * from './modify-form'; |
@ -0,0 +1,2 @@ |
|||||||
|
import ListTable from './src/listTable.vue'; |
||||||
|
export { ListTable }; |
@ -0,0 +1,2 @@ |
|||||||
|
import ModifyForm from './src/modifyForm.vue'; |
||||||
|
export { ModifyForm }; |
@ -0,0 +1,2 @@ |
|||||||
|
import SearchRow from './src/searchRow.vue'; |
||||||
|
export { SearchRow }; |
@ -1,7 +1,3 @@ |
|||||||
import WkbTag from './tag'; |
export * from "./base"; |
||||||
import ListTable from './list-table'; |
export * from "./tool"; |
||||||
import SearchRow from './search-row'; |
export * from "./manage"; |
||||||
import ModifyForm from './modify-form'; |
|
||||||
import Terminal from './termimal'; |
|
||||||
|
|
||||||
export { WkbTag, ListTable, SearchRow, ModifyForm, Terminal }; |
|
||||||
|
@ -1,2 +0,0 @@ |
|||||||
import listTable from "./src/listTable.vue" |
|
||||||
export default listTable; |
|
@ -0,0 +1,2 @@ |
|||||||
|
import Home from './src/home.vue'; |
||||||
|
export { Home }; |
@ -0,0 +1,102 @@ |
|||||||
|
<template> |
||||||
|
<el-container :style="appMain"> |
||||||
|
<el-aside :width="sizes.asideWidth"> |
||||||
|
<MenuTree v-show="state.showAside" :data="data" :type="type"></MenuTree> |
||||||
|
</el-aside> |
||||||
|
<el-container> |
||||||
|
<el-header class="app-head" :height="state.sizes.headHeight"> |
||||||
|
<Header v-show="state.showHeader" ref="header" /> |
||||||
|
</el-header> |
||||||
|
<el-main class="app-main"> |
||||||
|
<router-view /> |
||||||
|
</el-main> |
||||||
|
</el-container> |
||||||
|
</el-container> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script lang="ts" setup> |
||||||
|
import { reactive, onMounted, ref } from "vue"; |
||||||
|
import { useStore } from "vuex"; |
||||||
|
import { useRouter } from "vue-router"; |
||||||
|
import { MenuTree } from "../../menu-tree" |
||||||
|
|
||||||
|
const { commit, dispatch, state } = useStore(); |
||||||
|
const router = useRouter() |
||||||
|
dispatch("getWebConfig"); |
||||||
|
const appMain = reactive({ |
||||||
|
height: "", |
||||||
|
// backgroundImage: "url(" + publik.background + ")", |
||||||
|
}); |
||||||
|
|
||||||
|
const flag = reactive({ |
||||||
|
showHeader: true, |
||||||
|
showAside: true |
||||||
|
}) |
||||||
|
const sizes = reactive({ |
||||||
|
fullHeight: '', |
||||||
|
headHeight: '', |
||||||
|
asideWidth: '', |
||||||
|
mainHeight: '' |
||||||
|
|
||||||
|
}) |
||||||
|
|
||||||
|
const props = defineProps({ |
||||||
|
data: { |
||||||
|
type: Array<any>(), |
||||||
|
default: null |
||||||
|
}, |
||||||
|
type: { |
||||||
|
type: String, |
||||||
|
default: 'def', |
||||||
|
}, |
||||||
|
}); |
||||||
|
|
||||||
|
|
||||||
|
onMounted(() => { |
||||||
|
router.push("/") |
||||||
|
commit("updateState", { prop: "showHeader", value: false }); |
||||||
|
commit("updateState", { prop: "showAside", value: false }); |
||||||
|
commit("initSizes"); |
||||||
|
appMain.height = state.sizes.fullHeight; |
||||||
|
}); |
||||||
|
|
||||||
|
const initSizes = () => { |
||||||
|
const height = window.innerHeight; |
||||||
|
const navHead = flag.showHeader ? 60 : 0; |
||||||
|
const aside = flag.showAside ? 200 : 0; |
||||||
|
sizes.headHeight = navHead + 'px'; |
||||||
|
sizes.asideWidth = aside + 'px'; |
||||||
|
appMain.height = height + 'px'; |
||||||
|
}; |
||||||
|
|
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang='scss'> |
||||||
|
@charset "UTF-8"; |
||||||
|
// @import "./assets/style/element.scss"; |
||||||
|
// @import "./assets/style/base.scss"; |
||||||
|
|
||||||
|
.app-main { |
||||||
|
background-size: cover; |
||||||
|
background-position: center; |
||||||
|
background-repeat: no-repeat; |
||||||
|
} |
||||||
|
|
||||||
|
.el-header, |
||||||
|
.main-head, |
||||||
|
.main-table { |
||||||
|
padding: 0; |
||||||
|
} |
||||||
|
|
||||||
|
#app { |
||||||
|
background-color: #edf2f7; |
||||||
|
} |
||||||
|
|
||||||
|
.app-head { |
||||||
|
padding: 0px !important; |
||||||
|
} |
||||||
|
|
||||||
|
.app-main { |
||||||
|
padding: 0px !important; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,2 @@ |
|||||||
|
export * from './menu-tree'; |
||||||
|
export * from "./home" |
@ -0,0 +1,2 @@ |
|||||||
|
import MenuTree from './src/menuTree.vue'; |
||||||
|
export { MenuTree }; |
@ -0,0 +1,70 @@ |
|||||||
|
<template> |
||||||
|
<el-menu :default-active="active" class="menu-tree"> |
||||||
|
<template v-for="menu in data"> |
||||||
|
<template v-if="menu.children && menu.children.length > 0"> |
||||||
|
<el-sub-menu :index="menu.path" :key="menu.path"> |
||||||
|
<template #title> |
||||||
|
<Icon :color="style[type].menuColor" :name="menu.icon ? menu.icon : style[type].menuDefaultIcon" /> |
||||||
|
<span>{{ menu.title ? menu.title : defTitle }}</span> |
||||||
|
</template> |
||||||
|
<menu-tree :menus="menu.children"></menu-tree> |
||||||
|
</el-sub-menu> |
||||||
|
</template> |
||||||
|
<template v-else> |
||||||
|
<el-menu-item :index="menu.path" :key="menu.path" @click="clickMenu(menu)"> |
||||||
|
<Icon :color="style[type].menuColor" :name="menu.icon ? menu.icon : style[type].menuDefaultIcon" /> |
||||||
|
<span>{{ menu.title ? menu.title : defTitle }}</span> |
||||||
|
</el-menu-item> |
||||||
|
</template> |
||||||
|
</template> |
||||||
|
</el-menu> |
||||||
|
</template> |
||||||
|
<script setup lang="ts"> |
||||||
|
import { useStore } from "vuex"; |
||||||
|
import { useRouter } from "vue-router"; |
||||||
|
import { ref, onMounted } from "vue" |
||||||
|
import * as style from "./style"; |
||||||
|
|
||||||
|
const store = useStore() |
||||||
|
const props = defineProps({ |
||||||
|
data: { |
||||||
|
type: Array<any>(), |
||||||
|
default: null |
||||||
|
}, |
||||||
|
type: { |
||||||
|
type: String, |
||||||
|
default: 'def', |
||||||
|
}, |
||||||
|
}); |
||||||
|
|
||||||
|
const router = useRouter(); |
||||||
|
const clickMenu = (menu) => { |
||||||
|
router.push(menu.path); |
||||||
|
}; |
||||||
|
const active = ref(""); |
||||||
|
|
||||||
|
const defTitle = ""; |
||||||
|
|
||||||
|
onMounted(() => { |
||||||
|
active.value = props.data[0].path; |
||||||
|
}) |
||||||
|
|
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.el-sub-menu .icon, |
||||||
|
.el-menu-item .icon { |
||||||
|
vertical-align: middle; |
||||||
|
margin-right: 5px; |
||||||
|
width: 24px; |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
.is-active>.icon { |
||||||
|
color: var(--el-menu-active-color) !important; |
||||||
|
} |
||||||
|
|
||||||
|
.el-menu-item.is-active { |
||||||
|
background-color: v-bind('style[type].menuActiveBackground'); |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,23 @@ |
|||||||
|
export const def = { |
||||||
|
/* 侧边菜单 */ |
||||||
|
// 侧边菜单背景色
|
||||||
|
menuBackground: '#ffffff', |
||||||
|
// 侧边菜单文字颜色
|
||||||
|
menuColor: '#303133', |
||||||
|
// 侧边菜单激活项背景色
|
||||||
|
menuActiveBackground: '#ffffff', |
||||||
|
// 侧边菜单激活项文字色
|
||||||
|
menuActiveColor: '#409eff', |
||||||
|
// 侧边菜单顶栏背景色
|
||||||
|
menuTopBarBackground: '#fcfcfc', |
||||||
|
// 侧边菜单宽度(展开时),单位px
|
||||||
|
menuWidth: 260, |
||||||
|
// 侧边菜单项默认图标
|
||||||
|
menuDefaultIcon: 'el-icon-Minus', |
||||||
|
// 是否水平折叠收起菜单
|
||||||
|
menuCollapse: false, |
||||||
|
// 是否只保持一个子菜单的展开(手风琴)
|
||||||
|
menuUniqueOpened: false, |
||||||
|
// 显示菜单栏顶栏(LOGO)
|
||||||
|
menuShowTopBar: true, |
||||||
|
}; |
@ -1,2 +0,0 @@ |
|||||||
import ModifyForm from "./src/modifyForm.vue" |
|
||||||
export default ModifyForm; |
|
@ -1,2 +0,0 @@ |
|||||||
import SearchRow from "./src/searchRow.vue" |
|
||||||
export default SearchRow; |
|
@ -1,3 +0,0 @@ |
|||||||
import Terminal from './src/terminal.vue' |
|
||||||
|
|
||||||
export default Terminal |
|
@ -0,0 +1,2 @@ |
|||||||
|
export * from './termimal'; |
||||||
|
export * from './termimal-split'; |
@ -0,0 +1,3 @@ |
|||||||
|
import TerminalSplit from './src/terminal.vue'; |
||||||
|
|
||||||
|
export { TerminalSplit }; |
@ -0,0 +1,198 @@ |
|||||||
|
<template> |
||||||
|
<el-row> |
||||||
|
<el-col :span="12"> |
||||||
|
<div id="terminal" v-loading="flag.loading" ref="terminal" element-loading-text="拼命连接中" |
||||||
|
@click.right.native="showClear($event)"></div> |
||||||
|
</el-col> |
||||||
|
<el-col :span="12"> |
||||||
|
<div id="response" v-loading="flag.loading" ref="response" element-loading-text="拼命连接中"></div> |
||||||
|
</el-col> |
||||||
|
</el-row> |
||||||
|
</template> |
||||||
|
<script lang="ts" setup> |
||||||
|
import { ref, onMounted, onBeforeUnmount, watch, reactive } from "vue"; |
||||||
|
import { Terminal } from "xterm"; |
||||||
|
import "xterm/css/xterm.css"; |
||||||
|
const prop = defineProps({ |
||||||
|
url: { |
||||||
|
type: String, |
||||||
|
default: null |
||||||
|
}, |
||||||
|
msgFilter: { |
||||||
|
type: Function, |
||||||
|
defalut: msg => { |
||||||
|
return { unlock: false, data: msg }; |
||||||
|
} |
||||||
|
}, |
||||||
|
prmt: { |
||||||
|
type: String, |
||||||
|
default: ">" |
||||||
|
} |
||||||
|
}); |
||||||
|
const flag = reactive({ |
||||||
|
loading: true, |
||||||
|
lock: true |
||||||
|
}); |
||||||
|
const terminal = ref(null); |
||||||
|
const response = ref(null); |
||||||
|
|
||||||
|
const terminalSocket = ref(); |
||||||
|
const term = ref(); |
||||||
|
const rsp = ref(); |
||||||
|
let text = ""; |
||||||
|
|
||||||
|
const runRealTerminal = () => { |
||||||
|
flag.loading = false; |
||||||
|
term.value.write(prop.prmt); |
||||||
|
flag.lock = false; |
||||||
|
} |
||||||
|
|
||||||
|
const onWSReceive = (message) => { |
||||||
|
if (prop.msgFilter) { |
||||||
|
const data = prop.msgFilter(message.data); |
||||||
|
if (data) { |
||||||
|
rsp.value.writeln(data) |
||||||
|
} else { |
||||||
|
flag.lock = false |
||||||
|
term.value.write(prop.prmt) |
||||||
|
} |
||||||
|
} else { |
||||||
|
rsp.value.writeln(message.data) |
||||||
|
rsp.value.write(prop.prmt) |
||||||
|
flag.lock = false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const errorRealTerminal = (ex) => { |
||||||
|
let message = ex.message; |
||||||
|
if (!message) message = 'disconnected' |
||||||
|
term.value.write(`\x1b[31m${message}\x1b[m\r\n`) |
||||||
|
console.log("err"); |
||||||
|
} |
||||||
|
const closeRealTerminal = () => { |
||||||
|
console.log("close"); |
||||||
|
} |
||||||
|
|
||||||
|
const initWS = () => { |
||||||
|
if (!prop.url) { |
||||||
|
return; |
||||||
|
} |
||||||
|
terminalSocket.value = new WebSocket(prop.url); |
||||||
|
terminalSocket.value.onopen = runRealTerminal; |
||||||
|
terminalSocket.value.onmessage = onWSReceive; |
||||||
|
terminalSocket.value.onclose = closeRealTerminal; |
||||||
|
terminalSocket.value.onerror = errorRealTerminal; |
||||||
|
} |
||||||
|
|
||||||
|
const onKey = e => { |
||||||
|
if (flag.lock) { |
||||||
|
return; |
||||||
|
} |
||||||
|
//\x1B ESC |
||||||
|
//\x1BOP-\x1B[24~ F1-F12 |
||||||
|
const key = e.key; |
||||||
|
if (key.indexOf("\u001b") !== -1) { |
||||||
|
return; |
||||||
|
} |
||||||
|
if (isWsOpen()) { |
||||||
|
if (key === '\x7F') { |
||||||
|
if (text.length > 0) { |
||||||
|
term.value.write("\b \b"); |
||||||
|
text = text.substring(0, text.length - 1) |
||||||
|
} |
||||||
|
return; |
||||||
|
} |
||||||
|
if (key == '\r') { |
||||||
|
term.value.writeln(key) |
||||||
|
if (e.domEvent.ctrlKey) { |
||||||
|
text += key; |
||||||
|
} else { |
||||||
|
sendText(text); |
||||||
|
text = ""; |
||||||
|
} |
||||||
|
} else { |
||||||
|
text += key |
||||||
|
term.value.write(key) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
const initTerm = () => { |
||||||
|
const options = { |
||||||
|
lineHeight: 1.2, |
||||||
|
fontSize: 16, |
||||||
|
fontFamily: "Monaco, Menlo, Consolas, 'Courier New', monospace", |
||||||
|
theme: { |
||||||
|
background: '#181d28', |
||||||
|
}, |
||||||
|
// 光标闪烁 |
||||||
|
cursorBlink: true, |
||||||
|
cursorStyle: 'underline', |
||||||
|
scrollback: 100, |
||||||
|
tabStopWidth: 2, |
||||||
|
cols: 80 |
||||||
|
} |
||||||
|
options.cols = Math.ceil((window.innerWidth - 80) / 20) |
||||||
|
term.value = new Terminal(options); |
||||||
|
term.value.open(terminal.value); |
||||||
|
term.value.onKey(onKey); |
||||||
|
|
||||||
|
options.cursorBlink = false; |
||||||
|
rsp.value = new Terminal(options); |
||||||
|
rsp.value.open(response.value); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
const sendText = str => { |
||||||
|
if (str) { |
||||||
|
terminalSocket.value.send(str); |
||||||
|
flag.lock = true; |
||||||
|
} else { |
||||||
|
term.value.write(prop.prmt); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 是否连接中0 1 2 3 |
||||||
|
const isWsOpen = () => { |
||||||
|
const readyState = terminalSocket.value && terminalSocket.value.readyState; |
||||||
|
return readyState === 1 |
||||||
|
} |
||||||
|
|
||||||
|
const showClear = e => { |
||||||
|
// 去掉默认事件 |
||||||
|
document.oncontextmenu = function (e) { |
||||||
|
e.preventDefault(); |
||||||
|
}; |
||||||
|
navigator.clipboard.readText().then(content => { |
||||||
|
term.value.write(content) |
||||||
|
text += content; |
||||||
|
// sendText(content); |
||||||
|
}) |
||||||
|
// term.value.clear(); |
||||||
|
} |
||||||
|
|
||||||
|
//监听类型变化,重置term |
||||||
|
watch(() => prop.url, () => { |
||||||
|
term.value.reset(); |
||||||
|
flag.loading = true; |
||||||
|
flag.lock = false; |
||||||
|
terminalSocket.value && terminalSocket.value.close(); |
||||||
|
terminalSocket.value = null; |
||||||
|
initWS(); |
||||||
|
// 重置 |
||||||
|
}) |
||||||
|
|
||||||
|
onMounted(() => { |
||||||
|
initWS(); |
||||||
|
initTerm(); |
||||||
|
}) |
||||||
|
onBeforeUnmount(() => { |
||||||
|
terminalSocket.value && terminalSocket.value.close(); |
||||||
|
term.value.dispose(); |
||||||
|
}) |
||||||
|
</script> |
||||||
|
<style lang="scss" scoped> |
||||||
|
#terminal { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,3 @@ |
|||||||
|
import Terminal from './src/terminal.vue'; |
||||||
|
|
||||||
|
export { Terminal }; |
@ -0,0 +1,2 @@ |
|||||||
|
export * from "./message"; |
||||||
|
export * from "./rule"; |
@ -0,0 +1,248 @@ |
|||||||
|
export class SimpleRequired { |
||||||
|
required = true; |
||||||
|
message: string; |
||||||
|
trigger = 'blur'; |
||||||
|
|
||||||
|
constructor(name?: string) { |
||||||
|
if (name) { |
||||||
|
this.message = '请输入' + name; |
||||||
|
} else { |
||||||
|
this.message = '此处不能为空'; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export class SimpleCharacter { |
||||||
|
required: boolean; |
||||||
|
message: string; |
||||||
|
max?: number; |
||||||
|
trigger: string = 'blur'; |
||||||
|
|
||||||
|
constructor(name?: string, max?: number, required?: boolean) { |
||||||
|
if (required == null || required == undefined) { |
||||||
|
this.required = true; |
||||||
|
} else { |
||||||
|
this.required = required; |
||||||
|
} |
||||||
|
if (!max) { |
||||||
|
max = 255; |
||||||
|
} |
||||||
|
this.max = max; |
||||||
|
if (name) { |
||||||
|
if (this.required) { |
||||||
|
this.message = '请输入不超过' + max + '字符的' + name; |
||||||
|
} else { |
||||||
|
this.message = name + '最长不超过' + max + '字符'; |
||||||
|
} |
||||||
|
} else { |
||||||
|
this.message = '此处不能为空'; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export class Character { |
||||||
|
pattern: RegExp; |
||||||
|
message: string = '输入格式不正确'; |
||||||
|
trigger = 'blur'; |
||||||
|
|
||||||
|
constructor(pattern: RegExp) { |
||||||
|
this.pattern = pattern; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export class SimpleSelection { |
||||||
|
required: boolean; |
||||||
|
message: string; |
||||||
|
trigger: string; |
||||||
|
|
||||||
|
constructor(name?: string) { |
||||||
|
this.required = true; |
||||||
|
this.trigger = 'change'; |
||||||
|
if (name) { |
||||||
|
this.message = '请选择' + name; |
||||||
|
} else { |
||||||
|
this.message = '此处不能为空'; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export class SimpleNumber { |
||||||
|
trigger: string = 'blur'; |
||||||
|
min?: Number; |
||||||
|
max?: Number; |
||||||
|
validator = (rule: any, value: any, callback: any) => { |
||||||
|
if (value == null || value === '') { |
||||||
|
callback(); |
||||||
|
} |
||||||
|
if (!new RegExp(/^(0|-?[1-9]\d*)$/).test(value)) { |
||||||
|
callback(new Error('请输入整数')); |
||||||
|
} |
||||||
|
const num = parseInt(value); |
||||||
|
if (rule.min != null && num < rule.min) { |
||||||
|
callback(new Error('最小值为' + rule.min)); |
||||||
|
} |
||||||
|
if (rule.max != null && num > rule.max) { |
||||||
|
callback(new Error('最大值为' + rule.max)); |
||||||
|
} |
||||||
|
callback(); |
||||||
|
}; |
||||||
|
|
||||||
|
constructor(min?: number, max?: Number) { |
||||||
|
this.min = min; |
||||||
|
this.max = max; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export class Hexadecimal { |
||||||
|
trigger = 'blur'; |
||||||
|
min?: Number; |
||||||
|
max?: Number; |
||||||
|
validator = (rule: any, value: any, callback: any) => { |
||||||
|
if (value == null) { |
||||||
|
callback(); |
||||||
|
} else if ( |
||||||
|
value.trim().length == 0 || |
||||||
|
!new RegExp(/^[0-9a-fA-F\s]+$/).test(value) |
||||||
|
) { |
||||||
|
callback(new Error('请输入十六进制数字')); |
||||||
|
} else if (rule.min != null && value.length < rule.min) { |
||||||
|
callback(new Error('请输入至少' + rule.min + '位')); |
||||||
|
} else if (rule.max != null && value.length > rule.max) { |
||||||
|
callback(new Error('请输入最多' + rule.max + '位')); |
||||||
|
} else { |
||||||
|
callback(); |
||||||
|
} |
||||||
|
}; |
||||||
|
constructor(min?: number, max?: Number) { |
||||||
|
this.min = min; |
||||||
|
this.max = max; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export class Longitude extends Character { |
||||||
|
constructor() { |
||||||
|
super( |
||||||
|
new RegExp( |
||||||
|
/^-?((0|1?[0-7]?[0-9]?)(([.][0-9]{1,6})?)|180(([.][0]{1,6})?))$/ |
||||||
|
) |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
export class Latitude extends Character { |
||||||
|
constructor() { |
||||||
|
super( |
||||||
|
new RegExp( |
||||||
|
/^-?((0|1?[0-7]?[0-9]?)(([.][0-9]{1,6})?)|180(([.][0]{1,6})?))$/ |
||||||
|
) |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export class Email extends Character { |
||||||
|
constructor() { |
||||||
|
super( |
||||||
|
new RegExp( |
||||||
|
/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/ |
||||||
|
) |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
export class Phone extends Character { |
||||||
|
constructor() { |
||||||
|
super( |
||||||
|
new RegExp( |
||||||
|
/^(0|86|17951)?(13[0-9]|15[012356789]|17[0135678]|18[0-9]|14[57])[0-9]{8}$/ |
||||||
|
) |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export class Ipv4 extends Character { |
||||||
|
constructor() { |
||||||
|
super(new RegExp(/^((25[0-5]|2[0-4]\d|[01]?\d\d?)($|(?!\.$)\.)){4}$/)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export class Ipv6 extends Character { |
||||||
|
constructor() { |
||||||
|
super( |
||||||
|
new RegExp( |
||||||
|
/^([0-9a-fA-F]{1,4}:){7,7}([0-9a-fA-F]{1,4}|:)|([0-9a-fA-F]{1,4}:){1,6}(:[0-9a-fA-F]{1,4}|:)|([0-9a-fA-F]{1,4}:){1,5}((:[0-9a-fA-F]{1,4}){1,2}|:)|([0-9a-fA-F]{1,4}:){1,4}((:[0-9a-fA-F]{1,4}){1,3}|:)|([0-9a-fA-F]{1,4}:){1,3}((:[0-9a-fA-F]{1,4}){1,4}|:)|([0-9a-fA-F]{1,4}:){1,2}((:[0-9a-fA-F]{1,4}){1,5}|:)|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6}|:)|:((:[0-9a-fA-F]{1,4}){1,7}|:)/ |
||||||
|
) |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export class IdCard { |
||||||
|
trigger = 'blur'; |
||||||
|
validator = (rule: any, value: any, callback: any) => { |
||||||
|
if (value != null && value.length != 0) { |
||||||
|
let iSum = 0; |
||||||
|
const aCity = { |
||||||
|
11: '北京', |
||||||
|
12: '天津', |
||||||
|
13: '河北', |
||||||
|
14: '山西', |
||||||
|
15: '内蒙古', |
||||||
|
21: '辽宁', |
||||||
|
22: '吉林', |
||||||
|
23: '黑龙江', |
||||||
|
31: '上海', |
||||||
|
32: '江苏', |
||||||
|
33: '浙江', |
||||||
|
34: '安徽', |
||||||
|
35: '福建', |
||||||
|
36: '江西', |
||||||
|
37: '山东', |
||||||
|
41: '河南', |
||||||
|
42: '湖北', |
||||||
|
43: '湖南', |
||||||
|
44: '广东', |
||||||
|
45: '广西', |
||||||
|
46: '海南', |
||||||
|
50: '重庆', |
||||||
|
51: '四川', |
||||||
|
52: '贵州', |
||||||
|
53: '云南', |
||||||
|
54: '西藏', |
||||||
|
61: '陕西', |
||||||
|
62: '甘肃', |
||||||
|
63: '青海', |
||||||
|
64: '宁夏', |
||||||
|
65: '新疆', |
||||||
|
71: '台湾', |
||||||
|
81: '香港', |
||||||
|
82: '澳门', |
||||||
|
91: '国外', |
||||||
|
}; |
||||||
|
if (!/^\d{17}(\d|x)$/i.test(value)) { |
||||||
|
callback(new Error('你输入的身份证长度或格式错误')); |
||||||
|
} |
||||||
|
value = value.replace(/x$/i, 'a'); |
||||||
|
if (aCity[parseInt(value.substr(0, 2))] == null) { |
||||||
|
callback(new Error('你的身份证地区非法')); |
||||||
|
} |
||||||
|
|
||||||
|
const sBirthday = |
||||||
|
value.substr(6, 4) + |
||||||
|
'-' + |
||||||
|
Number(value.substr(10, 2)) + |
||||||
|
'-' + |
||||||
|
Number(value.substr(12, 2)); |
||||||
|
const d = new Date(sBirthday.replace(/-/g, '/')); |
||||||
|
if ( |
||||||
|
sBirthday != |
||||||
|
d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate() |
||||||
|
) { |
||||||
|
callback(new Error('身份证上的出生日期非法')); |
||||||
|
} |
||||||
|
for (let i = 17; i >= 0; i--) { |
||||||
|
iSum += (Math.pow(2, i) % 11) * parseInt(value.charAt(17 - i), 11); |
||||||
|
} |
||||||
|
if (iSum % 11 != 1) { |
||||||
|
callback(new Error('你输入的身份证号非法')); |
||||||
|
} |
||||||
|
} |
||||||
|
callback(); |
||||||
|
}; |
||||||
|
} |
Loading…
Reference in new issue