feat(ui): remove unused code and unused files

This commit is contained in:
LH_R
2025-06-23 16:26:38 +08:00
parent e93d894f04
commit 6ec7caf5ea
27 changed files with 207 additions and 846 deletions

View File

@@ -5,14 +5,6 @@ if (IS_PROD) {
plugins.push('transform-remove-console')
}
// lazy load ant-design-vue
// if your use import on Demand, Use this code
// plugins.push(['import', {
// 'libraryName': 'ant-design-vue',
// 'libraryDirectory': 'es',
// 'style': true // `style: true` 会加载 less 文件
// }])
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset',

View File

@@ -2,7 +2,7 @@ const ThemeColorReplacer = require('webpack-theme-color-replacer')
const generate = require('@ant-design/colors/lib/generate').default
const getAntdSerials = (color) => {
// 淡化(即lesstint
// Lighten (similar to less's tint)
const lightens = new Array(9).fill().map((t, i) => {
return ThemeColorReplacer.varyColor.lighten(color, i / 10)
})
@@ -13,8 +13,8 @@ const getAntdSerials = (color) => {
const themePluginOption = {
fileName: 'css/theme-colors-[contenthash:8].css',
matchColors: getAntdSerials('#2f54eb'), // 主色系列
// 改变样式选择器,解决样式覆盖问题
matchColors: getAntdSerials('#2f54eb'), // primary color series
// change style selectors to solve style override issues
changeSelector (selector) {
switch (selector) {
case '.ant-calendar-today .ant-calendar-date':

View File

@@ -60,133 +60,7 @@ export default {
})
)
// 注册富文本自定义元素
// const resume = {
// type: 'attachment',
// attachmentLabel: '',
// attachmentValue: '',
// children: [{ text: '' }], // void 元素必须有一个 children 其中只有一个空字符串重要
// }
function withAttachment(editor) {
// JS 语法
const { isInline, isVoid } = editor
const newEditor = editor
newEditor.isInline = (elem) => {
const type = DomEditor.getNodeType(elem)
if (type === 'attachment') return true // 针对 type: attachment 设置为 inline
return isInline(elem)
}
newEditor.isVoid = (elem) => {
const type = DomEditor.getNodeType(elem)
if (type === 'attachment') return true // 针对 type: attachment 设置为 void
return isVoid(elem)
}
return newEditor // 返回 newEditor 重要
}
Boot.registerPlugin(withAttachment)
/**
* 渲染附件元素到编辑器
* @param elem 附件元素即上文的 myResume
* @param children 元素子节点void 元素可忽略
* @param editor 编辑器实例
* @returns vnode 节点通过 snabbdom.js h 函数生成
*/
function renderAttachment(elem, children, editor) {
// JS 语法
// 获取附件的数据参考上文 myResume 数据结构
const { attachmentLabel = '', attachmentValue = '' } = elem
// 附件元素 vnode
const attachVnode = h(
// HTML tag
'span',
// HTML 属性样式事件
{
props: { contentEditable: false }, // HTML 属性驼峰式写法
style: {
display: 'inline-block',
margin: '0 3px',
padding: '0 3px',
backgroundColor: '#e6f7ff',
border: '1px solid #91d5ff',
borderRadius: '2px',
color: '#1890ff',
}, // style 驼峰式写法
on: {
click() {
console.log('clicked', attachmentValue)
} /* 其他... */,
},
},
// 子节点
[attachmentLabel]
)
return attachVnode
}
const renderElemConf = {
type: 'attachment', // 新元素 type 重要
renderElem: renderAttachment,
}
Boot.registerRenderElem(renderElemConf)
/**
* 生成附件元素的 HTML
* @param elem 附件元素即上文的 myResume
* @param childrenHtml 子节点的 HTML 代码void 元素可忽略
* @returns 附件元素的 HTML 字符串
*/
function attachmentToHtml(elem, childrenHtml) {
// JS 语法
// 获取附件元素的数据
const { attachmentValue = '', attachmentLabel = '' } = elem
// 生成 HTML 代码
const html = `<span data-w-e-type="attachment" data-w-e-is-void data-w-e-is-inline data-attachmentValue="${attachmentValue}" data-attachmentLabel="${attachmentLabel}">${attachmentLabel}</span>`
return html
}
const elemToHtmlConf = {
type: 'attachment', // 新元素的 type 重要
elemToHtml: attachmentToHtml,
}
Boot.registerElemToHtml(elemToHtmlConf)
/**
* 解析 HTML 字符串生成附件元素
* @param domElem HTML 对应的 DOM Element
* @param children 子节点
* @param editor editor 实例
* @returns 附件元素如上文的 myResume
*/
function parseAttachmentHtml(domElem, children, editor) {
// JS 语法
// DOM element 中获取附件的信息
const attachmentValue = domElem.getAttribute('data-attachmentValue') || ''
const attachmentLabel = domElem.getAttribute('data-attachmentLabel') || ''
// 生成附件元素按照此前约定的数据结构
const myResume = {
type: 'attachment',
attachmentValue,
attachmentLabel,
children: [{ text: '' }], // void node 必须有 children 其中有一个空字符串重要
}
return myResume
}
const parseHtmlConf = {
selector: 'span[data-w-e-type="attachment"]', // CSS 选择器匹配特定的 HTML 标签
parseElemHtml: parseAttachmentHtml,
}
Boot.registerParseElemHtml(parseHtmlConf)
this.handleEditor()
},
beforeDestroy() {
clearInterval(this.timer)
@@ -221,6 +95,119 @@ export default {
}
this.SET_LOCALE(saveLocale)
this.$i18n.locale = saveLocale
},
handleEditor() {
// register custom rich text element: attachment
function withAttachment(editor) {
const { isInline, isVoid } = editor
const newEditor = editor
newEditor.isInline = (elem) => {
const type = DomEditor.getNodeType(elem)
if (type === 'attachment') return true // For type: attachment, set to inline
return isInline(elem)
}
newEditor.isVoid = (elem) => {
const type = DomEditor.getNodeType(elem)
if (type === 'attachment') return true // For type: attachment set to void
return isVoid(elem)
}
return newEditor // Must return, important!!!
}
Boot.registerPlugin(withAttachment)
/**
* Render "attachment" element in editor
* @param elem Attachment element
* @param children Child nodes (ignored for void elements)
* @param editor Editor instance
* @returns vnode (generated by snabbdom's h function)
*/
function renderAttachment(elem, children, editor) {
const { attachmentLabel = '', attachmentValue = '' } = elem
const attachVnode = h(
// HTML tag
'span',
// HTML attr, style, event
{
props: { contentEditable: false },
style: {
display: 'inline-block',
margin: '0 3px',
padding: '0 3px',
backgroundColor: '#e6f7ff',
border: '1px solid #91d5ff',
borderRadius: '2px',
color: '#1890ff',
},
on: {
click() {
console.log('clicked', attachmentValue)
}
},
},
// child node
[attachmentLabel]
)
return attachVnode
}
const renderElemConf = {
type: 'attachment',
renderElem: renderAttachment,
}
Boot.registerRenderElem(renderElemConf)
/**
* Generate HTML for "attachment" element
* @param elem Attachment element
* @param childrenHtml Child HTML (ignored for void elements)
* @returns HTML string
*/
function attachmentToHtml(elem, childrenHtml) {
// Getting data for attached elements
const { attachmentValue = '', attachmentLabel = '' } = elem
// generate HTML
const html = `<span data-w-e-type="attachment" data-w-e-is-void data-w-e-is-inline data-attachmentValue="${attachmentValue}" data-attachmentLabel="${attachmentLabel}">${attachmentLabel}</span>`
return html
}
const elemToHtmlConf = {
type: 'attachment',
elemToHtml: attachmentToHtml,
}
Boot.registerElemToHtml(elemToHtmlConf)
/**
* Parse HTML to generate "attachment" element
* @param domElem DOM element
* @param children Children
* @param editor Editor instance
* @returns Attachment element
*/
function parseAttachmentHtml(domElem, children, editor) {
// Getting attachment information from DOM element
const attachmentValue = domElem.getAttribute('data-attachmentValue') || ''
const attachmentLabel = domElem.getAttribute('data-attachmentLabel') || ''
const myResume = {
type: 'attachment',
attachmentValue,
attachmentLabel,
children: [{ text: '' }], // The void node must have children with an empty string in it, important!!!!
}
return myResume
}
const parseHtmlConf = {
selector: 'span[data-w-e-type="attachment"]', // CSS selector to match specific HTML tags
parseElemHtml: parseAttachmentHtml,
}
Boot.registerParseElemHtml(parseHtmlConf)
}
},
}

