summaryrefslogtreecommitdiff
path: root/UI source code/dns_mapping_ui-master/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'UI source code/dns_mapping_ui-master/src/components')
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Breadcrumb/index.vue81
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Crud/CRUD.operation.vue268
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Crud/Pagination.vue18
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Crud/RR.operation.vue20
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Crud/UD.operation.vue71
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Crud/crud.js863
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/DateRangePicker/index.vue45
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Dict/Dict.js29
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Dict/index.js29
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Doc/index.vue16
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Echarts/BarChart.vue106
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Echarts/Category.vue438
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Egressdns.vue166
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Forwarder.vue166
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Fwdrdns.vue166
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Nonstandard.vue166
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Openrdns.vue166
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Echarts/Do53sj.vue166
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Echarts/Do53zg.vue145
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Echarts/Dohsj.vue163
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Echarts/Dohzg.vue145
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Echarts/Funnel.vue120
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Echarts/PieChart.vue84
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Echarts/Time.vue104
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/FilteredSearch/FilteredSearch.vue518
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/RecentSearch.vue103
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/SearchItem.vue343
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/TrimInput.vue88
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VAutoInput.vue16
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VInput.vue97
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VPicker.vue18
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VSelect.vue149
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VTimerange.vue164
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/cursorPosition.js14
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/historyApi.js86
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/keyboard.js31
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/GithubCorner/index.vue54
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Hamburger/index.vue44
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/HeaderSearch/index.vue188
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/IconSelect/index.vue68
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/IconSelect/requireIcons.js11
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Iframe/index.vue30
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/JavaEdit/index.vue78
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Pagination/index.vue101
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/PanThumb/index.vue140
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/ParentView/index.vue3
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Permission/index.js13
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Permission/permission.js21
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/RightPanel/index.vue149
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Screenfull/index.vue60
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Search/foot.vue55
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Search/input.vue12
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Search/left.vue100
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/Search/right.vue116
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/SearchInput/SearchInput.vue552
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/SearchList/count.vue502
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/SearchList/relation.vue56
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/SearchList/result.vue472
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/SearchList/resultTab.vue182
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/SizeSelect/index.vue57
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/SvgIcon/index.vue62
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/ThemePicker/index.vue165
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/UploadExcel/index.vue138
-rw-r--r--UI source code/dns_mapping_ui-master/src/components/YamlEdit/index.vue81
64 files changed, 8878 insertions, 0 deletions
diff --git a/UI source code/dns_mapping_ui-master/src/components/Breadcrumb/index.vue b/UI source code/dns_mapping_ui-master/src/components/Breadcrumb/index.vue
new file mode 100644
index 0000000..204ea59
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Breadcrumb/index.vue
@@ -0,0 +1,81 @@
+<template>
+ <el-breadcrumb class="app-breadcrumb" separator="/">
+ <transition-group name="breadcrumb">
+ <el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
+ <span v-if="item.redirect==='noredirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>
+ <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
+ </el-breadcrumb-item>
+ </transition-group>
+ </el-breadcrumb>
+</template>
+
+<script>
+import pathToRegexp from 'path-to-regexp'
+
+export default {
+ data() {
+ return {
+ levelList: null
+ }
+ },
+ watch: {
+ $route(route) {
+ // if you go to the redirect page, do not update the breadcrumbs
+ if (route.path.startsWith('/redirect/')) {
+ return
+ }
+ this.getBreadcrumb()
+ }
+ },
+ created() {
+ this.getBreadcrumb()
+ },
+ methods: {
+ getBreadcrumb() {
+ // only show routes with meta.title
+ let matched = this.$route.matched.filter(item => item.meta && item.meta.title)
+ const first = matched[0]
+
+ if (!this.isDashboard(first)) {
+ matched = [{ path: '/dashboard', meta: { title: '首页' }}].concat(matched)
+ }
+
+ this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
+ },
+ isDashboard(route) {
+ const name = route && route.name
+ if (!name) {
+ return false
+ }
+ return name.trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase()
+ },
+ pathCompile(path) {
+ // To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
+ const { params } = this.$route
+ var toPath = pathToRegexp.compile(path)
+ return toPath(params)
+ },
+ handleLink(item) {
+ const { redirect, path } = item
+ if (redirect) {
+ this.$router.push(redirect)
+ return
+ }
+ this.$router.push(this.pathCompile(path))
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.app-breadcrumb.el-breadcrumb {
+ display: inline-block;
+ font-size: 14px;
+ line-height: 50px;
+ margin-left: 8px;
+ .no-redirect {
+ color: #97a8be;
+ cursor: text;
+ }
+}
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Crud/CRUD.operation.vue b/UI source code/dns_mapping_ui-master/src/components/Crud/CRUD.operation.vue
new file mode 100644
index 0000000..33d2077
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Crud/CRUD.operation.vue
@@ -0,0 +1,268 @@
+<template>
+ <div class="crud-opts">
+ <span class="crud-opts-left">
+ <!--左侧插槽-->
+ <slot name="left" />
+ <el-button
+ v-if="crud.optShow.add"
+ v-permission="permission.add"
+ class="filter-item"
+ size="mini"
+ type="primary"
+ icon="el-icon-plus"
+ @click="crud.toAdd"
+ >
+ 新增
+ </el-button>
+ <el-button
+ v-if="crud.optShow.edit"
+ v-permission="permission.edit"
+ class="filter-item"
+ size="mini"
+ type="success"
+ icon="el-icon-edit"
+ :disabled="crud.selections.length !== 1"
+ @click="crud.toEdit(crud.selections[0])"
+ >
+ 修改
+ </el-button>
+ <el-button
+ v-if="crud.optShow.del"
+ slot="reference"
+ v-permission="permission.del"
+ class="filter-item"
+ type="danger"
+ icon="el-icon-delete"
+ size="mini"
+ :loading="crud.delAllLoading"
+ :disabled="crud.selections.length === 0"
+ @click="toDelete(crud.selections)"
+ >
+ 删除
+ </el-button>
+ <el-button
+ v-if="crud.optShow.download"
+ :loading="crud.downloadLoading"
+ :disabled="!crud.data.length"
+ class="filter-item"
+ size="mini"
+ type="warning"
+ icon="el-icon-download"
+ @click="crud.doExport"
+ >导出</el-button>
+ <!--右侧-->
+ <slot name="right" />
+ </span>
+ <el-button-group class="crud-opts-right">
+ <el-button
+ size="mini"
+ plain
+ type="info"
+ icon="el-icon-search"
+ @click="toggleSearch()"
+ />
+ <el-button
+ size="mini"
+ icon="el-icon-refresh"
+ @click="crud.refresh()"
+ />
+ <el-popover
+ placement="bottom-end"
+ width="150"
+ trigger="click"
+ >
+ <el-button
+ slot="reference"
+ size="mini"
+ icon="el-icon-s-grid"
+ >
+ <i
+ class="fa fa-caret-down"
+ aria-hidden="true"
+ />
+ </el-button>
+ <el-checkbox
+ v-model="allColumnsSelected"
+ :indeterminate="allColumnsSelectedIndeterminate"
+ @change="handleCheckAllChange"
+ >
+ 全选
+ </el-checkbox>
+ <el-checkbox
+ v-for="item in tableColumns"
+ :key="item.property"
+ v-model="item.visible"
+ @change="handleCheckedTableColumnsChange(item)"
+ >
+ {{ item.label }}
+ </el-checkbox>
+ </el-popover>
+ </el-button-group>
+ </div>
+</template>
+<script>
+import CRUD, { crud } from '@crud/crud'
+
+function sortWithRef(src, ref) {
+ const result = Object.assign([], ref)
+ let cursor = -1
+ src.forEach(e => {
+ const idx = result.indexOf(e)
+ if (idx === -1) {
+ cursor += 1
+ result.splice(cursor, 0, e)
+ } else {
+ cursor = idx
+ }
+ })
+ return result
+}
+
+export default {
+ mixins: [crud()],
+ props: {
+ permission: {
+ type: Object,
+ default: () => { return {} }
+ },
+ hiddenColumns: {
+ type: Array,
+ default: () => { return [] }
+ },
+ ignoreColumns: {
+ type: Array,
+ default: () => { return [] }
+ }
+ },
+ data() {
+ return {
+ tableColumns: [],
+ allColumnsSelected: true,
+ allColumnsSelectedIndeterminate: false,
+ tableUnwatcher: null,
+ // 忽略下次表格列变动
+ ignoreNextTableColumnsChange: false
+ }
+ },
+ watch: {
+ 'crud.props.table'() {
+ this.updateTableColumns()
+ this.tableColumns.forEach(column => {
+ if (this.hiddenColumns.indexOf(column.property) !== -1) {
+ column.visible = false
+ this.updateColumnVisible(column)
+ }
+ })
+ },
+ 'crud.props.table.store.states.columns'() {
+ this.updateTableColumns()
+ }
+ },
+ created() {
+ this.crud.updateProp('searchToggle', true)
+ },
+ methods: {
+ updateTableColumns() {
+ const table = this.crud.getTable()
+ if (!table) {
+ this.tableColumns = []
+ return
+ }
+ let cols = null
+ const columnFilter = e => e && e.type === 'default' && e.property && this.ignoreColumns.indexOf(e.property) === -1
+ const refCols = table.columns.filter(columnFilter)
+ if (this.ignoreNextTableColumnsChange) {
+ this.ignoreNextTableColumnsChange = false
+ return
+ }
+ this.ignoreNextTableColumnsChange = false
+ const columns = []
+ const fullTableColumns = table.$children.map(e => e.columnConfig).filter(columnFilter)
+ cols = sortWithRef(fullTableColumns, refCols)
+ cols.forEach(config => {
+ const column = {
+ property: config.property,
+ label: config.label,
+ visible: refCols.indexOf(config) !== -1
+ }
+ columns.push(column)
+ })
+ this.tableColumns = columns
+ },
+ toDelete(datas) {
+ this.$confirm(`确认删除选中的${datas.length}条数据?`, '提示', {
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ type: 'warning'
+ }).then(() => {
+ this.crud.delAllLoading = true
+ this.crud.doDelete(datas)
+ }).catch(() => {
+ })
+ },
+ handleCheckAllChange(val) {
+ if (val === false) {
+ this.allColumnsSelected = true
+ return
+ }
+ this.tableColumns.forEach(column => {
+ if (!column.visible) {
+ column.visible = true
+ this.updateColumnVisible(column)
+ }
+ })
+ this.allColumnsSelected = val
+ this.allColumnsSelectedIndeterminate = false
+ },
+ handleCheckedTableColumnsChange(item) {
+ let totalCount = 0
+ let selectedCount = 0
+ this.tableColumns.forEach(column => {
+ ++totalCount
+ selectedCount += column.visible ? 1 : 0
+ })
+ if (selectedCount === 0) {
+ this.crud.notify('请至少选择一列', CRUD.NOTIFICATION_TYPE.WARNING)
+ this.$nextTick(function() {
+ item.visible = true
+ })
+ return
+ }
+ this.allColumnsSelected = selectedCount === totalCount
+ this.allColumnsSelectedIndeterminate = selectedCount !== totalCount && selectedCount !== 0
+ this.updateColumnVisible(item)
+ },
+ updateColumnVisible(item) {
+ const table = this.crud.props.table
+ const vm = table.$children.find(e => e.prop === item.property)
+ const columnConfig = vm.columnConfig
+ if (item.visible) {
+ // 找出合适的插入点
+ const columnIndex = this.tableColumns.indexOf(item)
+ vm.owner.store.commit('insertColumn', columnConfig, columnIndex + 1, null)
+ } else {
+ vm.owner.store.commit('removeColumn', columnConfig, null)
+ }
+ this.ignoreNextTableColumnsChange = true
+ },
+ toggleSearch() {
+ this.crud.props.searchToggle = !this.crud.props.searchToggle
+ }
+ }
+}
+</script>
+
+<style>
+ .crud-opts {
+ padding: 4px 0;
+ display: -webkit-flex;
+ display: flex;
+ align-items: center;
+ }
+ .crud-opts .crud-opts-right {
+ margin-left: auto;
+ }
+ .crud-opts .crud-opts-right span {
+ float: left;
+ }
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Crud/Pagination.vue b/UI source code/dns_mapping_ui-master/src/components/Crud/Pagination.vue
new file mode 100644
index 0000000..d4482fb
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Crud/Pagination.vue
@@ -0,0 +1,18 @@
+<!--分页-->
+<template>
+ <el-pagination
+ :page-size.sync="page.size"
+ :total="page.total"
+ :current-page.sync="page.page"
+ style="margin-top: 8px;"
+ layout="total, prev, pager, next, sizes"
+ @size-change="crud.sizeChangeHandler($event)"
+ @current-change="crud.pageChangeHandler"
+ />
+</template>
+<script>
+import { pagination } from '@crud/crud'
+export default {
+ mixins: [pagination()]
+}
+</script>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Crud/RR.operation.vue b/UI source code/dns_mapping_ui-master/src/components/Crud/RR.operation.vue
new file mode 100644
index 0000000..df2c138
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Crud/RR.operation.vue
@@ -0,0 +1,20 @@
+<!--搜索与重置-->
+<template>
+ <span>
+ <el-button class="filter-item" size="mini" type="success" icon="el-icon-search" @click="crud.toQuery">搜索</el-button>
+ <el-button v-if="crud.optShow.reset" class="filter-item" size="mini" type="warning" icon="el-icon-refresh-left" @click="crud.resetQuery()">重置</el-button>
+ </span>
+</template>
+<script>
+import { crud } from '@crud/crud'
+export default {
+ mixins: [crud()],
+ props: {
+ itemClass: {
+ type: String,
+ required: false,
+ default: ''
+ }
+ }
+}
+</script>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Crud/UD.operation.vue b/UI source code/dns_mapping_ui-master/src/components/Crud/UD.operation.vue
new file mode 100644
index 0000000..c60abd7
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Crud/UD.operation.vue
@@ -0,0 +1,71 @@
+<template>
+ <div>
+ <el-button v-permission="permission.edit" :loading="crud.status.cu === 2" :disabled="disabledEdit" size="mini" type="primary" icon="el-icon-edit" @click="crud.toEdit(data)" />
+ <el-popover v-model="pop" v-permission="permission.del" placement="top" width="180" trigger="manual" @show="onPopoverShow" @hide="onPopoverHide">
+ <p>{{ msg }}</p>
+ <div style="text-align: right; margin: 0">
+ <el-button size="mini" type="text" @click="doCancel">取消</el-button>
+ <el-button :loading="crud.dataStatus[crud.getDataId(data)].delete === 2" type="primary" size="mini" @click="crud.doDelete(data)">确定</el-button>
+ </div>
+ <el-button slot="reference" :disabled="disabledDle" type="danger" icon="el-icon-delete" size="mini" @click="toDelete" />
+ </el-popover>
+ </div>
+</template>
+<script>
+import CRUD, { crud } from '@crud/crud'
+export default {
+ mixins: [crud()],
+ props: {
+ data: {
+ type: Object,
+ required: true
+ },
+ permission: {
+ type: Object,
+ required: true
+ },
+ disabledEdit: {
+ type: Boolean,
+ default: false
+ },
+ disabledDle: {
+ type: Boolean,
+ default: false
+ },
+ msg: {
+ type: String,
+ default: '确定删除本条数据吗?'
+ }
+ },
+ data() {
+ return {
+ pop: false
+ }
+ },
+ methods: {
+ doCancel() {
+ this.pop = false
+ this.crud.cancelDelete(this.data)
+ },
+ toDelete() {
+ this.pop = true
+ },
+ [CRUD.HOOK.afterDelete](crud, data) {
+ if (data === this.data) {
+ this.pop = false
+ }
+ },
+ onPopoverShow() {
+ setTimeout(() => {
+ document.addEventListener('click', this.handleDocumentClick)
+ }, 0)
+ },
+ onPopoverHide() {
+ document.removeEventListener('click', this.handleDocumentClick)
+ },
+ handleDocumentClick(event) {
+ this.pop = false
+ }
+ }
+}
+</script>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Crud/crud.js b/UI source code/dns_mapping_ui-master/src/components/Crud/crud.js
new file mode 100644
index 0000000..ae36765
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Crud/crud.js
@@ -0,0 +1,863 @@
+import { initData, download } from '@/api/data'
+import { parseTime, downloadFile } from '@/utils/index'
+import Vue from 'vue'
+
+/**
+ * CRUD配置
+ * @author moxun
+ * @param {*} options <br>
+ * @return crud instance.
+ * @example
+ * 要使用多crud时,请在关联crud的组件处使用crud-tag进行标记,如:<jobForm :job-status="dict.job_status" crud-tag="job" />
+ */
+function CRUD(options) {
+ const defaultOptions = {
+ tag: 'default',
+ // id字段名
+ idField: 'id',
+ // 标题
+ title: '',
+ // 请求数据的url
+ url: '',
+ // 表格数据
+ data: [],
+ // 选择项
+ selections: [],
+ // 待查询的对象
+ query: {},
+ // 查询数据的参数
+ params: {},
+ // Form 表单
+ form: {},
+ // 重置表单
+ defaultForm: () => {},
+ // 排序规则,默认 id 降序, 支持多字段排序 ['id,desc', 'createTime,asc']
+ sort: ['id,desc'],
+ // 等待时间
+ time: 50,
+ // CRUD Method
+ crudMethod: {
+ add: (form) => {},
+ del: (id) => {},
+ edit: (form) => {},
+ get: (id) => {}
+ },
+ // 主页操作栏显示哪些按钮
+ optShow: {
+ add: true,
+ edit: true,
+ del: true,
+ download: true,
+ reset: true
+ },
+ // 自定义一些扩展属性
+ props: {},
+ // 在主页准备
+ queryOnPresenterCreated: true,
+ // 调试开关
+ debug: false
+ }
+ options = mergeOptions(defaultOptions, options)
+ const data = {
+ ...options,
+ // 记录数据状态
+ dataStatus: {},
+ status: {
+ add: CRUD.STATUS.NORMAL,
+ edit: CRUD.STATUS.NORMAL,
+ // 添加或编辑状态
+ get cu() {
+ if (this.add === CRUD.STATUS.NORMAL && this.edit === CRUD.STATUS.NORMAL) {
+ return CRUD.STATUS.NORMAL
+ } else if (this.add === CRUD.STATUS.PREPARED || this.edit === CRUD.STATUS.PREPARED) {
+ return CRUD.STATUS.PREPARED
+ } else if (this.add === CRUD.STATUS.PROCESSING || this.edit === CRUD.STATUS.PROCESSING) {
+ return CRUD.STATUS.PROCESSING
+ }
+ throw new Error('wrong crud\'s cu status')
+ },
+ // 标题
+ get title() {
+ return this.add > CRUD.STATUS.NORMAL ? `新增${crud.title}` : this.edit > CRUD.STATUS.NORMAL ? `编辑${crud.title}` : crud.title
+ }
+ },
+ msg: {
+ submit: '提交成功',
+ add: '新增成功',
+ edit: '编辑成功',
+ del: '删除成功'
+ },
+ page: {
+ // 页码
+ page: 0,
+ // 每页数据条数
+ size: 10,
+ // 总数据条数
+ total: 0
+ },
+ // 整体loading
+ loading: false,
+ // 导出的 Loading
+ downloadLoading: false,
+ // 删除的 Loading
+ delAllLoading: false
+ }
+ const methods = {
+ /**
+ * 通用的提示
+ */
+ submitSuccessNotify() {
+ crud.notify(crud.msg.submit, CRUD.NOTIFICATION_TYPE.SUCCESS)
+ },
+ addSuccessNotify() {
+ crud.notify(crud.msg.add, CRUD.NOTIFICATION_TYPE.SUCCESS)
+ },
+ editSuccessNotify() {
+ crud.notify(crud.msg.edit, CRUD.NOTIFICATION_TYPE.SUCCESS)
+ },
+ delSuccessNotify() {
+ crud.notify(crud.msg.del, CRUD.NOTIFICATION_TYPE.SUCCESS)
+ },
+ // 搜索
+ toQuery() {
+ crud.page.page = 1
+ crud.refresh()
+ },
+ // 刷新
+ refresh() {
+ if (!callVmHook(crud, CRUD.HOOK.beforeRefresh)) {
+ return
+ }
+ return new Promise((resolve, reject) => {
+ crud.loading = true
+ // 请求数据
+ initData(crud.url, crud.getQueryParams()).then(data => {
+ const table = crud.getTable()
+ if (table && table.lazy) { // 懒加载子节点数据,清掉已加载的数据
+ table.store.states.treeData = {}
+ table.store.states.lazyTreeNodeMap = {}
+ }
+ crud.page.total = data.totalElements
+ crud.data = data.content
+ crud.resetDataStatus()
+ // time 毫秒后显示表格
+ setTimeout(() => {
+ crud.loading = false
+ callVmHook(crud, CRUD.HOOK.afterRefresh)
+ }, crud.time)
+ resolve(data)
+ }).catch(err => {
+ crud.loading = false
+ reject(err)
+ })
+ })
+ },
+ /**
+ * 启动添加
+ */
+ toAdd() {
+ crud.resetForm()
+ if (!(callVmHook(crud, CRUD.HOOK.beforeToAdd, crud.form) && callVmHook(crud, CRUD.HOOK.beforeToCU, crud.form))) {
+ return
+ }
+ crud.status.add = CRUD.STATUS.PREPARED
+ callVmHook(crud, CRUD.HOOK.afterToAdd, crud.form)
+ callVmHook(crud, CRUD.HOOK.afterToCU, crud.form)
+ },
+ /**
+ * 启动编辑
+ * @param {*} data 数据项
+ */
+ toEdit(data) {
+ crud.resetForm(JSON.parse(JSON.stringify(data)))
+ if (!(callVmHook(crud, CRUD.HOOK.beforeToEdit, crud.form) && callVmHook(crud, CRUD.HOOK.beforeToCU, crud.form))) {
+ return
+ }
+ crud.status.edit = CRUD.STATUS.PREPARED
+ crud.getDataStatus(crud.getDataId(data)).edit = CRUD.STATUS.PREPARED
+ callVmHook(crud, CRUD.HOOK.afterToEdit, crud.form)
+ callVmHook(crud, CRUD.HOOK.afterToCU, crud.form)
+ },
+ /**
+ * 启动删除
+ * @param {*} data 数据项
+ */
+ toDelete(data) {
+ crud.getDataStatus(crud.getDataId(data)).delete = CRUD.STATUS.PREPARED
+ },
+ /**
+ * 取消删除
+ * @param {*} data 数据项
+ */
+ cancelDelete(data) {
+ if (!callVmHook(crud, CRUD.HOOK.beforeDeleteCancel, data)) {
+ return
+ }
+ crud.getDataStatus(crud.getDataId(data)).delete = CRUD.STATUS.NORMAL
+ callVmHook(crud, CRUD.HOOK.afterDeleteCancel, data)
+ },
+ /**
+ * 取消新增/编辑
+ */
+ cancelCU() {
+ const addStatus = crud.status.add
+ const editStatus = crud.status.edit
+ if (addStatus === CRUD.STATUS.PREPARED) {
+ if (!callVmHook(crud, CRUD.HOOK.beforeAddCancel, crud.form)) {
+ return
+ }
+ crud.status.add = CRUD.STATUS.NORMAL
+ }
+ if (editStatus === CRUD.STATUS.PREPARED) {
+ if (!callVmHook(crud, CRUD.HOOK.beforeEditCancel, crud.form)) {
+ return
+ }
+ crud.status.edit = CRUD.STATUS.NORMAL
+ crud.getDataStatus(crud.getDataId(crud.form)).edit = CRUD.STATUS.NORMAL
+ }
+ crud.resetForm()
+ if (addStatus === CRUD.STATUS.PREPARED) {
+ callVmHook(crud, CRUD.HOOK.afterAddCancel, crud.form)
+ }
+ if (editStatus === CRUD.STATUS.PREPARED) {
+ callVmHook(crud, CRUD.HOOK.afterEditCancel, crud.form)
+ }
+ // 清除表单验证
+ if (crud.findVM('form').$refs['form']) {
+ crud.findVM('form').$refs['form'].clearValidate()
+ }
+ },
+ /**
+ * 提交新增/编辑
+ */
+ submitCU() {
+ if (!callVmHook(crud, CRUD.HOOK.beforeValidateCU)) {
+ return
+ }
+ crud.findVM('form').$refs['form'].validate(valid => {
+ if (!valid) {
+ return
+ }
+ if (!callVmHook(crud, CRUD.HOOK.afterValidateCU)) {
+ return
+ }
+ if (crud.status.add === CRUD.STATUS.PREPARED) {
+ crud.doAdd()
+ } else if (crud.status.edit === CRUD.STATUS.PREPARED) {
+ crud.doEdit()
+ }
+ })
+ },
+ /**
+ * 执行添加
+ */
+ doAdd() {
+ if (!callVmHook(crud, CRUD.HOOK.beforeSubmit)) {
+ return
+ }
+ crud.status.add = CRUD.STATUS.PROCESSING
+ crud.crudMethod.add(crud.form).then(() => {
+ crud.status.add = CRUD.STATUS.NORMAL
+ crud.resetForm()
+ crud.addSuccessNotify()
+ callVmHook(crud, CRUD.HOOK.afterSubmit)
+ crud.toQuery()
+ }).catch(() => {
+ crud.status.add = CRUD.STATUS.PREPARED
+ callVmHook(crud, CRUD.HOOK.afterAddError)
+ })
+ },
+ /**
+ * 执行编辑
+ */
+ doEdit() {
+ if (!callVmHook(crud, CRUD.HOOK.beforeSubmit)) {
+ return
+ }
+ crud.status.edit = CRUD.STATUS.PROCESSING
+ crud.crudMethod.edit(crud.form).then(() => {
+ crud.status.edit = CRUD.STATUS.NORMAL
+ crud.getDataStatus(crud.getDataId(crud.form)).edit = CRUD.STATUS.NORMAL
+ crud.editSuccessNotify()
+ crud.resetForm()
+ callVmHook(crud, CRUD.HOOK.afterSubmit)
+ crud.refresh()
+ }).catch(() => {
+ crud.status.edit = CRUD.STATUS.PREPARED
+ callVmHook(crud, CRUD.HOOK.afterEditError)
+ })
+ },
+ /**
+ * 执行删除
+ * @param {*} data 数据项
+ */
+ doDelete(data) {
+ let delAll = false
+ let dataStatus
+ const ids = []
+ if (data instanceof Array) {
+ delAll = true
+ data.forEach(val => {
+ ids.push(this.getDataId(val))
+ })
+ } else {
+ ids.push(this.getDataId(data))
+ dataStatus = crud.getDataStatus(this.getDataId(data))
+ }
+ if (!callVmHook(crud, CRUD.HOOK.beforeDelete, data)) {
+ return
+ }
+ if (!delAll) {
+ dataStatus.delete = CRUD.STATUS.PROCESSING
+ }
+ return crud.crudMethod.del(ids).then(() => {
+ if (delAll) {
+ crud.delAllLoading = false
+ } else dataStatus.delete = CRUD.STATUS.PREPARED
+ crud.dleChangePage(1)
+ crud.delSuccessNotify()
+ callVmHook(crud, CRUD.HOOK.afterDelete, data)
+ crud.refresh()
+ }).catch(() => {
+ if (delAll) {
+ crud.delAllLoading = false
+ } else dataStatus.delete = CRUD.STATUS.PREPARED
+ })
+ },
+ /**
+ * 通用导出
+ */
+ doExport() {
+ crud.downloadLoading = true
+ download(crud.url + '/download', crud.getQueryParams()).then(result => {
+ downloadFile(result, crud.title + '数据', 'xlsx')
+ crud.downloadLoading = false
+ }).catch(() => {
+ crud.downloadLoading = false
+ })
+ },
+ /**
+ * 获取查询参数
+ */
+ getQueryParams: function() {
+ // 清除参数无值的情况
+ Object.keys(crud.query).length !== 0 && Object.keys(crud.query).forEach(item => {
+ if (crud.query[item] === null || crud.query[item] === '') crud.query[item] = undefined
+ })
+ Object.keys(crud.params).length !== 0 && Object.keys(crud.params).forEach(item => {
+ if (crud.params[item] === null || crud.params[item] === '') crud.params[item] = undefined
+ })
+ return {
+ page: crud.page.page - 1,
+ size: crud.page.size,
+ sort: crud.sort,
+ ...crud.query,
+ ...crud.params
+ }
+ },
+ // 当前页改变
+ pageChangeHandler(e) {
+ crud.page.page = e
+ crud.refresh()
+ },
+ // 每页条数改变
+ sizeChangeHandler(e) {
+ crud.page.size = e
+ crud.page.page = 1
+ crud.refresh()
+ },
+ // 预防删除第二页最后一条数据时,或者多选删除第二页的数据时,页码错误导致请求无数据
+ dleChangePage(size) {
+ if (crud.data.length === size && crud.page.page !== 1) {
+ crud.page.page -= 1
+ }
+ },
+ // 选择改变
+ selectionChangeHandler(val) {
+ crud.selections = val
+ },
+ /**
+ * 重置查询参数
+ * @param {Boolean} toQuery 重置后进行查询操作
+ */
+ resetQuery(toQuery = true) {
+ const defaultQuery = JSON.parse(JSON.stringify(crud.defaultQuery))
+ const query = crud.query
+ Object.keys(query).forEach(key => {
+ query[key] = defaultQuery[key]
+ })
+ // 重置参数
+ this.params = {}
+ if (toQuery) {
+ crud.toQuery()
+ }
+ },
+ /**
+ * 重置表单
+ * @param {Array} data 数据
+ */
+ resetForm(data) {
+ const form = data || (typeof crud.defaultForm === 'object' ? JSON.parse(JSON.stringify(crud.defaultForm)) : crud.defaultForm.apply(crud.findVM('form')))
+ const crudFrom = crud.form
+ for (const key in form) {
+ if (crudFrom.hasOwnProperty(key)) {
+ crudFrom[key] = form[key]
+ } else {
+ Vue.set(crudFrom, key, form[key])
+ }
+ }
+ // add by ghl 2020-10-04 页面重复添加信息时,下拉框的校验会存在,需要找工取消
+ if (crud.findVM('form').$refs['form']) {
+ crud.findVM('form').$refs['form'].clearValidate()
+ }
+ },
+ /**
+ * 重置数据状态
+ */
+ resetDataStatus() {
+ const dataStatus = {}
+ function resetStatus(datas) {
+ datas.forEach(e => {
+ dataStatus[crud.getDataId(e)] = {
+ delete: 0,
+ edit: 0
+ }
+ if (e.children) {
+ resetStatus(e.children)
+ }
+ })
+ }
+ resetStatus(crud.data)
+ crud.dataStatus = dataStatus
+ },
+ /**
+ * 获取数据状态
+ * @param {Number | String} id 数据项id
+ */
+ getDataStatus(id) {
+ return crud.dataStatus[id]
+ },
+ /**
+ * 用于树形表格多选, 选中所有
+ * @param selection
+ */
+ selectAllChange(selection) {
+ // 如果选中的数目与请求到的数目相同就选中子节点,否则就清空选中
+ if (selection && selection.length === crud.data.length) {
+ selection.forEach(val => {
+ crud.selectChange(selection, val)
+ })
+ } else {
+ crud.getTable().clearSelection()
+ }
+ },
+ /**
+ * 用于树形表格多选,单选的封装
+ * @param selection
+ * @param row
+ */
+ selectChange(selection, row) {
+ // 如果selection中存在row代表是选中,否则是取消选中
+ if (selection.find(val => { return crud.getDataId(val) === crud.getDataId(row) })) {
+ if (row.children) {
+ row.children.forEach(val => {
+ crud.getTable().toggleRowSelection(val, true)
+ selection.push(val)
+ if (val.children) {
+ crud.selectChange(selection, val)
+ }
+ })
+ }
+ } else {
+ crud.toggleRowSelection(selection, row)
+ }
+ },
+ /**
+ * 切换选中状态
+ * @param selection
+ * @param data
+ */
+ toggleRowSelection(selection, data) {
+ if (data.children) {
+ data.children.forEach(val => {
+ crud.getTable().toggleRowSelection(val, false)
+ if (val.children) {
+ crud.toggleRowSelection(selection, val)
+ }
+ })
+ }
+ },
+ findVM(type) {
+ return crud.vms.find(vm => vm && vm.type === type).vm
+ },
+ notify(title, type = CRUD.NOTIFICATION_TYPE.INFO) {
+ crud.vms[0].vm.$notify({
+ title,
+ type,
+ duration: 2500
+ })
+ },
+ updateProp(name, value) {
+ Vue.set(crud.props, name, value)
+ },
+ getDataId(data) {
+ return data[this.idField]
+ },
+ getTable() {
+ return this.findVM('presenter').$refs.table
+ },
+ attchTable() {
+ const table = this.getTable()
+ this.updateProp('table', table)
+ const that = this
+ table.$on('expand-change', (row, expanded) => {
+ if (!expanded) {
+ return
+ }
+ const lazyTreeNodeMap = table.store.states.lazyTreeNodeMap
+ row.children = lazyTreeNodeMap[crud.getDataId(row)]
+ if (row.children) {
+ row.children.forEach(ele => {
+ const id = crud.getDataId(ele)
+ if (that.dataStatus[id] === undefined) {
+ that.dataStatus[id] = {
+ delete: 0,
+ edit: 0
+ }
+ }
+ })
+ }
+ })
+ }
+ }
+ const crud = Object.assign({}, data)
+ // 可观测化
+ Vue.observable(crud)
+ // 附加方法
+ Object.assign(crud, methods)
+ // 记录初始默认的查询参数,后续重置查询时使用
+ Object.assign(crud, {
+ defaultQuery: JSON.parse(JSON.stringify(data.query)),
+ // 预留4位存储:组件 主页、头部、分页、表单,调试查看也方便找
+ vms: Array(4),
+ /**
+ * 注册组件实例
+ * @param {String} type 类型
+ * @param {*} vm 组件实例
+ * @param {Number} index 该参数内部使用
+ */
+ registerVM(type, vm, index = -1) {
+ const vmObj = {
+ type,
+ vm: vm
+ }
+ if (index < 0) {
+ this.vms.push(vmObj)
+ return
+ }
+ if (index < 4) { // 内置预留vm数
+ this.vms[index] = vmObj
+ return
+ }
+ this.vms.length = Math.max(this.vms.length, index)
+ this.vms.splice(index, 1, vmObj)
+ },
+ /**
+ * 取消注册组件实例
+ * @param {*} vm 组件实例
+ */
+ unregisterVM(type, vm) {
+ for (let i = this.vms.length - 1; i >= 0; i--) {
+ if (this.vms[i] === undefined) {
+ continue
+ }
+ if (this.vms[i].type === type && this.vms[i].vm === vm) {
+ if (i < 4) { // 内置预留vm数
+ this.vms[i] = undefined
+ } else {
+ this.vms.splice(i, 1)
+ }
+ break
+ }
+ }
+ }
+ })
+ // 冻结处理,需要扩展数据的话,使用crud.updateProp(name, value),以crud.props.name形式访问,这个是响应式的,可以做数据绑定
+ Object.freeze(crud)
+ return crud
+}
+
+// hook VM
+function callVmHook(crud, hook) {
+ if (crud.debug) {
+ console.log('callVmHook: ' + hook)
+ }
+ const tagHook = crud.tag ? hook + '$' + crud.tag : null
+ let ret = true
+ const nargs = [crud]
+ for (let i = 2; i < arguments.length; ++i) {
+ nargs.push(arguments[i])
+ }
+ // 有些组件扮演了多个角色,调用钩子时,需要去重
+ const vmSet = new Set()
+ crud.vms.forEach(vm => vm && vmSet.add(vm.vm))
+ vmSet.forEach(vm => {
+ if (vm[hook]) {
+ ret = vm[hook].apply(vm, nargs) !== false && ret
+ }
+ if (tagHook && vm[tagHook]) {
+ ret = vm[tagHook].apply(vm, nargs) !== false && ret
+ }
+ })
+ return ret
+}
+
+function mergeOptions(src, opts) {
+ const optsRet = {
+ ...src
+ }
+ for (const key in src) {
+ if (opts.hasOwnProperty(key)) {
+ optsRet[key] = opts[key]
+ }
+ }
+ return optsRet
+}
+
+/**
+ * 查找crud
+ * @param {*} vm
+ * @param {string} tag
+ */
+function lookupCrud(vm, tag) {
+ tag = tag || vm.$attrs['crud-tag'] || 'default'
+ // function lookupCrud(vm, tag) {
+ if (vm.$crud) {
+ const ret = vm.$crud[tag]
+ if (ret) {
+ return ret
+ }
+ }
+ return vm.$parent ? lookupCrud(vm.$parent, tag) : undefined
+}
+
+/**
+ * crud主页
+ */
+function presenter(crud) {
+ if (crud) {
+ console.warn('[CRUD warn]: ' + 'please use $options.cruds() { return CRUD(...) or [CRUD(...), ...] }')
+ }
+ return {
+ data() {
+ // 在data中返回crud,是为了将crud与当前实例关联,组件观测crud相关属性变化
+ return {
+ crud: this.crud
+ }
+ },
+ beforeCreate() {
+ this.$crud = this.$crud || {}
+ let cruds = this.$options.cruds instanceof Function ? this.$options.cruds() : crud
+ if (!(cruds instanceof Array)) {
+ cruds = [cruds]
+ }
+ cruds.forEach(ele => {
+ if (this.$crud[ele.tag]) {
+ console.error('[CRUD error]: ' + 'crud with tag [' + ele.tag + ' is already exist')
+ }
+ this.$crud[ele.tag] = ele
+ ele.registerVM('presenter', this, 0)
+ })
+ this.crud = this.$crud['defalut'] || cruds[0]
+ },
+ methods: {
+ parseTime
+ },
+ created() {
+ for (const k in this.$crud) {
+ if (this.$crud[k].queryOnPresenterCreated) {
+ this.$crud[k].toQuery()
+ }
+ }
+ },
+ destroyed() {
+ for (const k in this.$crud) {
+ this.$crud[k].unregisterVM('presenter', this)
+ }
+ },
+ mounted() {
+ // 如果table未实例化(例如使用了v-if),请稍后在适当时机crud.attchTable刷新table信息
+ if (this.$refs.table !== undefined) {
+ this.crud.attchTable()
+ }
+ }
+ }
+}
+
+/**
+ * 头部
+ */
+function header() {
+ return {
+ data() {
+ return {
+ crud: this.crud,
+ query: this.crud.query
+ }
+ },
+ beforeCreate() {
+ this.crud = lookupCrud(this)
+ this.crud.registerVM('header', this, 1)
+ },
+ destroyed() {
+ this.crud.unregisterVM('header', this)
+ }
+ }
+}
+
+/**
+ * 分页
+ */
+function pagination() {
+ return {
+ data() {
+ return {
+ crud: this.crud,
+ page: this.crud.page
+ }
+ },
+ beforeCreate() {
+ this.crud = lookupCrud(this)
+ this.crud.registerVM('pagination', this, 2)
+ },
+ destroyed() {
+ this.crud.unregisterVM('pagination', this)
+ }
+ }
+}
+
+/**
+ * 表单
+ */
+function form(defaultForm) {
+ return {
+ data() {
+ return {
+ crud: this.crud,
+ form: this.crud.form
+ }
+ },
+ beforeCreate() {
+ this.crud = lookupCrud(this)
+ this.crud.registerVM('form', this, 3)
+ },
+ created() {
+ this.crud.defaultForm = defaultForm
+ this.crud.resetForm()
+ },
+ destroyed() {
+ this.crud.unregisterVM('form', this)
+ }
+ }
+}
+
+/**
+ * crud
+ */
+function crud(options = {}) {
+ const defaultOptions = {
+ type: undefined
+ }
+ options = mergeOptions(defaultOptions, options)
+ return {
+ data() {
+ return {
+ crud: this.crud
+ }
+ },
+ beforeCreate() {
+ this.crud = lookupCrud(this)
+ this.crud.registerVM(options.type, this)
+ },
+ destroyed() {
+ this.crud.unregisterVM(options.type, this)
+ }
+ }
+}
+
+/**
+ * CRUD钩子
+ */
+CRUD.HOOK = {
+ /** 刷新 - 之前 */
+ beforeRefresh: 'beforeCrudRefresh',
+ /** 刷新 - 之后 */
+ afterRefresh: 'afterCrudRefresh',
+ /** 删除 - 之前 */
+ beforeDelete: 'beforeCrudDelete',
+ /** 删除 - 之后 */
+ afterDelete: 'afterCrudDelete',
+ /** 删除取消 - 之前 */
+ beforeDeleteCancel: 'beforeCrudDeleteCancel',
+ /** 删除取消 - 之后 */
+ afterDeleteCancel: 'afterCrudDeleteCancel',
+ /** 新建 - 之前 */
+ beforeToAdd: 'beforeCrudToAdd',
+ /** 新建 - 之后 */
+ afterToAdd: 'afterCrudToAdd',
+ /** 编辑 - 之前 */
+ beforeToEdit: 'beforeCrudToEdit',
+ /** 编辑 - 之后 */
+ afterToEdit: 'afterCrudToEdit',
+ /** 开始 "新建/编辑" - 之前 */
+ beforeToCU: 'beforeCrudToCU',
+ /** 开始 "新建/编辑" - 之后 */
+ afterToCU: 'afterCrudToCU',
+ /** "新建/编辑" 验证 - 之前 */
+ beforeValidateCU: 'beforeCrudValidateCU',
+ /** "新建/编辑" 验证 - 之后 */
+ afterValidateCU: 'afterCrudValidateCU',
+ /** 添加取消 - 之前 */
+ beforeAddCancel: 'beforeCrudAddCancel',
+ /** 添加取消 - 之后 */
+ afterAddCancel: 'afterCrudAddCancel',
+ /** 编辑取消 - 之前 */
+ beforeEditCancel: 'beforeCrudEditCancel',
+ /** 编辑取消 - 之后 */
+ afterEditCancel: 'afterCrudEditCancel',
+ /** 提交 - 之前 */
+ beforeSubmit: 'beforeCrudSubmitCU',
+ /** 提交 - 之后 */
+ afterSubmit: 'afterCrudSubmitCU',
+ afterAddError: 'afterCrudAddError',
+ afterEditError: 'afterCrudEditError'
+}
+
+/**
+ * CRUD状态
+ */
+CRUD.STATUS = {
+ NORMAL: 0,
+ PREPARED: 1,
+ PROCESSING: 2
+}
+
+/**
+ * CRUD通知类型
+ */
+CRUD.NOTIFICATION_TYPE = {
+ SUCCESS: 'success',
+ WARNING: 'warning',
+ INFO: 'info',
+ ERROR: 'error'
+}
+
+export default CRUD
+
+export {
+ presenter,
+ header,
+ form,
+ pagination,
+ crud
+}
diff --git a/UI source code/dns_mapping_ui-master/src/components/DateRangePicker/index.vue b/UI source code/dns_mapping_ui-master/src/components/DateRangePicker/index.vue
new file mode 100644
index 0000000..eef79bd
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/DateRangePicker/index.vue
@@ -0,0 +1,45 @@
+<script>
+import { DatePicker, DatePickerOptions } from 'element-ui'
+import { calendarShortcuts } from '@/utils/shortcuts'
+
+export default {
+ name: 'DateRangePicker',
+ mixins: [DatePicker],
+ props: {
+ type: {
+ type: String,
+ default: 'daterange'
+ },
+ valueFormat: {
+ type: String,
+ default: 'yyyy-MM-dd HH:mm:ss'
+ },
+ defaultTime: {
+ type: Array,
+ default: _ => ['00:00:00', '23:59:59']
+ },
+ pickerOptions: {
+ type: DatePickerOptions,
+ default: _ => {
+ return { shortcuts: calendarShortcuts }
+ }
+ },
+ size: {
+ type: String,
+ default: 'small'
+ },
+ rangeSeparator: {
+ type: String,
+ default: ':'
+ },
+ startPlaceholder: {
+ type: String,
+ default: '开始日期'
+ },
+ endPlaceholder: {
+ type: String,
+ default: '结束日期'
+ }
+ }
+}
+</script>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Dict/Dict.js b/UI source code/dns_mapping_ui-master/src/components/Dict/Dict.js
new file mode 100644
index 0000000..48554de
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Dict/Dict.js
@@ -0,0 +1,29 @@
+import Vue from 'vue'
+import { get as getDictDetail } from '@/api/system/dictDetail'
+
+export default class Dict {
+ constructor(dict) {
+ this.dict = dict
+ }
+
+ async init(names, completeCallback) {
+ if (names === undefined || name === null) {
+ throw new Error('need Dict names')
+ }
+ const ps = []
+ names.forEach(n => {
+ Vue.set(this.dict.dict, n, {})
+ Vue.set(this.dict.label, n, {})
+ Vue.set(this.dict, n, [])
+ ps.push(getDictDetail(n).then(data => {
+ this.dict[n].splice(0, 0, ...data.content)
+ data.content.forEach(d => {
+ Vue.set(this.dict.dict[n], d.value, d)
+ Vue.set(this.dict.label[n], d.value, d.label)
+ })
+ }))
+ })
+ await Promise.all(ps)
+ completeCallback()
+ }
+}
diff --git a/UI source code/dns_mapping_ui-master/src/components/Dict/index.js b/UI source code/dns_mapping_ui-master/src/components/Dict/index.js
new file mode 100644
index 0000000..0952f43
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Dict/index.js
@@ -0,0 +1,29 @@
+import Dict from './Dict'
+
+const install = function(Vue) {
+ Vue.mixin({
+ data() {
+ if (this.$options.dicts instanceof Array) {
+ const dict = {
+ dict: {},
+ label: {}
+ }
+ return {
+ dict
+ }
+ }
+ return {}
+ },
+ created() {
+ if (this.$options.dicts instanceof Array) {
+ new Dict(this.dict).init(this.$options.dicts, () => {
+ this.$nextTick(() => {
+ this.$emit('dictReady')
+ })
+ })
+ }
+ }
+ })
+}
+
+export default { install }
diff --git a/UI source code/dns_mapping_ui-master/src/components/Doc/index.vue b/UI source code/dns_mapping_ui-master/src/components/Doc/index.vue
new file mode 100644
index 0000000..47c5e8d
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Doc/index.vue
@@ -0,0 +1,16 @@
+<template>
+ <div>
+ <svg-icon icon-class="doc" @click="click" />
+ </div>
+</template>
+
+<script>
+export default {
+ name: 'Doc',
+ methods: {
+ click() {
+ window.open('https://el-admin.vip/pages/010101/', '_blank')
+ }
+ }
+}
+</script>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/BarChart.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/BarChart.vue
new file mode 100644
index 0000000..fa265ef
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/BarChart.vue
@@ -0,0 +1,106 @@
+<template>
+ <div :class="className" :style="{height:height,width:width}" />
+</template>
+
+<script>
+import echarts from 'echarts'
+require('echarts/theme/macarons') // echarts theme
+import { debounce } from '@/utils'
+
+const animationDuration = 6000
+
+export default {
+ props: {
+ className: {
+ type: String,
+ default: 'chart'
+ },
+ width: {
+ type: String,
+ default: '100%'
+ },
+ height: {
+ type: String,
+ default: '300px'
+ }
+ },
+ data() {
+ return {
+ chart: null
+ }
+ },
+ mounted() {
+ this.initChart()
+ this.__resizeHandler = debounce(() => {
+ if (this.chart) {
+ this.chart.resize()
+ }
+ }, 100)
+ window.addEventListener('resize', this.__resizeHandler)
+ },
+ beforeDestroy() {
+ if (!this.chart) {
+ return
+ }
+ window.removeEventListener('resize', this.__resizeHandler)
+ this.chart.dispose()
+ this.chart = null
+ },
+ methods: {
+ initChart() {
+ this.chart = echarts.init(this.$el, 'macarons')
+
+ this.chart.setOption({
+ tooltip: {
+ trigger: 'axis',
+ axisPointer: { // 坐标轴指示器,坐标轴触发有效
+ type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
+ }
+ },
+ grid: {
+ top: 10,
+ left: '2%',
+ right: '2%',
+ bottom: '3%',
+ containLabel: true
+ },
+ xAxis: [{
+ type: 'category',
+ data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+ axisTick: {
+ alignWithLabel: true
+ }
+ }],
+ yAxis: [{
+ type: 'value',
+ axisTick: {
+ show: false
+ }
+ }],
+ series: [{
+ name: 'pageA',
+ type: 'bar',
+ stack: 'vistors',
+ barWidth: '60%',
+ data: [79, 52, 200, 334, 390, 330, 220],
+ animationDuration
+ }, {
+ name: 'pageB',
+ type: 'bar',
+ stack: 'vistors',
+ barWidth: '60%',
+ data: [80, 52, 200, 334, 390, 330, 220],
+ animationDuration
+ }, {
+ name: 'pageC',
+ type: 'bar',
+ stack: 'vistors',
+ barWidth: '60%',
+ data: [30, 52, 200, 334, 390, 330, 220],
+ animationDuration
+ }]
+ })
+ }
+ }
+}
+</script>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Category.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Category.vue
new file mode 100644
index 0000000..5859114
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Category.vue
@@ -0,0 +1,438 @@
+<template>
+ <div :class="className" :style="{height:height,width:width}" />
+</template>
+
+<script>
+import echarts from 'echarts'
+
+require('echarts/theme/macarons') // echarts theme
+import { debounce } from '@/utils'
+
+export default {
+ props: {
+ className: {
+ type: String,
+ default: 'chart'
+ },
+ width: {
+ type: String,
+ default: '100%'
+ },
+ height: {
+ type: String,
+ default: '500px'
+ }
+ },
+ data() {
+ return {
+ chart: null
+ }
+ },
+ mounted() {
+ this.initChart()
+ this.__resizeHandler = debounce(() => {
+ if (this.chart) {
+ this.chart.resize()
+ }
+ }, 100)
+ window.addEventListener('resize', this.__resizeHandler)
+ },
+ beforeDestroy() {
+ if (!this.chart) {
+ return
+ }
+ window.removeEventListener('resize', this.__resizeHandler)
+ this.chart.dispose()
+ this.chart = null
+ },
+ methods: {
+ initChart() {
+ this.chart = echarts.init(this.$el, 'macarons')
+ const dataMap = {}
+
+ function dataFormatter(obj) {
+ const pList = ['北京', '天津', '河北', '山西', '内蒙古', '辽宁', '吉林', '黑龙江', '上海', '江苏', '浙江', '安徽', '福建', '江西', '山东', '河南', '湖北', '湖南', '广东', '广西', '海南', '重庆', '四川', '贵州', '云南', '西藏', '陕西', '甘肃', '青海', '宁夏', '新疆']
+ let temp
+ for (let year = 2002; year <= 2011; year++) {
+ let max = 0
+ let sum = 0
+ temp = obj[year]
+ for (let i = 0, l = temp.length; i < l; i++) {
+ max = Math.max(max, temp[i])
+ sum += temp[i]
+ obj[year][i] = {
+ name: pList[i],
+ value: temp[i]
+ }
+ }
+ obj[year + 'max'] = Math.floor(max / 100) * 100
+ obj[year + 'sum'] = sum
+ }
+ return obj
+ }
+
+ dataMap.dataGDP = dataFormatter({
+ 2011: [16251.93, 11307.28, 24515.76, 11237.55, 14359.88, 22226.7, 10568.83, 12582, 19195.69, 49110.27, 32318.85, 15300.65, 17560.18, 11702.82, 45361.85, 26931.03, 19632.26, 19669.56, 53210.28, 11720.87, 2522.66, 10011.37, 21026.68, 5701.84, 8893.12, 605.83, 12512.3, 5020.37, 1670.44, 2102.21, 6610.05],
+ 2010: [14113.58, 9224.46, 20394.26, 9200.86, 11672, 18457.27, 8667.58, 10368.6, 17165.98, 41425.48, 27722.31, 12359.33, 14737.12, 9451.26, 39169.92, 23092.36, 15967.61, 16037.96, 46013.06, 9569.85, 2064.5, 7925.58, 17185.48, 4602.16, 7224.18, 507.46, 10123.48, 4120.75, 1350.43, 1689.65, 5437.47],
+ 2009: [12153.03, 7521.85, 17235.48, 7358.31, 9740.25, 15212.49, 7278.75, 8587, 15046.45, 34457.3, 22990.35, 10062.82, 12236.53, 7655.18, 33896.65, 19480.46, 12961.1, 13059.69, 39482.56, 7759.16, 1654.21, 6530.01, 14151.28, 3912.68, 6169.75, 441.36, 8169.8, 3387.56, 1081.27, 1353.31, 4277.05],
+ 2008: [11115, 6719.01, 16011.97, 7315.4, 8496.2, 13668.58, 6426.1, 8314.37, 14069.87, 30981.98, 21462.69, 8851.66, 10823.01, 6971.05, 30933.28, 18018.53, 11328.92, 11555, 36796.71, 7021, 1503.06, 5793.66, 12601.23, 3561.56, 5692.12, 394.85, 7314.58, 3166.82, 1018.62, 1203.92, 4183.21],
+ 2007: [9846.81, 5252.76, 13607.32, 6024.45, 6423.18, 11164.3, 5284.69, 7104, 12494.01, 26018.48, 18753.73, 7360.92, 9248.53, 5800.25, 25776.91, 15012.46, 9333.4, 9439.6, 31777.01, 5823.41, 1254.17, 4676.13, 10562.39, 2884.11, 4772.52, 341.43, 5757.29, 2703.98, 797.35, 919.11, 3523.16],
+ 2006: [8117.78, 4462.74, 11467.6, 4878.61, 4944.25, 9304.52, 4275.12, 6211.8, 10572.24, 21742.05, 15718.47, 6112.5, 7583.85, 4820.53, 21900.19, 12362.79, 7617.47, 7688.67, 26587.76, 4746.16, 1065.67, 3907.23, 8690.24, 2338.98, 3988.14, 290.76, 4743.61, 2277.35, 648.5, 725.9, 3045.26],
+ 2005: [6969.52, 3905.64, 10012.11, 4230.53, 3905.03, 8047.26, 3620.27, 5513.7, 9247.66, 18598.69, 13417.68, 5350.17, 6554.69, 4056.76, 18366.87, 10587.42, 6590.19, 6596.1, 22557.37, 3984.1, 918.75, 3467.72, 7385.1, 2005.42, 3462.73, 248.8, 3933.72, 1933.98, 543.32, 612.61, 2604.19],
+ 2004: [6033.21, 3110.97, 8477.63, 3571.37, 3041.07, 6672, 3122.01, 4750.6, 8072.83, 15003.6, 11648.7, 4759.3, 5763.35, 3456.7, 15021.84, 8553.79, 5633.24, 5641.94, 18864.62, 3433.5, 819.66, 3034.58, 6379.63, 1677.8, 3081.91, 220.34, 3175.58, 1688.49, 466.1, 537.11, 2209.09],
+ 2003: [5007.21, 2578.03, 6921.29, 2855.23, 2388.38, 6002.54, 2662.08, 4057.4, 6694.23, 12442.87, 9705.02, 3923.11, 4983.67, 2807.41, 12078.15, 6867.7, 4757.45, 4659.99, 15844.64, 2821.11, 713.96, 2555.72, 5333.09, 1426.34, 2556.02, 185.09, 2587.72, 1399.83, 390.2, 445.36, 1886.35],
+ 2002: [4315, 2150.76, 6018.28, 2324.8, 1940.94, 5458.22, 2348.54, 3637.2, 5741.03, 10606.85, 8003.67, 3519.72, 4467.55, 2450.48, 10275.5, 6035.48, 4212.82, 4151.54, 13502.42, 2523.73, 642.73, 2232.86, 4725.01, 1243.43, 2312.82, 162.04, 2253.39, 1232.03, 340.65, 377.16, 1612.6]
+ })
+
+ dataMap.dataPI = dataFormatter({
+ 2011: [136.27, 159.72, 2905.73, 641.42, 1306.3, 1915.57, 1277.44, 1701.5, 124.94, 3064.78, 1583.04, 2015.31, 1612.24, 1391.07, 3973.85, 3512.24, 2569.3, 2768.03, 2665.2, 2047.23, 659.23, 844.52, 2983.51, 726.22, 1411.01, 74.47, 1220.9, 678.75, 155.08, 184.14, 1139.03],
+ 2010: [124.36, 145.58, 2562.81, 554.48, 1095.28, 1631.08, 1050.15, 1302.9, 114.15, 2540.1, 1360.56, 1729.02, 1363.67, 1206.98, 3588.28, 3258.09, 2147, 2325.5, 2286.98, 1675.06, 539.83, 685.38, 2482.89, 625.03, 1108.38, 68.72, 988.45, 599.28, 134.92, 159.29, 1078.63],
+ 2009: [118.29, 128.85, 2207.34, 477.59, 929.6, 1414.9, 980.57, 1154.33, 113.82, 2261.86, 1163.08, 1495.45, 1182.74, 1098.66, 3226.64, 2769.05, 1795.9, 1969.69, 2010.27, 1458.49, 462.19, 606.8, 2240.61, 550.27, 1067.6, 63.88, 789.64, 497.05, 107.4, 127.25, 759.74],
+ 2008: [112.83, 122.58, 2034.59, 313.58, 907.95, 1302.02, 916.72, 1088.94, 111.8, 2100.11, 1095.96, 1418.09, 1158.17, 1060.38, 3002.65, 2658.78, 1780, 1892.4, 1973.05, 1453.75, 436.04, 575.4, 2216.15, 539.19, 1020.56, 60.62, 753.72, 462.27, 105.57, 118.94, 691.07],
+ 2007: [101.26, 110.19, 1804.72, 311.97, 762.1, 1133.42, 783.8, 915.38, 101.84, 1816.31, 986.02, 1200.18, 1002.11, 905.77, 2509.14, 2217.66, 1378, 1626.48, 1695.57, 1241.35, 361.07, 482.39, 2032, 446.38, 837.35, 54.89, 592.63, 387.55, 83.41, 97.89, 628.72],
+ 2006: [88.8, 103.35, 1461.81, 276.77, 634.94, 939.43, 672.76, 750.14, 93.81, 1545.05, 925.1, 1011.03, 865.98, 786.14, 2138.9, 1916.74, 1140.41, 1272.2, 1532.17, 1032.47, 323.48, 386.38, 1595.48, 382.06, 724.4, 50.9, 484.81, 334, 67.55, 79.54, 527.8],
+ 2005: [88.68, 112.38, 1400, 262.42, 589.56, 882.41, 625.61, 684.6, 90.26, 1461.51, 892.83, 966.5, 827.36, 727.37, 1963.51, 1892.01, 1082.13, 1100.65, 1428.27, 912.5, 300.75, 463.4, 1481.14, 368.94, 661.69, 48.04, 435.77, 308.06, 65.34, 72.07, 509.99],
+ 2004: [87.36, 105.28, 1370.43, 276.3, 522.8, 798.43, 568.69, 605.79, 83.45, 1367.58, 814.1, 950.5, 786.84, 664.5, 1778.45, 1649.29, 1020.09, 1022.45, 1248.59, 817.88, 278.76, 428.05, 1379.93, 334.5, 607.75, 44.3, 387.88, 286.78, 60.7, 65.33, 461.26],
+ 2003: [84.11, 89.91, 1064.05, 215.19, 420.1, 615.8, 488.23, 504.8, 81.02, 1162.45, 717.85, 749.4, 692.94, 560, 1480.67, 1198.7, 798.35, 886.47, 1072.91, 658.78, 244.29, 339.06, 1128.61, 298.69, 494.6, 40.7, 302.66, 237.91, 48.47, 55.63, 412.9],
+ 2002: [82.44, 84.21, 956.84, 197.8, 374.69, 590.2, 446.17, 474.2, 79.68, 1110.44, 685.2, 783.66, 664.78, 535.98, 1390, 1288.36, 707, 847.25, 1015.08, 601.99, 222.89, 317.87, 1047.95, 281.1, 463.44, 39.75, 282.21, 215.51, 47.31, 52.95, 305]
+ })
+
+ dataMap.dataSI = dataFormatter({
+ 2011: [3752.48, 5928.32, 13126.86, 6635.26, 8037.69, 12152.15, 5611.48, 5962.41, 7927.89, 25203.28, 16555.58, 8309.38, 9069.2, 6390.55, 24017.11, 15427.08, 9815.94, 9361.99, 26447.38, 5675.32, 714.5, 5543.04, 11029.13, 2194.33, 3780.32, 208.79, 6935.59, 2377.83, 975.18, 1056.15, 3225.9],
+ 2010: [3388.38, 4840.23, 10707.68, 5234, 6367.69, 9976.82, 4506.31, 5025.15, 7218.32, 21753.93, 14297.93, 6436.62, 7522.83, 5122.88, 21238.49, 13226.38, 7767.24, 7343.19, 23014.53, 4511.68, 571, 4359.12, 8672.18, 1800.06, 3223.49, 163.92, 5446.1, 1984.97, 744.63, 827.91, 2592.15],
+ 2009: [2855.55, 3987.84, 8959.83, 3993.8, 5114, 7906.34, 3541.92, 4060.72, 6001.78, 18566.37, 11908.49, 4905.22, 6005.3, 3919.45, 18901.83, 11010.5, 6038.08, 5687.19, 19419.7, 3381.54, 443.43, 3448.77, 6711.87, 1476.62, 2582.53, 136.63, 4236.42, 1527.24, 575.33, 662.32, 1929.59],
+ 2008: [2626.41, 3709.78, 8701.34, 4242.36, 4376.19, 7158.84, 3097.12, 4319.75, 6085.84, 16993.34, 11567.42, 4198.93, 5318.44, 3554.81, 17571.98, 10259.99, 5082.07, 5028.93, 18502.2, 3037.74, 423.55, 3057.78, 5823.39, 1370.03, 2452.75, 115.56, 3861.12, 1470.34, 557.12, 609.98, 2070.76],
+ 2007: [2509.4, 2892.53, 7201.88, 3454.49, 3193.67, 5544.14, 2475.45, 3695.58, 5571.06, 14471.26, 10154.25, 3370.96, 4476.42, 2975.53, 14647.53, 8282.83, 4143.06, 3977.72, 16004.61, 2425.29, 364.26, 2368.53, 4648.79, 1124.79, 2038.39, 98.48, 2986.46, 1279.32, 419.03, 455.04, 1647.55],
+ 2006: [2191.43, 2457.08, 6110.43, 2755.66, 2374.96, 4566.83, 1915.29, 3365.31, 4969.95, 12282.89, 8511.51, 2711.18, 3695.04, 2419.74, 12574.03, 6724.61, 3365.08, 3187.05, 13469.77, 1878.56, 308.62, 1871.65, 3775.14, 967.54, 1705.83, 80.1, 2452.44, 1043.19, 331.91, 351.58, 1459.3],
+ 2005: [2026.51, 2135.07, 5271.57, 2357.04, 1773.21, 3869.4, 1580.83, 2971.68, 4381.2, 10524.96, 7164.75, 2245.9, 3175.92, 1917.47, 10478.62, 5514.14, 2852.12, 2612.57, 11356.6, 1510.68, 240.83, 1564, 3067.23, 821.16, 1426.42, 63.52, 1951.36, 838.56, 264.61, 281.05, 1164.79],
+ 2004: [1853.58, 1685.93, 4301.73, 1919.4, 1248.27, 3061.62, 1329.68, 2487.04, 3892.12, 8437.99, 6250.38, 1844.9, 2770.49, 1566.4, 8478.69, 4182.1, 2320.6, 2190.54, 9280.73, 1253.7, 205.6, 1376.91, 2489.4, 681.5, 1281.63, 52.74, 1553.1, 713.3, 211.7, 244.05, 914.47],
+ 2003: [1487.15, 1337.31, 3417.56, 1463.38, 967.49, 2898.89, 1098.37, 2084.7, 3209.02, 6787.11, 5096.38, 1535.29, 2340.82, 1204.33, 6485.05, 3310.14, 1956.02, 1777.74, 7592.78, 984.08, 175.82, 1135.31, 2014.8, 569.37, 1047.66, 47.64, 1221.17, 572.02, 171.92, 194.27, 719.54],
+ 2002: [1249.99, 1069.08, 2911.69, 1134.31, 754.78, 2609.85, 943.49, 1843.6, 2622.45, 5604.49, 4090.48, 1337.04, 2036.97, 941.77, 5184.98, 2768.75, 1709.89, 1523.5, 6143.4, 846.89, 148.88, 958.87, 1733.38, 481.96, 934.88, 32.72, 1007.56, 501.69, 144.51, 153.06, 603.15]
+ })
+
+ dataMap.dataTI = dataFormatter({
+ 2011: [12363.18, 5219.24, 8483.17, 3960.87, 5015.89, 8158.98, 3679.91, 4918.09, 11142.86, 20842.21, 14180.23, 4975.96, 6878.74, 3921.2, 17370.89, 7991.72, 7247.02, 7539.54, 24097.7, 3998.33, 1148.93, 3623.81, 7014.04, 2781.29, 3701.79, 322.57, 4355.81, 1963.79, 540.18, 861.92, 2245.12],
+ 2010: [10600.84, 4238.65, 7123.77, 3412.38, 4209.03, 6849.37, 3111.12, 4040.55, 9833.51, 17131.45, 12063.82, 4193.69, 5850.62, 3121.4, 14343.14, 6607.89, 6053.37, 6369.27, 20711.55, 3383.11, 953.67, 2881.08, 6030.41, 2177.07, 2892.31, 274.82, 3688.93, 1536.5, 470.88, 702.45, 1766.69],
+ 2009: [9179.19, 3405.16, 6068.31, 2886.92, 3696.65, 5891.25, 2756.26, 3371.95, 8930.85, 13629.07, 9918.78, 3662.15, 5048.49, 2637.07, 11768.18, 5700.91, 5127.12, 5402.81, 18052.59, 2919.13, 748.59, 2474.44, 5198.8, 1885.79, 2519.62, 240.85, 3143.74, 1363.27, 398.54, 563.74, 1587.72],
+ 2008: [8375.76, 2886.65, 5276.04, 2759.46, 3212.06, 5207.72, 2412.26, 2905.68, 7872.23, 11888.53, 8799.31, 3234.64, 4346.4, 2355.86, 10358.64, 5099.76, 4466.85, 4633.67, 16321.46, 2529.51, 643.47, 2160.48, 4561.69, 1652.34, 2218.81, 218.67, 2699.74, 1234.21, 355.93, 475, 1421.38],
+ 2007: [7236.15, 2250.04, 4600.72, 2257.99, 2467.41, 4486.74, 2025.44, 2493.04, 6821.11, 9730.91, 7613.46, 2789.78, 3770, 1918.95, 8620.24, 4511.97, 3812.34, 3835.4, 14076.83, 2156.76, 528.84, 1825.21, 3881.6, 1312.94, 1896.78, 188.06, 2178.2, 1037.11, 294.91, 366.18, 1246.89],
+ 2006: [5837.55, 1902.31, 3895.36, 1846.18, 1934.35, 3798.26, 1687.07, 2096.35, 5508.48, 7914.11, 6281.86, 2390.29, 3022.83, 1614.65, 7187.26, 3721.44, 3111.98, 3229.42, 11585.82, 1835.12, 433.57, 1649.2, 3319.62, 989.38, 1557.91, 159.76, 1806.36, 900.16, 249.04, 294.78, 1058.16],
+ 2005: [4854.33, 1658.19, 3340.54, 1611.07, 1542.26, 3295.45, 1413.83, 1857.42, 4776.2, 6612.22, 5360.1, 2137.77, 2551.41, 1411.92, 5924.74, 3181.27, 2655.94, 2882.88, 9772.5, 1560.92, 377.17, 1440.32, 2836.73, 815.32, 1374.62, 137.24, 1546.59, 787.36, 213.37, 259.49, 929.41],
+ 2004: [4092.27, 1319.76, 2805.47, 1375.67, 1270, 2811.95, 1223.64, 1657.77, 4097.26, 5198.03, 4584.22, 1963.9, 2206.02, 1225.8, 4764.7, 2722.4, 2292.55, 2428.95, 8335.3, 1361.92, 335.3, 1229.62, 2510.3, 661.8, 1192.53, 123.3, 1234.6, 688.41, 193.7, 227.73, 833.36],
+ 2003: [3435.95, 1150.81, 2439.68, 1176.65, 1000.79, 2487.85, 1075.48, 1467.9, 3404.19, 4493.31, 3890.79, 1638.42, 1949.91, 1043.08, 4112.43, 2358.86, 2003.08, 1995.78, 7178.94, 1178.25, 293.85, 1081.35, 2189.68, 558.28, 1013.76, 96.76, 1063.89, 589.91, 169.81, 195.46, 753.91],
+ 2002: [2982.57, 997.47, 2149.75, 992.69, 811.47, 2258.17, 958.88, 1319.4, 3038.9, 3891.92, 3227.99, 1399.02, 1765.8, 972.73, 3700.52, 1978.37, 1795.93, 1780.79, 6343.94, 1074.85, 270.96, 956.12, 1943.68, 480.37, 914.5, 89.56, 963.62, 514.83, 148.83, 171.14, 704.5]
+ })
+
+ dataMap.dataEstate = dataFormatter({
+ 2011: [1074.93, 411.46, 918.02, 224.91, 384.76, 876.12, 238.61, 492.1, 1019.68, 2747.89, 1677.13, 634.92, 911.16, 402.51, 1838.14, 987, 634.67, 518.04, 3321.31, 465.68, 208.71, 396.28, 620.62, 160.3, 222.31, 17.44, 398.03, 134.25, 29.05, 79.01, 176.22],
+ 2010: [1006.52, 377.59, 697.79, 192, 309.25, 733.37, 212.32, 391.89, 1002.5, 2600.95, 1618.17, 532.17, 679.03, 340.56, 1622.15, 773.23, 564.41, 464.21, 2813.95, 405.79, 188.33, 266.38, 558.56, 139.64, 223.45, 14.54, 315.95, 110.02, 25.41, 60.53, 143.44],
+ 2009: [1062.47, 308.73, 612.4, 173.31, 286.65, 605.27, 200.14, 301.18, 1237.56, 2025.39, 1316.84, 497.94, 656.61, 305.9, 1329.59, 622.98, 546.11, 400.11, 2470.63, 348.98, 121.76, 229.09, 548.14, 136.15, 205.14, 13.28, 239.92, 101.37, 23.05, 47.56, 115.23],
+ 2008: [844.59, 227.88, 513.81, 166.04, 273.3, 500.81, 182.7, 244.47, 939.34, 1626.13, 1052.03, 431.27, 506.98, 281.96, 1104.95, 512.42, 526.88, 340.07, 2057.45, 282.96, 95.6, 191.21, 453.63, 104.81, 195.48, 15.08, 193.27, 93.8, 19.96, 38.85, 89.79],
+ 2007: [821.5, 183.44, 467.97, 134.12, 191.01, 410.43, 153.03, 225.81, 958.06, 1365.71, 981.42, 366.57, 511.5, 225.96, 953.69, 447.44, 409.65, 301.8, 2029.77, 239.45, 67.19, 196.06, 376.84, 93.19, 193.59, 13.24, 153.98, 83.52, 16.98, 29.49, 91.28],
+ 2006: [658.3, 156.64, 397.14, 117.01, 136.5, 318.54, 131.01, 194.7, 773.61, 1017.91, 794.41, 281.98, 435.22, 184.67, 786.51, 348.7, 294.73, 254.81, 1722.07, 192.2, 44.45, 158.2, 336.2, 80.24, 165.92, 11.92, 125.2, 73.21, 15.17, 25.53, 68.9],
+ 2005: [493.73, 122.67, 330.87, 106, 98.75, 256.77, 112.29, 163.34, 715.97, 799.73, 688.86, 231.66, 331.8, 171.88, 664.9, 298.19, 217.17, 215.63, 1430.37, 165.05, 38.2, 143.88, 286.23, 76.38, 148.69, 10.02, 108.62, 63.78, 14.1, 22.97, 55.79],
+ 2004: [436.11, 106.14, 231.08, 95.1, 73.81, 203.1, 97.93, 137.74, 666.3, 534.17, 587.83, 188.28, 248.44, 167.2, 473.27, 236.44, 204.8, 191.5, 1103.75, 122.52, 30.64, 129.12, 264.3, 68.3, 116.54, 5.8, 95.9, 56.84, 13, 20.78, 53.55],
+ 2003: [341.88, 92.31, 185.19, 78.73, 61.05, 188.49, 91.99, 127.2, 487.82, 447.47, 473.16, 162.63, 215.84, 138.02, 418.21, 217.58, 176.8, 186.49, 955.66, 100.93, 25.14, 113.69, 231.72, 59.86, 103.79, 4.35, 83.9, 48.09, 11.41, 16.85, 47.84],
+ 2002: [298.02, 73.04, 140.89, 65.83, 51.48, 130.94, 76.11, 118.7, 384.86, 371.09, 360.63, 139.18, 188.09, 125.27, 371.13, 199.31, 145.17, 165.29, 808.16, 82.83, 21.45, 90.48, 210.82, 53.49, 95.68, 3.42, 77.68, 41.52, 9.74, 13.46, 43.04]
+ })
+
+ dataMap.dataFinancial = dataFormatter({
+ 2011: [2215.41, 756.5, 746.01, 519.32, 447.46, 755.57, 207.65, 370.78, 2277.4, 2600.11, 2730.29, 503.85, 862.41, 357.44, 1640.41, 868.2, 674.57, 501.09, 2916.13, 445.37, 105.24, 704.66, 868.15, 297.27, 456.23, 31.7, 432.11, 145.05, 62.56, 134.18, 288.77],
+ 2010: [1863.61, 572.99, 615.42, 448.3, 346.44, 639.27, 190.12, 304.59, 1950.96, 2105.92, 2326.58, 396.17, 767.58, 241.49, 1361.45, 697.68, 561.27, 463.16, 2658.76, 384.53, 78.12, 496.56, 654.7, 231.51, 375.08, 27.08, 384.75, 100.54, 54.53, 97.87, 225.2],
+ 2009: [1603.63, 461.2, 525.67, 361.64, 291.1, 560.2, 180.83, 227.54, 1804.28, 1596.98, 1899.33, 359.6, 612.2, 165.1, 1044.9, 499.92, 479.11, 402.57, 2283.29, 336.82, 65.73, 389.97, 524.63, 194.44, 351.74, 23.17, 336.21, 88.27, 45.63, 75.54, 198.87],
+ 2008: [1519.19, 368.1, 420.74, 290.91, 219.09, 455.07, 147.24, 177.43, 1414.21, 1298.48, 1653.45, 313.81, 497.65, 130.57, 880.28, 413.83, 393.05, 334.32, 1972.4, 249.01, 47.33, 303.01, 411.14, 151.55, 277.66, 22.42, 287.16, 72.49, 36.54, 64.8, 171.97],
+ 2007: [1302.77, 288.17, 347.65, 218.73, 148.3, 386.34, 126.03, 155.48, 1209.08, 1054.25, 1251.43, 223.85, 385.84, 101.34, 734.9, 302.31, 337.27, 260.14, 1705.08, 190.73, 34.43, 247.46, 359.11, 122.25, 168.55, 11.51, 231.03, 61.6, 27.67, 51.05, 149.22],
+ 2006: [982.37, 186.87, 284.04, 169.63, 108.21, 303.41, 100.75, 74.17, 825.2, 653.25, 906.37, 166.01, 243.9, 79.75, 524.94, 219.72, 174.99, 204.72, 899.91, 129.14, 16.37, 213.7, 299.5, 89.43, 143.62, 6.44, 152.25, 50.51, 23.69, 36.99, 99.25],
+ 2005: [840.2, 147.4, 213.47, 135.07, 72.52, 232.85, 83.63, 35.03, 675.12, 492.4, 686.32, 127.05, 186.12, 69.55, 448.36, 181.74, 127.32, 162.37, 661.81, 91.93, 13.16, 185.18, 262.26, 73.67, 130.5, 7.57, 127.58, 44.73, 20.36, 32.25, 80.34],
+ 2004: [713.79, 136.97, 209.1, 110.29, 55.89, 188.04, 77.17, 32.2, 612.45, 440.5, 523.49, 94.1, 171, 65.1, 343.37, 170.82, 118.85, 118.64, 602.68, 74, 11.56, 162.38, 236.5, 60.3, 118.4, 5.4, 90.1, 42.99, 19, 27.92, 70.3],
+ 2003: [635.56, 112.79, 199.87, 118.48, 55.89, 145.38, 73.15, 32.2, 517.97, 392.11, 451.54, 87.45, 150.09, 64.31, 329.71, 165.11, 107.31, 99.35, 534.28, 61.59, 10.68, 147.04, 206.24, 48.01, 105.48, 4.74, 77.87, 42.31, 17.98, 24.8, 64.92],
+ 2002: [561.91, 76.86, 179.6, 124.1, 48.39, 137.18, 75.45, 31.6, 485.25, 368.86, 347.53, 81.85, 138.28, 76.51, 310.07, 158.77, 96.95, 92.43, 454.65, 35.86, 10.08, 134.52, 183.13, 41.45, 102.39, 2.81, 67.3, 42.08, 16.75, 21.45, 52.18]
+ })
+
+ this.chart.setOption({
+ baseOption: {
+ timeline: {
+ axisType: 'category',
+ autoPlay: true,
+ playInterval: 1000,
+ data: [
+ '2002-01-01', '2003-01-01', '2004-01-01',
+ {
+ value: '2005-01-01',
+ tooltip: {
+ formatter: '{b} GDP达到一个高度'
+ },
+ symbol: 'diamond',
+ symbolSize: 16
+ },
+ '2006-01-01', '2007-01-01', '2008-01-01', '2009-01-01', '2010-01-01',
+ {
+ value: '2011-01-01',
+ tooltip: {
+ formatter: function(params) {
+ return params.name + 'GDP达到又一个高度'
+ }
+ },
+ symbol: 'diamond',
+ symbolSize: 18
+ }
+ ],
+ label: {
+ formatter: function(s) {
+ return (new Date(s)).getFullYear()
+ }
+ }
+ },
+ title: {
+ subtext: '数据来自国家统计局'
+ },
+ tooltip: {},
+ legend: {
+ x: 'right',
+ data: ['第一产业', '第二产业', '第三产业', 'GDP', '金融', '房地产'],
+ selected: {
+ 'GDP': false, '金融': false, '房地产': false
+ }
+ },
+ calculable: true,
+ grid: {
+ top: 80,
+ bottom: 100,
+ tooltip: {
+ trigger: 'axis',
+ axisPointer: {
+ type: 'shadow',
+ label: {
+ show: true,
+ formatter: function(params) {
+ return params.value.replace('\n', '')
+ }
+ }
+ }
+ }
+ },
+ xAxis: [
+ {
+ 'type': 'category',
+ 'axisLabel': {
+ 'interval': 0,
+ rotate: 45
+ },
+ 'data': [
+ '北京', '\n天津', '河北', '\n山西', '内蒙古', '\n辽宁', '吉林', '\n黑龙江',
+ '上海', '\n江苏', '浙江', '\n安徽', '福建', '\n江西', '山东', '\n河南',
+ '湖北', '\n湖南', '广东', '\n广西', '海南', '\n重庆', '四川', '\n贵州',
+ '云南', '\n西藏', '陕西', '\n甘肃', '青海', '\n宁夏', '新疆'
+ ],
+ splitLine: { show: false }
+ }
+ ],
+ yAxis: [
+ {
+ type: 'value',
+ name: 'GDP(亿元)'
+ }
+ ],
+ series: [
+ { name: 'GDP', type: 'bar' },
+ { name: '金融', type: 'bar' },
+ { name: '房地产', type: 'bar' },
+ { name: '第一产业', type: 'bar' },
+ { name: '第二产业', type: 'bar' },
+ { name: '第三产业', type: 'bar' },
+ {
+ name: 'GDP占比',
+ type: 'pie',
+ center: ['75%', '35%'],
+ radius: '28%',
+ z: 100
+ }
+ ]
+ },
+ options: [
+ {
+ title: { text: '2002全国宏观经济指标' },
+ series: [
+ { data: dataMap.dataGDP['2002'] },
+ { data: dataMap.dataFinancial['2002'] },
+ { data: dataMap.dataEstate['2002'] },
+ { data: dataMap.dataPI['2002'] },
+ { data: dataMap.dataSI['2002'] },
+ { data: dataMap.dataTI['2002'] },
+ {
+ data: [
+ { name: '第一产业', value: dataMap.dataPI['2002sum'] },
+ { name: '第二产业', value: dataMap.dataSI['2002sum'] },
+ { name: '第三产业', value: dataMap.dataTI['2002sum'] }
+ ]
+ }
+ ]
+ },
+ {
+ title: { text: '2003全国宏观经济指标' },
+ series: [
+ { data: dataMap.dataGDP['2003'] },
+ { data: dataMap.dataFinancial['2003'] },
+ { data: dataMap.dataEstate['2003'] },
+ { data: dataMap.dataPI['2003'] },
+ { data: dataMap.dataSI['2003'] },
+ { data: dataMap.dataTI['2003'] },
+ {
+ data: [
+ { name: '第一产业', value: dataMap.dataPI['2003sum'] },
+ { name: '第二产业', value: dataMap.dataSI['2003sum'] },
+ { name: '第三产业', value: dataMap.dataTI['2003sum'] }
+ ]
+ }
+ ]
+ },
+ {
+ title: { text: '2004全国宏观经济指标' },
+ series: [
+ { data: dataMap.dataGDP['2004'] },
+ { data: dataMap.dataFinancial['2004'] },
+ { data: dataMap.dataEstate['2004'] },
+ { data: dataMap.dataPI['2004'] },
+ { data: dataMap.dataSI['2004'] },
+ { data: dataMap.dataTI['2004'] },
+ {
+ data: [
+ { name: '第一产业', value: dataMap.dataPI['2004sum'] },
+ { name: '第二产业', value: dataMap.dataSI['2004sum'] },
+ { name: '第三产业', value: dataMap.dataTI['2004sum'] }
+ ]
+ }
+ ]
+ },
+ {
+ title: { text: '2005全国宏观经济指标' },
+ series: [
+ { data: dataMap.dataGDP['2005'] },
+ { data: dataMap.dataFinancial['2005'] },
+ { data: dataMap.dataEstate['2005'] },
+ { data: dataMap.dataPI['2005'] },
+ { data: dataMap.dataSI['2005'] },
+ { data: dataMap.dataTI['2005'] },
+ {
+ data: [
+ { name: '第一产业', value: dataMap.dataPI['2005sum'] },
+ { name: '第二产业', value: dataMap.dataSI['2005sum'] },
+ { name: '第三产业', value: dataMap.dataTI['2005sum'] }
+ ]
+ }
+ ]
+ },
+ {
+ title: { text: '2006全国宏观经济指标' },
+ series: [
+ { data: dataMap.dataGDP['2006'] },
+ { data: dataMap.dataFinancial['2006'] },
+ { data: dataMap.dataEstate['2006'] },
+ { data: dataMap.dataPI['2006'] },
+ { data: dataMap.dataSI['2006'] },
+ { data: dataMap.dataTI['2006'] },
+ {
+ data: [
+ { name: '第一产业', value: dataMap.dataPI['2006sum'] },
+ { name: '第二产业', value: dataMap.dataSI['2006sum'] },
+ { name: '第三产业', value: dataMap.dataTI['2006sum'] }
+ ]
+ }
+ ]
+ },
+ {
+ title: { text: '2007全国宏观经济指标' },
+ series: [
+ { data: dataMap.dataGDP['2007'] },
+ { data: dataMap.dataFinancial['2007'] },
+ { data: dataMap.dataEstate['2007'] },
+ { data: dataMap.dataPI['2007'] },
+ { data: dataMap.dataSI['2007'] },
+ { data: dataMap.dataTI['2007'] },
+ {
+ data: [
+ { name: '第一产业', value: dataMap.dataPI['2007sum'] },
+ { name: '第二产业', value: dataMap.dataSI['2007sum'] },
+ { name: '第三产业', value: dataMap.dataTI['2007sum'] }
+ ]
+ }
+ ]
+ },
+ {
+ title: { text: '2008全国宏观经济指标' },
+ series: [
+ { data: dataMap.dataGDP['2008'] },
+ { data: dataMap.dataFinancial['2008'] },
+ { data: dataMap.dataEstate['2008'] },
+ { data: dataMap.dataPI['2008'] },
+ { data: dataMap.dataSI['2008'] },
+ { data: dataMap.dataTI['2008'] },
+ {
+ data: [
+ { name: '第一产业', value: dataMap.dataPI['2008sum'] },
+ { name: '第二产业', value: dataMap.dataSI['2008sum'] },
+ { name: '第三产业', value: dataMap.dataTI['2008sum'] }
+ ]
+ }
+ ]
+ },
+ {
+ title: { text: '2009全国宏观经济指标' },
+ series: [
+ { data: dataMap.dataGDP['2009'] },
+ { data: dataMap.dataFinancial['2009'] },
+ { data: dataMap.dataEstate['2009'] },
+ { data: dataMap.dataPI['2009'] },
+ { data: dataMap.dataSI['2009'] },
+ { data: dataMap.dataTI['2009'] },
+ {
+ data: [
+ { name: '第一产业', value: dataMap.dataPI['2009sum'] },
+ { name: '第二产业', value: dataMap.dataSI['2009sum'] },
+ { name: '第三产业', value: dataMap.dataTI['2009sum'] }
+ ]
+ }
+ ]
+ },
+ {
+ title: { text: '2010全国宏观经济指标' },
+ series: [
+ { data: dataMap.dataGDP['2010'] },
+ { data: dataMap.dataFinancial['2010'] },
+ { data: dataMap.dataEstate['2010'] },
+ { data: dataMap.dataPI['2010'] },
+ { data: dataMap.dataSI['2010'] },
+ { data: dataMap.dataTI['2010'] },
+ {
+ data: [
+ { name: '第一产业', value: dataMap.dataPI['2010sum'] },
+ { name: '第二产业', value: dataMap.dataSI['2010sum'] },
+ { name: '第三产业', value: dataMap.dataTI['2010sum'] }
+ ]
+ }
+ ]
+ },
+ {
+ title: { text: '2011全国宏观经济指标' },
+ series: [
+ { data: dataMap.dataGDP['2011'] },
+ { data: dataMap.dataFinancial['2011'] },
+ { data: dataMap.dataEstate['2011'] },
+ { data: dataMap.dataPI['2011'] },
+ { data: dataMap.dataSI['2011'] },
+ { data: dataMap.dataTI['2011'] },
+ {
+ data: [
+ { name: '第一产业', value: dataMap.dataPI['2011sum'] },
+ { name: '第二产业', value: dataMap.dataSI['2011sum'] },
+ { name: '第三产业', value: dataMap.dataTI['2011sum'] }
+ ]
+ }
+ ]
+ }
+ ]
+ })
+ }
+ }
+}
+</script>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Egressdns.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Egressdns.vue
new file mode 100644
index 0000000..a7ec7a7
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Egressdns.vue
@@ -0,0 +1,166 @@
+<template>
+ <div class="wrapper">
+ <div id="chart3" class="chart" />
+ </div>
+</template>
+
+<script>
+import echarts from 'echarts'
+export default {
+ props: ['do53egressdns'],
+ data() {
+ return {}
+ },
+ mounted() {
+ this.getWorld(this.do53egressdns)
+ var myChartContainer = document.getElementById('chart3')
+ // 获取自适应的高度和宽度
+ var resizeMyChartContainer = function() {
+ // myChartContainer.style.height = window.innerHeight * 0.65 + 'px';
+ // myChartContainer.style.width = window.innerWidth * 0.75 + 'px';
+ myChartContainer.style.height = 300 + 'px'
+ myChartContainer.style.width = 600 + 'px'
+ if (window.innerWidth > 768 && window.innerWidth < 1370) {
+ myChartContainer.style.width = 500 + 'px'
+ }
+ }
+ // 设置容器高和宽
+ resizeMyChartContainer()
+ var myChart = echarts.init(myChartContainer)
+ const option = {}
+ myChart.setOption(option)
+ },
+ methods: {
+ changeKey(arr, key) {
+ const newArr = []
+ arr.forEach((item, index) => {
+ const newObj = {}
+ for (var i = 0; i < key.length; i++) {
+ newObj[key[i]] = item[Object.keys(item)[i]]
+ }
+ newArr.push(newObj)
+ })
+ return newArr
+ },
+ getWorld(data) {
+ const list = this.changeKey(this.do53egressdns, ['name', 'value'])
+ var that = this
+ // const {ctx} = getCurrentInstance()
+ this.$axios.get('/sjData/word.json').then(function(res) {
+ // console.log(list,111);
+ const namemap = res.data.namemap
+ const dataArr = list
+ // let dataArr = data.data
+ that.drawChart(namemap, dataArr)
+ })
+ },
+ drawChart(name, data) {
+ // 基于准备好的dom,初始化echarts实例
+ const chart = echarts.init(document.getElementById('chart3'))
+
+ // 监听屏幕变化自动缩放图表
+ window.addEventListener('resize', function() {
+ chart.resize()
+ })
+ // 绘制图表
+ chart.setOption({
+ // 图表主标题
+ // title: {
+ // text: '世界地图', // 主标题文本,支持使用 \n 换行
+ // top: 10, // 定位 值: 'top', 'middle', 'bottom' 也可以是具体的值或者百分比
+ // left: 'center', // 值: 'left', 'center', 'right' 同上
+ // textStyle: { // 文本样式
+ // fontSize: 24,
+ // fontWeight: 600,
+ // color: '#000'
+ // }
+ // },
+
+ grid: {
+ width: '100%',
+ height: '100%',
+ left: '0%',
+ right: '0%',
+ bottom: '0%',
+ containLabel: true
+ },
+ // 提示框组件
+ tooltip: {
+ trigger: 'item', // 触发类型, 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用
+ // 提示框浮层内容格式器,支持字符串模板和回调函数两种形式
+ // 使用函数模板 传入的数据值 -> value: number | Array
+ formatter: function(val) {
+ if (val.data == null) return
+ return val.data.name + ': ' + val.data.value
+ }
+ },
+ // 视觉映射组件
+ visualMap: {
+ min: 0,
+ max: 10000000,
+ text: ['max', 'min'],
+ realtime: false,
+ calculable: true,
+ color: ['#4608AD', '#d9e4ff']
+ },
+ series: [
+ {
+ type: 'map', // 类型
+ // 系列名称,用于tooltip的显示,legend 的图例筛选 在 setOption 更新数据和配置项时用于指定对应的系列
+ name: '世界地图',
+ mapType: 'world', // 地图类型
+ // 是否开启鼠标缩放和平移漫游 默认不开启 如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move' 设置成 true 为都开启
+ roam: true,
+ // 图形上的文本标签
+ label: {
+ show: false // 是否显示对应地名
+ },
+ zoom: 1.2,
+ // 地图区域的多边形 图形样式
+ itemStyle: {
+ // areaColor: '#7B68EE', // 地图区域的颜色 如果设置了visualMap,areaColor属性将不起作用
+ borderWidth: 0.5, // 描边线宽 为 0 时无描边
+ borderColor: '#000', // 图形的描边颜色 支持的颜色格式同 color,不支持回调函数
+ borderType: 'solid' // 描边类型,默认为实线,支持 'solid', 'dashed', 'dotted'
+ },
+ // 高亮状态下的多边形和标签样式
+ emphasis: {
+ label: {
+ show: true, // 是否显示标签
+ color: '#fff' // 文字的颜色 如果设置为 'auto',则为视觉映射得到的颜色,如系列色
+ },
+ itemStyle: {
+ areaColor: '#FF6347' // 地图区域的颜色
+ }
+ },
+ // 自定义地区的名称映射
+ nameMap: name,
+ // 地图系列中的数据内容数组 数组项可以为单个数值
+ data: data
+ }
+ ]
+ })
+ }
+ }
+}
+</script>
+<style lang="scss">
+.wrapper {
+ width: 100%;
+}
+.wrapper .chart1{
+ width: 60%;
+ /* margin:0 auto; */
+ height: 400px;
+ /* border: 1px solid #eeeeee; */
+ /* background: url(../../public/static/bg.png) no-repeat; 背景图设置*/
+ background-size: 100% 100%;
+ background-color: #fff;
+}
+.chart1 {
+ width: 100%;
+ height: 100%;
+ background-color: yellow;
+
+}
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Forwarder.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Forwarder.vue
new file mode 100644
index 0000000..b660498
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Forwarder.vue
@@ -0,0 +1,166 @@
+<template>
+ <div class="wrapper">
+ <div id="chart2" class="chart" />
+ </div>
+</template>
+
+<script>
+import echarts from 'echarts'
+export default {
+ props: ['do53forwarder'],
+ data() {
+ return {}
+ },
+ mounted() {
+ this.getWorld(this.do53forwarder)
+ var myChartContainer = document.getElementById('chart2')
+ // 获取自适应的高度和宽度
+ var resizeMyChartContainer = function() {
+ // myChartContainer.style.height = window.innerHeight * 0.65 + 'px';
+ // myChartContainer.style.width = window.innerWidth * 0.75 + 'px';
+ myChartContainer.style.height = 300 + 'px'
+ myChartContainer.style.width = 600 + 'px'
+ if (window.innerWidth > 768 && window.innerWidth < 1370) {
+ myChartContainer.style.width = 500 + 'px'
+ }
+ }
+ // 设置容器高和宽
+ resizeMyChartContainer()
+ var myChart = echarts.init(myChartContainer)
+ const option = {}
+ myChart.setOption(option)
+ },
+ methods: {
+ changeKey(arr, key) {
+ const newArr = []
+ arr.forEach((item, index) => {
+ const newObj = {}
+ for (var i = 0; i < key.length; i++) {
+ newObj[key[i]] = item[Object.keys(item)[i]]
+ }
+ newArr.push(newObj)
+ })
+ return newArr
+ },
+ getWorld(data) {
+ const list = this.changeKey(this.do53forwarder, ['name', 'value'])
+ var that = this
+ // const {ctx} = getCurrentInstance()
+ this.$axios.get('/sjData/word.json').then(function(res) {
+ // console.log(list,111);
+ const namemap = res.data.namemap
+ const dataArr = list
+ // let dataArr = data.data
+ that.drawChart(namemap, dataArr)
+ })
+ },
+ drawChart(name, data) {
+ // 基于准备好的dom,初始化echarts实例
+ const chart = echarts.init(document.getElementById('chart2'))
+
+ // 监听屏幕变化自动缩放图表
+ window.addEventListener('resize', function() {
+ chart.resize()
+ })
+ // 绘制图表
+ chart.setOption({
+ // 图表主标题
+ // title: {
+ // text: '世界地图', // 主标题文本,支持使用 \n 换行
+ // top: 10, // 定位 值: 'top', 'middle', 'bottom' 也可以是具体的值或者百分比
+ // left: 'center', // 值: 'left', 'center', 'right' 同上
+ // textStyle: { // 文本样式
+ // fontSize: 24,
+ // fontWeight: 600,
+ // color: '#000'
+ // }
+ // },
+
+ grid: {
+ width: '100%',
+ height: '100%',
+ left: '0%',
+ right: '0%',
+ bottom: '0%',
+ containLabel: true
+ },
+ // 提示框组件
+ tooltip: {
+ trigger: 'item', // 触发类型, 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用
+ // 提示框浮层内容格式器,支持字符串模板和回调函数两种形式
+ // 使用函数模板 传入的数据值 -> value: number | Array
+ formatter: function(val) {
+ if (val.data == null) return
+ return val.data.name + ': ' + val.data.value
+ }
+ },
+ // 视觉映射组件
+ visualMap: {
+ min: 0,
+ max: 10000,
+ text: ['max', 'min'],
+ realtime: false,
+ calculable: true,
+ color: ['#4608AD', '#d9e4ff']
+ },
+ series: [
+ {
+ type: 'map', // 类型
+ // 系列名称,用于tooltip的显示,legend 的图例筛选 在 setOption 更新数据和配置项时用于指定对应的系列
+ name: '世界地图',
+ mapType: 'world', // 地图类型
+ // 是否开启鼠标缩放和平移漫游 默认不开启 如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move' 设置成 true 为都开启
+ roam: true,
+ // 图形上的文本标签
+ label: {
+ show: false // 是否显示对应地名
+ },
+ zoom: 1.2,
+ // 地图区域的多边形 图形样式
+ itemStyle: {
+ // areaColor: '#7B68EE', // 地图区域的颜色 如果设置了visualMap,areaColor属性将不起作用
+ borderWidth: 0.5, // 描边线宽 为 0 时无描边
+ borderColor: '#000', // 图形的描边颜色 支持的颜色格式同 color,不支持回调函数
+ borderType: 'solid' // 描边类型,默认为实线,支持 'solid', 'dashed', 'dotted'
+ },
+ // 高亮状态下的多边形和标签样式
+ emphasis: {
+ label: {
+ show: true, // 是否显示标签
+ color: '#fff' // 文字的颜色 如果设置为 'auto',则为视觉映射得到的颜色,如系列色
+ },
+ itemStyle: {
+ areaColor: '#FF6347' // 地图区域的颜色
+ }
+ },
+ // 自定义地区的名称映射
+ nameMap: name,
+ // 地图系列中的数据内容数组 数组项可以为单个数值
+ data: data
+ }
+ ]
+ })
+ }
+ }
+}
+</script>
+<style lang="scss">
+.wrapper {
+ width: 100%;
+}
+.wrapper .chart1{
+ width: 60%;
+ /* margin:0 auto; */
+ height: 400px;
+ /* border: 1px solid #eeeeee; */
+ /* background: url(../../public/static/bg.png) no-repeat; 背景图设置*/
+ background-size: 100% 100%;
+ background-color: #fff;
+}
+.chart1 {
+ width: 100%;
+ height: 100%;
+ background-color: yellow;
+
+}
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Fwdrdns.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Fwdrdns.vue
new file mode 100644
index 0000000..0be12ba
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Fwdrdns.vue
@@ -0,0 +1,166 @@
+<template>
+ <div class="wrapper">
+ <div id="chart4" class="chart" />
+ </div>
+</template>
+
+<script>
+import echarts from 'echarts'
+export default {
+ props: ['do53fwdrdns'],
+ data() {
+ return {}
+ },
+ mounted() {
+ this.getWorld(this.do53fwdrdns)
+ var myChartContainer = document.getElementById('chart4')
+ // 获取自适应的高度和宽度
+ var resizeMyChartContainer = function() {
+ // myChartContainer.style.height = window.innerHeight * 0.65 + 'px';
+ // myChartContainer.style.width = window.innerWidth * 0.75 + 'px';
+ myChartContainer.style.height = 300 + 'px'
+ myChartContainer.style.width = 600 + 'px'
+ if (window.innerWidth > 768 && window.innerWidth < 1370) {
+ myChartContainer.style.width = 500 + 'px'
+ }
+ }
+ // 设置容器高和宽
+ resizeMyChartContainer()
+ var myChart = echarts.init(myChartContainer)
+ const option = {}
+ myChart.setOption(option)
+ },
+ methods: {
+ changeKey(arr, key) {
+ const newArr = []
+ arr.forEach((item, index) => {
+ const newObj = {}
+ for (var i = 0; i < key.length; i++) {
+ newObj[key[i]] = item[Object.keys(item)[i]]
+ }
+ newArr.push(newObj)
+ })
+ return newArr
+ },
+ getWorld(data) {
+ const list = this.changeKey(this.do53fwdrdns, ['name', 'value'])
+ var that = this
+ // const {ctx} = getCurrentInstance()
+ this.$axios.get('/sjData/word.json').then(function(res) {
+ // console.log(list,111);
+ const namemap = res.data.namemap
+ const dataArr = list
+ // let dataArr = data.data
+ that.drawChart(namemap, dataArr)
+ })
+ },
+ drawChart(name, data) {
+ // 基于准备好的dom,初始化echarts实例
+ const chart = echarts.init(document.getElementById('chart4'))
+
+ // 监听屏幕变化自动缩放图表
+ window.addEventListener('resize', function() {
+ chart.resize()
+ })
+ // 绘制图表
+ chart.setOption({
+ // 图表主标题
+ // title: {
+ // text: '世界地图', // 主标题文本,支持使用 \n 换行
+ // top: 10, // 定位 值: 'top', 'middle', 'bottom' 也可以是具体的值或者百分比
+ // left: 'center', // 值: 'left', 'center', 'right' 同上
+ // textStyle: { // 文本样式
+ // fontSize: 24,
+ // fontWeight: 600,
+ // color: '#000'
+ // }
+ // },
+
+ grid: {
+ width: '100%',
+ height: '100%',
+ left: '0%',
+ right: '0%',
+ bottom: '0%',
+ containLabel: true
+ },
+ // 提示框组件
+ tooltip: {
+ trigger: 'item', // 触发类型, 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用
+ // 提示框浮层内容格式器,支持字符串模板和回调函数两种形式
+ // 使用函数模板 传入的数据值 -> value: number | Array
+ formatter: function(val) {
+ if (val.data == null) return
+ return val.data.name + ': ' + val.data.value
+ }
+ },
+ // 视觉映射组件
+ visualMap: {
+ min: 0,
+ max: 10000,
+ text: ['max', 'min'],
+ realtime: false,
+ calculable: true,
+ color: ['#4608AD', '#d9e4ff']
+ },
+ series: [
+ {
+ type: 'map', // 类型
+ // 系列名称,用于tooltip的显示,legend 的图例筛选 在 setOption 更新数据和配置项时用于指定对应的系列
+ name: '世界地图',
+ mapType: 'world', // 地图类型
+ // 是否开启鼠标缩放和平移漫游 默认不开启 如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move' 设置成 true 为都开启
+ roam: true,
+ // 图形上的文本标签
+ label: {
+ show: false // 是否显示对应地名
+ },
+ zoom: 1.2,
+ // 地图区域的多边形 图形样式
+ itemStyle: {
+ // areaColor: '#7B68EE', // 地图区域的颜色 如果设置了visualMap,areaColor属性将不起作用
+ borderWidth: 0.5, // 描边线宽 为 0 时无描边
+ borderColor: '#000', // 图形的描边颜色 支持的颜色格式同 color,不支持回调函数
+ borderType: 'solid' // 描边类型,默认为实线,支持 'solid', 'dashed', 'dotted'
+ },
+ // 高亮状态下的多边形和标签样式
+ emphasis: {
+ label: {
+ show: true, // 是否显示标签
+ color: '#fff' // 文字的颜色 如果设置为 'auto',则为视觉映射得到的颜色,如系列色
+ },
+ itemStyle: {
+ areaColor: '#FF6347' // 地图区域的颜色
+ }
+ },
+ // 自定义地区的名称映射
+ nameMap: name,
+ // 地图系列中的数据内容数组 数组项可以为单个数值
+ data: data
+ }
+ ]
+ })
+ }
+ }
+}
+</script>
+<style lang="scss">
+.wrapper {
+ width: 100%;
+}
+.wrapper .chart1{
+ width: 60%;
+ /* margin:0 auto; */
+ height: 400px;
+ /* border: 1px solid #eeeeee; */
+ /* background: url(../../public/static/bg.png) no-repeat; 背景图设置*/
+ background-size: 100% 100%;
+ background-color: #fff;
+}
+.chart1 {
+ width: 100%;
+ height: 100%;
+ background-color: yellow;
+
+}
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Nonstandard.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Nonstandard.vue
new file mode 100644
index 0000000..7e5cc9b
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Nonstandard.vue
@@ -0,0 +1,166 @@
+<template>
+ <div class="wrapper">
+ <div id="chart6" class="chart" />
+ </div>
+</template>
+
+<script>
+import echarts from 'echarts'
+export default {
+ props: ['do53nonstandard'],
+ data() {
+ return {}
+ },
+ mounted() {
+ this.getWorld(this.do53nonstandard)
+ var myChartContainer = document.getElementById('chart6')
+ // 获取自适应的高度和宽度
+ var resizeMyChartContainer = function() {
+ // myChartContainer.style.height = window.innerHeight * 0.65 + 'px';
+ // myChartContainer.style.width = window.innerWidth * 0.75 + 'px';
+ myChartContainer.style.height = 300 + 'px'
+ myChartContainer.style.width = 600 + 'px'
+ if (window.innerWidth > 768 && window.innerWidth < 1370) {
+ myChartContainer.style.width = 500 + 'px'
+ }
+ }
+ // 设置容器高和宽
+ resizeMyChartContainer()
+ var myChart = echarts.init(myChartContainer)
+ const option = {}
+ myChart.setOption(option)
+ },
+ methods: {
+ changeKey(arr, key) {
+ const newArr = []
+ arr.forEach((item, index) => {
+ const newObj = {}
+ for (var i = 0; i < key.length; i++) {
+ newObj[key[i]] = item[Object.keys(item)[i]]
+ }
+ newArr.push(newObj)
+ })
+ return newArr
+ },
+ getWorld(data) {
+ const list = this.changeKey(this.do53nonstandard, ['name', 'value'])
+ var that = this
+ // const {ctx} = getCurrentInstance()
+ this.$axios.get('/sjData/word.json').then(function(res) {
+ // console.log(list,111);
+ const namemap = res.data.namemap
+ const dataArr = list
+ // let dataArr = data.data
+ that.drawChart(namemap, dataArr)
+ })
+ },
+ drawChart(name, data) {
+ // 基于准备好的dom,初始化echarts实例
+ const chart = echarts.init(document.getElementById('chart6'))
+
+ // 监听屏幕变化自动缩放图表
+ window.addEventListener('resize', function() {
+ chart.resize()
+ })
+ // 绘制图表
+ chart.setOption({
+ // 图表主标题
+ // title: {
+ // text: '世界地图', // 主标题文本,支持使用 \n 换行
+ // top: 10, // 定位 值: 'top', 'middle', 'bottom' 也可以是具体的值或者百分比
+ // left: 'center', // 值: 'left', 'center', 'right' 同上
+ // textStyle: { // 文本样式
+ // fontSize: 24,
+ // fontWeight: 600,
+ // color: '#000'
+ // }
+ // },
+
+ grid: {
+ width: '100%',
+ height: '100%',
+ left: '0%',
+ right: '0%',
+ bottom: '0%',
+ containLabel: true
+ },
+ // 提示框组件
+ tooltip: {
+ trigger: 'item', // 触发类型, 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用
+ // 提示框浮层内容格式器,支持字符串模板和回调函数两种形式
+ // 使用函数模板 传入的数据值 -> value: number | Array
+ formatter: function(val) {
+ if (val.data == null) return
+ return val.data.name + ': ' + val.data.value
+ }
+ },
+ // 视觉映射组件
+ visualMap: {
+ min: 0,
+ max: 10000,
+ text: ['max', 'min'],
+ realtime: false,
+ calculable: true,
+ color: ['#4608AD', '#d9e4ff']
+ },
+ series: [
+ {
+ type: 'map', // 类型
+ // 系列名称,用于tooltip的显示,legend 的图例筛选 在 setOption 更新数据和配置项时用于指定对应的系列
+ name: '世界地图',
+ mapType: 'world', // 地图类型
+ // 是否开启鼠标缩放和平移漫游 默认不开启 如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move' 设置成 true 为都开启
+ roam: true,
+ // 图形上的文本标签
+ label: {
+ show: false // 是否显示对应地名
+ },
+ zoom: 1.2,
+ // 地图区域的多边形 图形样式
+ itemStyle: {
+ // areaColor: '#7B68EE', // 地图区域的颜色 如果设置了visualMap,areaColor属性将不起作用
+ borderWidth: 0.5, // 描边线宽 为 0 时无描边
+ borderColor: '#000', // 图形的描边颜色 支持的颜色格式同 color,不支持回调函数
+ borderType: 'solid' // 描边类型,默认为实线,支持 'solid', 'dashed', 'dotted'
+ },
+ // 高亮状态下的多边形和标签样式
+ emphasis: {
+ label: {
+ show: true, // 是否显示标签
+ color: '#fff' // 文字的颜色 如果设置为 'auto',则为视觉映射得到的颜色,如系列色
+ },
+ itemStyle: {
+ areaColor: '#FF6347' // 地图区域的颜色
+ }
+ },
+ // 自定义地区的名称映射
+ nameMap: name,
+ // 地图系列中的数据内容数组 数组项可以为单个数值
+ data: data
+ }
+ ]
+ })
+ }
+ }
+}
+</script>
+<style lang="scss">
+.wrapper {
+ width: 100%;
+}
+.wrapper .chart1{
+ width: 60%;
+ /* margin:0 auto; */
+ height: 400px;
+ /* border: 1px solid #eeeeee; */
+ /* background: url(../../public/static/bg.png) no-repeat; 背景图设置*/
+ background-size: 100% 100%;
+ background-color: #fff;
+}
+.chart1 {
+ width: 100%;
+ height: 100%;
+ background-color: yellow;
+
+}
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Openrdns.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Openrdns.vue
new file mode 100644
index 0000000..20a42cf
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Openrdns.vue
@@ -0,0 +1,166 @@
+<template>
+ <div class="wrapper">
+ <div id="chart5" class="chart" />
+ </div>
+</template>
+
+<script>
+import echarts from 'echarts'
+export default {
+ props: ['do53opendns'],
+ data() {
+ return {}
+ },
+ mounted() {
+ this.getWorld(this.do53opendns)
+ var myChartContainer = document.getElementById('chart5')
+ // 获取自适应的高度和宽度
+ var resizeMyChartContainer = function() {
+ // myChartContainer.style.height = window.innerHeight * 0.65 + 'px';
+ // myChartContainer.style.width = window.innerWidth * 0.75 + 'px';
+ myChartContainer.style.height = 300 + 'px'
+ myChartContainer.style.width = 600 + 'px'
+ if (window.innerWidth > 768 && window.innerWidth < 1370) {
+ myChartContainer.style.width = 500 + 'px'
+ }
+ }
+ // 设置容器高和宽
+ resizeMyChartContainer()
+ var myChart = echarts.init(myChartContainer)
+ const option = {}
+ myChart.setOption(option)
+ },
+ methods: {
+ changeKey(arr, key) {
+ const newArr = []
+ arr.forEach((item, index) => {
+ const newObj = {}
+ for (var i = 0; i < key.length; i++) {
+ newObj[key[i]] = item[Object.keys(item)[i]]
+ }
+ newArr.push(newObj)
+ })
+ return newArr
+ },
+ getWorld(data) {
+ const list = this.changeKey(this.do53opendns, ['name', 'value'])
+ var that = this
+ // const {ctx} = getCurrentInstance()
+ this.$axios.get('/sjData/word.json').then(function(res) {
+ // console.log(list,111);
+ const namemap = res.data.namemap
+ const dataArr = list
+ // let dataArr = data.data
+ that.drawChart(namemap, dataArr)
+ })
+ },
+ drawChart(name, data) {
+ // 基于准备好的dom,初始化echarts实例
+ const chart = echarts.init(document.getElementById('chart5'))
+
+ // 监听屏幕变化自动缩放图表
+ window.addEventListener('resize', function() {
+ chart.resize()
+ })
+ // 绘制图表
+ chart.setOption({
+ // 图表主标题
+ // title: {
+ // text: '世界地图', // 主标题文本,支持使用 \n 换行
+ // top: 10, // 定位 值: 'top', 'middle', 'bottom' 也可以是具体的值或者百分比
+ // left: 'center', // 值: 'left', 'center', 'right' 同上
+ // textStyle: { // 文本样式
+ // fontSize: 24,
+ // fontWeight: 600,
+ // color: '#000'
+ // }
+ // },
+
+ grid: {
+ width: '100%',
+ height: '100%',
+ left: '0%',
+ right: '0%',
+ bottom: '0%',
+ containLabel: true
+ },
+ // 提示框组件
+ tooltip: {
+ trigger: 'item', // 触发类型, 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用
+ // 提示框浮层内容格式器,支持字符串模板和回调函数两种形式
+ // 使用函数模板 传入的数据值 -> value: number | Array
+ formatter: function(val) {
+ if (val.data == null) return
+ return val.data.name + ': ' + val.data.value
+ }
+ },
+ // 视觉映射组件
+ visualMap: {
+ min: 0,
+ max: 10000,
+ text: ['max', 'min'],
+ realtime: false,
+ calculable: true,
+ color: ['#4608AD', '#d9e4ff']
+ },
+ series: [
+ {
+ type: 'map', // 类型
+ // 系列名称,用于tooltip的显示,legend 的图例筛选 在 setOption 更新数据和配置项时用于指定对应的系列
+ name: '世界地图',
+ mapType: 'world', // 地图类型
+ // 是否开启鼠标缩放和平移漫游 默认不开启 如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move' 设置成 true 为都开启
+ roam: true,
+ // 图形上的文本标签
+ label: {
+ show: false // 是否显示对应地名
+ },
+ zoom: 1.2,
+ // 地图区域的多边形 图形样式
+ itemStyle: {
+ // areaColor: '#7B68EE', // 地图区域的颜色 如果设置了visualMap,areaColor属性将不起作用
+ borderWidth: 0.5, // 描边线宽 为 0 时无描边
+ borderColor: '#000', // 图形的描边颜色 支持的颜色格式同 color,不支持回调函数
+ borderType: 'solid' // 描边类型,默认为实线,支持 'solid', 'dashed', 'dotted'
+ },
+ // 高亮状态下的多边形和标签样式
+ emphasis: {
+ label: {
+ show: true, // 是否显示标签
+ color: '#fff' // 文字的颜色 如果设置为 'auto',则为视觉映射得到的颜色,如系列色
+ },
+ itemStyle: {
+ areaColor: '#FF6347' // 地图区域的颜色
+ }
+ },
+ // 自定义地区的名称映射
+ nameMap: name,
+ // 地图系列中的数据内容数组 数组项可以为单个数值
+ data: data
+ }
+ ]
+ })
+ }
+ }
+}
+</script>
+<style lang="scss">
+.wrapper {
+ width: 100%;
+}
+.wrapper .chart1{
+ width: 60%;
+ /* margin:0 auto; */
+ height: 400px;
+ /* border: 1px solid #eeeeee; */
+ /* background: url(../../public/static/bg.png) no-repeat; 背景图设置*/
+ background-size: 100% 100%;
+ background-color: #fff;
+}
+.chart1 {
+ width: 100%;
+ height: 100%;
+ background-color: yellow;
+
+}
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53sj.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53sj.vue
new file mode 100644
index 0000000..06ff958
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53sj.vue
@@ -0,0 +1,166 @@
+<template>
+ <div class="wrapper">
+ <div id="chart1" class="chart" />
+ </div>
+</template>
+
+<script>
+import echarts from 'echarts'
+export default {
+ props: ['do53sj'],
+ data() {
+ return {}
+ },
+ mounted() {
+ this.getWorld(this.do53sj)
+ var myChartContainer = document.getElementById('chart1')
+ // 获取自适应的高度和宽度
+ var resizeMyChartContainer = function() {
+ // myChartContainer.style.height = window.innerHeight * 0.65 + 'px';
+ // myChartContainer.style.width = window.innerWidth * 0.75 + 'px';
+ myChartContainer.style.height = 300 + 'px'
+ myChartContainer.style.width = 600 + 'px'
+ if (window.innerWidth > 768 && window.innerWidth < 1370) {
+ myChartContainer.style.width = 500 + 'px'
+ }
+ }
+ // 设置容器高和宽
+ resizeMyChartContainer()
+ var myChart = echarts.init(myChartContainer)
+ const option = {}
+ myChart.setOption(option)
+ },
+ methods: {
+ changeKey(arr, key) {
+ const newArr = []
+ arr.forEach((item, index) => {
+ const newObj = {}
+ for (var i = 0; i < key.length; i++) {
+ newObj[key[i]] = item[Object.keys(item)[i]]
+ }
+ newArr.push(newObj)
+ })
+ return newArr
+ },
+ getWorld(data) {
+ const list = this.changeKey(this.do53sj, ['name', 'value'])
+ var that = this
+ // const {ctx} = getCurrentInstance()
+ this.$axios.get('/sjData/word.json').then(function(res) {
+ // console.log(res);
+ const namemap = res.data.namemap
+ const dataArr = list
+ // let dataArr = data.data
+ that.drawChart(namemap, dataArr)
+ })
+ },
+ drawChart(name, data) {
+ // 基于准备好的dom,初始化echarts实例
+ const chart = echarts.init(document.getElementById('chart1'))
+
+ // 监听屏幕变化自动缩放图表
+ window.addEventListener('resize', function() {
+ chart.resize()
+ })
+ // 绘制图表
+ chart.setOption({
+ // 图表主标题
+ // title: {
+ // text: '世界地图', // 主标题文本,支持使用 \n 换行
+ // top: 10, // 定位 值: 'top', 'middle', 'bottom' 也可以是具体的值或者百分比
+ // left: 'center', // 值: 'left', 'center', 'right' 同上
+ // textStyle: { // 文本样式
+ // fontSize: 24,
+ // fontWeight: 600,
+ // color: '#000'
+ // }
+ // },
+
+ grid: {
+ width: '100%',
+ height: '100%',
+ left: '0%',
+ right: '0%',
+ bottom: '0%',
+ containLabel: true
+ },
+ // 提示框组件
+ tooltip: {
+ trigger: 'item', // 触发类型, 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用
+ // 提示框浮层内容格式器,支持字符串模板和回调函数两种形式
+ // 使用函数模板 传入的数据值 -> value: number | Array
+ formatter: function(val) {
+ if (val.data == null) return
+ return val.data.name + ': ' + val.data.value
+ }
+ },
+ // 视觉映射组件
+ visualMap: {
+ min: 0,
+ max: 10000,
+ text: ['max', 'min'],
+ realtime: false,
+ calculable: true,
+ color: ['#4608AD', '#d9e4ff']
+ },
+ series: [
+ {
+ type: 'map', // 类型
+ // 系列名称,用于tooltip的显示,legend 的图例筛选 在 setOption 更新数据和配置项时用于指定对应的系列
+ name: '世界地图',
+ mapType: 'world', // 地图类型
+ // 是否开启鼠标缩放和平移漫游 默认不开启 如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move' 设置成 true 为都开启
+ roam: true,
+ // 图形上的文本标签
+ label: {
+ show: false // 是否显示对应地名
+ },
+ zoom: 1.2,
+ // 地图区域的多边形 图形样式
+ itemStyle: {
+ // areaColor: '#7B68EE', // 地图区域的颜色 如果设置了visualMap,areaColor属性将不起作用
+ borderWidth: 0.5, // 描边线宽 为 0 时无描边
+ borderColor: '#000', // 图形的描边颜色 支持的颜色格式同 color,不支持回调函数
+ borderType: 'solid' // 描边类型,默认为实线,支持 'solid', 'dashed', 'dotted'
+ },
+ // 高亮状态下的多边形和标签样式
+ emphasis: {
+ label: {
+ show: true, // 是否显示标签
+ color: '#fff' // 文字的颜色 如果设置为 'auto',则为视觉映射得到的颜色,如系列色
+ },
+ itemStyle: {
+ areaColor: '#FF6347' // 地图区域的颜色
+ }
+ },
+ // 自定义地区的名称映射
+ nameMap: name,
+ // 地图系列中的数据内容数组 数组项可以为单个数值
+ data: data
+ }
+ ]
+ })
+ }
+ }
+}
+</script>
+<style lang="scss">
+.wrapper {
+ width: 100%;
+}
+.wrapper .chart1{
+ width: 60%;
+ /* margin:0 auto; */
+ height: 400px;
+ /* border: 1px solid #eeeeee; */
+ /* background: url(../../public/static/bg.png) no-repeat; 背景图设置*/
+ background-size: 100% 100%;
+ background-color: #fff;
+}
+.chart1 {
+ width: 100%;
+ height: 100%;
+ background-color: yellow;
+
+}
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53zg.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53zg.vue
new file mode 100644
index 0000000..3ab40d6
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53zg.vue
@@ -0,0 +1,145 @@
+<template>
+ <div id="map1" ref="do53zg" :style="{ width: '100%', height: '100%' }" />
+</template>
+<script>
+import chinaGeoCoordMap from '../../utils/chinamap'
+import echarts from 'echarts'
+export default {
+ name: 'Map1',
+ props: ['do53zg'],
+ data() {
+ return {}
+ },
+ mounted() {
+ // console.log(this.dohzg,234);
+ var myChartContainer = document.getElementById('map1')
+ // 获取自适应的高度和宽度
+ var resizeMyChartContainer = function() {
+ myChartContainer.style.height = 300 + 'px'
+ myChartContainer.style.width = 600 + 'px'
+ if (window.innerWidth > 768 && window.innerWidth < 1370) {
+ myChartContainer.style.width = 500 + 'px'
+ }
+ }
+ // 设置容器高和宽
+ resizeMyChartContainer()
+ var map = echarts.init(myChartContainer)
+ const option = {}
+ map.setOption(option)
+ const dohzglist = this.changeKey(this.do53zg, ['name', 'value'])
+ // console.log(dohzglist,234);
+ this.initditu(dohzglist, chinaGeoCoordMap.chinaGeoCoordMap)
+ },
+ methods: {
+ changeKey(arr, key) {
+ const newArr = []
+ arr.forEach((item, index) => {
+ const newObj = {}
+ for (var i = 0; i < key.length; i++) {
+ newObj[key[i]] = item[Object.keys(item)[i]]
+ }
+ newArr.push(newObj)
+ })
+ return newArr
+ },
+
+ initditu(dataCount) {
+ // console.log(dataCount,1111);
+ var datasa = dataCount
+ // var chinaDatas = this.transmitData;
+ // 基于准备好的dom,初始化echarts实例
+ const map = this.$echarts.init(document.getElementById('map1'))
+ // var chinaDatas = transmitData;
+
+ var series = []
+ var color = ['#57df1c'];
+ [['', this.chinaDatas]].forEach(function(item, i) {
+ // console.log(item, 123);
+ series.push(
+ {
+ type: 'lines'
+ },
+ {
+ type: 'effectScatter',
+ coordinateSystem: 'geo'
+ },
+ // 被攻击点
+ {
+ type: 'effectScatter',
+ coordinateSystem: 'geo',
+ zlevel: 2
+ },
+ {
+ type: 'map',
+ map: 'china',
+ geoIndex: 0,
+ aspectScale: 0.75, // 长宽比
+ showLegendSymbol: false, // 存在legend时显示
+ label: {
+ normal: {
+ show: true
+ },
+ emphasis: {
+ show: false,
+ textStyle: {
+ color: '#fff'
+ }
+ }
+ },
+ roam: true,
+ animation: false,
+ data: datasa
+ }
+ )
+ })
+
+ map.setOption({
+ tooltip: {
+ trigger: 'item',
+ formatter: function(val) {
+ if (val.data == null) return
+ return val.data.name + ': ' + val.data.value
+ }
+ },
+ visualMap: {
+ show: true,
+ min: 0,
+ max: 200,
+ left: 'left',
+ top: 'bottom',
+ text: ['max', 'min'], // 文本,默认为数值文本
+ calculable: true,
+ seriesIndex: [3],
+ inRange: {
+ color: ['#d9e4ff', '#4608AD']
+ }
+ },
+ geo: {
+ map: 'china',
+ roam: true, // 是否允许缩放
+ zoom: 1.14,
+ label: {
+ emphasis: {
+ show: true
+ }
+ },
+ itemStyle: {
+ normal: {
+ show: false,
+ color: 'rgba(48,97,186,0)', // 地图背景色
+ borderColor: '#000' // 省市边界线
+ },
+ emphasis: {
+ show: false,
+ color: '#ff6347' // 悬浮背景
+ }
+ }
+ },
+ series: series
+ })
+ }
+ }
+}
+</script>
+<style scoped>
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Dohsj.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Dohsj.vue
new file mode 100644
index 0000000..03510a5
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Dohsj.vue
@@ -0,0 +1,163 @@
+<template>
+ <div id="wrapper" class="wrapper">
+ <div id="chart" class="chart" />
+ </div>
+</template>
+
+<script>
+import echarts from 'echarts'
+export default {
+ props: ['dohsj'],
+ data() {
+ return {}
+ },
+ mounted() {
+ this.getWorld(this.dohsj)
+ var myChartContainer = document.getElementById('chart')
+ var resizeMyChartContainer = function() {
+ myChartContainer.style.height = 300 + 'px'
+ myChartContainer.style.width = 600 + 'px'
+ // console.log(window.innerWidth)
+ if (window.innerWidth > 768 && window.innerWidth < 1370) {
+ myChartContainer.style.width = 500 + 'px'
+ }
+ }
+ // 设置容器高和宽
+ resizeMyChartContainer()
+ var map = echarts.init(myChartContainer)
+ const option = {}
+ map.setOption(option)
+ },
+ methods: {
+ changeKey(arr, key) {
+ const newArr = []
+ arr.forEach((item, index) => {
+ const newObj = {}
+ for (var i = 0; i < key.length; i++) {
+ newObj[key[i]] = item[Object.keys(item)[i]]
+ }
+ newArr.push(newObj)
+ })
+ return newArr
+ },
+
+ getWorld(data) {
+ const list = this.changeKey(this.dohsj, ['name', 'value'])
+ // console.log(list,456);
+ var that = this
+ this.$axios.get('/sjData/word.json').then(function(res) {
+ // console.log(list,333);
+ const namemap = res.data.namemap
+ const dataArr = list
+ // console.log(dataArr,6666);
+ // let dataArr = data.data
+ that.drawChart(namemap, dataArr)
+ })
+ },
+
+ drawChart(name, data) {
+ // 基于准备好的dom,初始化echarts实例
+ const chart = echarts.init(document.getElementById('chart'))
+
+ // 监听屏幕变化自动缩放图表
+ window.addEventListener('resize', function() {
+ chart.resize()
+ })
+ // 绘制图表
+ chart.setOption({
+ // 图表主标题
+ // title: {
+ // text: '世界地图', // 主标题文本,支持使用 \n 换行
+ // top: 10, // 定位 值: 'top', 'middle', 'bottom' 也可以是具体的值或者百分比
+ // left: 'center', // 值: 'left', 'center', 'right' 同上
+ // textStyle: { // 文本样式
+ // fontSize: 24,
+ // fontWeight: 600,
+ // color: '#000'
+ // }
+ // },
+ grid: {
+ width: '100%',
+ height: '100%',
+ left: '0%',
+ right: '0%',
+ bottom: '0%',
+ containLabel: true
+ },
+ // 提示框组件
+ tooltip: {
+ trigger: 'item', // 触发类型, 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用
+ // 提示框浮层内容格式器,支持字符串模板和回调函数两种形式
+ // 使用函数模板 传入的数据值 -> value: number | Array
+ formatter: function(val) {
+ if (val.data == null) return
+ return val.data.name + ': ' + val.data.value
+ }
+ },
+ // 视觉映射组件
+ visualMap: {
+ min: 0,
+ max: 100000,
+ text: ['max', 'min'],
+ realtime: false,
+ calculable: true,
+ color: ['#4608AD', '#d9e4ff']
+ },
+ series: [
+ {
+ type: 'map', // 类型
+ // 系列名称,用于tooltip的显示,legend 的图例筛选 在 setOption 更新数据和配置项时用于指定对应的系列
+ name: '世界地图',
+ mapType: 'world', // 地图类型
+ // 是否开启鼠标缩放和平移漫游 默认不开启 如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move' 设置成 true 为都开启
+ roam: true,
+ // 图形上的文本标签
+ label: {
+ show: false // 是否显示对应地名
+ },
+ zoom: 1.2,
+ // 地图区域的多边形 图形样式
+ itemStyle: {
+ // areaColor: '#7B68EE', // 地图区域的颜色 如果设置了visualMap,areaColor属性将不起作用
+ borderWidth: 0.5, // 描边线宽 为 0 时无描边
+ borderColor: '#000', // 图形的描边颜色 支持的颜色格式同 color,不支持回调函数
+ borderType: 'solid' // 描边类型,默认为实线,支持 'solid', 'dashed', 'dotted'
+ },
+ // 高亮状态下的多边形和标签样式
+ emphasis: {
+ label: {
+ show: true, // 是否显示标签
+ color: '#fff' // 文字的颜色 如果设置为 'auto',则为视觉映射得到的颜色,如系列色
+ },
+ itemStyle: {
+ areaColor: '#FF6347' // 地图区域的颜色
+ }
+ },
+ // 自定义地区的名称映射
+ nameMap: name,
+ // 地图系列中的数据内容数组 数组项可以为单个数值
+ data: data
+ }
+ ]
+ })
+ }
+ }
+}
+</script>
+<style lang="scss">
+.wrapper {
+ width: 100%;
+ height: 100%;
+}
+.wrapper .chart {
+ width: 100%;
+ background-size: 100% 100%;
+ background-color: #fff;
+}
+.chart {
+ width: 100%;
+ height: 100%;
+ // background-color: yellow;
+
+}
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Dohzg.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Dohzg.vue
new file mode 100644
index 0000000..812b58e
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Dohzg.vue
@@ -0,0 +1,145 @@
+<template>
+ <div id="map" ref="dohzg" :style="{ width: '100%', height: '100%' }" />
+</template>
+<script>
+import chinaGeoCoordMap from '../../utils/chinamap'
+import echarts from 'echarts'
+export default {
+ name: 'Map',
+ props: ['dohzg'],
+ data() {
+ return {}
+ },
+ mounted() {
+ // console.log(this.dohzg,234);
+ var myChartContainer = document.getElementById('map')
+ // 获取自适应的高度和宽度
+ var resizeMyChartContainer = function() {
+ myChartContainer.style.height = 300 + 'px'
+ myChartContainer.style.width = 600 + 'px'
+ if (window.innerWidth > 768 && window.innerWidth < 1370) {
+ myChartContainer.style.width = 500 + 'px'
+ }
+ }
+ // 设置容器高和宽
+ resizeMyChartContainer()
+ var map = echarts.init(myChartContainer)
+ const option = {}
+ map.setOption(option)
+ const dohzglist = this.changeKey(this.dohzg, ['name', 'value'])
+ // console.log(dohzglist,234);
+ this.initditu(dohzglist, chinaGeoCoordMap.chinaGeoCoordMap)
+ },
+ methods: {
+ changeKey(arr, key) {
+ const newArr = []
+ arr.forEach((item, index) => {
+ const newObj = {}
+ for (var i = 0; i < key.length; i++) {
+ newObj[key[i]] = item[Object.keys(item)[i]]
+ }
+ newArr.push(newObj)
+ })
+ return newArr
+ },
+
+ initditu(dataCount, chinaGeoCoordMap) {
+ // console.log(dataCount,1111);
+ var datasa = dataCount
+ // var chinaDatas = this.transmitData;
+ // 基于准备好的dom,初始化echarts实例
+ const map = this.$echarts.init(document.getElementById('map'))
+ // var chinaDatas = transmitData;
+
+ var series = []
+ var color = ['#57df1c'];
+ [['', this.chinaDatas]].forEach(function(item, i) {
+ // console.log(item, 123);
+ series.push(
+ {
+ type: 'lines'
+ },
+ {
+ type: 'effectScatter',
+ coordinateSystem: 'geo'
+ },
+ // 被攻击点
+ {
+ type: 'effectScatter',
+ coordinateSystem: 'geo',
+ zlevel: 2
+ },
+ {
+ type: 'map',
+ map: 'china',
+ geoIndex: 0,
+ aspectScale: 0.75, // 长宽比
+ showLegendSymbol: false, // 存在legend时显示
+ label: {
+ normal: {
+ show: true
+ },
+ emphasis: {
+ show: false,
+ textStyle: {
+ color: '#fff'
+ }
+ }
+ },
+ roam: true,
+ animation: false,
+ data: datasa
+ }
+ )
+ })
+
+ map.setOption({
+ tooltip: {
+ trigger: 'item',
+ formatter: function(val) {
+ if (val.data == null) return
+ return val.data.name + ': ' + val.data.value
+ }
+ },
+ visualMap: {
+ show: true,
+ min: 0,
+ max: 200,
+ left: 'left',
+ top: 'bottom',
+ text: ['max', 'min'], // 文本,默认为数值文本
+ calculable: true,
+ seriesIndex: [3],
+ inRange: {
+ color: ['#d9e4ff', '#4608AD']
+ }
+ },
+ geo: {
+ map: 'china',
+ roam: true, // 是否允许缩放
+ zoom: 1.14,
+ label: {
+ emphasis: {
+ show: true
+ }
+ },
+ itemStyle: {
+ normal: {
+ show: false,
+ color: 'rgba(48,97,186,0)', // 地图背景色
+ borderColor: '#000' // 省市边界线
+ },
+ emphasis: {
+ show: false,
+ color: '#ff6347' // 悬浮背景
+ }
+ }
+ },
+ series: series
+ })
+ }
+ }
+}
+</script>
+<style scoped>
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Funnel.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Funnel.vue
new file mode 100644
index 0000000..380b373
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Funnel.vue
@@ -0,0 +1,120 @@
+<template>
+ <div :class="className" :style="{height:height,width:width}" />
+</template>
+
+<script>
+import echarts from 'echarts'
+
+require('echarts/theme/macarons') // echarts theme
+import { debounce } from '@/utils'
+
+export default {
+ props: {
+ className: {
+ type: String,
+ default: 'chart'
+ },
+ width: {
+ type: String,
+ default: '100%'
+ },
+ height: {
+ type: String,
+ default: '300px'
+ }
+ },
+ data() {
+ return {
+ chart: null
+ }
+ },
+ mounted() {
+ this.initChart()
+ this.__resizeHandler = debounce(() => {
+ if (this.chart) {
+ this.chart.resize()
+ }
+ }, 100)
+ window.addEventListener('resize', this.__resizeHandler)
+ },
+ beforeDestroy() {
+ if (!this.chart) {
+ return
+ }
+ window.removeEventListener('resize', this.__resizeHandler)
+ this.chart.dispose()
+ this.chart = null
+ },
+ methods: {
+ initChart() {
+ this.chart = echarts.init(this.$el, 'macarons')
+
+ this.chart.setOption({
+ title: {
+ text: '漏斗图',
+ subtext: '纯属虚构'
+ },
+ tooltip: {
+ trigger: 'item',
+ formatter: '{a} <br/>{b} : {c}%'
+ },
+ toolbox: {
+ feature: {
+ dataView: { readOnly: false },
+ restore: {},
+ saveAsImage: {}
+ }
+ },
+ legend: {
+ data: ['展现', '点击', '访问', '咨询', '订单']
+ },
+ calculable: true,
+ series: [
+ {
+ name: '漏斗图',
+ type: 'funnel',
+ left: '10%',
+ top: 60,
+ bottom: 60,
+ width: '80%',
+ // height: {totalHeight} - y - y2,
+ min: 0,
+ max: 100,
+ minSize: '0%',
+ maxSize: '100%',
+ sort: 'descending',
+ gap: 2,
+ label: {
+ show: true,
+ position: 'inside'
+ },
+ labelLine: {
+ length: 10,
+ lineStyle: {
+ width: 1,
+ type: 'solid'
+ }
+ },
+ itemStyle: {
+ borderColor: '#fff',
+ borderWidth: 1
+ },
+ emphasis: {
+ label: {
+ fontSize: 20
+ }
+ },
+ data: [
+ { value: 60, name: '访问' },
+ { value: 40, name: '咨询' },
+ { value: 20, name: '订单' },
+ { value: 80, name: '点击' },
+ { value: 100, name: '展现' }
+ ]
+ }
+ ]
+ })
+ }
+ }
+}
+</script>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/PieChart.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/PieChart.vue
new file mode 100644
index 0000000..ff1bc52
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/PieChart.vue
@@ -0,0 +1,84 @@
+<template>
+ <div :class="className" :style="{height:height,width:width}" />
+</template>
+
+<script>
+import echarts from 'echarts'
+require('echarts/theme/macarons') // echarts theme
+import { debounce } from '@/utils'
+
+export default {
+ props: {
+ className: {
+ type: String,
+ default: 'chart'
+ },
+ width: {
+ type: String,
+ default: '100%'
+ },
+ height: {
+ type: String,
+ default: '300px'
+ }
+ },
+ data() {
+ return {
+ chart: null
+ }
+ },
+ mounted() {
+ this.initChart()
+ this.__resizeHandler = debounce(() => {
+ if (this.chart) {
+ this.chart.resize()
+ }
+ }, 100)
+ window.addEventListener('resize', this.__resizeHandler)
+ },
+ beforeDestroy() {
+ if (!this.chart) {
+ return
+ }
+ window.removeEventListener('resize', this.__resizeHandler)
+ this.chart.dispose()
+ this.chart = null
+ },
+ methods: {
+ initChart() {
+ this.chart = echarts.init(this.$el, 'macarons')
+
+ this.chart.setOption({
+ tooltip: {
+ trigger: 'item',
+ formatter: '{a} <br/>{b} : {c} ({d}%)'
+ },
+ legend: {
+ left: 'center',
+ bottom: '10',
+ data: ['Industries', 'Technology', 'Forex', 'Gold', 'Forecasts']
+ },
+ calculable: true,
+ series: [
+ {
+ name: 'WEEKLY WRITE ARTICLES',
+ type: 'pie',
+ roseType: 'radius',
+ radius: [15, 95],
+ center: ['50%', '38%'],
+ data: [
+ { value: 320, name: 'Industries' },
+ { value: 240, name: 'Technology' },
+ { value: 149, name: 'Forex' },
+ { value: 100, name: 'Gold' },
+ { value: 59, name: 'Forecasts' }
+ ],
+ animationEasing: 'cubicInOut',
+ animationDuration: 2600
+ }
+ ]
+ })
+ }
+ }
+}
+</script>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Time.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Time.vue
new file mode 100644
index 0000000..4ab9c55
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Time.vue
@@ -0,0 +1,104 @@
+<template>
+ <!-- <div id="Time" class="Time" :style="{height:height,width:width}" /> -->
+ <div class="wrapper">
+ <div id="Time" class="chart" />
+ </div>
+</template>
+
+<script>
+import echarts from 'echarts'
+export default {
+
+ data() {
+ return {
+
+ }
+ },
+ mounted() {
+ // this.initChart()
+ var myChartContainer = document.getElementById('Time')
+
+ // 获取自适应的高度和宽度
+ var resizeMyChartContainer = function() {
+ // myChartContainer.style.height = window.innerHeight * 0.65 + 'px';
+ // myChartContainer.style.width = window.innerWidth * 0.75 + 'px';
+ myChartContainer.style.height = 100 + 'px'
+ myChartContainer.style.width = 1182+'px'
+ if (window.innerWidth > 768 && window.innerWidth < 1370) {
+ myChartContainer.style.width = 945 + 'px'
+ }
+ }
+ // 设置容器高和宽
+ resizeMyChartContainer()
+ var myChart = echarts.init(myChartContainer)
+ const option = {}
+ myChart.setOption(option)
+ this.initChart()
+ },
+ methods: {
+ initChart() {
+ // this.chart = echarts.init(this.$el, 'macarons')
+ const chart = echarts.init(document.getElementById('Time'))
+ // 监听屏幕变化自动缩放图表
+ window.addEventListener('resize', function() {
+ chart.resize()
+ })
+
+
+
+ chart.setOption({
+ baseOption: {
+ timeline: {
+ axisType: 'category',
+ autoPlay: true,
+ playInterval: 1000,
+ data: [
+ '2002-01-01', '2003-01-01', '2004-01-01',
+ {
+ value: '2005-01-01',
+ tooltip: {
+ formatter: '{b} GDP达到一个高度'
+ },
+ symbol: 'diamond',
+ symbolSize: 16
+ },
+ '2006-01-01', '2007-01-01', '2008-01-01', '2009-01-01', '2010-01-01',
+ {
+ value: '2011-01-01',
+ tooltip: {
+ formatter: function(params) {
+ return params.name + 'GDP达到又一个高度'
+ }
+ },
+ symbol: 'diamond',
+ symbolSize: 18
+ }
+ ],
+ label: {
+ formatter: function(s) {
+ return (new Date(s)).getFullYear()
+ }
+ }
+ },
+
+ calculable: true,
+
+
+ series: [
+
+ ]
+ },
+ options: [
+
+
+ ]
+ })
+ }
+ }
+}
+</script>
+<style scoped>
+.wrapper {
+ width: 100%;
+}
+</style> \ No newline at end of file
diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/FilteredSearch.vue b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/FilteredSearch.vue
new file mode 100644
index 0000000..afe1155
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/FilteredSearch.vue
@@ -0,0 +1,518 @@
+<template>
+ <div class="filtered-search-container" v-clickoutside="handleClickoutside" v-idscope id="filtersearch">
+ <!-- 搜索框容器 -->
+ <div class="filtered-search-box" :class="isFocus ? 'focus':''">
+ <!-- 历史记录下拉菜单...` -->
+ <!-- <recent-search ref="historySearch" @selectHistory="setDefaultItems"/> -->
+ <!-- <el-divider direction="vertical" class="divider"></el-divider> -->
+ <div class="scroll-container">
+ <div class="list-container">
+ <search-item
+ :key="item.id"
+ v-for="(item,index) in selectItems"
+ :id="item.label"
+ @del="handleDel"
+ @active="handleActive"
+ @moveTo="handleMove"
+ @clickItem="handleClickItem"
+ :currentIndex="index"
+ :isLast="index === selectItems.length-1"
+ :selectItem="item" :ref="'selectItem'+index"/>
+ <el-select
+ id="select-label"
+ ref="select"
+ :popper-append-to-body="true"
+ popper-class="select-popper select-list-zindex"
+ class="label-select"
+ v-if="conditionConfig.isShow"
+ v-model="conditionConfig.currentCondition"
+ @change="addCondition"
+ @focus="handleFocus"
+ @blur="handleBlur"
+ size="mini"
+ remote
+ filterable
+ :allow-create="false"
+ default-first-option
+ @keydown.native="handleKeydown"
+ @visible-change="visibleChangeHandle"
+ placeholder="请输入检索内容">
+ <template v-for="item in conditionConfig.conditionList">
+ <el-option
+ :id="item.id"
+ v-idscope
+ :disabled="item.disabled === true"
+ :key="item.id"
+ v-if="item.visible!==false"
+ :label="item.name"
+ :value="item.id">
+ </el-option>
+ </template>
+ </el-select>
+ </div>
+ </div>
+ <i id="searchClear" v-if="selectItems && selectItems.length>0" class="el-icon-close clear-icon"
+ @click="handleClear"></i>
+ </div>
+ <i id="searchQuery" class="el-icon-search search-icon" @click="handleQuery"></i>
+ </div>
+</template>
+
+<script>
+ /*
+ * {
+ id: 1,
+ name: 'ID',
+ icon: 'iconfont icon-id',
+ type: 'input',
+ label: 'profileId',
+ disabled: false,
+ visiable:true,
+ value:''
+ },
+ * */
+ // import fireKeyEvent from './components/keyboard'
+ import searchHistory from './components/historyApi'
+ import SearchItem from './components/SearchItem.vue'
+ import lodashCloneDeep from 'lodash/cloneDeep'
+ import getTxt1CursorPosition from './components/cursorPosition'
+ import {cloneDeep, debounce} from "lodash";
+
+
+ export default {
+ name: "FilteredSearch",
+ components: {
+ // GlIcon,
+ RecentSearch: () => import('./components/RecentSearch.vue'),
+ SearchItem
+ },
+ props: { //参数 ...
+ historyKey: {},
+ sourceList: {}, //原始 查询条件列表
+ defaultList: {} //默认选中值 --可选
+ },
+ data() {
+ return {
+ //标签列表 可选的参数分类
+ conditionConfig: {
+ conditionList: [],
+ isShow: true,
+ currentCondition: "", //当前搜索条件
+ currentIndex: 0 //当前 指针位置
+ },
+ //选中的数据 ...
+ selectItems: [],
+ //对外输入框 搜索过滤框
+ isFocus: false,
+ permission: JSON.parse(localStorage.getItem('permissions'))
+ };
+ },
+ created() {
+ this.setDefaultItems()
+ },
+ methods: {
+ sortConditoins() {
+ //列表排序 ...
+ // conditionConfig.conditionList
+
+ },
+ // handleClickItem() {
+ // // 下拉 和 历史数据悬浮同时存在 问题(预留)
+ // // this.$refs.historySearch ? this.$refs.historySearch.visible=false :''
+ // },
+ // handleClickoutside() {
+
+ // },
+ handleMove({toIndex, self}) {
+ if (toIndex < 0 || toIndex > this.selectItems.length - 1) {
+ self.handleBlur()
+ return
+ }
+ this.focusItem(toIndex)
+ },
+ handleActive({currentIndex, currentItem}) {
+ if (currentIndex === this.conditionConfig.currentIndex) {
+ return
+ }
+ // this.conditionConfig.currentCondition=currentItem.id
+ this.conditionConfig.currentIndex = currentIndex
+ },
+ validator(resultMap) {
+ var validField = ['id', 'profileId']
+ var errList = []
+ var reg = /^[\d,]*$/;
+ validField.forEach((field) => {
+ var val = resultMap[field] || '';
+ if (field === 'id' || field === 'profileId') {
+ var idList = val.split(',')
+ idList.forEach((item) => {
+ if (item && !reg.test(item)) {
+ errList.push(this.$t('i18n.overall.searchInfo.idValid'))
+ } else {
+ if (item && (+item >= 2147483647)) {
+ errList.push(this.$t("maxnumTips"))
+ }
+ }
+ })
+ }
+ });
+ return errList
+ },
+ handleQuery: debounce(function () {
+ //执行查询方法 对外抛出查询参数...
+ console.log("执行查询方法");
+ searchHistory.addItem(this.selectItems, this.historyKey);
+ var resultMap = {}
+ this.selectItems.forEach((item, index) => {
+ resultMap[item.label] = item.value
+ });
+ //校验查询条件
+ var errList = []
+ console.log(resultMap);
+ errList = this.validator(resultMap) || []
+ if (errList.length > 0) {
+ this.$message.error(errList[0]);
+ return
+ }
+
+ this.$emit('query', resultMap, this.selectItems);
+ //重新刷新一下 下拉(防止用户反复回车-可以删除)
+ this.conditionConfig.isShow = false
+ setTimeout(() => {
+ this.isFocus = false
+ this.conditionConfig.isShow = true
+ })
+ }, 500),
+ handleKeydown(e) {
+ var keyCode = window.event ? e.keyCode : e.which;
+ //删除事件
+ this.$nextTick(() => {
+ var dom = this.$refs.select ? $(this.$refs.select.$el).find('input')[0] : '';
+ var cursorIndex = dom ? getTxt1CursorPosition(dom, document) || 0 : 0;
+
+ //回车 直接回车搜索(备用)
+ if (keyCode === 13) {
+ if (this.$refs.select && this.$refs.select.hoverIndex === -1) {
+ this.$refs.select.visible = false;
+ if (this.isFocus) {
+ this.handleQuery()
+ }
+ this.isFocus = false
+ }
+ }
+ if (keyCode === 8) {
+ if (this.$refs.select.query === "" || this.$refs.select.query == null) {
+ var focusIndex = this.conditionConfig.currentIndex - 1;
+ setTimeout(() => {
+ this.focusItem(focusIndex)
+ })
+ }
+ }
+ if (keyCode === 37) { //左箭头 || 38 右箭头
+ if (cursorIndex === 0) {
+ // console.log('左箭头到头了');
+ var leftIndex = this.conditionConfig.currentIndex - 1;
+ setTimeout(() => {
+ this.focusItem(leftIndex)
+ })
+ }
+ }
+ if (keyCode === 39) { //左箭头 || 38 右箭头
+ if (!this.$refs.select.query || cursorIndex === this.$refs.select.query.length) {
+ // console.log('右箭头到头了');
+ }
+ }
+ });
+ },
+ setDefaultItems(historyList = []) {
+ // this.handleClear();
+ var permanentItems = [{
+ id: -1,
+ name: this.$t("i18n.overall.searchList.defaultName"),
+ }];
+ for(let v of this.sourceList){
+ if(v.id === 6||v.id === 666){
+ if(!this.permission['system_accounts/system_UserManagement']){
+ v.visible=false
+ }
+ }
+ }
+ this.conditionConfig.conditionList = permanentItems.concat(this.sourceList);
+ //存在 历史记录 就走历史记录, 否则就选中 默认选中值...
+ var selectList = [];
+ var conditionList = [];
+
+ if (historyList && historyList.length > 0) {
+ selectList = historyList;
+ } else {
+ selectList = this.defaultList;
+ }
+
+ conditionList = lodashCloneDeep(this.conditionConfig.conditionList) || [];
+ //获取已存在 字段id
+ conditionList = conditionList.filter((item, index) => {
+ var findIndex = null;
+ var findItem = selectList.find((selItem, selIndex) => {
+ if (selItem.id === item.id) {
+ findIndex = selIndex;
+ return true //考虑对象合并
+ }
+ return false
+ });
+
+ if (findItem) {
+ return false
+ }
+ return true
+ });
+ this.conditionConfig.conditionList = conditionList;
+ this.selectItems = selectList
+ //点击历史记录输入框聚焦
+ if (historyList && historyList.length > 0) {
+ this.$nextTick((x) => {
+ this.$refs.select.focus()
+ })
+ }
+ },
+ visibleChangeHandle(state) {
+ if (state) {
+ this.isFocus = true
+ this.handleClickItem()
+ }
+ },
+ triggerFocus() {
+ this.$nextTick(() => {
+ if (this.conditionConfig.isShow === true) {
+ if (this.conditionConfig.conditionList.length <= 0) {
+ return
+ }
+ var dom = this.$refs.select.$el.children[0]; //获取输入框DOM 索引
+ dom.click();
+ }
+ })
+ // setTimeout(() => {
+ // if (this.conditionConfig.isShow === true) {
+ // if (this.conditionConfig.conditionList.length <= 0) {
+ // return
+ // }
+ // var dom = this.$refs.select.$el.children[0]; //获取输入框DOM 索引
+ // dom.click();
+ // }
+ // }, 200)
+ },
+ handleFocus() {
+ this.isFocus = true
+ },
+ handleBlur() {
+ this.isFocus = false
+ },
+ focusItem(index) {
+ //选中某一项
+ if (this.selectItems && this.selectItems.length > 0) {
+ this.$nextTick(() => {
+ var lastComponent = this.$refs['selectItem' + index] && this.$refs['selectItem' + index][0];
+ lastComponent && lastComponent.handleFocus && lastComponent.handleFocus()
+ });
+ }
+ },
+ addCondition(conditionCode) {
+ if (conditionCode === -1) {
+ this.handleQuery();
+ this.conditionConfig.currentCondition = null;
+ this.$refs.select.visible = false;
+ return
+ }
+ var currentIndex = null;
+ var addItem = this.conditionConfig.conditionList.find((item, index) => {
+ if (item.id === conditionCode) {
+ currentIndex = index;
+ return true
+ }
+ return false
+ });
+ //增加一项选中数据 且 删除标签该项
+ if (addItem) {
+ addItem.value = addItem.defaultVal;
+ this.selectItems.push(addItem);
+ this.conditionConfig.conditionList.splice(currentIndex, 1)
+ }
+ //最后一个搜索项 聚焦
+ // if (this.selectItems && this.selectItems.length > 0) {
+ // this.$nextTick(() => {
+ // var lastIndex = this.selectItems.length - 1;
+ // var lastComponent = this.$refs['selectItem' + lastIndex] && this.$refs['selectItem' + lastIndex][0];
+ // lastComponent && lastComponent.handleFocus && lastComponent.handleFocus()
+ // });
+ // }
+ var lastIndex = this.selectItems.length - 1;
+ this.focusItem(lastIndex)
+ this.conditionConfig.currentCondition = null
+ this.conditionConfig.isShow = false
+ },
+ handleReset() {
+ this.selectItems = []
+ this.conditionConfig.currentCondition = ""
+ this.conditionConfig.currentIndex = 0
+ },
+ handleClear() {
+ this.selectItems.forEach((item, index) => {
+ item.value = ''
+ this.conditionConfig.conditionList.push(item)
+ });
+ this.selectItems = [];
+
+ this.conditionConfig.isShow = true
+ },
+ handleDel(delItem) {
+ var delIndex = this.selectItems.findIndex((item, index) => {
+ if (delItem.id === item.id) {
+ delIndex = index;
+ return true
+ }
+ return false
+ });
+ this.selectItems.splice(delIndex, 1);
+ delItem.value = delItem.defaultVal;
+ this.conditionConfig.conditionList.push(delItem);
+ }
+ },
+ watch: {
+ isFocus(n, o) {
+ this.$emit("focus", n)
+ },
+ 'conditionConfig.isShow': {
+ handler(n, o) {
+ if (n) {
+ //如果是 展示了那么
+ this.conditionConfig.currentIndex = this.selectItems.length
+ }
+ },
+ deep: false,
+ immediate: true
+ },
+ sourceList: {
+ handler(n, o) {
+ this.setDefaultItems()
+ // this.conditionConfig.conditionList = n;
+ },
+ deep: false,
+ immediate: false
+ },
+ selectItems: {
+ handler: debounce(function (n, o) {
+ //当选中数据变化的时候 ,去修改标签可选择列表项
+ this.$emit('change', {
+ selectItems: this.selectItems,
+ conditionList: this.conditionConfig.conditionList
+ })
+ }, 100),
+ deep: true,
+ immediate: false
+ }
+ }
+ };
+</script>
+<style lang="less" scoped>
+ .filtered-search-container {
+ /*padding: 0 10px;*/
+ display: flex;
+
+ .filtered-search-box {
+ flex: 1;
+ }
+
+ /deep/ .label-select input.el-input__inner {
+ width: 100%;
+ padding-right: 10px;
+ }
+ }
+
+ /* 聚焦样式 */
+ .filtered-search-box.focus {
+ border-color: #73afea;
+ box-shadow: 0 0 4px rgba(115, 175, 234, 0.4);
+ }
+
+ .filtered-search-box {
+ position: relative;
+ display: flex;
+ width: 100%;
+ min-width: 0;
+ border: 1px solid #e5e5e5;
+ background-color: #fff;
+ border-radius: 4px 0 0 4px;
+ /*padding: 2px 0;*/
+ }
+
+ .divider {
+ height: auto !important;
+ margin: 0 !important;
+ }
+
+ .list-container {
+ list-style: none;
+ display: flex;
+ position: relative;
+ margin-bottom: 0;
+ width: auto;
+ padding-left: 8px;
+ box-sizing: border-box;
+ }
+
+ .scroll-container {
+ flex: auto;
+ overflow-y: auto;
+ }
+
+ .clear-icon {
+ line-height: 24px;
+ padding: 0 10px;
+ cursor: pointer;
+ }
+
+ /deep/ .el-input--mini .el-input__inner {
+ height: 24px;
+ line-height: 24px;
+ border: none;
+ border-radius: unset;
+ }
+
+ .label-select {
+ flex: auto;
+ }
+
+ /deep/ .label-select .el-input__inner {
+ padding-left: 0 !important;
+ min-width: 180px;
+ }
+
+ .list-container {
+ white-space: nowrap;
+ width: 100%;
+ }
+
+ .search-icon {
+ line-height: 26px;
+ padding: 0 10px;
+ cursor: pointer;
+ border-radius: 0 4px 4px 0;
+
+ text-align: center;
+ background: #31739C;
+ color: #ffffff;
+ }
+
+ .search-icon:hover {
+ background: #2d4b6f;
+ color: #fff;
+ }
+
+ /deep/ input {
+ outline: none;
+ box-shadow: none !important;
+ }
+
+
+</style>
+
+
diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/RecentSearch.vue b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/RecentSearch.vue
new file mode 100644
index 0000000..a6338b3
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/RecentSearch.vue
@@ -0,0 +1,103 @@
+<template>
+ <el-popover
+ :popper-append-to-body="true"
+ popper-class="RecentSearch"
+ placement="bottom-start"
+ trigger="hover"
+ width="160"
+ v-model="visible">
+ <div class="list-container" >
+ <template v-if="historyList.length>0">
+ <template v-for="(item,index) in historyList">
+ <div class="el-dropdown-menu__item history-item" :id="'historyItem'+index" v-idscope @click="handleSelect(item)">
+ <template v-for="(condition,conditionIndex) in item">
+ <template v-if="conditionIndex>0">;</template>{{ condition.name }} = {{ formatVal(condition.value,condition.options) }}
+ </template>
+ </div>
+ </template>
+ </template>
+ <template v-else>
+ <div class="history-item">{{$t('i18n.overall.searchInfo.noData')}} </div>
+ </template>
+ </div>
+ <div class="clear-all el-dropdown-menu__item" id="clearHistory" @click="handleClear">{{ $t('i18n.overall.searchInfo.clearHistory') }}</div>
+ <i class="el-icon-time history-icon" slot="reference"></i>
+ </el-popover>
+</template>
+
+<script>
+ import searchHistory from './historyApi'
+ export default {
+ name: "RecentSearch",
+ data() {
+ return {
+ visible: false,
+ historyList:[]
+ }
+ },
+ mounted() {
+
+ },
+ methods:{
+ formatVal(val,options){
+ if(val && Array.isArray(val)){
+ return val.join(' - ')
+ }
+ if(options && Array.isArray(options)){
+ var selectItem=options.find(item=>{
+ return item.value === val
+ })
+ return selectItem ? selectItem.label : val
+ }
+ return val
+ },
+ handleClear(){
+ searchHistory.clearPageHistory(this.$parent.historyKey)
+ this.getHistotyList()
+ this.visible=false
+ },
+ handleSelect(item){
+ //选中一条历史记录 回调函数...
+ this.$emit("selectHistory",item)
+ this.visible=false
+ },
+ getHistotyList(){
+ this.historyList=searchHistory.getPageHistory(this.$parent.historyKey)
+ }
+ },
+ watch:{
+ visible:{
+ handler(n,o){
+ this.getHistotyList()
+ },
+ immediate:false,
+ deep:false
+ }
+ }
+ }
+</script>
+
+<style scoped>
+ .history-icon {
+ padding: 0 10px;
+ cursor: pointer;
+ line-height: 24px;
+ }
+ .list-container{
+ max-height: 300px;
+ overflow-y: auto;
+ }
+ .clear-all{
+ font-size: 12px;
+ line-height: 32px;
+ text-align: center;
+ border-top: 1px solid #DCDFE6;
+ cursor: pointer;
+ }
+ .history-item{
+ line-height: 28px;
+ padding: 0 20px;
+ text-align: left;
+ font-size: 12px;
+ }
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/SearchItem.vue b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/SearchItem.vue
new file mode 100644
index 0000000..1cdf097
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/SearchItem.vue
@@ -0,0 +1,343 @@
+<template>
+ <div class="ListItem clearfix" :class="{'last-item':isLast && isFocus}">
+ <!-- label 标签 -->
+ <div class="label">
+ <span class="el-tag el-tag--info el-tag--mini el-tag--light" @click.stop="editlabel">
+ <span class="el-select__tags-text">{{ label }}</span>
+ </span>
+ </div>
+ <!-- value 标签 -->
+ <div class="value" v-show="!isFocus" :class="{'none': !value || ( Array.isArray(value) && value.length<=0)}">
+ <span class="el-tag el-tag--info el-tag--mini el-tag--light" @click.stop="editVal">
+ <el-tooltip class="item" effect="light" :content="getVal(value,selectItem.type || 'input')" placement="bottom">
+ <span class="el-select__tags-text">{{ getVal(value,selectItem.type || 'input') }}</span>
+ </el-tooltip>
+ <i class="el-tag__close el-icon-close" @click.stop="handleDel"></i>
+ </span>
+ </div>
+ <!-- 输入框操作项 -->
+ <div class="input-item" v-show="isFocus">
+ <template v-if="type==='timeRange'">
+ <v-timerange
+ @move="handleMove"
+ @del="handleDel"
+ @focus="handleFocus"
+ @blur="handleBlur"
+ @keydown="handleKeydown"
+ @active="handleActive"
+ ref="item"
+ class="input"
+ :placeholder="placeholder"
+ v-model="value"/>
+ </template>
+ <template v-else-if="type === 'select'">
+ <v-select
+ @move="handleMove"
+ @active="handleActive"
+ @del="handleDel"
+ @focus="handleFocus"
+ @blur="handleBlur"
+ @keydown="handleKeydown"
+ ref="item"
+ class="input"
+ :popper-append-to-body="false"
+ popper-class="autocomplete-popover"
+ :placeholder="placeholder"
+ v-model="value"
+ :options="selectItem.options"/>
+ </template>
+ <template v-else>
+ <v-input
+ @move="handleMove"
+ @active="handleActive"
+ @del="handleDel"
+ @focus="handleFocus"
+ @blur="handleBlur"
+ @keydown="handleKeydown"
+ ref="item"
+ class="input"
+ :popper-append-to-body="false"
+ popper-class="autocomplete-popover"
+ v-model="value"
+ :maxlength="255"
+ :placeholder="placeholder"/>
+ </template>
+ </div>
+ </div>
+</template>
+
+<script>
+ import VPicker from './VPicker.vue'
+ import VInput from './VInput.vue'
+ import VTimerange from './VTimerange.vue'
+ import VSelect from './VSelect.vue'
+
+ var timer=null
+ export default {
+ name: "ListItem",
+ props: ['selectItem', "isLast", 'currentIndex'],
+ data() {
+ return {
+ loading: "",
+ isFocus: false,
+ placeholder: "",
+ label: "",
+ type: "", //time timeRange select input ,当前输入框类型
+ }
+ },
+ created() {
+ this.label = this.selectItem.name || null;
+ this.type = this.selectItem.type || null;
+ this.placeholder = this.selectItem.placeholder || null
+ },
+ mounted() {
+ //新增一项数据 直接触发聚焦事件
+
+ },
+ methods: {
+ clickItem(){
+ setTimeout(()=>{
+ this.$emit('clickItem')
+ })
+ },
+ handleMove(direction) {
+ //direction left right 移动方向 ...
+ setTimeout(()=>{
+ if (direction === 'left') {
+ if (this.currentIndex) {
+ this.$emit('moveTo', {
+ self:this,
+ toIndex: this.currentIndex - 1,
+ })
+ }
+ } else {
+ this.$emit('moveTo', {
+ self:this,
+ toIndex: this.currentIndex + 1,
+ })
+ }
+ })
+ },
+ handleActive() {
+ //会执行 多次,但是不会影响功能
+ this.$emit('active', {
+ currentIndex: this.currentIndex,
+ currentItem: this.selectItem
+ })
+ },
+ visibleChangeHandle() {
+ //输入框 可能需要异步请求接口
+ },
+ getVal(value, type = 'input') {
+ if (type === 'timeRange' && value) {
+ return value.join(' - ')
+ }
+ if (type === 'select' && value) {
+ var selItem=this.selectItem.options.find((item,index)=>{
+ return item.value === value
+ })
+ return (selItem && selItem.label) || value
+ }
+ return value
+ },
+ handleFocus() {
+ this.isFocus = true; //修改当前组件的 操作状态
+ this.$parent.conditionConfig.isShow = false; //展示 搜索的字段
+ this.$parent.isFocus = true;
+ this.$refs.item && this.$refs.item.triggerFocus() //触发 光标移入 或者下拉 ...
+ },
+ handleBlur() {
+
+ if(this.type=='timeRange'){
+ var time1 = this.value[0]
+ var time2 = this.value[1]
+ if(new Date(time1).getTime()==new Date(time2).getTime()){
+ this.$message.error(this.$t('i18n.overall.other.dateTimeTips'));
+ this.handleFocus();
+ return false
+ }
+ }
+
+ this.isFocus = false;
+ this.$parent.isFocus = false;
+ this.$parent.conditionConfig.isShow = true;
+
+ clearTimeout(timer)
+ timer=setTimeout(()=>{
+ this.$parent.triggerFocus()
+ clearTimeout(timer)
+ },300)
+ },
+ handleKeydown() {
+ var keyCode = window.event ? e.keyCode : e.which;
+ //删除事件
+ if (keyCode === 8) { //删除
+
+ }
+ if (keyCode === 13) { //回车
+
+ }
+ },
+ handleClear() {
+ //清空所有 选中内容
+ if (this.type === 'timeRange') {
+ this.value = [];
+ return
+ }
+ this.value = ""
+ },
+ handleDel() {
+ this.$emit("del", this.selectItem)
+ this.clickItem()
+ },
+ editVal() {
+ //编辑值
+ this.isFocus = true;
+ this.$parent.isFocus = true;
+ this.$parent.conditionConfig.isShow = false;
+ this.$refs.item && this.$refs.item.triggerFocus()
+ this.clickItem()
+ },
+ editlabel() {
+ //编辑label
+ this.isFocus = true;
+ this.$parent.isFocus = true;
+ this.$parent.conditionConfig.isShow = false;
+ this.$refs.item && this.$refs.item.triggerFocus()
+ this.clickItem()
+ }
+ },
+ computed: {
+ value: {
+ get() {
+ return this.selectItem.value
+ },
+ set(val) {
+ // this.selectItem.value = val
+ this.$set(this.selectItem, 'value',val)
+ }
+ }
+ },
+ components: {
+ VPicker,
+ VInput,
+ VTimerange,
+ VSelect,
+ },
+ destroyed() {
+ clearTimeout(timer);
+ timer=null
+ },
+ deactivated() {
+ clearTimeout(timer);
+ timer=null
+ }
+ }
+</script>
+
+<style lang="less" scoped>
+ .input-item {
+ flex: auto;
+ }
+
+ .input-item .input {
+ width: 100%;
+ }
+
+ /deep/ .input-item input {
+ min-width: 200px;
+ width: 100%;
+ border: none;
+ box-shadow: none;
+ }
+
+
+ /deep/ .autocomplete-popover {
+ width: auto !important;
+ max-width: 300px !important;
+ }
+
+ /deep/ .input .el-input__inner {
+ font-size: 12px;
+ height: 24px;
+ line-height: 24px;
+ padding: 0 2px;
+ }
+
+ .ListItem {
+ font-size: 0;
+ margin-right: 8px;
+ display: flex;
+ }
+
+ .ListItem div {
+ /*float: left;*/
+ white-space: nowrap;
+ display: inline-block;
+ }
+
+ .clearfix:after {
+ content: ".";
+ display: block;
+ height: 0;
+ clear: both;
+ visibility: hidden;
+ }
+
+ .label {
+ margin: 1px;
+ }
+
+ .value {
+ margin: 1px;
+ }
+
+ .el-tag {
+ height: 16px;
+ line-height: 16px;
+ }
+
+ .ListItem:hover .el-tag.el-tag--info {
+ background-color: #DFDFDF;
+ }
+
+ .el-tag.el-tag--info {
+ background-color: #f4f4f5;
+ }
+
+ /* 空数据 */
+ .none .el-tag {
+ padding: 0;
+ }
+
+ .none .el-tag .el-tag__close {
+ left: 0px;
+ /*top: -1px;*/
+ }
+
+ .last-item {
+ display: flex;
+ flex: auto;
+ }
+
+ .el-tag {
+ vertical-align: middle;
+ box-sizing: inherit;
+ }
+
+ .el-select__tags-text {
+ vertical-align: unset;
+ float: none !important;
+ }
+
+ .el-tag .el-icon-close {
+ /*top: -5px*/
+ vertical-align: top;
+ top:0;
+ }
+
+
+ /deep/ .item {
+ max-width: 240px;
+ }
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/TrimInput.vue b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/TrimInput.vue
new file mode 100644
index 0000000..f126f2c
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/TrimInput.vue
@@ -0,0 +1,88 @@
+<template>
+ <!-- input 类型 -->
+ <el-input
+ :type="type"
+ class="rel-input trim-input"
+ ref="input"
+ :maxlength="maxlength"
+ :autoComplete="autoComplete || 'on'"
+ autosize
+ v-model="valCopy"
+ @keydown.native="handleKeydown"
+ :placeholder="placeholder || $t('i18n.overall.placeholder.enter')"
+ @blur="trim"
+ :disabled='disabled'
+ @input="handleName"
+ v-bind="$attrs"
+ :rows="rows"
+ :show-word-limit="showWordLimit"
+ :id="$attrs.id+'1'"
+ >
+ </el-input>
+</template>
+
+<script>
+ import getTxt1CursorPosition from './cursorPosition'
+ import lodashCloneDeep from 'lodash/cloneDeep'
+
+ export default {
+ name: "Trim-input",
+ data() {
+ return {
+ valCopy: null,
+ }
+ },
+ props: ['specialCharacters','value', 'type', 'rows', 'disabled', 'maxlength', 'autoComplete', 'showPassword', 'placeholder', 'showWordLimit'],
+ model: {
+ prop: 'value',
+ event: 'change'
+ },
+ created() {
+ this.valCopy = lodashCloneDeep(this.value)
+ },
+ mounted() {
+ },
+ methods: {
+ trim(){
+ if(this.valCopy!==''&&this.valCopy!=null){
+ this.valCopy = this.valCopy.replace(/(^\s*)|(\s*$)/g, "")
+ }
+ this.$emit('blur', this.valCopy)
+ },
+ handleKeydown(e) {
+ if(!this.specialCharacters){
+ this.valCopy = this.valCopy.replace(/(^\s*)/g, "")
+ }
+ this.$emit('change', this.valCopy)
+ },
+ handleName(){
+ if(this.specialCharacters){
+ let name = this.profileName_regular(this.valCopy)
+ this.valCopy = name.replace(/(^\s*)/g, "")
+ }
+ this.$emit('input',this.valCopy)
+ },
+ },
+ watch: {
+ valCopy(n, o) {
+ if (this.value !== n) {
+ this.$emit('change', this.valCopy)
+ }
+ },
+ value(n, o) {
+ this.valCopy = n
+ }
+ }
+ }
+</script>
+
+<style lang="less" scoped>
+ /deep/ .el-input__inner {
+ padding-left: 10px !important;
+ min-width: 180px;
+ font-size: 12px;
+ }
+ /deep/ .el-textarea__inner{
+ height: auto !important;
+ }
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VAutoInput.vue b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VAutoInput.vue
new file mode 100644
index 0000000..049f200
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VAutoInput.vue
@@ -0,0 +1,16 @@
+<template>
+ <!-- 带搜索建议的下拉 -->
+ <div class="VAutoInput">
+
+ </div>
+</template>
+
+<script>
+ export default {
+ name: "VAutoInput"
+ }
+</script>
+
+<style lang="less" scoped>
+
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VInput.vue b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VInput.vue
new file mode 100644
index 0000000..31cd2a5
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VInput.vue
@@ -0,0 +1,97 @@
+<template>
+ <!-- input 类型 -->
+ <el-input size="mini"
+ class="rel-input v-input"
+ ref="input"
+ :maxlength="255"
+ :autoComplete="autoComplete || 'off'"
+ autosize
+ v-bind="$props"
+ v-on="$listeners"
+ v-model="valCopy"
+ @keydown.native="handleKeydown"
+ :placeholder="placeholder || $t('i18n.overall.searchInfo.inputVal')"
+ >
+ </el-input>
+</template>
+
+<script>
+ import getTxt1CursorPosition from './cursorPosition'
+ import lodashCloneDeep from 'lodash/cloneDeep'
+
+ export default {
+ name: "v-input",
+ data() {
+ return {
+ valCopy: null,
+ }
+ },
+ props: ['value', 'type', 'rows', 'disabled', 'maxlength', 'autoComplete', 'showPassword', 'placeholder'],
+ model: {
+ prop: 'value',
+ event: 'change'
+ },
+ created() {
+ this.valCopy = lodashCloneDeep(this.value)
+ },
+ mounted() {
+ },
+ methods: {
+ handleKeydown(e) {
+ var dom = this.$refs.input ? $(this.$refs.input.$el).find('input')[0] : '';
+ var cursorIndex = dom ? getTxt1CursorPosition(dom, document) || 0 : 0;
+ var keyCode = window.event ? e.keyCode : e.which;
+ //删除事件
+ if (keyCode === 8) {
+ if (this.valCopy === "" || this.valCopy == null) {
+ this.$emit("del")
+ }
+ return
+ }
+ if (keyCode === 13) { //回车
+ this.$emit("blur")
+ return
+ }
+
+ if (keyCode === 37) { //左箭头 || 37 右箭头
+ if (dom && cursorIndex === 0) {
+ this.$emit("move", 'left')
+ }
+ return
+ }
+ if (keyCode === 39) { //右箭头 || 39 右箭头
+ if (!this.valCopy || cursorIndex === this.valCopy.length) {
+ this.$emit("move", 'right')
+ }
+ return
+ }
+ },
+ triggerFocus() {
+ this.$emit("active")
+ this.$nextTick(() => {
+ //并非 触发聚焦事件 而是光标移入 类似
+ var dom = this.$refs.input.$el.children[0]; //获取输入框DOM 索引
+ dom.focus();
+ })
+ }
+ },
+ watch: {
+ valCopy(n, o) {
+ if (this.value !== n) {
+ this.$emit('change', this.valCopy)
+ }
+ },
+ value(n, o) {
+ this.valCopy = n
+ }
+ }
+ }
+</script>
+
+<style lang="less" scoped>
+ /deep/ .el-input__inner {
+ padding-left: 0 !important;
+ min-width: 180px;
+ font-size: 12px;
+ }
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VPicker.vue b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VPicker.vue
new file mode 100644
index 0000000..497280c
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VPicker.vue
@@ -0,0 +1,18 @@
+<template>
+ <!-- 单个时间选择器(暂不开发) -->
+ <div class="v-picker">
+ </div>
+</template>
+
+<script>
+ import lodashCloneDeep from 'lodash/cloneDeep'
+
+ export default {
+ name: "v-picker",
+
+ }
+</script>
+
+<style lang="" scoped>
+
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VSelect.vue b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VSelect.vue
new file mode 100644
index 0000000..5572a6c
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VSelect.vue
@@ -0,0 +1,149 @@
+<template>
+ <!-- 暂时不支持 异步,关联下拉 需要的话 请在该组件改写 -->
+ <el-select
+ :popper-append-to-body="true"
+ popper-class="select-popper"
+ @focus.stop
+ @blur.stop
+ class="v-select"
+ ref="select"
+ :collapse-tags="collapseTags"
+ size="mini"
+ autosize
+ filterable
+ v-model="valCopy"
+ @visible-change="visibleChangeHandle"
+ v-bind="$props"
+ :loading="loading"
+ @keydown.native="handleKeydown"
+ :placeholder="placeholder || $t('i18n.overall.searchInfo.selectVal')"
+ >
+ <!--&lt;!&ndash;:allow-create="true"&ndash;&gt; 根据TSG-9309 问题关闭创建条目需求 后期有其他需求再另加判断-->
+ <template v-for="(item,index) in optionsCopy">
+ <el-option
+ :id="item.value"
+ v-idscope
+ :disabled="item.disabled"
+ :label="item.label"
+ :value="item.value">
+ </el-option>
+ </template>
+ </el-select>
+</template>
+
+<script>
+ import lodashCloneDeep from 'lodash/cloneDeep'
+ import getTxt1CursorPosition from "./cursorPosition";
+ export default {
+ name: "v-select",
+ props: ['value', 'collapseTags', 'options', 'multiple', 'filterable', 'disabled', 'clearable', 'wrapper','placeholder'],
+ data () {
+ return {
+ optionsCopy: [], //下拉框的值
+ valCopy: null, //绑定值
+ loading: false,
+ }
+ },
+ model: {
+ prop: 'value',
+ event: 'change'
+ },
+ created () {
+ this.value ? this.valCopy = lodashCloneDeep(this.value) : '';
+ this.setOptions()
+ },
+ mounted () {
+
+ },
+ methods: {
+ handleKeydown(e) {
+ var keyCode = window.event ? e.keyCode : e.which;
+ var dom =this.$refs.select ? $(this.$refs.select.$el).find('input')[0] :'';
+ var cursorIndex = dom ? getTxt1CursorPosition(dom, document) || 0 : 0;
+ //删除事件
+ if (keyCode === 8) {
+ if (this.$refs.select.query === "" || this.$refs.select.query == null ) {
+ this.$emit("blur");
+ this.$emit("del")
+ }
+ }
+ // if (keyCode === 13) { //回车
+ // this.$emit("blur")
+ // }
+ if (keyCode === 37) { //左箭头 || 38 右箭头
+ if (dom && cursorIndex === 0) {
+ this.$refs.select.visible=false
+ this.$emit("blur")
+ this.$emit("move", 'left')
+ }
+ return
+ }
+ if (keyCode === 39) { //左箭头 || 38 右箭头
+ if (!this.$refs.select.query || cursorIndex === this.$refs.select.query.length) {
+ this.$refs.select.visible=false
+ this.$emit("blur")
+ this.$emit("move", 'right')
+ }
+ }
+ },
+ triggerFocus(){
+ this.$emit("active")
+ this.$nextTick(() => {
+ //触发 下拉事件
+ var dom = this.$refs.select.$el.children[0]; //获取输入框DOM 索引
+ dom.click();
+ })
+ // this.$nextTick(() => {
+ // this.$refs.select.visible=true
+ // })
+ },
+ visibleChangeHandle (status) {
+ //放弃 原生事件, 重写聚焦 失焦事件(原因 里面有个输入框, 不好界定 聚焦 失焦)
+ if(status === false){
+ this.$emit("blur")
+ }else {
+ this.$emit("focus")
+ }
+ },
+ setOptions(){
+ this.optionsCopy = this.options ? lodashCloneDeep(this.options) : []
+ // if (typeof this.options === Function) {
+ // this.options=[];
+ // this.loading=true;
+ // this.options().then(options=>{
+ // this.loading=false;
+ // this.optionsCopy =options
+ // });
+ // }else {
+ // this.optionsCopy = this.options ? lodashCloneDeep(this.options) : []
+ // }
+ }
+ },
+ watch: {
+ options (n, o) {
+ //监听下拉数据的变化
+ this.optionsCopy = this.options ? [...this.options] : []
+ },
+ valCopy (n, o) {
+ if (this.value !== n) {
+ this.$emit('change', this.valCopy)
+ }
+ },
+ value (n, o) {
+ this.valCopy = n
+ }
+ }
+ }
+</script>
+
+<style lang="less" scoped>
+ .v-select{
+ width: auto;
+ }
+ /deep/ .el-input__suffix{
+ display: none;
+ }
+ /deep/ input{
+ padding-left: 0 !important;
+ }
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VTimerange.vue b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VTimerange.vue
new file mode 100644
index 0000000..ca891c6
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VTimerange.vue
@@ -0,0 +1,164 @@
+<template>
+ <!-- 时间范围 -->
+ <div class="v-timerange" style="position: relative" @click.stop>
+ <el-input
+ ref="input"
+ autosize
+ size="mini"
+ @focus="handleFocus"
+ :placeholder="placeholder || $t('i18n.overall.searchInfo.selectTime')"
+ @keydown.native="handleKeydown"
+ v-model="inputVal"/>
+ <el-date-picker
+ @change="handleChange"
+ v-bind="$props"
+ v-on="$listeners"
+ format="yyyy-MM-dd HH:mm:ss"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ class="time-picker"
+ size="mini"
+ ref="timePicker"
+ :picker-options="pickerOptions"
+ v-model="valCopy"
+ type="datetimerange"
+ start-placeholder="Start Time"
+ end-placeholder="End Time"
+ :default-time="['00:00:00','23:59:59']">
+ </el-date-picker>
+ </div>
+</template>
+
+<script>
+ import Moment from 'moment'
+ import lodashCloneDeep from 'lodash/cloneDeep'
+ import getTxt1CursorPosition from "./cursorPosition";
+ var dateTime;
+ export default {
+ name: "v-timerange",
+ props: ['value', 'type', 'disabled', 'placeholder'],
+ data() {
+ return {
+ input: '',
+ valCopy: [],
+ pickerOptions:{
+ },
+ }
+ },
+ model: {
+ prop: 'value',
+ event: 'change'
+ },
+ methods: {
+ focus(value){
+ console.log(value);
+ },
+ blur(value){
+ console.log(value);
+ },
+ handleKeydown(e) {
+ var keyCode = window.event ? e.keyCode : e.which;
+ var dom = this.$refs.input ? $(this.$refs.input.$el).find('input')[0] : '';
+ var cursorIndex = dom ? getTxt1CursorPosition(dom, document) || 0 : 0;
+ //删除事件
+ if (keyCode === 8) {
+ this.$emit("del")
+ this.$emit("blur")
+ return
+ }
+ if (keyCode === 13) { //回车
+ this.$refs.timePicker.pickerVisible = false
+ this.$emit("blur")
+ return
+ }
+ if (keyCode === 37) { //左箭头 || 37 右箭头
+ if (dom && cursorIndex === 0) {
+ this.$refs.timePicker.pickerVisible = false
+ this.$emit("move", 'left')
+ }
+ return
+ }
+ if (keyCode === 39) { //右箭头 || 39 右箭头
+ if (!this.inputVal || cursorIndex === this.inputVal.length) {
+ this.$refs.timePicker.pickerVisible = false
+ this.$emit("move", 'right')
+ }
+ return
+ }
+ },
+ handleChange(value) {
+ if(value){
+
+ }
+ },
+ triggerFocus() {
+ //下拉 日期面板展示
+ this.$emit("active")
+ this.$refs.timePicker.pickerVisible = true;
+ this.$nextTick(() => {
+ //并非 触发聚焦事件 而是光标移入 类似
+ var dom = this.$refs.input.$el.children[0]; //获取输入框DOM 索引
+ dom.focus();
+ })
+ },
+ handleFocus() {
+ //输入框聚焦
+ this.$nextTick(() => {
+ this.$refs.timePicker.focus()
+ })
+ }
+ },
+ created() {
+ this.valCopy = this.value ? lodashCloneDeep(this.value) : [];
+ },
+ mounted() {
+ },
+ computed: {
+ inputVal: {
+ get() {
+ var timeVal = this.valCopy || []
+ return this.valCopy.join(' - ')
+ },
+ set(val) {
+ //不允许手动修改时间 校验麻烦
+ }
+ }
+ },
+ watch: {
+ valCopy(n, o) {
+ if (this.value !== n) {
+ this.$emit('change', this.valCopy)
+ }
+ },
+ value(n, o) {
+ this.valCopy = n || []
+ }
+ }
+ }
+</script>
+
+<style lang="less" scoped>
+ .v-timerange {
+ position: relative;
+ }
+
+ .time-picker {
+ visibility: hidden;
+ }
+
+ /deep/ .el-date-editor {
+ position: absolute;
+ left: 0;
+ right: 0;
+ width: auto;
+ overflow: hidden;
+ border: none;
+ padding: 0;
+ height: 24px;
+ }
+
+ /deep/ .el-input__inner {
+ padding-left: 0 !important;
+ min-width: 248px !important;
+ font-size: 12px;
+ }
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/cursorPosition.js b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/cursorPosition.js
new file mode 100644
index 0000000..ffe12fd
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/cursorPosition.js
@@ -0,0 +1,14 @@
+/* 不能导入导出 global 是不支持document的 */
+
+export default function getTxt1CursorPosition(dom,document){
+ var oTxt1 =dom
+ var cursurPosition=-1;
+ if(oTxt1.selectionStart || oTxt1.selectionStart===0){//非IE浏览器
+ cursurPosition= oTxt1.selectionStart;
+ }else{//IE
+ var range = document.selection.createRange();
+ range.moveStart("character",-oTxt1.value.length);
+ cursurPosition=range.text.length;
+ }
+ return cursurPosition
+}
diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/historyApi.js b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/historyApi.js
new file mode 100644
index 0000000..8b5a305
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/historyApi.js
@@ -0,0 +1,86 @@
+import remove from 'lodash/remove'
+import Moment from 'moment'
+/* 配置文件 */
+import vue from '@/main.js'
+import isEqual from 'lodash/isEqual'
+
+//时间的历史纪录
+class searchHistory {
+ constructor(key = 'searchHistory', maxLength = 10) {
+ this.key = key
+ this.maxLength = maxLength
+ if (!this.getHistory()) {
+ localStorage.setItem(this.key, '{}');
+ }
+ }
+
+ getSaveKey() {
+ //暂时 不这么写
+ //获取 页面对应的关键字 , 因为页签的问题, 一个页面 可能出现两个搜索框的问题 ....
+ var route = vue.$route.path;
+ return route
+ }
+
+ getHistory() {
+ var historyList = JSON.parse(localStorage.getItem(this.key))
+ return historyList
+ }
+
+ getPageHistory(saveKey) { //获取当前页的搜索数据...
+ var route = saveKey || vue.$route.path;
+ var historyMap = JSON.parse(localStorage.getItem(this.key)) || {}
+ return historyMap[route] || []
+ }
+
+ setHistory(val) {
+ localStorage.setItem(this.key, JSON.stringify(val));
+ }
+
+ addItem(item, saveKey) {
+ // var route = vue.$route.name
+ var route = saveKey || vue.$route.path; //fullPath path name(使用name最好,就是需要改 )
+ var historyMap = JSON.parse(localStorage.getItem(this.key)) || {};
+ if (!historyMap[route]) {
+ historyMap[route] = []
+ }
+
+ //删除 重复的搜索历史记录
+ var itemObj = {}
+ item.forEach((obj) => {
+ itemObj[obj.name] = obj.value
+ });
+ historyMap[route] = historyMap[route].filter((historyList, index) => {
+ var historyItemObj = {};
+ historyList.forEach((item) => {
+ historyItemObj[item.name] = item.value
+ });
+ return !isEqual(itemObj, historyItemObj);
+ });
+
+
+ // historyMap[route].push(item);
+ historyMap[route].unshift(item);
+
+ if (historyMap[route].length > this.maxLength) {
+ historyMap[route].pop()
+ }
+ var info = JSON.stringify(historyMap)
+ localStorage.setItem(this.key, info);
+ }
+
+ clearPageHistory(saveKey) {
+ //清除当前 页的搜索数据...
+ var route = saveKey || vue.$route.path; //fullPath path name(使用name最好,就是需要改 )
+ var historyMap = JSON.parse(localStorage.getItem(this.key) || '{}');
+ historyMap[route] = []
+ var info = JSON.stringify(historyMap)
+ localStorage.setItem(this.key, info);
+ }
+
+ clear() {
+ localStorage.setItem(this.key, '{}');
+ }
+}
+
+var history = new searchHistory();
+export default history
diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/keyboard.js b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/keyboard.js
new file mode 100644
index 0000000..9f3ee00
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/keyboard.js
@@ -0,0 +1,31 @@
+export function fireKeyEvent(el, evtType, keyCode) {
+ var evtObj;
+ if (document.createEvent) {
+ if (window.KeyEvent) {//firefox 浏览器下模拟事件
+ evtObj = document.createEvent('KeyEvents');
+ evtObj.initKeyEvent(evtType, true, true, window, true, false, false, false, keyCode, 0);
+ } else {//chrome 浏览器下模拟事件
+ evtObj = document.createEvent('UIEvents');
+ evtObj.initUIEvent(evtType, true, true, window, 1);
+
+ delete evtObj.keyCode;
+ if (typeof evtObj.keyCode === "undefined") {//为了模拟keycode
+ Object.defineProperty(evtObj, "keyCode", { value: keyCode });
+ } else {
+ evtObj.key = String.fromCharCode(keyCode);
+ }
+
+ if (typeof evtObj.ctrlKey === 'undefined') {//为了模拟ctrl键
+ Object.defineProperty(evtObj, "ctrlKey", { value: true });
+ } else {
+ evtObj.ctrlKey = true;
+ }
+ }
+ el.dispatchEvent(evtObj);
+
+ } else if (document.createEventObject) {//IE 浏览器下模拟事件
+ evtObj = document.createEventObject();
+ evtObj.keyCode = keyCode
+ el.fireEvent('on' + evtType, evtObj);
+ }
+}
diff --git a/UI source code/dns_mapping_ui-master/src/components/GithubCorner/index.vue b/UI source code/dns_mapping_ui-master/src/components/GithubCorner/index.vue
new file mode 100644
index 0000000..bc79cbf
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/GithubCorner/index.vue
@@ -0,0 +1,54 @@
+<template>
+ <a href="https://github.com/elunez/eladmin" target="_blank" class="github-corner" aria-label="View source on Github">
+ <svg
+ width="80"
+ height="80"
+ viewBox="0 0 250 250"
+ style="fill:#40c9c6; color:#fff;"
+ aria-hidden="true"
+ >
+ <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z" />
+ <path
+ d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
+ fill="currentColor"
+ style="transform-origin: 130px 106px;"
+ class="octo-arm"
+ />
+ <path
+ d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
+ fill="currentColor"
+ class="octo-body"
+ />
+ </svg>
+ </a>
+</template>
+
+<style scoped>
+.github-corner:hover .octo-arm {
+ animation: octocat-wave 560ms ease-in-out
+}
+
+@keyframes octocat-wave {
+ 0%,
+ 100% {
+ transform: rotate(0)
+ }
+ 20%,
+ 60% {
+ transform: rotate(-25deg)
+ }
+ 40%,
+ 80% {
+ transform: rotate(10deg)
+ }
+}
+
+/* @media (max-width:500px) {
+ .github-corner:hover .octo-arm {
+ animation: none
+ }
+ .github-corner .octo-arm {
+ animation: octocat-wave 560ms ease-in-out
+ }
+} */
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Hamburger/index.vue b/UI source code/dns_mapping_ui-master/src/components/Hamburger/index.vue
new file mode 100644
index 0000000..368b002
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Hamburger/index.vue
@@ -0,0 +1,44 @@
+<template>
+ <div style="padding: 0 15px;" @click="toggleClick">
+ <svg
+ :class="{'is-active':isActive}"
+ class="hamburger"
+ viewBox="0 0 1024 1024"
+ xmlns="http://www.w3.org/2000/svg"
+ width="64"
+ height="64"
+ >
+ <path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
+ </svg>
+ </div>
+</template>
+
+<script>
+export default {
+ name: 'Hamburger',
+ props: {
+ isActive: {
+ type: Boolean,
+ default: false
+ }
+ },
+ methods: {
+ toggleClick() {
+ this.$emit('toggleClick')
+ }
+ }
+}
+</script>
+
+<style scoped>
+.hamburger {
+ display: inline-block;
+ vertical-align: middle;
+ width: 20px;
+ height: 20px;
+}
+
+.hamburger.is-active {
+ transform: rotate(180deg);
+}
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/HeaderSearch/index.vue b/UI source code/dns_mapping_ui-master/src/components/HeaderSearch/index.vue
new file mode 100644
index 0000000..c713efc
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/HeaderSearch/index.vue
@@ -0,0 +1,188 @@
+<template>
+ <div :class="{'show':show}" class="header-search">
+ <svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
+ <el-select
+ ref="headerSearchSelect"
+ v-model="search"
+ :remote-method="querySearch"
+ filterable
+ default-first-option
+ remote
+ placeholder="Search"
+ class="header-search-select"
+ @change="change"
+ >
+ <el-option v-for="item in options" :key="item.path" :value="item" :label="item.title.join(' > ')" />
+ </el-select>
+ </div>
+</template>
+
+<script>
+// fuse is a lightweight fuzzy-search module
+// make search results more in line with expectations
+import Fuse from 'fuse.js'
+import path from 'path'
+
+export default {
+ name: 'HeaderSearch',
+ data() {
+ return {
+ search: '',
+ options: [],
+ searchPool: [],
+ show: false,
+ fuse: undefined
+ }
+ },
+ computed: {
+ routes() {
+ return this.$store.state.permission.routers
+ }
+ },
+ watch: {
+ routes() {
+ this.searchPool = this.generateRoutes(this.routes)
+ },
+ searchPool(list) {
+ this.initFuse(list)
+ },
+ show(value) {
+ if (value) {
+ document.body.addEventListener('click', this.close)
+ } else {
+ document.body.removeEventListener('click', this.close)
+ }
+ }
+ },
+ mounted() {
+ this.searchPool = this.generateRoutes(this.routes)
+ },
+ methods: {
+ click() {
+ this.show = !this.show
+ if (this.show) {
+ this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus()
+ }
+ },
+ close() {
+ this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur()
+ this.options = []
+ this.show = false
+ },
+ change(val) {
+ if (this.ishttp(val.path)) {
+ // http(s):// 路径新窗口打开
+ window.open(val.path, '_blank')
+ } else {
+ this.$router.push(val.path)
+ }
+ this.search = ''
+ this.options = []
+ this.$nextTick(() => {
+ this.show = false
+ })
+ },
+ initFuse(list) {
+ this.fuse = new Fuse(list, {
+ shouldSort: true,
+ threshold: 0.4,
+ location: 0,
+ distance: 100,
+ maxPatternLength: 32,
+ minMatchCharLength: 1,
+ keys: [{
+ name: 'title',
+ weight: 0.7
+ }, {
+ name: 'path',
+ weight: 0.3
+ }]
+ })
+ },
+ // Filter out the routes that can be displayed in the sidebar
+ // And generate the internationalized title
+ generateRoutes(routes, basePath = '/', prefixTitle = []) {
+ let res = []
+
+ for (const router of routes) {
+ // skip hidden router
+ if (router.hidden) { continue }
+
+ const data = {
+ path: !this.ishttp(router.path) ? path.resolve(basePath, router.path) : router.path,
+ title: [...prefixTitle]
+ }
+
+ if (router.meta && router.meta.title) {
+ data.title = [...data.title, router.meta.title]
+
+ if (router.redirect !== 'noRedirect') {
+ // only push the routes with title
+ // special case: need to exclude parent router without redirect
+ res.push(data)
+ }
+ }
+
+ // recursive child routes
+ if (router.children) {
+ const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
+ if (tempRoutes.length >= 1) {
+ res = [...res, ...tempRoutes]
+ }
+ }
+ }
+ return res
+ },
+ querySearch(query) {
+ if (query !== '') {
+ this.options = this.fuse.search(query)
+ } else {
+ this.options = []
+ }
+ },
+ ishttp(url) {
+ return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.header-search {
+ font-size: 0 !important;
+
+ .search-icon {
+ cursor: pointer;
+ font-size: 18px;
+ vertical-align: middle;
+ }
+
+ .header-search-select {
+ font-size: 18px;
+ transition: width 0.2s;
+ width: 0;
+ overflow: hidden;
+ background: transparent;
+ border-radius: 0;
+ display: inline-block;
+ vertical-align: middle;
+
+ ::v-deep .el-input__inner {
+ border-radius: 0;
+ border: 0;
+ padding-left: 0;
+ padding-right: 0;
+ box-shadow: none !important;
+ border-bottom: 1px solid #d9d9d9;
+ vertical-align: middle;
+ }
+ }
+
+ &.show {
+ .header-search-select {
+ width: 210px;
+ margin-left: 10px;
+ }
+ }
+}
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/IconSelect/index.vue b/UI source code/dns_mapping_ui-master/src/components/IconSelect/index.vue
new file mode 100644
index 0000000..b0ec9fa
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/IconSelect/index.vue
@@ -0,0 +1,68 @@
+<!-- @author zhengjie -->
+<template>
+ <div class="icon-body">
+ <el-input v-model="name" style="position: relative;" clearable placeholder="请输入图标名称" @clear="filterIcons" @input.native="filterIcons">
+ <i slot="suffix" class="el-icon-search el-input__icon" />
+ </el-input>
+ <div class="icon-list">
+ <div v-for="(item, index) in iconList" :key="index" @click="selectedIcon(item)">
+ <svg-icon :icon-class="item" style="height: 30px;width: 16px;" />
+ <span>{{ item }}</span>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+import icons from './requireIcons'
+export default {
+ name: 'IconSelect',
+ data() {
+ return {
+ name: '',
+ iconList: icons
+ }
+ },
+ methods: {
+ filterIcons() {
+ this.iconList = icons
+ if (this.name) {
+ this.iconList = this.iconList.filter(item => item.includes(this.name))
+ }
+ },
+ selectedIcon(name) {
+ this.$emit('selected', name)
+ document.body.click()
+ },
+ reset() {
+ this.name = ''
+ this.iconList = icons
+ }
+ }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+ .icon-body {
+ width: 100%;
+ padding: 10px;
+ .icon-list {
+ height: 200px;
+ overflow-y: scroll;
+ div {
+ height: 30px;
+ line-height: 30px;
+ margin-bottom: -5px;
+ cursor: pointer;
+ width: 33%;
+ float: left;
+ }
+ span {
+ display: inline-block;
+ vertical-align: -0.15em;
+ fill: currentColor;
+ overflow: hidden;
+ }
+ }
+ }
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/IconSelect/requireIcons.js b/UI source code/dns_mapping_ui-master/src/components/IconSelect/requireIcons.js
new file mode 100644
index 0000000..99e5c54
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/IconSelect/requireIcons.js
@@ -0,0 +1,11 @@
+
+const req = require.context('../../assets/icons/svg', false, /\.svg$/)
+const requireAll = requireContext => requireContext.keys()
+
+const re = /\.\/(.*)\.svg/
+
+const icons = requireAll(req).map(i => {
+ return i.match(re)[1]
+})
+
+export default icons
diff --git a/UI source code/dns_mapping_ui-master/src/components/Iframe/index.vue b/UI source code/dns_mapping_ui-master/src/components/Iframe/index.vue
new file mode 100644
index 0000000..9f395a3
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Iframe/index.vue
@@ -0,0 +1,30 @@
+<template>
+ <div v-loading="loading" :style="'height:'+ height">
+ <iframe :src="src" frameborder="no" style="width: 100%;height: 100%" scrolling="auto" />
+ </div>
+</template>
+<script>
+export default {
+ props: {
+ src: {
+ type: String,
+ required: true
+ }
+ },
+ data() {
+ return {
+ height: document.documentElement.clientHeight - 94.5 + 'px;',
+ loading: true
+ }
+ },
+ mounted: function() {
+ setTimeout(() => {
+ this.loading = false
+ }, 230)
+ const that = this
+ window.onresize = function temp() {
+ that.height = document.documentElement.clientHeight - 94.5 + 'px;'
+ }
+ }
+}
+</script>
diff --git a/UI source code/dns_mapping_ui-master/src/components/JavaEdit/index.vue b/UI source code/dns_mapping_ui-master/src/components/JavaEdit/index.vue
new file mode 100644
index 0000000..c703829
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/JavaEdit/index.vue
@@ -0,0 +1,78 @@
+<template>
+ <div class="json-editor">
+ <textarea ref="textarea" />
+ </div>
+</template>
+
+<script>
+import CodeMirror from 'codemirror'
+import 'codemirror/lib/codemirror.css'
+// 替换主题这里需修改名称
+import 'codemirror/theme/idea.css'
+import 'codemirror/mode/clike/clike'
+export default {
+ props: {
+ value: {
+ type: String,
+ required: true
+ },
+ height: {
+ type: String,
+ required: true
+ }
+ },
+ data() {
+ return {
+ editor: false
+ }
+ },
+ watch: {
+ value(value) {
+ const editorValue = this.editor.getValue()
+ if (value !== editorValue) {
+ this.editor.setValue(this.value)
+ }
+ },
+ height(value) {
+ this.editor.setSize('auto', this.height)
+ }
+ },
+ mounted() {
+ this.editor = CodeMirror.fromTextArea(this.$refs.textarea, {
+ mode: 'text/x-java',
+ lineNumbers: true,
+ lint: true,
+ lineWrapping: true,
+ tabSize: 2,
+ cursorHeight: 0.9,
+ // 替换主题这里需修改名称
+ theme: 'idea',
+ readOnly: true
+ })
+ this.editor.setSize('auto', this.height)
+ this.editor.setValue(this.value)
+ },
+ methods: {
+ getValue() {
+ return this.editor.getValue()
+ }
+ }
+}
+</script>
+
+<style scoped>
+ .json-editor{
+ height: 100%;
+ margin-bottom: 10px;
+ }
+ .json-editor >>> .CodeMirror {
+ font-size: 14px;
+ overflow-y:auto;
+ font-weight:normal
+ }
+ .json-editor >>> .CodeMirror-scroll{
+ }
+ .json-editor >>> .cm-s-rubyblue span.cm-string {
+ color: #F08047;
+ }
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Pagination/index.vue b/UI source code/dns_mapping_ui-master/src/components/Pagination/index.vue
new file mode 100644
index 0000000..c815e13
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Pagination/index.vue
@@ -0,0 +1,101 @@
+<template>
+ <div :class="{'hidden':hidden}" class="pagination-container">
+ <el-pagination
+ :background="background"
+ :current-page.sync="currentPage"
+ :page-size.sync="pageSize"
+ :layout="layout"
+ :page-sizes="pageSizes"
+ :total="total"
+ v-bind="$attrs"
+ @size-change="handleSizeChange"
+ @current-change="handleCurrentChange"
+ />
+ </div>
+</template>
+
+<script>
+import { scrollTo } from '@/utils/scroll-to'
+
+export default {
+ name: 'Pagination',
+ props: {
+ total: {
+ required: true,
+ type: Number
+ },
+ page: {
+ type: Number,
+ default: 1
+ },
+ limit: {
+ type: Number,
+ default: 20
+ },
+ pageSizes: {
+ type: Array,
+ default() {
+ return [10, 20, 30, 50]
+ }
+ },
+ layout: {
+ type: String,
+ default: 'total, sizes, prev, pager, next, jumper'
+ },
+ background: {
+ type: Boolean,
+ default: true
+ },
+ autoScroll: {
+ type: Boolean,
+ default: true
+ },
+ hidden: {
+ type: Boolean,
+ default: false
+ }
+ },
+ computed: {
+ currentPage: {
+ get() {
+ return this.page
+ },
+ set(val) {
+ this.$emit('update:page', val)
+ }
+ },
+ pageSize: {
+ get() {
+ return this.limit
+ },
+ set(val) {
+ this.$emit('update:limit', val)
+ }
+ }
+ },
+ methods: {
+ handleSizeChange(val) {
+ this.$emit('pagination', { page: this.currentPage, limit: val })
+ if (this.autoScroll) {
+ scrollTo(0, 800)
+ }
+ },
+ handleCurrentChange(val) {
+ this.$emit('pagination', { page: val, limit: this.pageSize })
+ if (this.autoScroll) {
+ scrollTo(0, 800)
+ }
+ }
+ }
+}
+</script>
+
+<style scoped>
+.pagination-container {
+ background: #fff;
+ padding: 32px 16px;
+}
+.pagination-container.hidden {
+ display: none;
+}
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/PanThumb/index.vue b/UI source code/dns_mapping_ui-master/src/components/PanThumb/index.vue
new file mode 100644
index 0000000..de6940a
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/PanThumb/index.vue
@@ -0,0 +1,140 @@
+<template>
+ <div :style="{zIndex:zIndex,height:height,width:width}" class="pan-item">
+ <div class="pan-info">
+ <div class="pan-info-roles-container">
+ <slot />
+ </div>
+ </div>
+ <img :src="image" class="pan-thumb">
+ </div>
+</template>
+
+<script>
+export default {
+ name: 'PanThumb',
+ props: {
+ image: {
+ type: String,
+ required: true
+ },
+ zIndex: {
+ type: Number,
+ default: 1
+ },
+ width: {
+ type: String,
+ default: '150px'
+ },
+ height: {
+ type: String,
+ default: '150px'
+ }
+ }
+}
+</script>
+
+<style scoped>
+.pan-item {
+ width: 200px;
+ height: 200px;
+ border-radius: 50%;
+ display: inline-block;
+ position: relative;
+ cursor: default;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
+}
+
+.pan-info-roles-container {
+ padding: 20px;
+ text-align: center;
+}
+
+.pan-thumb {
+ width: 100%;
+ height: 100%;
+ background-size: 100%;
+ border-radius: 50%;
+ overflow: hidden;
+ position: absolute;
+ transform-origin: 95% 40%;
+ transition: all 0.3s ease-in-out;
+}
+
+.pan-thumb:after {
+ content: '';
+ width: 8px;
+ height: 8px;
+ position: absolute;
+ border-radius: 50%;
+ top: 40%;
+ left: 95%;
+ margin: -4px 0 0 -4px;
+ background: radial-gradient(ellipse at center, rgba(14, 14, 14, 1) 0%, rgba(125, 126, 125, 1) 100%);
+ box-shadow: 0 0 1px rgba(255, 255, 255, 0.9);
+}
+
+.pan-info {
+ position: absolute;
+ width: inherit;
+ height: inherit;
+ border-radius: 50%;
+ overflow: hidden;
+ box-shadow: inset 0 0 0 5px rgba(0, 0, 0, 0.05);
+}
+
+.pan-info h3 {
+ color: #fff;
+ text-transform: uppercase;
+ position: relative;
+ letter-spacing: 2px;
+ font-size: 18px;
+ margin: 0 60px;
+ padding: 22px 0 0 0;
+ height: 85px;
+ font-family: 'Open Sans', Arial, sans-serif;
+ text-shadow: 0 0 1px #fff, 0 1px 2px rgba(0, 0, 0, 0.3);
+}
+
+.pan-info p {
+ color: #fff;
+ padding: 10px 5px;
+ font-style: italic;
+ margin: 0 30px;
+ font-size: 12px;
+ border-top: 1px solid rgba(255, 255, 255, 0.5);
+}
+
+.pan-info p a {
+ display: block;
+ color: #333;
+ width: 80px;
+ height: 80px;
+ background: rgba(255, 255, 255, 0.3);
+ border-radius: 50%;
+ color: #fff;
+ font-style: normal;
+ font-weight: 700;
+ text-transform: uppercase;
+ font-size: 9px;
+ letter-spacing: 1px;
+ padding-top: 24px;
+ margin: 7px auto 0;
+ font-family: 'Open Sans', Arial, sans-serif;
+ opacity: 0;
+ transition: transform 0.3s ease-in-out 0.2s, opacity 0.3s ease-in-out 0.2s, background 0.2s linear 0s;
+ transform: translateX(60px) rotate(90deg);
+}
+
+.pan-info p a:hover {
+ background: rgba(255, 255, 255, 0.5);
+}
+
+.pan-item:hover .pan-thumb {
+ transform: rotate(-110deg);
+}
+
+.pan-item:hover .pan-info p a {
+ opacity: 1;
+ transform: translateX(0px) rotate(0deg);
+}
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/ParentView/index.vue b/UI source code/dns_mapping_ui-master/src/components/ParentView/index.vue
new file mode 100644
index 0000000..98240ae
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/ParentView/index.vue
@@ -0,0 +1,3 @@
+<template>
+ <router-view />
+</template>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Permission/index.js b/UI source code/dns_mapping_ui-master/src/components/Permission/index.js
new file mode 100644
index 0000000..e5dadd3
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Permission/index.js
@@ -0,0 +1,13 @@
+import permission from './permission'
+
+const install = function(Vue) {
+ Vue.directive('permission', permission)
+}
+
+if (window.Vue) {
+ window['permission'] = permission
+ Vue.use(install); // eslint-disable-line
+}
+
+permission.install = install
+export default permission
diff --git a/UI source code/dns_mapping_ui-master/src/components/Permission/permission.js b/UI source code/dns_mapping_ui-master/src/components/Permission/permission.js
new file mode 100644
index 0000000..9a6ba28
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Permission/permission.js
@@ -0,0 +1,21 @@
+import store from '@/store'
+
+export default {
+ inserted(el, binding) {
+ const { value } = binding
+ const roles = store.getters && store.getters.roles
+ if (value && value instanceof Array) {
+ if (value.length > 0) {
+ const permissionRoles = value
+ const hasPermission = roles.some(role => {
+ return permissionRoles.includes(role)
+ })
+ if (!hasPermission) {
+ el.parentNode && el.parentNode.removeChild(el)
+ }
+ }
+ } else {
+ throw new Error(`使用方式: v-permission="['admin','editor']"`)
+ }
+ }
+}
diff --git a/UI source code/dns_mapping_ui-master/src/components/RightPanel/index.vue b/UI source code/dns_mapping_ui-master/src/components/RightPanel/index.vue
new file mode 100644
index 0000000..b65ecec
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/RightPanel/index.vue
@@ -0,0 +1,149 @@
+<template>
+ <div ref="rightPanel" :class="{show:show}" class="rightPanel-container">
+ <div class="rightPanel-background" />
+ <div class="rightPanel">
+ <div class="rightPanel-items">
+ <slot />
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+import { addClass, removeClass } from '@/utils'
+
+export default {
+ name: 'RightPanel',
+ props: {
+ clickNotClose: {
+ default: false,
+ type: Boolean
+ },
+ buttonTop: {
+ default: 250,
+ type: Number
+ }
+ },
+ computed: {
+ show: {
+ get() {
+ return this.$store.state.settings.showSettings
+ },
+ set(val) {
+ this.$store.dispatch('settings/changeSetting', {
+ key: 'showSettings',
+ value: val
+ })
+ }
+ },
+ theme() {
+ return this.$store.state.settings.theme
+ }
+ },
+ watch: {
+ show(value) {
+ if (value && !this.clickNotClose) {
+ this.addEventClick()
+ }
+ if (value) {
+ addClass(document.body, 'showRightPanel')
+ } else {
+ removeClass(document.body, 'showRightPanel')
+ }
+ }
+ },
+ mounted() {
+ this.insertToBody()
+ this.addEventClick()
+ },
+ beforeDestroy() {
+ const elx = this.$refs.rightPanel
+ elx.remove()
+ },
+ methods: {
+ addEventClick() {
+ window.addEventListener('click', this.closeSidebar)
+ },
+ closeSidebar(evt) {
+ const parent = evt.target.closest('.rightPanel')
+ if (!parent) {
+ this.show = false
+ window.removeEventListener('click', this.closeSidebar)
+ }
+ },
+ insertToBody() {
+ const elx = this.$refs.rightPanel
+ const body = document.querySelector('body')
+ body.insertBefore(elx, body.firstChild)
+ }
+ }
+}
+</script>
+
+<style>
+ .showRightPanel {
+ overflow: hidden;
+ position: relative;
+ width: calc(100% - 15px);
+ }
+</style>
+
+<style lang="scss" scoped>
+ .rightPanel-background {
+ position: fixed;
+ top: 0;
+ left: 0;
+ opacity: 0;
+ transition: opacity .3s cubic-bezier(.7, .3, .1, 1);
+ background: rgba(0, 0, 0, .2);
+ z-index: -1;
+ }
+
+ .rightPanel {
+ width: 100%;
+ max-width: 260px;
+ height: 100vh;
+ position: fixed;
+ top: 0;
+ right: 0;
+ box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, .05);
+ transition: all .25s cubic-bezier(.7, .3, .1, 1);
+ transform: translate(100%);
+ background: #fff;
+ z-index: 40000;
+ }
+
+ .show {
+ transition: all .3s cubic-bezier(.7, .3, .1, 1);
+
+ .rightPanel-background {
+ z-index: 20000;
+ opacity: 1;
+ width: 100%;
+ height: 100%;
+ }
+
+ .rightPanel {
+ transform: translate(0);
+ }
+ }
+
+ .handle-button {
+ width: 48px;
+ height: 48px;
+ position: absolute;
+ left: -48px;
+ text-align: center;
+ font-size: 24px;
+ border-radius: 6px 0 0 6px !important;
+ z-index: 0;
+ pointer-events: auto;
+ cursor: pointer;
+ color: #fff;
+ line-height: 48px;
+ i {
+ font-size: 24px;
+ line-height: 48px;
+ }
+ }
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Screenfull/index.vue b/UI source code/dns_mapping_ui-master/src/components/Screenfull/index.vue
new file mode 100644
index 0000000..260c90d
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Screenfull/index.vue
@@ -0,0 +1,60 @@
+<template>
+ <div>
+ <svg-icon :icon-class="isFullscreen?'exit-fullscreen':'fullscreen'" @click="click" />
+ </div>
+</template>
+
+<script>
+import screenfull from 'screenfull'
+
+export default {
+ name: 'Screenfull',
+ data() {
+ return {
+ isFullscreen: false
+ }
+ },
+ mounted() {
+ this.init()
+ },
+ beforeDestroy() {
+ this.destroy()
+ },
+ methods: {
+ click() {
+ if (!screenfull.enabled) {
+ this.$message({
+ message: 'you browser can not work',
+ type: 'warning'
+ })
+ return false
+ }
+ screenfull.toggle()
+ },
+ change() {
+ this.isFullscreen = screenfull.isFullscreen
+ },
+ init() {
+ if (screenfull.enabled) {
+ screenfull.on('change', this.change)
+ }
+ },
+ destroy() {
+ if (screenfull.enabled) {
+ screenfull.off('change', this.change)
+ }
+ }
+ }
+}
+</script>
+
+<style scoped>
+.screenfull-svg {
+ display: inline-block;
+ cursor: pointer;
+ fill: #5a5e66;;
+ width: 20px;
+ height: 20px;
+ vertical-align: 10px;
+}
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Search/foot.vue b/UI source code/dns_mapping_ui-master/src/components/Search/foot.vue
new file mode 100644
index 0000000..b34cfd4
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Search/foot.vue
@@ -0,0 +1,55 @@
+<template>
+ <div class="block">
+ <el-pagination
+ :current-page="currentPage4"
+ :page-sizes="[10, 20, 30, 40]"
+ :page-size="100"
+ layout="total, sizes, prev, pager, next, jumper"
+ :total="400"
+ @size-change="handleSizeChange"
+ @current-change="handleCurrentChange"
+ />
+ </div>
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ currentPage1: 5,
+ currentPage2: 5,
+ currentPage3: 5,
+ currentPage4: 4
+ }
+ },
+ methods: {
+ handleSizeChange(val) {
+ console.log(`每页 ${val} 条`)
+ },
+ handleCurrentChange(val) {
+ console.log(`当前页: ${val}`)
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.block{
+ display: flex;
+ justify-content: flex-end;
+ float: right;
+ width: 76%;
+ height: 50px;
+ line-height: 50px;
+ background-color: #fff;
+}
+ .block >>> .el-pagination{
+ height: 50px;
+ line-height: 50px;
+ padding: 10px 5px;
+ // align-items: center;
+ .active{
+ color: #4608ad;
+ }
+ }
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Search/input.vue b/UI source code/dns_mapping_ui-master/src/components/Search/input.vue
new file mode 100644
index 0000000..e0a30d5
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Search/input.vue
@@ -0,0 +1,12 @@
+<template>
+ <div class="input">
+
+ </div>
+</template>
+
+<script>
+export default {};
+</script>
+
+<style>
+</style> \ No newline at end of file
diff --git a/UI source code/dns_mapping_ui-master/src/components/Search/left.vue b/UI source code/dns_mapping_ui-master/src/components/Search/left.vue
new file mode 100644
index 0000000..434299a
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Search/left.vue
@@ -0,0 +1,100 @@
+<template>
+ <div class="left">
+ <el-collapse v-model="activeNames">
+ <el-collapse-item title="端口" name="1">
+ <div v-for="(val,key,i) in left.portList" :key="i" class="item">
+ <p>{{ val.port }}</p>
+ <p>{{ val.count }}</p>
+ </div>
+ </el-collapse-item>
+ <el-collapse-item title="地域" name="2">
+ <div v-for="(val,key,i) in left.regionList" :key="i" class="item">
+ <p>{{ val.province }}</p>
+ <p>{{ val.count }}</p>
+ </div>
+ </el-collapse-item>
+ <el-collapse-item title="服务类别" name="3">
+ <div v-for="(val,key,i) in left.serviceCategoryList" :key="i" class="item">
+ <p>{{ val.key }}</p>
+ <p>{{ val.count }}</p>
+ </div>
+ </el-collapse-item>
+ <el-collapse-item title="运营商" name="4">
+ <div v-for="(val,key,i) in left.providerList" :key="i" class="item">
+ <p>{{ val.provider }}</p>
+ <p>{{ val.count }}</p>
+ </div>
+ </el-collapse-item>
+ <el-collapse-item title="服务组件" name="5">
+ <div v-for="(val,key,i) in left.componentList" :key="i" class="item">
+ <p>{{ val.component }}</p>
+ <p>{{ val.count }}</p>
+ </div>
+ </el-collapse-item>
+ <el-collapse-item title="漏洞威胁" name="6">
+ <div v-for="(val,key,i) in left.vulnerabilityCountList" :key="i" class="item">
+ <p>{{ val.vulnerability }}</p>
+ <p>{{ val.count }}</p>
+ </div>
+ </el-collapse-item>
+ </el-collapse>
+ </div>
+</template>
+
+<script>
+import { mapActions, mapGetters } from 'vuex'
+export default {
+ data() {
+ return {
+ activeNames: ['1']
+ }
+ },
+ computed: {
+ ...mapGetters({
+ left: 'searchlist/left'
+ })
+ },
+ methods: {
+ ...mapActions({
+ leftlistActions: 'searchlist/leftlistActions'
+ })
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.left {
+ width: 22%;
+ float: left;
+ // border-radius: 20px;
+ z-index: 2;
+ .el-collapse {
+ border-radius: 20px;
+ border-top: none;
+ }
+ .item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0px 10px;
+ font-size: 15px;
+ height: 30px;
+
+ p:nth-of-type(1) {
+ color: #4608ad;
+ }
+ p:nth-of-type(2) {
+ color: #aca9b3;
+ }
+ }
+}
+.left >>> .el-collapse-item__header {
+ font-size: 16px;
+ font-weight: 600;
+ padding-left: 10px;
+}
+.left >>> .el-loading-mask{
+ z-index: 1 !important;
+ background-color: white;
+}
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/Search/right.vue b/UI source code/dns_mapping_ui-master/src/components/Search/right.vue
new file mode 100644
index 0000000..ae109f6
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/Search/right.vue
@@ -0,0 +1,116 @@
+<template>
+ <div class="right bigbox">
+ <div class="title">
+ <div :class="tabshow == 1 ? 'active' : ''" @click="tab(1)">
+ 检索结果
+ </div>
+ <div :class="tabshow == 2 ? 'active' : ''" @click="tab(2)">
+ 数据统计
+ </div>
+ <div :class="tabshow == 3 ? 'active' : ''" @click="tab(3)">
+ 关联分析
+ </div>
+ <div class="inp">
+ <input type="text" placeholder="近一年">
+ <el-button type="primary">导出</el-button>
+ </div>
+ </div>
+
+ <div class="containerbox">
+ <div v-show="tabshow == 1"><Result /></div>
+ <div v-show="tabshow == 2"><Count /></div>
+ <div v-show="tabshow == 3"><Relation /></div>
+ </div>
+ </div>
+</template>
+
+<script>
+import Result from '../SearchList/result.vue'
+import Count from '../SearchList/count.vue'
+import Relation from '../SearchList/relation.vue'
+// import { mapGetters } from 'vuex'
+export default {
+ components: {
+ Result,
+ Count,
+ Relation
+ },
+ data() {
+ return {
+ tabshow: 1,
+ }
+ },
+ // computed:{
+ // ...mapGetters({
+ // maplist: "searchlist/maplist",
+ // })
+ // },
+ created() {},
+ methods: {
+ tab(val) {
+ this.tabshow = val;
+ // console.log(val);
+ var page = document.getElementsByClassName('block')[0];
+ if(val == 2 || val == 3){
+ page.style.display = "none"
+ }else{
+ page.style.display = "block"
+ }
+ },
+
+ },
+
+}
+</script>
+
+<style lang="scss" scoped>
+.right {
+ float: right;
+ width: 76%;
+}
+.bigbox .title {
+ background-color: #fff;
+ height: 60px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+.title{
+ color: #aca9b3;
+// .inp{
+// flex: 1;
+// }
+ div:nth-of-type(1){
+ margin-left:10px;
+ }
+ div:hover{
+ color: #4608ad;
+ cursor:pointer
+ }
+ .inp input{
+ height: 32px;
+ width: 300px;
+ border:1px solid #aca9b3;
+ outline-style: none;
+ border-radius: 5px;
+ }
+ .inp button{
+ vertical-align: top;
+ margin-right: 10px;
+ background-color: #4608ad;
+ border-color: #4608ad;
+ }
+}
+.active {
+ font-weight: 600;
+ color: #4608ad !important;
+ border-bottom:4px solid #4608ad;
+}
+html,body{
+ scroll-behavior:smooth;
+}
+.right >>> .el-loading-mask{
+ z-index: 6 !important;
+ background-color: white;
+}
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/SearchInput/SearchInput.vue b/UI source code/dns_mapping_ui-master/src/components/SearchInput/SearchInput.vue
new file mode 100644
index 0000000..60d5d15
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/SearchInput/SearchInput.vue
@@ -0,0 +1,552 @@
+<template>
+ <!-- 父盒子 -->
+ <div class="father_box">
+ <div class="sea_box" @click="onclick">
+ <div
+ v-for="(item, index) in keyword"
+ :key="index"
+ class="spanbox"
+ ref="Tag"
+ >
+ <span v-if="Array.isArray(item)" class="tagspan">
+ <span v-for="(a, i) in item" :key="i">{{ a[a.length - 1] }}</span>
+ </span>
+ <span class="tagspan" v-else>{{ item }}</span>
+
+ <!-- <span class="tagspan" v-if="Array.isArray(item)">{{ item[item.length-1] }}</span> -->
+ <!-- <span class="tagspan" v-for="(a,i) in item" :key="a" v-if="Array.isArray(item)">{{item[0]}}</span> -->
+ <i
+ class="span_close"
+ @click="removeTag(index, item)"
+ v-if="index % 2 != 0"
+ ></i>
+ </div>
+ <el-input
+ placeholder="请输入检索内容"
+ v-model="currentval"
+ @keydown.native="handleKeydown"
+ @focus="searchFoucs"
+ :style="inputStyle"
+ class="inputTag"
+ ref="inputTag"
+ type="text"
+ v-if="type === 'input'"
+ ></el-input>
+ <el-select
+ placeholder="请输入检索内容"
+ v-model="currentval"
+ @change="addTags"
+ @keyup.native="handleKeydown"
+ @focus="searchFoucs"
+ :style="inputStyle"
+ class="inputTag"
+ ref="inputTag"
+ type="text"
+ filterable
+ remote
+ default-first-option
+ v-else-if="type == 'select'"
+ >
+ <el-option
+ v-for="item in options"
+ :key="item.value"
+ :label="item.label"
+ :value="item.value"
+ :disabled="item.disabled"
+ >
+ </el-option>
+ </el-select>
+
+ <el-cascader
+ :options="options"
+ :props="{ multiple: true, checkStrictly: true }"
+ clearable
+ v-model="currentval"
+ @change="addTags"
+ @keyup.native="handleKeydown"
+ @focus="searchFoucs"
+ :style="inputStyle"
+ class="inputTag"
+ ref="inputTag"
+ type="text"
+ filterable
+ remote
+ default-first-option
+ v-else-if="type == 'more'"
+ ></el-cascader>
+
+ <el-select
+ placeholder="请输入检索内容"
+ v-model="currentval"
+ @change="addTags"
+ @keyup.native="handleKeydown"
+ @focus="searchFoucs"
+ :style="inputStyle"
+ class="inputTag"
+ ref="inputTag"
+ type="text"
+ filterable
+ remote
+ default-first-option
+ v-else
+ >
+ <el-option
+ v-for="item in options"
+ :key="item.value"
+ :label="item.label"
+ :value="item.value"
+ :disabled="item.disabled"
+ >
+ </el-option>
+ </el-select>
+ </div>
+ </div>
+</template>
+
+<script>
+export default {
+ name: "inputTags",
+ props: {
+ parentArr: {
+ type: Array,
+ default() {
+ return ["service", "dns-doh"];
+ },
+ },
+ limit: {
+ type: Number,
+ },
+ },
+ data() {
+ return {
+ currentval: "",
+ keyword: [],
+ inputLength: "",
+ // Object: {
+ // arr: [
+ // {
+ // id: 1,
+ // name: "service",
+ // value: "选项1",
+ // type: "select",
+ // child: [
+ // {
+ // value: "dns-doh",
+ // label: "dns-doh",
+ // },
+ // {
+ // value: "dns-do53",
+ // label: "dns-do53",
+ // },
+ // ],
+ // },
+ // {
+ // id: 2,
+ // name: "ip",
+ // type: "input",
+ // },
+ // {
+ // id: 3,
+ // name: "port",
+ // type: "input",
+ // },
+ // ],
+ // },
+ options: [],
+ options1: [
+ {
+ value: "service",
+ label: "service",
+ // disabled: false,
+ },
+ {
+ value: "ip",
+ label: "ip",
+ // disabled: false,
+ },
+ {
+ value: "port",
+ label: "port",
+ // disabled: false,
+ },
+ ],
+ // options2: [
+ // {
+ // value: "dns-doh",
+ // label: "dns-doh",
+ // disabled: false,
+ // },
+ // {
+ // value: "dns-do53",
+ // label: "dns-do53",
+ // disabled: false,
+ // },
+ // ],
+ options2: [
+ {
+ value: "DNS",
+ label: "DNS",
+ disabled: false,
+ children: [
+ {
+ value: "dns-doh",
+ label: "dns-doh",
+ disabled: false,
+ // children: [
+ // {
+ // value: "open-rdns",
+ // label: "open-rdns",
+ // disabled: false,
+ // },
+ // {
+ // value: "egress-rdns",
+ // label: "egress-rdns",
+ // disabled: false,
+ // },
+ // {
+ // value: "forwarder",
+ // label: "forwarder",
+ // disabled: false,
+ // },
+ // {
+ // value: "fwd/rdns",
+ // label: "fwd/rdns",
+ // disabled: false,
+ // },
+ // {
+ // value: "nonstandard",
+ // label: "nonstandard",
+ // disabled: false,
+ // },
+ // {
+ // value: "root",
+ // label: "root",
+ // disabled: false,
+ // },
+ // {
+ // value: "tld",
+ // label: "tld",
+ // disabled: false,
+ // },
+ // {
+ // value: "ns",
+ // label: "ns",
+ // disabled: false,
+ // },
+ // ],
+ },
+ {
+ value: "dns-do53",
+ label: "dns-do53",
+ disabled: false,
+ // children: [
+ // {
+ // value: "proxy",
+ // label: "proxy",
+ // disabled: false,
+ // },
+ // {
+ // value: "server",
+ // label: "server",
+ // disabled: false,
+ // },
+ // ],
+ },
+ ],
+ },
+ {
+ value: "email",
+ label: "email",
+ children: [
+ {
+ value: "email-1",
+ label: "email-1",
+ },
+ {
+ value: "email-2",
+ label: "email-2",
+ },
+ ],
+ },
+ ],
+ isFocus: false,
+ type: "select",
+ };
+ },
+ watch: {
+ keyword() {
+ this.$emit("on-change", this.keyword);
+ },
+ currentval(val) {
+ this.inputLength = this.$refs.inputTag.value.length * 12 + 50;
+ },
+ parentArr() {
+ this.keyword = this.parentArr.length ? this.parentArr : [];
+ },
+ },
+ computed: {
+ inputStyle() {
+ let style = {};
+ style.width = `${this.inputLength}px`;
+ return style;
+ },
+ finall() {
+ return this.keyword.join(",");
+ },
+ },
+ mounted() {
+ this.keyword = this.parentArr;
+ this.options = this.options1;
+ // this.edit();
+ },
+
+ // directives:{
+ // focus:{
+ // inserted:function (e) {
+ // console.log(e);
+ // }
+ // }
+ // },
+ methods: {
+ removeTag(index, item) {
+ // console.log(index-1, item);
+ this.keyword.splice(index, 1);
+ this.keyword.splice(index - 1, 1);
+ // this.options1.forEach((item) => {
+ // item.disabled = false;
+ // });
+ // this.options2.forEach((item) => {
+ // item.disabled = false;
+ // });
+ },
+ addTags() {
+ // console.log(this.currentval, "code输入");
+ // console.log(this.options1, this.options2, "edit");
+ if (this.currentval == "service") {
+ this.options = this.options2;
+ this.type = "more";
+ this.keyword.push(this.currentval);
+ this.currentval = "";
+ } else if (this.currentval == "ip" || this.currentval == "port") {
+ this.type = "input";
+ this.keyword.push(this.currentval);
+ this.currentval = "";
+ } else {
+ this.options = this.options1;
+ this.type = "select";
+ this.keyword.push(this.currentval);
+ this.currentval = "";
+ }
+ // for (var i = 0; i < this.keyword.length; i++) {
+ // console.log(this.keyword[i], 787);
+ // if (this.keyword[i] == "dns-doh") {
+ // // console.log(this.options2[this.options2.findIndex((item) => item.value === "dns-doh")].disabled);
+ // this.options2[
+ // this.options2.findIndex((item) => item.value === "dns-doh")
+ // ].disabled = true;
+ // } else if (this.keyword[i] == "dns-do53") {
+ // this.options2[
+ // this.options2.findIndex((item) => item.value === "dns-do53")
+ // ].disabled = true;
+ // } else if (this.keyword[i] == "ip") {
+ // // console.log(this.options1[this.options2.findIndex((item) => item.value === "dns-doh")].disabled);
+ // this.options1[
+ // this.options1.findIndex((item) => item.value === "ip")
+ // ].disabled = true;
+ // } else if (this.keyword[i] == "port") {
+ // this.options1[
+ // this.options1.findIndex((item) => item.value === "port")
+ // ].disabled = true;
+ // }
+ // }
+ console.log(this.keyword, "add");
+
+ // this.edit();
+ },
+ open() {
+ this.$alert("输入值不能为空", "提示", {
+ confirmButtonText: "确定",
+ });
+ },
+ handleKeydown(e) {
+ // console.log(e);
+ var keyCode = window.event ? e.keyCode : e.which;
+ this.$nextTick(() => {
+ if (keyCode === 8) {
+ // console.log(this.$refs.inputTag.value,'----value');
+ // console.log(this.$refs.inputTag.query,'----query');
+ // console.log(this.currentval,'cur');
+ if (
+ this.$refs.inputTag.query === "" ||
+ (this.currentval == "" && this.$refs.inputTag.query == undefined)
+ ) {
+ setTimeout(() => {
+ // console.log(888);
+ this.keyword.pop();
+ this.searchFoucs();
+ });
+ }
+ }
+ if (keyCode == 13) {
+ if (
+ (this.$refs.inputTag &&
+ this.type == "select" &&
+ this.currentval != "") ||
+ this.type == "input"
+ ) {
+ console.log(this.$refs.inputTag, this.type, this.currentval);
+ // this.$refs.inputTag.visible = false;
+ setTimeout(() => {
+ this.addTags();
+ });
+ }
+ }
+ });
+ },
+ onclick() {
+ this.$nextTick(() => {
+ // this.$refs.inputTag.focus();
+ this.searchFoucs();
+ });
+ },
+ // 输入框键盘删除键删除tag
+ // deleteTags(state) {
+ // var keyCode = window.event ? e.keyCode : e.which;
+ // if (state) {
+ // setTimeout(() => {
+ // this.keyword.pop();
+ // this.searchFoucs();
+ // });
+ // }
+ // },
+ // changeArr(arr) {
+ // var item = {};
+ // // arr = arr.toString().split("");
+ // for (var i = 0; i < arr.length; i++) {
+ // var dt = arr[i];
+ // if (item[dt]) {
+ // item[dt]++;
+ // } else {
+ // item[dt] = 1;
+ // }
+ // }
+ // return item;
+ // },
+ searchFoucs() {
+ // console.log(this.keyword,"---keyword");
+ var len = this.keyword.length;
+ var last = this.keyword[len - 1];
+ if (last == "service") {
+ this.options = this.options2;
+ this.type = "more";
+ } else if (last == "ip" || last == "port") {
+ this.type = "input";
+ } else {
+ this.options = this.options1;
+ this.type = "select";
+ }
+ },
+ // changeInput() {
+ // // console.log("changeInput");
+ // },
+ },
+};
+</script>
+
+<style lang="scss" scoped>
+/* 外层div */
+.father_box {
+ /* width: 300px; */
+ box-sizing: border-box;
+ background-color: white;
+ border: 1px solid #dcdee2;
+ border-radius: 4px;
+ font-size: 12px;
+ text-align: left;
+ padding-left: 5px;
+ word-wrap: break-word;
+ overflow: hidden;
+}
+/* 标签 */
+.key,
+.value {
+ display: inline-block;
+ font-size: 14px;
+ margin: 3px 4px 3px 0;
+ background-color: rgb(229, 229, 229);
+ border: 1px solid #e8eaec;
+ border-radius: 3px;
+}
+.spanbox {
+ display: inline-block;
+ font-size: 14px;
+ margin: 3px 4px 3px 0;
+ background-color: rgb(229, 229, 229);
+ border: 1px solid #e8eaec;
+ border-radius: 3px;
+}
+.tagspan {
+ height: 24px;
+ line-height: 22px;
+ max-width: 100%;
+ position: relative;
+ display: inline-block;
+ padding-left: 8px;
+ padding-right: 8px;
+ color: #495060;
+ font-size: 14px;
+ cursor: pointer;
+ opacity: 1;
+ vertical-align: middle;
+ overflow: hidden;
+ transition: 0.25s linear;
+ color: rgb(26, 26, 26);
+ font-weight: 600;
+}
+.span_close {
+ padding: 0 4px 0 4px;
+ opacity: 1;
+ -webkit-filter: none;
+ filter: none;
+ color: rgb(26, 26, 26);
+ font-weight: 600;
+}
+.span_close:after {
+ content: "\00D7";
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ /* line-height: 27px; */
+ transition: 0.3s, color 0s;
+}
+/* input */
+.inputTag {
+ font-size: 16px;
+ border: none;
+ box-shadow: none;
+ outline: none;
+ background-color: transparent;
+ padding: 0;
+ width: auto;
+ min-width: 250px;
+ vertical-align: top;
+ height: 32px;
+ color: #495060;
+ line-height: 32px;
+}
+.el-select--small >>> .el-input--small .el-input__inner {
+ border: none;
+}
+.el-select--small >>> .el-input--small .el-input__suffix {
+ display: none;
+}
+.el-input--small >>> .el-input__inner {
+ border: none;
+}
+.el-cascader >>> .el-input--small .el-input__inner {
+ border: none;
+}
+.el-cascader >>> .el-input--small .el-input__suffix {
+ display: none;
+}
+</style>
+ \ No newline at end of file
diff --git a/UI source code/dns_mapping_ui-master/src/components/SearchList/count.vue b/UI source code/dns_mapping_ui-master/src/components/SearchList/count.vue
new file mode 100644
index 0000000..7c95d45
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/SearchList/count.vue
@@ -0,0 +1,502 @@
+<template>
+ <div class="count">
+ <ul class="count_list">
+ <!-- 时间轴 -->
+ <li>
+ <Time />
+ </li>
+ <!-- DNS-DoH世界分布 -->
+ <li>
+ <div class="nav">
+ <p>DoH世界分布</p>
+ </div>
+ <div class="charts">
+ <!-- 右侧图表 -->
+ <div class="DOHSJ">
+ <DOHSJ
+ v-if="maplist.dohWorldMapDataList != undefined"
+ :dohsj="maplist.dohWorldMapDataList"
+ />
+ </div>
+ <div class="solid">
+ <ul>
+ <!-- 左侧排序 -->
+ <li
+ v-for="(item, index) in demolist(maplist.dohWorldMapDataList,8)"
+ :key="index"
+ >
+ <div class="first_column">{{ item.country }}</div>
+ <div class="second_column">
+ <el-progress
+ id="text"
+ :percentage="getPercentage(item.count,maplist.dohWorldMapDataList[0].count)"
+ :stroke-width="12"
+ />
+ </div>
+ <div class="third_column">{{ item.count }}</div>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </li>
+ <!-- DoH中国分布 -->
+ <li>
+ <div class="nav">
+ <p>DoH中国分布</p>
+ </div>
+ <div class="charts">
+ <!-- 左侧图表 -->
+ <div class="DOHSJ">
+ <DOHZG
+ v-if="maplist.dohChinaMapList != undefined"
+ :dohzg="maplist.dohChinaMapList"
+ />
+ </div>
+ <!-- 右侧排序 -->
+ <div class="solid">
+ <ul>
+ <li
+ v-for="(item, index) in demolist(maplist.dohChinaMapList, 8)"
+ :key="index"
+ >
+ <div class="first_column">{{ item.province }}</div>
+ <div class="second_column">
+ <el-progress
+ id="text"
+ :percentage="
+ getPercentage(
+ item.count,
+ maplist.dohChinaMapList[0].count
+ )
+ "
+ :stroke-width="12"
+ />
+ </div>
+ <div class="third_column">{{ item.count }}</div>
+ <br>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </li>
+ <!-- DNS-Do53世界分布 -->
+ <li>
+ <div class="nav">
+ <p>DNS-Do53世界分布</p>
+ </div>
+ <div class="charts">
+ <div class="DOHSJ">
+ <DO53SJ
+ v-if="maplist.do53WorldMapDataList != undefined"
+ :do53sj="maplist.do53WorldMapDataList"
+ />
+ </div>
+ <div class="solid">
+ <ul>
+ <li
+ v-for="(item, id) in demolist(maplist.do53WorldMapDataList, 8)"
+ :key="id"
+ >
+ <div class="first_column">{{ item.country }}</div>
+ <div class="second_column">
+ <el-progress
+ id="text"
+ :percentage="
+ getPercentage(
+ item.count,
+ maplist.do53WorldMapDataList[0].count
+ )
+ "
+ :stroke-width="12"
+ />
+ </div>
+ <div class="third_column">{{ item.count }}</div>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </li>
+ <!-- DNS-Do53中国分布 -->
+ <li>
+ <div class="nav">
+ <p>Do53中国分布</p>
+ </div>
+ <div class="charts">
+ <!-- 左侧图表 -->
+ <div class="DOHSJ">
+ <DO53ZG
+ v-if="maplist.do53ChinaMapList != undefined"
+ :do53zg="maplist.do53ChinaMapList"
+ />
+ </div>
+ <!-- 右侧排序 -->
+ <div class="solid">
+ <ul>
+ <li
+ v-for="(item, id) in demolist(maplist.do53ChinaMapList, 8)"
+ :key="id"
+ >
+ <div class="first_column">{{ item.province }}</div>
+ <div class="second_column">
+ <el-progress
+ id="text"
+ :percentage="
+ getPercentage(
+ item.count,
+ maplist.do53ChinaMapList[0].count
+ )
+ "
+ :stroke-width="12"
+ />
+ </div>
+ <div class="third_column">{{ item.count }}</div>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </li>
+ <!-- Do53Forwarder世界分布 -->
+ <li>
+ <div class="nav">
+ <p>Do53Forwarder世界分布</p>
+ </div>
+ <div class="charts">
+ <!-- 右侧图表 -->
+ <div class="DOHSJ">
+ <Do53Forwarder
+ v-if="maplist.do53ForwarderList != undefined"
+ :do53forwarder="maplist.do53ForwarderList"
+ />
+ </div>
+ <div class="solid">
+ <ul>
+ <!-- 左侧排序 -->
+ <li
+ v-for="(item, id) in demolist(maplist.do53ForwarderList, 8)"
+ :key="id"
+ >
+ <div class="first_column">{{ item.country }}</div>
+ <div class="second_column">
+ <el-progress
+ id="text"
+ :percentage="
+ getPercentage(
+ item.count,
+ maplist.do53ForwarderList[0].count
+ )
+ "
+ :stroke-width="12"
+ />
+ </div>
+ <div class="third_column">{{ item.count }}</div>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </li>
+ <!-- egress-dns世界分布 -->
+ <li>
+ <div class="nav">
+ <p>egress-dns世界分布</p>
+ </div>
+ <div class="charts">
+ <!-- 右侧图表 -->
+ <div class="DOHSJ">
+ <Do53Egressdns
+ v-if="maplist.do53EgressDnsList != undefined"
+ :do53egressdns="maplist.do53EgressDnsList"
+ />
+ </div>
+ <div class="solid">
+ <ul>
+ <!-- 左侧排序 -->
+ <li
+ v-for="(item, id) in demolist(maplist.do53EgressDnsList, 8)"
+ :key="id"
+ >
+ <div class="first_column">{{ item.country }}</div>
+ <div class="second_column">
+ <el-progress
+ id="text"
+ :percentage="
+ getPercentage(
+ item.count,
+ maplist.do53EgressDnsList[0].count
+ )
+ "
+ :stroke-width="12"
+ />
+ </div>
+ <div class="third_column">{{ item.count }}</div>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </li>
+ <!-- fwd/rdns世界分布 -->
+ <li>
+ <div class="nav">
+ <p>fwd/rdns世界分布</p>
+ </div>
+ <div class="charts">
+ <!-- 右侧图表 -->
+ <div class="DOHSJ">
+ <Do53Fwdrdns
+ v-if="maplist.do53FwdRdnsList != undefined"
+ :do53fwdrdns="maplist.do53FwdRdnsList"
+ />
+ </div>
+ <div class="solid">
+ <ul>
+ <!-- 左侧排序 -->
+ <li
+ v-for="(item, id) in demolist(maplist.do53FwdRdnsList, 8)"
+ :key="id"
+ >
+ <div class="first_column">{{ item.country }}</div>
+ <div class="second_column">
+ <el-progress
+ id="text"
+ :percentage="
+ getPercentage(
+ item.count,
+ maplist.do53FwdRdnsList[0].count
+ )
+ "
+ :stroke-width="12"
+ />
+ </div>
+ <div class="third_column">{{ item.count }}</div>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </li>
+ <!-- open-rdns世界分布 -->
+ <li>
+ <div class="nav">
+ <p>open-rdns世界分布</p>
+ </div>
+ <div class="charts">
+ <!-- 右侧图表 -->
+ <div class="DOHSJ">
+ <Do53Opendns
+ v-if="maplist.do53OpenRdnsList != undefined"
+ :do53opendns="maplist.do53OpenRdnsList"
+ />
+ </div>
+ <div class="solid">
+ <ul>
+ <!-- 左侧排序 -->
+ <li
+ v-for="(item, id) in demolist(maplist.do53OpenRdnsList, 8)"
+ :key="id"
+ >
+ <div class="first_column">{{ item.country }}</div>
+ <div class="second_column">
+ <el-progress
+ id="text"
+ :percentage="
+ getPercentage(
+ item.count,
+ maplist.do53OpenRdnsList[0].count
+ )
+ "
+ :stroke-width="12"
+ />
+ </div>
+ <div class="third_column">{{ item.count }}</div>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </li>
+ <!-- nonstandard世界分布 -->
+ <li>
+ <div class="nav">
+ <p>nonstandard世界分布</p>
+ </div>
+ <div class="charts">
+ <!-- 右侧图表 -->
+ <div class="DOHSJ">
+ <Do53Nonstandard
+ v-if="maplist.do53NonstandardList != undefined"
+ :do53nonstandard="maplist.do53NonstandardList"
+ />
+ </div>
+ <div class="solid">
+ <ul>
+ <!-- 左侧排序 -->
+ <li
+ v-for="(item, id) in demolist(maplist.do53NonstandardList, 8)"
+ :key="id"
+ >
+ <div class="first_column">{{ item.country }}</div>
+ <div class="second_column">
+ <el-progress
+ id="text"
+ :percentage="
+ getPercentage(
+ item.count,
+ maplist.do53NonstandardList[0].count
+ )
+ "
+ :stroke-width="12"
+ />
+ </div>
+ <div class="third_column">{{ item.count }}</div>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </li>
+ </ul>
+ </div>
+</template>
+
+<script>
+import Time from '../../components/Echarts/Time.vue'
+import DOHSJ from '../../components/Echarts/Dohsj.vue'
+import DOHZG from '../../components/Echarts/Dohzg.vue'
+import DO53SJ from '../../components/Echarts/Do53sj.vue'
+import DO53ZG from '../../components/Echarts/Do53zg.vue'
+import Do53Forwarder from '../../components/Echarts/Do53Forwarder.vue'
+import Do53Egressdns from '../../components/Echarts/Do53Egressdns.vue'
+import Do53Fwdrdns from '../../components/Echarts/Do53Fwdrdns.vue'
+import Do53Opendns from '../../components/Echarts/Do53Openrdns.vue'
+import Do53Nonstandard from '../../components/Echarts/Do53Nonstandard.vue'
+import { mapActions, mapGetters } from 'vuex'
+export default {
+ components: {
+ Time,
+ DOHSJ,
+ DOHZG,
+ DO53SJ,
+ DO53ZG,
+ Do53Forwarder,
+ Do53Egressdns,
+ Do53Fwdrdns,
+ Do53Opendns,
+ Do53Nonstandard
+ },
+ data() {
+ return {}
+ },
+ computed: {
+ ...mapGetters({
+ maplist: 'searchlist/maplist'
+ })
+ },
+ // created(){
+ // this.cmap()
+ // },
+
+ methods: {
+ ...mapActions({
+ maplistActions: 'searchlist/maplistActions'
+ }),
+ demolist(data, number) {
+ if (data != undefined) {
+ var newData = data.filter((item, i) => {
+ return i < number
+ })
+ return newData
+ }
+ },
+ getPercentage(value, maxValue) {
+ return (value / this.ceilNumber(maxValue)) * 100
+ },
+ ceilNumber(number) {
+ let bite = 0
+ if (number < 10) {
+ return 10
+ }
+ if (number < 100) {
+ return Math.ceil(number) * Math.pow(10, 1)
+ }
+ while (number >= 100) {
+ number /= 10
+ bite += 1
+ }
+ return Math.ceil(number) * Math.pow(10, bite)
+ }
+ },
+ mounted() {
+ this.maplistActions()
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.count {
+ width: 100%;
+ .count_list {
+ width: 100%;
+ padding: 0;
+ margin: 0;
+ li {
+ width: 100%;
+ list-style: none;
+ .nav {
+ width: 100%;
+ background-color: white;
+ border-bottom: 1px solid #dcdcdc;
+ height: 50px;
+ line-height: 50px;
+ padding: 0px 20px;
+ font-weight: bolder;
+ }
+ .charts {
+ background-color: white;
+ display: flex;
+ // width: 100%;
+ justify-content: space-evenly;
+ align-items: center;
+ .DOHSJ {
+ width: 500px;
+ height: 300px;
+ }
+ .solid {
+ width: 50%;
+ }
+ .solid ul {
+ padding-left: 0px;
+ }
+ .solid ul li {
+ // width:50%;
+ // background-color: yellow;
+ line-height: 30px;
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ .first_column {
+ padding-right: 10px;
+ }
+ .second_column {
+ width: 360px;
+ }
+ @media only screen and (min-width: 768px) and (max-width: 1370px) {
+ .second_column {
+ width: 320px;
+ }
+ }
+ // @media only screen and (min-width: 1371px) and (max-width: 2400px) {
+ // .dashboard-container .text >>> .massage {
+ // width: 63%;
+ // }
+ // }
+ }
+ }
+ }
+ }
+}
+#text >>> .el-progress-bar {
+ width: 360px !important;
+ .el-progress-bar__inner {
+ background-color: #4608ad;
+ }
+}
+#text >>> .el-progress__text {
+ display: none !important;
+}
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/SearchList/relation.vue b/UI source code/dns_mapping_ui-master/src/components/SearchList/relation.vue
new file mode 100644
index 0000000..0510504
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/SearchList/relation.vue
@@ -0,0 +1,56 @@
+<template>
+ <div class="relation">
+ <title>数据统计分析工具</title>
+ <div class="tip">
+ <p>类型统计</p>
+ <p>|</p>
+ <p>总计<span>&nbsp;&nbsp;0 &nbsp;&nbsp;</span>类</p>
+ </div>
+ <div class="content">
+ <el-empty description="暂无数据"></el-empty>
+ </div>
+ </div>
+</template>
+
+<script>
+export default {}
+</script>
+
+<style lang="scss" scoped>
+.relation {
+ width: 100%;
+ font-weight: 600;
+
+ title {
+ display: block;
+ height: 45px;
+ line-height: 45px;
+ margin-top: 12px;
+ padding-left: 12px;
+ background-color: #fff;
+ }
+ .tip {
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ height: 45px;
+ line-height: 45px;
+ margin-top: 12px;
+ padding-left: 12px;
+ p:nth-of-type(2) {
+ margin: 0px 10px;
+ color: #ccc;
+ }
+ span {
+ color: #4608ad;
+ }
+ }
+ // .content{
+ // height: 500px;
+ // line-height: 500px;
+ // text-align: center;
+ // color: #ccc;
+ // background-color: #fff;
+ // }
+}
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/SearchList/result.vue b/UI source code/dns_mapping_ui-master/src/components/SearchList/result.vue
new file mode 100644
index 0000000..049893c
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/SearchList/result.vue
@@ -0,0 +1,472 @@
+<template>
+ <div class="result">
+ <div class="box">
+ <ul>
+ <li v-for="(item1, index1) in list.list" :key="index1" class="item">
+ <!-- 详情的标题 -->
+ <div class="title">
+ <div class="title_left">
+ <span>{{ item1.ip }}</span>
+ <span>{{
+ item1.ipInformation ? item1.ipInformation.country : ""
+ }}</span>
+ <span>{{
+ item1.ipInformation ? item1.ipInformation.province : ""
+ }}</span>
+ <span>{{
+ item1.ipInformation ? item1.ipInformation.city : ""
+ }}</span>
+ </div>
+ <div class="title_right">
+ <i class="el-icon-time" /><span>{{ item1.timestamp }}</span>
+ </div>
+ </div>
+ <!-- 详情的内容 -->
+ <div class="content">
+ <!-- 详情左侧 -->
+ <div class="content_left">
+ <!-- 左侧头部标签 -->
+ <div class="tag">
+ <div class="tag_left">
+ <p>漏洞威胁</p>
+ </div>
+ <div class="tag_right">
+ <span><i class="el-icon-receiving" />{{ item1.protocolType }}</span>
+ <span><i class="el-icon-film" />{{ item1.ipType }}</span>
+ </div>
+ </div>
+ <!-- 左侧链接接内容 -->
+ <div class="link">
+ <i class="el-icon-thumb" />
+ <p>{{ item1.statusCode }}</p>
+ </div>
+ <!-- 左侧列表内容 -->
+ <div class="content_list">
+ <div class="list_left">
+ <div class="text">
+ <p>自治域编号</p>
+ <p
+ :title="`${
+ item1.ipInformation
+ ? item1.ipInformation.asnumber
+ ? item1.ipInformation.asnumber
+ : ''
+ : ''
+ }`"
+ >
+ {{
+ item1.ipInformation
+ ? item1.ipInformation.asnumber
+ ? item1.ipInformation.asnumber
+ : "--"
+ : "--"
+ }}
+ </p>
+ </div>
+ <div class="text">
+ <p>自治域</p>
+ <p>--</p>
+ </div>
+ <div class="text">
+ <p>运营商</p>
+ <p
+ :title="`${
+ item1.ipInformation
+ ? item1.ipInformation.provider
+ ? item1.ipInformation.provider
+ : ''
+ : ''
+ }`"
+ >
+ {{
+ item1.ipInformation
+ ? item1.ipInformation.provider
+ ? item1.ipInformation.provider
+ : "--"
+ : "--"
+ }}
+ </p>
+ </div>
+ <div class="text">
+ <p> IP归属</p>
+ <p
+ :title="`${
+ item1.ipInformation
+ ? item1.ipInformation.isp
+ ? item1.ipInformation.isp
+ : ''
+ : ''
+ }`"
+ >
+ {{
+ item1.ipInformation
+ ? item1.ipInformation.isp
+ ? item1.ipInformation.isp
+ : "--"
+ : "--"
+ }}
+ </p>
+ </div>
+ </div>
+ <div class="list_right">
+ <div class="text">
+ <p>服务组件</p>
+ <select
+ v-if="item1.componentList && item1.componentList.length != 0"
+ id=""
+ name=""
+ >
+ <option
+ v-for="(a, index) in item1.componentList"
+ :key="index"
+ value=""
+ >
+ {{ a }}
+ </option>
+ </select>
+ <p v-else>--</p>
+ </div>
+ <div class="text">
+ <p>访问路径</p>
+ <!-- <select v-if="item1.pathList.length != 0" id="" name=""> -->
+ <select v-if="item1.pathList ? item1.pathList.length : ''" id="" name="">
+ <option
+ v-for="(b, index) in item1.pathList"
+ :key="index"
+ value=""
+ :title="`${b}`"
+ >{{ b }}
+ </option>
+ </select>
+ <p v-else>--</p>
+ </div>
+ <div class="text">
+ <p>主机名</p>
+ <p :title="`${item1.host}`">
+ {{ item1.host ? item1.host : "--" }}
+ </p>
+ </div>
+ <div class="text">
+ <p>服务类别</p>
+ <!-- <p>DNS,DNS-DoH,转发服务器</p> -->
+ <!-- <div class="tag"> -->
+ <div class="tag_left">
+ <el-tag
+ v-for="(c, index) in item1.tags"
+ :key="index"
+ :title="`${c}`"
+ >
+ {{ c }}
+ </el-tag>
+ </div>
+ <!-- </div> -->
+ </div>
+ </div>
+ </div>
+ <!-- 底部小框 -->
+ <div class="content_bottom">
+ <i class="el-icon-data-analysis" />
+ <p v-for="(d, index) in item1.ipCert" :key="index" :title="`${d.ca}`">
+ {{ d.ca }}
+ </p>
+ </div>
+ </div>
+ <!-- 详情右侧 -->
+ <div class="content_right">
+ <result-tab :tab-data="item1" />
+ </div>
+ </div>
+ </li>
+ </ul>
+ </div>
+ </div>
+</template>
+
+<script>
+import { mapActions, mapGetters } from 'vuex'
+import resultTab from './resultTab.vue'
+// import { Tab } from "./xxk";
+// import indexVue from "../Breadcrumb/index.vue";
+
+export default {
+ components: { resultTab },
+ data() {
+ return {}
+ },
+ created() {},
+ computed: {
+ ...mapGetters({
+ list: 'searchlist/list'
+ })
+ },
+ methods: {
+ ...mapActions({
+ listAction: 'searchlist/listActions'
+ })
+ },
+ mounted() {}
+}
+</script>
+
+<style lang="scss" scoped>
+.box {
+ ul {
+ padding: 0px;
+ margin: 10px 0px;
+ li {
+ list-style: none;
+ background-color: #fff;
+ margin-bottom: 15px;
+ }
+ }
+ .item {
+ // width: 100%;
+ .title {
+ // width: 50%;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ background-color: white;
+ padding: 0px 20px;
+ height: 50px;
+ border-bottom: 1px solid #dcdcdc;
+ margin: 0px;
+ .title_left span:nth-of-type(1) {
+ font-size: 20px;
+ color: #4608ad;
+ }
+ .title_left span:nth-of-type(2),
+ span:nth-of-type(3),
+ span:nth-of-type(4) {
+ color: #aca9b3;
+ padding-left: 13px;
+ font-size: 15px;
+ }
+ }
+ .content {
+ width: 100%;
+ // width: 566px;
+ display: flex;
+ .content_left {
+ width: 50%;
+ border-right: 1px solid #dcdcdc;
+ // 左侧标签
+ .tag {
+ height: 50px;
+ // background-color: palevioletred;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0px 20px;
+ p {
+ display: inline-block;
+ height: 30px;
+ width: 72px;
+ line-height: 30px;
+ text-align: center;
+ border-radius: 7px;
+ font-size: 13px;
+ }
+ p:nth-of-type(1) {
+ background-color: #d9e4ff;
+ color: #4608ad;
+ }
+ // p:nth-of-type(2) {
+ // background-color: #eef7fc;
+ // color: #5abee7;
+ // }
+ }
+ // 左侧链接
+ .link {
+ width: 95%;
+ height: 30px;
+ margin: 10px auto;
+ background-color: #d9e4ff;
+ border-radius: 16px;
+ position: relative;
+ .el-icon-thumb {
+ display: inline-block;
+ border-radius: 50%;
+ background-color: #4608ad;
+ color: #fff;
+ width: 25px;
+ height: 25px;
+ line-height: 25px;
+ text-align: center;
+ position: absolute;
+ left: 10px;
+ top: 3px;
+ }
+ p {
+ // margin-left: 35px;
+ line-height: 30px;
+ margin: 0px 40px;
+ }
+ }
+ // 左侧列表内容
+ .content_list {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ margin: 10px 0px;
+ .list_right {
+ border-left: 1px solid #dcdcdc;
+ }
+ .list_left,
+ .list_right {
+ width: 50%;
+ .text {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ // width: 283px;
+ // background-color: #ff0;
+ padding: 0px 20px;
+ font-size: 15px;
+ select {
+ border: 0px;
+ outline-style: none;
+ margin-right: 50px;
+ }
+ @media only screen and (min-width: 768px) and (max-width: 1370px) {
+ select {
+ margin-right: 10px;
+ width: 50%;
+ }
+ }
+ @media only screen and (min-width: 1371px) and (max-width: 2048px) {
+ select {
+ margin-right: 15px;
+ width: 50%;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ }
+ }
+ p {
+ line-height: 30px;
+ margin: 0px;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ cursor: pointer;
+ width: 50%;
+ }
+ .tag_left {
+ display: flex;
+ width: 50%;
+ flex-wrap: wrap;
+ cursor: pointer;
+ .el-tag--small {
+ background-color: #d9e4ff;
+ color: #4608ad;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ width: 65px;
+ margin-right: 3px;
+ }
+ @media only screen and (min-width: 768px) and (max-width: 1370px) {
+ .el-tag--small {
+ width: 45px;
+ }
+ }
+ @media only screen and (min-width: 1371px) and (max-width: 2048px) {
+ .el-tag--small {
+ width: 50px;
+ }
+ }
+ // flex-direction: column !important;
+ // p {
+ // display: inline-block;
+ // height: 30px;
+ // width: 67px !important;
+ // line-height: 30px;
+ // text-align: center;
+ // border-radius: 7px;
+ // font-size: 13px;
+ // margin-bottom: 3px;
+ // margin-right: 3px;
+ // }
+ }
+ p:nth-of-type(2) {
+ // flex: 1;
+ // -webkit-box-flex: 1;
+ width: 50%;
+ text-align: center;
+ // width: 90px;
+ }
+ }
+ }
+ }
+ }
+ // 右侧列表
+ .content_right {
+ // display: flex;
+ width: 50%;
+ }
+ }
+ }
+}
+
+.el-tabs__content >>> .el-tab-pane #text {
+ width: 100% !important;
+ resize: none;
+ outline: none;
+ border: none;
+ background-color: #f9fafb;
+ color: #aca9b3;
+ font-size: 16px;
+}
+.content_bottom {
+ display: flex;
+ align-items: center;
+ padding-left: 20px;
+ height: 30px;
+ line-height: 30px;
+ margin: 10px 0px;
+ width: 93%;
+ // width: auto;
+ // border: 1px solid transparent;
+ // border-radius:7px ;
+ .el-icon-data-analysis {
+ display: inline-block;
+ border-radius: 10px 0px 0px 10px;
+ background-color: #4608ad;
+ color: white;
+ display: inline-block;
+ height: 30px;
+ line-height: 30px;
+ width: 30px;
+ text-align: center;
+ }
+ P {
+ padding: 0px 7px;
+ display: inline-block;
+ background-color: #d9e4ff;
+ font-size: 15px;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ cursor: pointer;
+ }
+ p:last-child {
+ border-left: 1px solid #cbc8c8;
+ border-radius: 0px 10px 10px 0px;
+ }
+}
+.tab input {
+ background: #f6f3f3;
+ border: 1px solid #ff0000;
+}
+.tab .active {
+ background: #e9d4d4;
+}
+.tab div {
+ width: 300px;
+ height: 250px;
+ display: none;
+ padding: 10px;
+ background: #e9d4d4;
+ border: 1px solid #ff0000;
+}
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/SearchList/resultTab.vue b/UI source code/dns_mapping_ui-master/src/components/SearchList/resultTab.vue
new file mode 100644
index 0000000..6e358b3
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/SearchList/resultTab.vue
@@ -0,0 +1,182 @@
+<template>
+ <!-- 详情右侧 -->
+ <el-tabs v-model="activeName" @tab-click="handleClick">
+ <el-tab-pane label="响应" name="a1">
+ <div class="contentright_box">
+ <div>
+ <textarea
+ id=""
+ v-model="xylist"
+ readonly
+ name=""
+ cols="30"
+ rows="10"
+ />
+ </div>
+ </div>
+ </el-tab-pane>
+ <el-tab-pane label="证书" name="a2">
+ <div class="contentright_box">
+ <div>
+ <textarea
+ id=""
+ v-model="zslist"
+ readonly
+ name=""
+ cols="30"
+ rows="10"
+ />
+ </div>
+ </div>
+ </el-tab-pane>
+ <el-tab-pane label="http" name="a3">
+ <div class="contentright_box">
+ <div>
+ <textarea id="" v-model="httplist" name="" cols="30" rows="10" />
+ </div>
+ </div>
+ </el-tab-pane>
+ </el-tabs>
+</template>
+
+<script>
+export default {
+ props: { tabData: {}},
+ data() {
+ return {
+ // first: 1,
+ // second: 2,
+ // third: 3,
+ activeName: 'a1'
+ }
+ },
+ computed: {
+ // 处理证书展示
+ zslist: function() {
+ let zslist1 = ''
+ // console.log(this.tabData.ipCert);
+ if (this.tabData.ipCert == undefined || this.tabData.ipCert == null) {
+ return zslist1
+ } else {
+ if (this.tabData.ipCert.length >= 1) {
+ this.tabData.ipCert.map((item, index) => {
+ // console.log(item, index, 999);
+ zslist1 += `${item.certificate}\n-----------------------\n`
+ })
+ return zslist1
+ }
+ }
+ },
+ // banner 响应区
+ xylist: function() {
+ let xylist1 = ''
+ // doh 设置展示数据格式
+ if (this.tabData.banner && this.tabData.dnsType == undefined) {
+ if (this.tabData.banner.length >= 1) {
+ this.tabData.banner.map((item, index) => {
+ // console.log(item,"length");
+ xylist1 += `${item}\n----------------------\n`
+ })
+ return xylist1
+ }
+ } else if (this.tabData.banner === undefined) {
+ return xylist1
+ } else if (this.tabData.dnsType == 5) {
+ console.log(555);
+ if (this.tabData.banner.length >= 1) {
+ this.tabData.banner.map((item, index) => {
+ console.log(item);
+ if(index===0){
+ xylist1 += `${item}\n----------------------\n`
+ }else{
+ xylist1 +=`record=${item.record}\n----------------------\n`
+ }
+ // else{
+ // xylist1 =`record=${this.tabData.record}`
+ // }
+ })
+ }
+ return xylist1
+ // return `record=${this.tabData.record}`
+ } else if (this.tabData.dnsType === 3 || this.tabData.dnsType === 2) {
+ if (this.tabData.banner.length >= 1) {
+ this.tabData.banner.map((item, index) => {
+ if(index===0){
+ xylist1 += `${item}\n--------------------\n`
+ }else{
+ xylist1 += JSON.stringify(item)+`\n--------------------\n`
+ // xylist1 +=
+ // `服务器ip地址:${item.city}\n` +
+ // `IP所属国家:${item.country}\n` +
+ // `IP所属省份:${item.province}\n` +
+ // `IP所属城市:${item.city}\n` +
+ // `IP所属区县:${item.district}\n` +
+ // `IP所属提供服务商:${item.provider}\n` +
+ // `IP所属运行商:${item.isp}\n` +
+ // `自治域编码:${item.asnumber}\n----------------\n`;
+
+ }
+ // console.log(item,"length");
+ // this.xylist += JSON.stringify(item)+'\n'
+
+ })
+ return xylist1
+ } else {
+ return this.tabData.banner[0]
+ }
+ } else {
+ xylist1 = this.tabData.banner[0]
+ }
+ return xylist1
+ },
+ // http页签展示处理
+ httplist: function() {
+ // 数据格式和接口返回值暂时版
+ let httpHearders = ''
+ if (this.tabData.httpContent === undefined || this.tabData.httpContent === null) {
+ return httpHearders
+ } else {
+ this.tabData.httpContent.map((item, index) => {
+ // console.log(item,"length");
+ httpHearders += `${item}\n-------------------------------\n`
+ })
+ return httpHearders
+ }
+ return httpHearders
+ }
+ },
+ created() {},
+ methods: {
+ handleClick(tab, event) {
+ // console.log(tab, event);
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+textarea {
+ width: 100%;
+ resize: none;
+ outline: none;
+ border: none;
+ background-color: #f9fafb;
+ color: #aca9b3;
+ font-size: 16px;
+}
+
+</style>
+<style>
+.el-tabs__nav-scroll {
+ padding-left: 12px;
+}
+.el-tabs__nav-scroll .is-active {
+ color: #4608ad !important;
+}
+.el-tabs__active-bar {
+ background-color: #4608ad !important;
+}
+.el-tabs__nav :hover{
+ color: #4608ad !important;
+}
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/SizeSelect/index.vue b/UI source code/dns_mapping_ui-master/src/components/SizeSelect/index.vue
new file mode 100644
index 0000000..e490dce
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/SizeSelect/index.vue
@@ -0,0 +1,57 @@
+<template>
+ <el-dropdown trigger="click" @command="handleSetSize">
+ <div>
+ <svg-icon class-name="size-icon" icon-class="size" />
+ </div>
+ <el-dropdown-menu slot="dropdown">
+ <el-dropdown-item v-for="item of sizeOptions" :key="item.value" :disabled="size===item.value" :command="item.value">
+ {{
+ item.label }}
+ </el-dropdown-item>
+ </el-dropdown-menu>
+ </el-dropdown>
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ sizeOptions: [
+ { label: 'Default', value: 'default' },
+ { label: 'Medium', value: 'medium' },
+ { label: 'Small', value: 'small' },
+ { label: 'Mini', value: 'mini' }
+ ]
+ }
+ },
+ computed: {
+ size() {
+ return this.$store.getters.size
+ }
+ },
+ methods: {
+ handleSetSize(size) {
+ this.$ELEMENT.size = size
+ this.$store.dispatch('app/setSize', size)
+ this.refreshView()
+ this.$message({
+ message: '布局设置成功',
+ type: 'success'
+ })
+ },
+ refreshView() {
+ // In order to make the cached page re-rendered
+ this.$store.dispatch('tagsView/delAllCachedViews', this.$route)
+
+ const { fullPath } = this.$route
+
+ this.$nextTick(() => {
+ this.$router.replace({
+ path: '/redirect' + fullPath
+ })
+ })
+ }
+ }
+
+}
+</script>
diff --git a/UI source code/dns_mapping_ui-master/src/components/SvgIcon/index.vue b/UI source code/dns_mapping_ui-master/src/components/SvgIcon/index.vue
new file mode 100644
index 0000000..9a3318e
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/SvgIcon/index.vue
@@ -0,0 +1,62 @@
+<template>
+ <div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
+ <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
+ <use :href="iconName" />
+ </svg>
+</template>
+
+<script>
+// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
+import { isExternal } from '@/utils/validate'
+
+export default {
+ name: 'SvgIcon',
+ props: {
+ iconClass: {
+ type: String,
+ required: true
+ },
+ className: {
+ type: String,
+ default: ''
+ }
+ },
+ computed: {
+ isExternal() {
+ return isExternal(this.iconClass)
+ },
+ iconName() {
+ return `#icon-${this.iconClass}`
+ },
+ svgClass() {
+ if (this.className) {
+ return 'svg-icon ' + this.className
+ } else {
+ return 'svg-icon'
+ }
+ },
+ styleExternalIcon() {
+ return {
+ mask: `url(${this.iconClass}) no-repeat 50% 50%`,
+ '-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
+ }
+ }
+ }
+}
+</script>
+
+<style scoped>
+.svg-icon {
+ width: 1em;
+ height: 1em;
+ vertical-align: -0.15em;
+ fill: currentColor;
+ overflow: hidden;
+}
+
+.svg-external-icon {
+ background-color: currentColor;
+ mask-size: cover!important;
+ display: inline-block;
+}
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/ThemePicker/index.vue b/UI source code/dns_mapping_ui-master/src/components/ThemePicker/index.vue
new file mode 100644
index 0000000..2fc497b
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/ThemePicker/index.vue
@@ -0,0 +1,165 @@
+<template>
+ <el-color-picker
+ v-model="theme"
+ :predefine="['#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d']"
+ class="theme-picker"
+ popper-class="theme-picker-dropdown"
+ />
+</template>
+
+<script>
+const version = require('element-ui/package.json').version // element-ui version from node_modules
+const ORIGINAL_THEME = '#409EFF' // default color
+import Cookies from 'js-cookie'
+export default {
+ data() {
+ return {
+ chalk: '', // content of theme-chalk css
+ theme: ''
+ }
+ },
+ computed: {
+ defaultTheme() {
+ return this.$store.state.settings.theme
+ }
+ },
+ watch: {
+ defaultTheme: {
+ handler: function(val, oldVal) {
+ this.theme = val
+ },
+ immediate: true
+ },
+ async theme(val) {
+ Cookies.set('theme', val, { expires: 365 })
+ const oldVal = this.chalk ? this.theme : Cookies.get('theme') ? Cookies.get('theme') : ORIGINAL_THEME
+ if (typeof val !== 'string') return
+ const themeCluster = this.getThemeCluster(val.replace('#', ''))
+ const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
+
+ const getHandler = (variable, id) => {
+ return () => {
+ const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
+ const newStyle = this.updateStyle(this[variable], originalCluster, themeCluster)
+
+ let styleTag = document.getElementById(id)
+ if (!styleTag) {
+ styleTag = document.createElement('style')
+ styleTag.setAttribute('id', id)
+ document.head.appendChild(styleTag)
+ }
+ styleTag.innerText = newStyle
+ }
+ }
+
+ if (!this.chalk) {
+ const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`
+ await this.getCSSString(url, 'chalk')
+ }
+
+ const chalkHandler = getHandler('chalk', 'chalk-style')
+
+ chalkHandler()
+
+ const styles = [].slice.call(document.querySelectorAll('style'))
+ .filter(style => {
+ const text = style.innerText
+ return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
+ })
+ styles.forEach(style => {
+ const { innerText } = style
+ if (typeof innerText !== 'string') return
+ style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
+ })
+
+ this.$emit('change', val)
+ }
+ },
+
+ methods: {
+ updateStyle(style, oldCluster, newCluster) {
+ let newStyle = style
+ oldCluster.forEach((color, index) => {
+ newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
+ })
+ return newStyle
+ },
+
+ getCSSString(url, variable) {
+ return new Promise(resolve => {
+ const xhr = new XMLHttpRequest()
+ xhr.onreadystatechange = () => {
+ if (xhr.readyState === 4 && xhr.status === 200) {
+ this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
+ resolve()
+ }
+ }
+ xhr.open('GET', url)
+ xhr.send()
+ })
+ },
+
+ getThemeCluster(theme) {
+ const tintColor = (color, tint) => {
+ let red = parseInt(color.slice(0, 2), 16)
+ let green = parseInt(color.slice(2, 4), 16)
+ let blue = parseInt(color.slice(4, 6), 16)
+
+ if (tint === 0) { // when primary color is in its rgb space
+ return [red, green, blue].join(',')
+ } else {
+ red += Math.round(tint * (255 - red))
+ green += Math.round(tint * (255 - green))
+ blue += Math.round(tint * (255 - blue))
+
+ red = red.toString(16)
+ green = green.toString(16)
+ blue = blue.toString(16)
+
+ return `#${red}${green}${blue}`
+ }
+ }
+
+ const shadeColor = (color, shade) => {
+ let red = parseInt(color.slice(0, 2), 16)
+ let green = parseInt(color.slice(2, 4), 16)
+ let blue = parseInt(color.slice(4, 6), 16)
+
+ red = Math.round((1 - shade) * red)
+ green = Math.round((1 - shade) * green)
+ blue = Math.round((1 - shade) * blue)
+
+ red = red.toString(16)
+ green = green.toString(16)
+ blue = blue.toString(16)
+
+ return `#${red}${green}${blue}`
+ }
+
+ const clusters = [theme]
+ for (let i = 0; i <= 9; i++) {
+ clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
+ }
+ clusters.push(shadeColor(theme, 0.1))
+ return clusters
+ }
+ }
+}
+</script>
+
+<style>
+.theme-message,
+.theme-picker-dropdown {
+ z-index: 99999 !important;
+}
+
+.theme-picker .el-color-picker__trigger {
+ height: 26px !important;
+ width: 26px !important;
+ padding: 2px;
+}
+
+.theme-picker-dropdown .el-color-dropdown__link-btn {
+ display: none;
+}
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/UploadExcel/index.vue b/UI source code/dns_mapping_ui-master/src/components/UploadExcel/index.vue
new file mode 100644
index 0000000..a78f966
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/UploadExcel/index.vue
@@ -0,0 +1,138 @@
+<template>
+ <div>
+ <input ref="excel-upload-input" class="excel-upload-input" type="file" accept=".xlsx, .xls" @change="handleClick">
+ <div class="drop" @drop="handleDrop" @dragover="handleDragover" @dragenter="handleDragover">
+ 拖拽excel文件到此处 或者
+ <el-button :loading="loading" style="margin-left:16px;" size="mini" type="primary" @click="handleUpload">
+ 浏览
+ </el-button>
+ </div>
+ </div>
+</template>
+
+<script>
+import XLSX from 'xlsx'
+
+export default {
+ props: {
+ beforeUpload: Function, // eslint-disable-line
+ onSuccess: Function// eslint-disable-line
+ },
+ data() {
+ return {
+ loading: false,
+ excelData: {
+ header: null,
+ results: null
+ }
+ }
+ },
+ methods: {
+ generateData({ header, results }) {
+ this.excelData.header = header
+ this.excelData.results = results
+ this.onSuccess && this.onSuccess(this.excelData)
+ },
+ handleDrop(e) {
+ e.stopPropagation()
+ e.preventDefault()
+ if (this.loading) return
+ const files = e.dataTransfer.files
+ if (files.length !== 1) {
+ this.$message.error('只支持单个文件上传!')
+ return
+ }
+ const rawFile = files[0]
+
+ if (!this.isExcel(rawFile)) {
+ this.$message.error('只支持.xlsx, .xls, .csv 格式文件')
+ return false
+ }
+ this.upload(rawFile)
+ e.stopPropagation()
+ e.preventDefault()
+ },
+ handleDragover(e) {
+ e.stopPropagation()
+ e.preventDefault()
+ e.dataTransfer.dropEffect = 'copy'
+ },
+ handleUpload() {
+ this.$refs['excel-upload-input'].click()
+ },
+ handleClick(e) {
+ const files = e.target.files
+ const rawFile = files[0] // only use files[0]
+ if (!rawFile) return
+ this.upload(rawFile)
+ },
+ upload(rawFile) {
+ this.$refs['excel-upload-input'].value = null // fix can't select the same excel
+
+ if (!this.beforeUpload) {
+ this.readerData(rawFile)
+ return
+ }
+ const before = this.beforeUpload(rawFile)
+ if (before) {
+ this.readerData(rawFile)
+ }
+ },
+ readerData(rawFile) {
+ this.loading = true
+ return new Promise((resolve, reject) => {
+ const reader = new FileReader()
+ reader.onload = e => {
+ const data = e.target.result
+ const workbook = XLSX.read(data, { type: 'array' })
+ const firstSheetName = workbook.SheetNames[0]
+ const worksheet = workbook.Sheets[firstSheetName]
+ const header = this.getHeaderRow(worksheet)
+ const results = XLSX.utils.sheet_to_json(worksheet)
+ this.generateData({ header, results })
+ this.loading = false
+ resolve()
+ }
+ reader.readAsArrayBuffer(rawFile)
+ })
+ },
+ getHeaderRow(sheet) {
+ const headers = []
+ const range = XLSX.utils.decode_range(sheet['!ref'])
+ let C
+ const R = range.s.r
+ /* start in the first row */
+ for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */
+ const cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })]
+ /* find the cell in the first row */
+ let hdr = 'UNKNOWN ' + C // <-- replace with your desired default
+ if (cell && cell.t) hdr = XLSX.utils.format_cell(cell)
+ headers.push(hdr)
+ }
+ return headers
+ },
+ isExcel(file) {
+ return /\.(xlsx|xls|csv)$/.test(file.name)
+ }
+ }
+}
+</script>
+
+<style scoped>
+.excel-upload-input{
+ display: none;
+ z-index: -9999;
+}
+.drop{
+ border: 2px dashed #bbb;
+ width: 600px;
+ height: 160px;
+ line-height: 160px;
+ margin: 0 auto;
+ font-size: 24px;
+ border-radius: 5px;
+ text-align: center;
+ color: #bbb;
+ position: relative;
+}
+</style>
diff --git a/UI source code/dns_mapping_ui-master/src/components/YamlEdit/index.vue b/UI source code/dns_mapping_ui-master/src/components/YamlEdit/index.vue
new file mode 100644
index 0000000..83778f4
--- /dev/null
+++ b/UI source code/dns_mapping_ui-master/src/components/YamlEdit/index.vue
@@ -0,0 +1,81 @@
+<template>
+ <div class="json-editor">
+ <textarea ref="textarea" />
+ </div>
+</template>
+
+<script>
+import CodeMirror from 'codemirror'
+import 'codemirror/lib/codemirror.css'
+// 替换主题这里需修改名称
+import 'codemirror/theme/idea.css'
+import 'codemirror/mode/yaml/yaml'
+export default {
+ props: {
+ value: {
+ type: String,
+ required: true
+ },
+ height: {
+ type: String,
+ required: true
+ }
+ },
+ data() {
+ return {
+ editor: false
+ }
+ },
+ watch: {
+ value(value) {
+ const editorValue = this.editor.getValue()
+ if (value !== editorValue) {
+ this.editor.setValue(this.value)
+ }
+ },
+ height(value) {
+ this.editor.setSize('auto', this.height)
+ }
+ },
+ mounted() {
+ this.editor = CodeMirror.fromTextArea(this.$refs.textarea, {
+ mode: 'text/x-yaml',
+ lineNumbers: true,
+ lint: true,
+ lineWrapping: true,
+ tabSize: 2,
+ cursorHeight: 0.9,
+ // 替换主题这里需修改名称
+ theme: 'idea'
+ })
+ this.editor.setSize('auto', this.height)
+ this.editor.setValue(this.value)
+ this.editor.on('change', cm => {
+ this.$emit('changed', cm.getValue())
+ this.$emit('input', cm.getValue())
+ })
+ },
+ methods: {
+ getValue() {
+ return this.editor.getValue()
+ }
+ }
+}
+</script>
+
+<style scoped>
+ .json-editor{
+ height: 100%;
+ margin-bottom: 10px;
+ }
+ .json-editor >>> .CodeMirror {
+ font-size: 13px;
+ overflow-y:auto;
+ font-weight:normal
+ }
+ .json-editor >>> .CodeMirror-scroll{
+ }
+ .json-editor >>> .cm-s-rubyblue span.cm-string {
+ color: #F08047;
+ }
+</style>