mirror of
https://github.com/veops/cmdb.git
synced 2025-08-25 20:09:00 +08:00
feat(ui): remove unused code and unused files
This commit is contained in:
@@ -5,14 +5,6 @@ if (IS_PROD) {
|
|||||||
plugins.push('transform-remove-console')
|
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 = {
|
module.exports = {
|
||||||
presets: [
|
presets: [
|
||||||
'@vue/cli-plugin-babel/preset',
|
'@vue/cli-plugin-babel/preset',
|
||||||
|
@@ -2,7 +2,7 @@ const ThemeColorReplacer = require('webpack-theme-color-replacer')
|
|||||||
const generate = require('@ant-design/colors/lib/generate').default
|
const generate = require('@ant-design/colors/lib/generate').default
|
||||||
|
|
||||||
const getAntdSerials = (color) => {
|
const getAntdSerials = (color) => {
|
||||||
// 淡化(即less的tint)
|
// Lighten (similar to less's tint)
|
||||||
const lightens = new Array(9).fill().map((t, i) => {
|
const lightens = new Array(9).fill().map((t, i) => {
|
||||||
return ThemeColorReplacer.varyColor.lighten(color, i / 10)
|
return ThemeColorReplacer.varyColor.lighten(color, i / 10)
|
||||||
})
|
})
|
||||||
@@ -13,8 +13,8 @@ const getAntdSerials = (color) => {
|
|||||||
|
|
||||||
const themePluginOption = {
|
const themePluginOption = {
|
||||||
fileName: 'css/theme-colors-[contenthash:8].css',
|
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) {
|
changeSelector (selector) {
|
||||||
switch (selector) {
|
switch (selector) {
|
||||||
case '.ant-calendar-today .ant-calendar-date':
|
case '.ant-calendar-today .ant-calendar-date':
|
||||||
|
@@ -60,133 +60,7 @@ export default {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
// 注册富文本自定义元素
|
this.handleEditor()
|
||||||
// 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)
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
clearInterval(this.timer)
|
clearInterval(this.timer)
|
||||||
@@ -221,6 +95,119 @@ export default {
|
|||||||
}
|
}
|
||||||
this.SET_LOCALE(saveLocale)
|
this.SET_LOCALE(saveLocale)
|
||||||
this.$i18n.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)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@@ -4,7 +4,6 @@ export const ruleTypeList = () => {
|
|||||||
return [
|
return [
|
||||||
{ value: 'and', label: i18n.t('cmdbFilterComp.and') },
|
{ value: 'and', label: i18n.t('cmdbFilterComp.and') },
|
||||||
{ value: 'or', label: i18n.t('cmdbFilterComp.or') },
|
{ 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: '~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: '~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') },
|
{ value: 'value', label: i18n.t('cmdbFilterComp.value') },
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@@ -301,7 +301,7 @@ export default {
|
|||||||
return [
|
return [
|
||||||
{ value: 'is', label: this.$t('cmdbFilterComp.is') },
|
{ value: 'is', label: this.$t('cmdbFilterComp.is') },
|
||||||
{ 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') },
|
{ value: 'value', label: this.$t('cmdbFilterComp.value') },
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@@ -87,8 +87,10 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
/**
|
||||||
|
* @param isInitOne When the initialization exp is null, does the ruleList default to giving one
|
||||||
|
*/
|
||||||
visibleChange(open, isInitOne = true) {
|
visibleChange(open, isInitOne = true) {
|
||||||
// isInitOne 初始化exp为空时,ruleList是否默认给一条
|
|
||||||
// const regQ = /(?<=q=).+(?=&)|(?<=q=).+$/g
|
// const regQ = /(?<=q=).+(?=&)|(?<=q=).+$/g
|
||||||
const exp = this.expression.match(new RegExp(this.regQ, 'g'))
|
const exp = this.expression.match(new RegExp(this.regQ, 'g'))
|
||||||
? this.expression.match(new RegExp(this.regQ, 'g'))[0]
|
? this.expression.match(new RegExp(this.regQ, 'g'))[0]
|
||||||
@@ -204,7 +206,7 @@ export default {
|
|||||||
},
|
},
|
||||||
handleSubmit() {
|
handleSubmit() {
|
||||||
if (this.ruleList && this.ruleList.length) {
|
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 = ''
|
this.filterExp = ''
|
||||||
const expList = this.ruleList.map((rule) => {
|
const expList = this.ruleList.map((rule) => {
|
||||||
let singleRuleExp = ''
|
let singleRuleExp = ''
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
/**
|
/**
|
||||||
* 元素折叠过度效果
|
* Collapse transition effect for elements
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
name: 'CollapseTransition',
|
name: 'CollapseTransition',
|
||||||
@@ -33,20 +33,17 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
collapseBeforeEnter(el) {
|
collapseBeforeEnter(el) {
|
||||||
// console.log('11, collapseBeforeEnter');
|
|
||||||
this.oldPaddingBottom = el.style.paddingBottom
|
this.oldPaddingBottom = el.style.paddingBottom
|
||||||
this.oldPaddingTop = el.style.paddingTop
|
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.paddingTop = '0'
|
||||||
el.style.paddingBottom = '0'
|
el.style.paddingBottom = '0'
|
||||||
el.style.maxHeight = '0'
|
el.style.maxHeight = '0'
|
||||||
},
|
},
|
||||||
collapseEnter(el, done) {
|
collapseEnter(el, done) {
|
||||||
// console.log('22, collapseEnter');
|
|
||||||
//
|
|
||||||
this.oldOverflow = el.style.overflow
|
this.oldOverflow = el.style.overflow
|
||||||
const elHeight = el.scrollHeight
|
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) {
|
if (elHeight > 0) {
|
||||||
el.style.maxHeight = elHeight + 'px'
|
el.style.maxHeight = elHeight + 'px'
|
||||||
} else {
|
} else {
|
||||||
@@ -59,24 +56,20 @@ export default {
|
|||||||
// done();
|
// done();
|
||||||
const onTransitionDone = function() {
|
const onTransitionDone = function() {
|
||||||
done()
|
done()
|
||||||
// console.log('enter onTransitionDone');
|
|
||||||
el.removeEventListener('transitionend', onTransitionDone, false)
|
el.removeEventListener('transitionend', onTransitionDone, false)
|
||||||
el.removeEventListener('transitioncancel', 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('transitionend', onTransitionDone, false)
|
||||||
el.addEventListener('transitioncancel', onTransitionDone, false)
|
el.addEventListener('transitioncancel', onTransitionDone, false)
|
||||||
},
|
},
|
||||||
collapseAfterEnter(el) {
|
collapseAfterEnter(el) {
|
||||||
// console.log('33, collapseAfterEnter');
|
// Restore maxHeight after transition is complete
|
||||||
// 过渡效果完成后恢复元素的maxHeight
|
|
||||||
el.style.maxHeight = ''
|
el.style.maxHeight = ''
|
||||||
el.style.overflow = this.oldOverflow
|
el.style.overflow = this.oldOverflow
|
||||||
},
|
},
|
||||||
|
|
||||||
collapseBeforeLeave(el) {
|
collapseBeforeLeave(el) {
|
||||||
// console.log('44, collapseBeforeLeave', el.scrollHeight);
|
|
||||||
|
|
||||||
this.oldPaddingBottom = el.style.paddingBottom
|
this.oldPaddingBottom = el.style.paddingBottom
|
||||||
this.oldPaddingTop = el.style.paddingTop
|
this.oldPaddingTop = el.style.paddingTop
|
||||||
this.oldOverflow = el.style.overflow
|
this.oldOverflow = el.style.overflow
|
||||||
@@ -85,8 +78,6 @@ export default {
|
|||||||
el.style.overflow = 'hidden'
|
el.style.overflow = 'hidden'
|
||||||
},
|
},
|
||||||
collapseLeave(el, done) {
|
collapseLeave(el, done) {
|
||||||
// console.log('55, collapseLeave', el.scrollHeight);
|
|
||||||
|
|
||||||
if (el.scrollHeight !== 0) {
|
if (el.scrollHeight !== 0) {
|
||||||
el.style.maxHeight = '0'
|
el.style.maxHeight = '0'
|
||||||
el.style.paddingBottom = '0'
|
el.style.paddingBottom = '0'
|
||||||
@@ -95,16 +86,14 @@ export default {
|
|||||||
// done();
|
// done();
|
||||||
const onTransitionDone = function() {
|
const onTransitionDone = function() {
|
||||||
done()
|
done()
|
||||||
// console.log('leave onTransitionDone');
|
|
||||||
el.removeEventListener('transitionend', onTransitionDone, false)
|
el.removeEventListener('transitionend', onTransitionDone, false)
|
||||||
el.removeEventListener('transitioncancel', 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('transitionend', onTransitionDone, false)
|
||||||
el.addEventListener('transitioncancel', onTransitionDone, false)
|
el.addEventListener('transitioncancel', onTransitionDone, false)
|
||||||
},
|
},
|
||||||
collapseAfterLeave(el) {
|
collapseAfterLeave(el) {
|
||||||
// console.log('66, collapseAfterLeave');
|
|
||||||
el.style.maxHeight = ''
|
el.style.maxHeight = ''
|
||||||
el.style.overflow = this.oldOverflow
|
el.style.overflow = this.oldOverflow
|
||||||
el.style.paddingBottom = this.oldPaddingBottom
|
el.style.paddingBottom = this.oldPaddingBottom
|
||||||
|
@@ -1,9 +1,6 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
/*
|
/*
|
||||||
!!!!!!!
|
cron表达式验证
|
||||||
以下为凶残的cron表达式验证,胆小肾虚及心脏病者慎入!!!
|
|
||||||
不听劝告者后果自负T T
|
|
||||||
!!!!!!!
|
|
||||||
cron表达式为秒,分,时,日,月,周,年
|
cron表达式为秒,分,时,日,月,周,年
|
||||||
判断正误方法:错误的话返回错误信息,正确的话返回true
|
判断正误方法:错误的话返回错误信息,正确的话返回true
|
||||||
*/
|
*/
|
||||||
|
@@ -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>
|
|
@@ -1,2 +0,0 @@
|
|||||||
import GlobalFooter from './GlobalFooter'
|
|
||||||
export default GlobalFooter
|
|
@@ -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>)
|
|
||||||
}
|
|
||||||
}
|
|
@@ -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>
|
|
@@ -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>
|
|
@@ -1,2 +0,0 @@
|
|||||||
import SettingDrawer from './SettingDrawer'
|
|
||||||
export default SettingDrawer
|
|
@@ -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 }
|
|
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template slot="title">文档中心</template>
|
<template slot="title">{{ $t('documentCenter') }}</template>
|
||||||
<span class="document-link">
|
<span class="document-link">
|
||||||
<a-icon type="question-circle" @click="handleClick" />
|
<a-icon type="question-circle" @click="handleClick" />
|
||||||
</span>
|
</span>
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable */
|
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import router from './router'
|
import router from './router'
|
||||||
import store from './store'
|
import store from './store'
|
||||||
@@ -11,16 +10,23 @@ import i18n from '@/lang'
|
|||||||
|
|
||||||
NProgress.configure({ showSpinner: false })
|
NProgress.configure({ showSpinner: false })
|
||||||
|
|
||||||
// 不用认证的页面
|
// pages that do not require authentication
|
||||||
const whitePath = ['/user/login', '/user/logout', '/user/register', '/api/sso/login', '/api/sso/logout', '/user/forgetPassword']
|
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) => {
|
router.beforeEach(async (to, from, next) => {
|
||||||
NProgress.start() // start progress bar
|
NProgress.start() // start progress bar
|
||||||
to.meta && (!!to.meta.title && setDocumentTitle(`${i18n.t(to.meta.title)} - ${domTitle}`))
|
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')
|
const auth_type = localStorage.getItem('ops_auth_type')
|
||||||
if (whitePath.includes(to.path)) {
|
if (whitePath.includes(to.path)) {
|
||||||
next()
|
next()
|
||||||
@@ -28,17 +34,17 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
store.dispatch('GetAuthDataEnable')
|
store.dispatch('GetAuthDataEnable')
|
||||||
store.dispatch('GetInfo').then(res => {
|
store.dispatch('GetInfo').then(res => {
|
||||||
const roles = res.result && res.result.role
|
const roles = res.result && res.result.role
|
||||||
store.dispatch("loadAllUsers")
|
store.dispatch('loadAllUsers')
|
||||||
store.dispatch("loadAllEmployees")
|
store.dispatch('loadAllEmployees')
|
||||||
store.dispatch("loadAllDepartments")
|
store.dispatch('loadAllDepartments')
|
||||||
store.dispatch('GenerateRoutes', { roles }).then(() => {
|
store.dispatch('GenerateRoutes', { roles }).then(() => {
|
||||||
router.addRoutes(store.getters.appRoutes)
|
router.addRoutes(store.getters.appRoutes)
|
||||||
const redirect = decodeURIComponent(from.query.redirect || to.path)
|
const redirect = decodeURIComponent(from.query.redirect || to.path)
|
||||||
if (to.path === redirect) {
|
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 })
|
next({ ...to, replace: true })
|
||||||
} else {
|
} else {
|
||||||
// 跳转到目的路由
|
// Redirect to the target route
|
||||||
next({ path: redirect })
|
next({ path: redirect })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@@ -109,6 +109,10 @@ export default {
|
|||||||
default: 'default',
|
default: 'default',
|
||||||
tip: 'Tip',
|
tip: 'Tip',
|
||||||
cmdbSearch: 'Search',
|
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: {
|
exception: {
|
||||||
backToHome: 'Back to home page',
|
backToHome: 'Back to home page',
|
||||||
desc1: 'Sorry, you are not authorized to access this page',
|
desc1: 'Sorry, you are not authorized to access this page',
|
||||||
|
@@ -109,6 +109,10 @@ export default {
|
|||||||
default: '默认',
|
default: '默认',
|
||||||
tip: '提示',
|
tip: '提示',
|
||||||
cmdbSearch: '搜索一下',
|
cmdbSearch: '搜索一下',
|
||||||
|
requestError: '出现错误,请稍后再试',
|
||||||
|
requestServiceError: '服务端未知错误, 请联系管理员!',
|
||||||
|
requestWait: '修改已提交,请等待审核({time}s)',
|
||||||
|
documentCenter: '文档中心',
|
||||||
exception: {
|
exception: {
|
||||||
backToHome: '返回首页',
|
backToHome: '返回首页',
|
||||||
desc1: '抱歉,你无权访问该页面',
|
desc1: '抱歉,你无权访问该页面',
|
||||||
|
@@ -63,8 +63,6 @@ import RouteView from './RouteView'
|
|||||||
import MultiTab from '@/components/MultiTab'
|
import MultiTab from '@/components/MultiTab'
|
||||||
import SideMenu from '@/components/Menu/SideMenu'
|
import SideMenu from '@/components/Menu/SideMenu'
|
||||||
import GlobalHeader from '@/components/GlobalHeader'
|
import GlobalHeader from '@/components/GlobalHeader'
|
||||||
import GlobalFooter from '@/components/GlobalFooter'
|
|
||||||
import SettingDrawer from '@/components/SettingDrawer'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'BasicLayout',
|
name: 'BasicLayout',
|
||||||
@@ -74,8 +72,6 @@ export default {
|
|||||||
MultiTab,
|
MultiTab,
|
||||||
SideMenu,
|
SideMenu,
|
||||||
GlobalHeader,
|
GlobalHeader,
|
||||||
GlobalFooter,
|
|
||||||
SettingDrawer,
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable */
|
|
||||||
import '@babel/polyfill'
|
import '@babel/polyfill'
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
@@ -14,10 +13,9 @@ import i18n from './lang'
|
|||||||
|
|
||||||
import iconFont from '../public/iconfont/iconfont'
|
import iconFont from '../public/iconfont/iconfont'
|
||||||
|
|
||||||
// 存在直接crash的风险 还未到
|
|
||||||
const customIcon = Icon.createFromIconfontCN(iconFont)
|
const customIcon = Icon.createFromIconfontCN(iconFont)
|
||||||
Vue.component('ops-icon', customIcon)
|
Vue.component('ops-icon', customIcon)
|
||||||
var vue;
|
var vue
|
||||||
|
|
||||||
async function start() {
|
async function start() {
|
||||||
const _vue = new Vue({
|
const _vue = new Vue({
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable */
|
|
||||||
import { UserLayout, BasicLayout, RouteView } from '@/layouts'
|
import { UserLayout, BasicLayout, RouteView } from '@/layouts'
|
||||||
import appConfig from '@/config/app'
|
import appConfig from '@/config/app'
|
||||||
import { getAppAclRouter } from './utils'
|
import { getAppAclRouter } from './utils'
|
||||||
@@ -7,7 +6,7 @@ import store from '../store'
|
|||||||
export const generatorDynamicRouter = async () => {
|
export const generatorDynamicRouter = async () => {
|
||||||
const packages = []
|
const packages = []
|
||||||
const { apps = undefined } = store.getters.userInfo
|
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)) {
|
if (!apps || !apps.length || apps.includes(appName)) {
|
||||||
const module = await import(`@/modules/${appName}/index.js`)
|
const module = await import(`@/modules/${appName}/index.js`)
|
||||||
const r = await module.default.route()
|
const r = await module.default.route()
|
||||||
@@ -91,7 +90,7 @@ export const generatorDynamicRouter = async () => {
|
|||||||
component: () => import(/* webpackChunkName: "setting" */ '@/views/setting/auth/index')
|
component: () => import(/* webpackChunkName: "setting" */ '@/views/setting/auth/index')
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},])
|
}, ])
|
||||||
return routes
|
return routes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable */
|
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import Router from 'vue-router'
|
import Router from 'vue-router'
|
||||||
import { constantRouterMap } from '@/router/config'
|
import { constantRouterMap } from '@/router/config'
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
/* eslint-disable */
|
|
||||||
|
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import Vuex from 'vuex'
|
import Vuex from 'vuex'
|
||||||
import app from './global/app'
|
import app from './global/app'
|
||||||
|
@@ -1,10 +1,8 @@
|
|||||||
/* eslint-disable */
|
|
||||||
export function intersection(thisSet, otherSet) {
|
export function intersection(thisSet, otherSet) {
|
||||||
//初始化一个新集合,用于表示交集。
|
// 初始化一个新集合,用于表示交集。
|
||||||
var interSectionSet = new Set()
|
var interSectionSet = new Set()
|
||||||
var values = Array.from(thisSet)
|
var values = Array.from(thisSet)
|
||||||
for (var i = 0; i < values.length; i++) {
|
for (var i = 0; i < values.length; i++) {
|
||||||
|
|
||||||
if (otherSet.has(values[i])) {
|
if (otherSet.has(values[i])) {
|
||||||
interSectionSet.add(values[i])
|
interSectionSet.add(values[i])
|
||||||
}
|
}
|
||||||
@@ -20,8 +18,8 @@ export function union(thisSet, otherSet) {
|
|||||||
unionSet.add(values[i])
|
unionSet.add(values[i])
|
||||||
}
|
}
|
||||||
values = Array.from(otherSet)
|
values = Array.from(otherSet)
|
||||||
for (var i = 0; i < values.length; i++) {
|
for (var j = 0; j < values.length; j++) {
|
||||||
unionSet.add(values[i])
|
unionSet.add(values[j])
|
||||||
}
|
}
|
||||||
|
|
||||||
return unionSet
|
return unionSet
|
||||||
@@ -31,7 +29,6 @@ export function difference(thisSet, otherSet) {
|
|||||||
var differenceSet = new Set()
|
var differenceSet = new Set()
|
||||||
var values = Array.from(thisSet)
|
var values = Array.from(thisSet)
|
||||||
for (var i = 0; i < values.length; i++) {
|
for (var i = 0; i < values.length; i++) {
|
||||||
|
|
||||||
if (!otherSet.has(values[i])) {
|
if (!otherSet.has(values[i])) {
|
||||||
differenceSet.add(values[i])
|
differenceSet.add(values[i])
|
||||||
}
|
}
|
||||||
|
@@ -14,12 +14,11 @@ module.exports = {
|
|||||||
plugins: [
|
plugins: [
|
||||||
// Ignore all locale files of moment.js
|
// Ignore all locale files of moment.js
|
||||||
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
|
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
|
||||||
// 生成仅包含颜色的替换样式(主题色等)
|
// generate theme color replacement styles
|
||||||
// TODO 需要增加根据环境不开启主题需求
|
|
||||||
new ThemeColorReplacer({
|
new ThemeColorReplacer({
|
||||||
fileName: 'css/theme-colors-[contenthash:8].css',
|
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) {
|
changeSelector(selector) {
|
||||||
switch (selector) {
|
switch (selector) {
|
||||||
case '.ant-calendar-today .ant-calendar-date':
|
case '.ant-calendar-today .ant-calendar-date':
|
||||||
@@ -63,29 +62,14 @@ module.exports = {
|
|||||||
.options({
|
.options({
|
||||||
name: 'assets/[name].[hash:8].[ext]',
|
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: {
|
css: {
|
||||||
loaderOptions: {
|
loaderOptions: {
|
||||||
less: {
|
less: {
|
||||||
modifyVars: {
|
modifyVars: {
|
||||||
/* less 变量覆盖,用于自定义 ant design 主题 */
|
// override less variables for custom ant design theme
|
||||||
'primary-color': '#2f54eb',
|
'primary-color': '#2f54eb',
|
||||||
// 'link-color': '#F5222D',
|
|
||||||
// 'border-radius-base': '4px',
|
|
||||||
},
|
},
|
||||||
javascriptEnabled: true,
|
javascriptEnabled: true,
|
||||||
},
|
},
|
||||||
@@ -119,7 +103,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getAntdSerials(color) {
|
function getAntdSerials(color) {
|
||||||
// 淡化(即less的tint)
|
// Lighten (similar to less's tint)
|
||||||
const lightens = new Array(9).fill().map((t, i) => {
|
const lightens = new Array(9).fill().map((t, i) => {
|
||||||
return ThemeColorReplacer.varyColor.lighten(color, i / 10)
|
return ThemeColorReplacer.varyColor.lighten(color, i / 10)
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user