View File

@@ -4,7 +4,6 @@ export const ruleTypeList = () => {
return [
{ value: 'and', label: i18n.t('cmdbFilterComp.and') },
{ value: 'or', label: i18n.t('cmdbFilterComp.or') },
// { value: 'not', label: '非' },
]
}
@@ -18,7 +17,7 @@ export const expList = () => {
{ value: '~start_with', label: i18n.t('cmdbFilterComp.~start_with') },
{ value: 'end_with', label: i18n.t('cmdbFilterComp.end_with') },
{ value: '~end_with', label: i18n.t('cmdbFilterComp.~end_with') },
{ value: '~value', label: i18n.t('cmdbFilterComp.~value') }, // 为空的定义有点绕
{ value: '~value', label: i18n.t('cmdbFilterComp.~value') },
{ value: 'value', label: i18n.t('cmdbFilterComp.value') },
]
}

View File

@@ -301,7 +301,7 @@ export default {
return [
{ value: 'is', label: this.$t('cmdbFilterComp.is') },
{ value: '~is', label: this.$t('cmdbFilterComp.~is') },
{ value: '~value', label: this.$t('cmdbFilterComp.~value') }, // 为空的定义有点绕
{ value: '~value', label: this.$t('cmdbFilterComp.~value') },
{ value: 'value', label: this.$t('cmdbFilterComp.value') },
]
}

