diff options
Diffstat (limited to 'UI source code/dns_mapping_ui-master/src/components')
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')" + > + <!--<!–:allow-create="true"–> 根据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> 0 </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> |