View File

@@ -87,8 +87,10 @@ export default {
},
methods: {
/**
* @param isInitOne When the initialization exp is null, does the ruleList default to giving one
*/
visibleChange(open, isInitOne = true) {
// isInitOne 初始化exp为空时ruleList是否默认给一条
// const regQ = /(?<=q=).+(?=&)|(?<=q=).+$/g
const exp = this.expression.match(new RegExp(this.regQ, 'g'))
? this.expression.match(new RegExp(this.regQ, 'g'))[0]
@@ -204,7 +206,7 @@ export default {
},
handleSubmit() {
if (this.ruleList && this.ruleList.length) {
this.ruleList[0].type = 'and' // 增删后以防万一第一个不是and
this.ruleList[0].type = 'and' // after add/delete, just in case the first one is not 'and'
this.filterExp = ''
const expList = this.ruleList.map((rule) => {
let singleRuleExp = ''

View File

@@ -14,7 +14,7 @@
<script>
/**
* 元素折叠过度效果
* Collapse transition effect for elements
*/
export default {
name: 'CollapseTransition',
@@ -33,20 +33,17 @@ export default {
},
methods: {
collapseBeforeEnter(el) {
// console.log('11, collapseBeforeEnter');
this.oldPaddingBottom = el.style.paddingBottom
this.oldPaddingTop = el.style.paddingTop
// 过渡效果开始前设置元素的maxHeight为0让元素maxHeight有一个初始值
// set the element's maxHeight to 0 before the transition effect starts so that the element's maxHeight has an initial value
el.style.paddingTop = '0'
el.style.paddingBottom = '0'
el.style.maxHeight = '0'
},
collapseEnter(el, done) {
// console.log('22, collapseEnter');
//
this.oldOverflow = el.style.overflow
const elHeight = el.scrollHeight
// 过渡效果进入后将元素的maxHeight设置为元素本身的高度将元素maxHeight设置为auto不会有过渡效果
// After entering, set maxHeight to the element's height; setting maxHeight to auto will not have a transition effect
if (elHeight > 0) {
el.style.maxHeight = elHeight + 'px'
} else {
@@ -59,24 +56,20 @@ export default {
// done();
const onTransitionDone = function() {
done()
// console.log('enter onTransitionDone');
el.removeEventListener('transitionend', onTransitionDone, false)
el.removeEventListener('transitioncancel', onTransitionDone, false)
}
// 绑定元素的transition完成事件在transition完成后立即完成vue的过度动效
// Bind transition end event to finish Vue's transition immediately after the CSS transition
el.addEventListener('transitionend', onTransitionDone, false)
el.addEventListener('transitioncancel', onTransitionDone, false)
},
collapseAfterEnter(el) {
// console.log('33, collapseAfterEnter');
// 过渡效果完成后恢复元素的maxHeight
// Restore maxHeight after transition is complete
el.style.maxHeight = ''
el.style.overflow = this.oldOverflow
},
collapseBeforeLeave(el) {
// console.log('44, collapseBeforeLeave', el.scrollHeight);
this.oldPaddingBottom = el.style.paddingBottom
this.oldPaddingTop = el.style.paddingTop
this.oldOverflow = el.style.overflow
@@ -85,8 +78,6 @@ export default {
el.style.overflow = 'hidden'
},
collapseLeave(el, done) {
// console.log('55, collapseLeave', el.scrollHeight);
if (el.scrollHeight !== 0) {
el.style.maxHeight = '0'
el.style.paddingBottom = '0'
@@ -95,16 +86,14 @@ export default {
// done();
const onTransitionDone = function() {
done()
// console.log('leave onTransitionDone');
el.removeEventListener('transitionend', onTransitionDone, false)
el.removeEventListener('transitioncancel', onTransitionDone, false)
}
// 绑定元素的transition完成事件在transition完成后立即完成vue的过度动效
// Bind transition end event to finish Vue's transition immediately after the CSS transition
el.addEventListener('transitionend', onTransitionDone, false)
el.addEventListener('transitioncancel', onTransitionDone, false)
},
collapseAfterLeave(el) {
// console.log('66, collapseAfterLeave');
el.style.maxHeight = ''
el.style.overflow = this.oldOverflow
el.style.paddingBottom = this.oldPaddingBottom

View File

@@ -1,9 +1,6 @@
/* eslint-disable */
/*
!!!!!!!
以下为凶残的cron表达式验证胆小肾虚及心脏病者慎入!!!
不听劝告者后果自负T T
!!!!!!!
cron表达式验证
cron表达式为秒
判断正误方法错误的话返回错误信息正确的话返回true
*/

View File

@@ -1,58 +0,0 @@
<template>
<div class="footer">
<div class="links">
<a
href="https://veops.cn/"
target="_blank"
>维易科技</a>
<a
href="https://github.com/sendya/ant-design-pro-vue"
target="_blank"
>
<a-icon type="github" />
</a>
</div>
<div class="copyright">
Copyright
<a-icon type="copyright" /> 2021-2023 <span>@维易科技</span>
</div>
</div>
</template>
<script>
export default {
name: 'GlobalFooter',
data () {
return {}
}
}
</script>
<style lang="less" scoped>
.footer {
padding: 0 16px;
margin: 48px 0 24px;
text-align: center;
.links {
margin-bottom: 8px;
a {
color: rgba(0, 0, 0, 0.45);
&:hover {
color: rgba(0, 0, 0, 0.65);
}
&:not(:last-child) {
margin-right: 40px;
}
}
}
.copyright {
color: rgba(0, 0, 0, 0.45);
font-size: 14px;
}
}
</style>

View File

@@ -1,2 +0,0 @@
import GlobalFooter from './GlobalFooter'
export default GlobalFooter

View File

@@ -1,10 +0,0 @@
import { Spin } from 'ant-design-vue'
export default {
name: 'PageLoading',
render () {
return (<div style={{ paddingTop: 100, textAlign: 'center' }}>
<Spin size="large" />
</div>)
}
}

View File

@@ -1,352 +0,0 @@
<template>
<div class="setting-drawer" ref="settingDrawer">
<a-drawer
width="300"
placement="right"
@close="onClose"
:closable="false"
:visible="visible"
>
<div class="setting-drawer-index-content">
<div :style="{ marginBottom: '24px' }">
<h3 class="setting-drawer-index-title">整体风格设置</h3>
<div class="setting-drawer-index-blockChecbox">
<a-tooltip>
<template slot="title">
暗色菜单风格
</template>
<div class="setting-drawer-index-item" @click="handleMenuTheme('dark')">
<img src="https://gw.alipayobjects.com/zos/rmsportal/LCkqqYNmvBEbokSDscrm.svg" alt="dark">
<div class="setting-drawer-index-selectIcon" v-if="navTheme === 'dark'">
<a-icon type="check"/>
</div>
</div>
</a-tooltip>
<a-tooltip>
<template slot="title">
亮色菜单风格
</template>
<div class="setting-drawer-index-item" @click="handleMenuTheme('light')">
<img src="https://gw.alipayobjects.com/zos/rmsportal/jpRkZQMyYRryryPNtyIC.svg" alt="light">
<div class="setting-drawer-index-selectIcon" v-if="navTheme !== 'dark'">
<a-icon type="check"/>
</div>
</div>
</a-tooltip>
</div>
</div>
<div :style="{ marginBottom: '24px' }">
<h3 class="setting-drawer-index-title">主题色</h3>
<div style="height: 20px">
<a-tooltip class="setting-drawer-theme-color-colorBlock" v-for="(item, index) in colorList" :key="index">
<template slot="title">
{{ item.key }}
</template>
<a-tag :color="item.color" @click="changeColor(item.color)">
<a-icon type="check" v-if="item.color === primaryColor"></a-icon>
</a-tag>
</a-tooltip>
</div>
</div>
<a-divider />
<div :style="{ marginBottom: '24px' }">
<h3 class="setting-drawer-index-title">导航模式</h3>
<div class="setting-drawer-index-blockChecbox">
<a-tooltip>
<template slot="title">
侧边栏导航
</template>
<div class="setting-drawer-index-item" @click="handleLayout('sidemenu')">
<img src="https://gw.alipayobjects.com/zos/rmsportal/JopDzEhOqwOjeNTXkoje.svg" alt="sidemenu">
<div class="setting-drawer-index-selectIcon" v-if="layoutMode === 'sidemenu'">
<a-icon type="check"/>
</div>
</div>
</a-tooltip>
<a-tooltip>
<template slot="title">
顶部栏导航
</template>
<div class="setting-drawer-index-item" @click="handleLayout('topmenu')">
<img src="https://gw.alipayobjects.com/zos/rmsportal/KDNDBbriJhLwuqMoxcAr.svg" alt="topmenu">
<div class="setting-drawer-index-selectIcon" v-if="layoutMode !== 'sidemenu'">
<a-icon type="check"/>
</div>
</div>
</a-tooltip>
</div>
<div :style="{ marginTop: '24px' }">
<a-list :split="false">
<a-list-item>
<a-tooltip slot="actions">
<template slot="title">
该设定仅 [顶部栏导航] 时有效
</template>
<a-select size="small" style="width: 80px;" :defaultValue="contentWidth" @change="handleContentWidthChange">
<a-select-option value="Fixed">固定</a-select-option>
<a-select-option value="Fluid" v-if="layoutMode !== 'sidemenu'">流式</a-select-option>
</a-select>
</a-tooltip>
<a-list-item-meta>
<div slot="title">内容区域宽度</div>
</a-list-item-meta>
</a-list-item>
<a-list-item>
<a-switch slot="actions" size="small" :defaultChecked="fixedHeader" @change="handleFixedHeader" />
<a-list-item-meta>
<div slot="title">固定 Header</div>
</a-list-item-meta>
</a-list-item>
<a-list-item>
<a-switch slot="actions" size="small" :disabled="!fixedHeader" :defaultChecked="autoHideHeader" @change="handleFixedHeaderHidden" />
<a-list-item-meta>
<a-tooltip slot="title" placement="left">
<template slot="title">固定 Header 时可配置</template>
<div :style="{ opacity: !fixedHeader ? '0.5' : '1' }">下滑时隐藏 Header</div>
</a-tooltip>
</a-list-item-meta>
</a-list-item>
<a-list-item >
<a-switch slot="actions" size="small" :disabled="(layoutMode === 'topmenu')" :defaultChecked="fixSiderbar" @change="handleFixSiderbar" />
<a-list-item-meta>
<div slot="title" :style="{ textDecoration: layoutMode === 'topmenu' ? 'line-through' : 'unset' }">固定侧边菜单</div>
</a-list-item-meta>
</a-list-item>
</a-list>
</div>
</div>
<a-divider />
<div :style="{ marginBottom: '24px' }">
<h3 class="setting-drawer-index-title">其他设置</h3>
<div>
<a-list :split="false">
<a-list-item>
<a-switch slot="actions" size="small" :defaultChecked="colorWeak" @change="onColorWeak" />
<a-list-item-meta>
<div slot="title">色弱模式</div>
</a-list-item-meta>
</a-list-item>
<a-list-item>
<a-switch slot="actions" size="small" :defaultChecked="multiTab" @change="onMultiTab" />
<a-list-item-meta>
<div slot="title">多页签模式</div>
</a-list-item-meta>
</a-list-item>
</a-list>
</div>
</div>
<a-divider />
<div :style="{ marginBottom: '24px' }">
<a-button
@click="doCopy"
icon="copy"
block
>拷贝设置</a-button>
<a-alert type="warning" :style="{ marginTop: '24px' }">
<span slot="message">
配置栏只在开发环境用于预览生产环境不会展现请手动修改配置文件
<a href="https://github.com/sendya/ant-design-pro-vue/blob/master/src/config/setting.js" target="_blank">src/config/setting.js</a>
</span>
</a-alert>
</div>
</div>
<div class="setting-drawer-index-handle" @click="toggle">
<a-icon type="setting" v-if="!visible"/>
<a-icon type="close" v-else/>
</div>
</a-drawer>
</div>
</template>
<script>
import SettingItem from './SettingItem'
import config from '@/config/setting'
import { updateTheme, updateColorWeak, colorList } from './settingConfig'
import { mixin, mixinDevice } from '@/utils/mixin'
export default {
components: {
SettingItem
},
mixins: [mixin, mixinDevice],
data () {
return {
visible: true,
colorList
}
},
watch: {
},
mounted () {
const vm = this
setTimeout(() => {
vm.visible = false
}, 16)
updateTheme(this.primaryColor)
if (this.colorWeak !== config.colorWeak) {
updateColorWeak(this.colorWeak)
}
},
methods: {
showDrawer () {
this.visible = true
},
onClose () {
this.visible = false
},
toggle () {
this.visible = !this.visible
},
onColorWeak (checked) {
this.$store.dispatch('ToggleWeak', checked)
updateColorWeak(checked)
},
onMultiTab (checked) {
this.$store.dispatch('ToggleMultiTab', checked)
},
handleMenuTheme (theme) {
this.$store.dispatch('ToggleTheme', theme)
},
doCopy () {
// get current settings from mixin or this.$store.state.app, pay attention to the property name
const text = `export default {
primaryColor: '${this.primaryColor}', // primary color of ant design
navTheme: '${this.navTheme}', // theme for nav menu
layout: '${this.layoutMode}', // nav menu position: sidemenu or topmenu
contentWidth: '${this.contentWidth}', // layout of content: Fluid or Fixed, only works when layout is topmenu
fixedHeader: ${this.fixedHeader}, // sticky header
fixSiderbar: ${this.fixSiderbar}, // sticky siderbar
autoHideHeader: ${this.autoHideHeader}, // auto hide header
colorWeak: ${this.colorWeak},
multiTab: ${this.multiTab},
production: process.env.NODE_ENV === 'production' && process.env.VUE_APP_PREVIEW !== 'true',
// vue-ls options
storageOptions: {
namespace: 'pro__',
name: 'ls',
storage: 'local',
}
}`
this.$copyText(text).then(message => {
console.log('copy', message)
this.$message.success('复制完毕')
}).catch(err => {
console.log('copy.err', err)
this.$message.error('复制失败')
})
},
handleLayout (mode) {
this.$store.dispatch('ToggleLayoutMode', mode)
// 因为顶部菜单不能固定左侧菜单栏所以强制关闭
this.handleFixSiderbar(false)
},
handleContentWidthChange (type) {
this.$store.dispatch('ToggleContentWidth', type)
},
changeColor (color) {
if (this.primaryColor !== color) {
this.$store.dispatch('ToggleColor', color)
updateTheme(color)
}
},
handleFixedHeader (fixed) {
this.$store.dispatch('ToggleFixedHeader', fixed)
},
handleFixedHeaderHidden (autoHidden) {
this.$store.dispatch('ToggleFixedHeaderHidden', autoHidden)
},
handleFixSiderbar (fixed) {
if (this.layoutMode === 'topmenu') {
this.$store.dispatch('ToggleFixSiderbar', false)
return
}
this.$store.dispatch('ToggleFixSiderbar', fixed)
}
}
}
</script>
<style lang="less" scoped>
.setting-drawer-index-content {
.setting-drawer-index-blockChecbox {
display: flex;
.setting-drawer-index-item {
margin-right: 16px;
position: relative;
border-radius: 4px;
cursor: pointer;
img {
width: 48px;
}
.setting-drawer-index-selectIcon {
position: absolute;
top: 0;
right: 0;
width: 100%;
padding-top: 15px;
padding-left: 24px;
height: 100%;
color: #1890ff;
font-size: 14px;
font-weight: 700;
}
}
}
.setting-drawer-theme-color-colorBlock {
width: 20px;
height: 20px;
border-radius: 2px;
float: left;
cursor: pointer;
margin-right: 8px;
padding-left: 0px;
padding-right: 0px;
text-align: center;
color: #fff;
font-weight: 700;
i {
font-size: 14px;
}
}
}
.setting-drawer-index-handle {
position: absolute;
top: 240px;
background: #1890ff;
width: 48px;
height: 48px;
right: 300px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
pointer-events: auto;
z-index: 1001;
text-align: center;
font-size: 16px;
border-radius: 4px 0 0 4px;
i {
color: rgb(255, 255, 255);
font-size: 20px;
}
}
</style>

View File

@@ -1,38 +0,0 @@
<template>
<div class="setting-drawer-index-item">
<h3 class="setting-drawer-index-title">{{ title }}</h3>
<slot></slot>
<a-divider v-if="divider"/>
</div>
</template>
<script>
export default {
name: 'SettingItem',
props: {
title: {
type: String,
default: ''
},
divider: {
type: Boolean,
default: false
}
}
}
</script>
<style lang="less" scoped>
.setting-drawer-index-item {
margin-bottom: 24px;
.setting-drawer-index-title {
font-size: 14px;
color: rgba(0, 0, 0, .85);
line-height: 22px;
margin-bottom: 12px;
}
}
</style>

View File

@@ -1,2 +0,0 @@
import SettingDrawer from './SettingDrawer'
export default SettingDrawer

View File

@@ -1,105 +0,0 @@
import { message } from 'ant-design-vue/es'
// import setting from '../setting';
import themeColor from './themeColor.js'
// let lessNodesAppended
const colorList = [
{
key: '薄暮', color: '#F5222D'
},
{
key: '火山', color: '#FA541C'
},
{
key: '日暮', color: '#FAAD14'
},
{
key: '明青', color: '#13C2C2'
},
{
key: '极光绿', color: '#52C41A'
},
{
key: '拂晓蓝(默认)', color: '#1890FF'
},
{
key: '极客蓝', color: '#2F54EB'
},
{
key: '酱紫', color: '#722ED1'
}
]
const updateTheme = newPrimaryColor => {
const hideMessage = message.loading('正在切换主题!', 0)
themeColor.changeColor(newPrimaryColor).finally(t => {
hideMessage()
})
}
/*
const updateTheme = primaryColor => {
// Don't compile less in production!
/* if (process.env.NODE_ENV === 'production') {
return;
} * /
// Determine if the component is remounted
if (!primaryColor) {
return
}
const hideMessage = message.loading('正在编译主题!', 0)
function buildIt () {
if (!window.less) {
return
}
setTimeout(() => {
window.less
.modifyVars({
'@primary-color': primaryColor
})
.then(() => {
hideMessage()
})
.catch(() => {
message.error('Failed to update theme')
hideMessage()
})
}, 200)
}
if (!lessNodesAppended) {
// insert less.js and color.less
const lessStyleNode = document.createElement('link')
const lessConfigNode = document.createElement('script')
const lessScriptNode = document.createElement('script')
lessStyleNode.setAttribute('rel', 'stylesheet/less')
lessStyleNode.setAttribute('href', '/color.less')
lessConfigNode.innerHTML = `
window.less = {
async: true,
env: 'production',
javascriptEnabled: true
};
`
lessScriptNode.src = 'https://gw.alipayobjects.com/os/lib/less.js/3.8.1/less.min.js'
lessScriptNode.async = true
lessScriptNode.onload = () => {
buildIt()
lessScriptNode.onload = null
}
document.body.appendChild(lessStyleNode)
document.body.appendChild(lessConfigNode)
document.body.appendChild(lessScriptNode)
lessNodesAppended = true
} else {
buildIt()
}
}
*/
const updateColorWeak = colorWeak => {
// document.body.className = colorWeak ? 'colorWeak' : '';
colorWeak ? document.body.classList.add('colorWeak') : document.body.classList.remove('colorWeak')
}
export { updateTheme, colorList, updateColorWeak }

View File

@@ -1,23 +0,0 @@
import client from 'webpack-theme-color-replacer/client'
import generate from '@ant-design/colors/lib/generate'
export default {
getAntdSerials (color) {
// 淡化即less的tint
const lightens = new Array(9).fill().map((t, i) => {
return client.varyColor.lighten(color, i / 10)
})
// colorPalette变换得到颜色值
const colorPalettes = generate(color)
return lightens.concat(colorPalettes)
},
changeColor (newColor) {
var options = {
newColors: this.getAntdSerials(newColor), // new colors array, one-to-one corresponde with `matchColors`
changeUrl (cssUrl) {
return `/${cssUrl}` // while router is not `hash` mode, it needs absolute path
}
}
return client.changer.changeColor(options, Promise)
}
}

View File

@@ -1,6 +1,6 @@
<template>
<a-tooltip>
<template slot="title">文档中心</template>
<template slot="title">{{ $t('documentCenter') }}</template>
<span class="document-link">
<a-icon type="question-circle" @click="handleClick" />
</span>

View File

@@ -1,4 +1,3 @@
/* eslint-disable */
import Vue from 'vue'
import router from './router'
import store from './store'
@@ -11,16 +10,23 @@ import i18n from '@/lang'
NProgress.configure({ showSpinner: false })
// 不用认证的页面
const whitePath = ['/user/login', '/user/logout', '/user/register', '/api/sso/login', '/api/sso/logout', '/user/forgetPassword']
// pages that do not require authentication
const whitePath = [
'/user/login',
'/user/logout',
'/user/register',
'/api/sso/login',
'/api/sso/logout',
'/user/forgetPassword'
]
// 此处不处理登录, 只处理 是否有用户信息的认证 前端permission的处理 axios处理401 -> 登录
// 登录页面处理处理 是否使用单点登录
// Only handle user info authentication here, not login logic.
// Frontend permission handling; axios handles 401 -> login.
// Login page handles whether to use SSO.
router.beforeEach(async (to, from, next) => {
NProgress.start() // start progress bar
to.meta && (!!to.meta.title && setDocumentTitle(`${i18n.t(to.meta.title)} - ${domTitle}`))
const authed = store.state.authed
const auth_type = localStorage.getItem('ops_auth_type')
if (whitePath.includes(to.path)) {
next()
@@ -28,17 +34,17 @@ router.beforeEach(async (to, from, next) => {
store.dispatch('GetAuthDataEnable')
store.dispatch('GetInfo').then(res => {
const roles = res.result && res.result.role
store.dispatch("loadAllUsers")
store.dispatch("loadAllEmployees")
store.dispatch("loadAllDepartments")
store.dispatch('loadAllUsers')
store.dispatch('loadAllEmployees')
store.dispatch('loadAllDepartments')
store.dispatch('GenerateRoutes', { roles }).then(() => {
router.addRoutes(store.getters.appRoutes)
const redirect = decodeURIComponent(from.query.redirect || to.path)
if (to.path === redirect) {
// hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
// Ensure addRoutes is complete, set replace: true so navigation will not leave a history record
next({ ...to, replace: true })
} else {
// 跳转到目的路由
// Redirect to the target route
next({ path: redirect })
}
})

View File

@@ -109,6 +109,10 @@ export default {
default: 'default',
tip: 'Tip',
cmdbSearch: 'Search',
requestError: 'An error occurred, please try again later',
requestServiceError: 'Unknown error on the server, please contact the administrator',
requestWait: 'The modification has been submitted, please wait for review ({time} seconds)',
documentCenter: 'Document Center',
exception: {
backToHome: 'Back to home page',
desc1: 'Sorry, you are not authorized to access this page',

View File

@@ -109,6 +109,10 @@ export default {
default: '默认',
tip: '提示',
cmdbSearch: '搜索一下',
requestError: '出现错误,请稍后再试',
requestServiceError: '服务端未知错误, 请联系管理员!',
requestWait: '修改已提交,请等待审核({time}s',
documentCenter: '文档中心',
exception: {
backToHome: '返回首页',
desc1: '抱歉,你无权访问该页面',

View File

@@ -63,8 +63,6 @@ import RouteView from './RouteView'
import MultiTab from '@/components/MultiTab'
import SideMenu from '@/components/Menu/SideMenu'
import GlobalHeader from '@/components/GlobalHeader'
import GlobalFooter from '@/components/GlobalFooter'
import SettingDrawer from '@/components/SettingDrawer'
export default {
name: 'BasicLayout',
@@ -74,8 +72,6 @@ export default {
MultiTab,
SideMenu,
GlobalHeader,
GlobalFooter,
SettingDrawer,
},
data() {
return {

View File

@@ -1,4 +1,3 @@
/* eslint-disable */
import '@babel/polyfill'
import Vue from 'vue'
import App from './App.vue'
@@ -14,10 +13,9 @@ import i18n from './lang'
import iconFont from '../public/iconfont/iconfont'
// 存在直接crash的风险 还未到
const customIcon = Icon.createFromIconfontCN(iconFont)
Vue.component('ops-icon', customIcon)
var vue;
var vue
async function start() {
const _vue = new Vue({

View File

@@ -1,4 +1,3 @@
/* eslint-disable */
import { UserLayout, BasicLayout, RouteView } from '@/layouts'
import appConfig from '@/config/app'
import { getAppAclRouter } from './utils'
@@ -7,7 +6,7 @@ import store from '../store'
export const generatorDynamicRouter = async () => {
const packages = []
const { apps = undefined } = store.getters.userInfo
for (let appName of appConfig.buildModules) {
for (const appName of appConfig.buildModules) {
if (!apps || !apps.length || apps.includes(appName)) {
const module = await import(`@/modules/${appName}/index.js`)
const r = await module.default.route()

View File

@@ -1,4 +1,3 @@
/* eslint-disable */
import Vue from 'vue'
import Router from 'vue-router'
import { constantRouterMap } from '@/router/config'

View File

@@ -1,5 +1,3 @@
/* eslint-disable */
import Vue from 'vue'
import Vuex from 'vuex'
import app from './global/app'

View File

@@ -1,10 +1,8 @@
/* eslint-disable */
export function intersection(thisSet, otherSet) {
// 初始化一个新集合,用于表示交集。
var interSectionSet = new Set()
var values = Array.from(thisSet)
for (var i = 0; i < values.length; i++) {
if (otherSet.has(values[i])) {
interSectionSet.add(values[i])
}
@@ -20,8 +18,8 @@ export function union(thisSet, otherSet) {
unionSet.add(values[i])
}
values = Array.from(otherSet)
for (var i = 0; i < values.length; i++) {
unionSet.add(values[i])
for (var j = 0; j < values.length; j++) {
unionSet.add(values[j])
}
return unionSet
@@ -31,7 +29,6 @@ export function difference(thisSet, otherSet) {
var differenceSet = new Set()
var values = Array.from(thisSet)
for (var i = 0; i < values.length; i++) {
if (!otherSet.has(values[i])) {
differenceSet.add(values[i])
}

View File

@@ -14,12 +14,11 @@ module.exports = {
plugins: [
// Ignore all locale files of moment.js
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
// 生成仅包含颜色的替换样式(主题色等)
// TODO 需要增加根据环境不开启主题需求
// generate theme color replacement styles
new ThemeColorReplacer({
fileName: 'css/theme-colors-[contenthash:8].css',
matchColors: getAntdSerials('#2f54eb'), // 主色系列
// 改变样式选择器,解决样式覆盖问题
matchColors: getAntdSerials('#2f54eb'), // primary color series
// change style selectors to solve style override issues
changeSelector(selector) {
switch (selector) {
case '.ant-calendar-today .ant-calendar-date':
@@ -63,29 +62,14 @@ module.exports = {
.options({
name: 'assets/[name].[hash:8].[ext]',
})
/* svgRule.oneOf('inline')
.resourceQuery(/inline/)
.use('vue-svg-loader')
.loader('vue-svg-loader')
.end()
.end()
.oneOf('external')
.use('file-loader')
.loader('file-loader')
.options({
name: 'assets/[name].[hash:8].[ext]'
})
*/
},
css: {
loaderOptions: {
less: {
modifyVars: {
/* less 变量覆盖,用于自定义 ant design 主题 */
// override less variables for custom ant design theme
'primary-color': '#2f54eb',
// 'link-color': '#F5222D',
// 'border-radius-base': '4px',
},
javascriptEnabled: true,
},
@@ -119,7 +103,7 @@ module.exports = {
}
function getAntdSerials(color) {
// 淡化(即lesstint
// Lighten (similar to less's tint)
const lightens = new Array(9).fill().map((t, i) => {
return ThemeColorReplacer.varyColor.lighten(color, i / 10)
})