代码改动,修复了一些问题

master
toesbieya 6 years ago
parent f754005959
commit f5cc749772
  1. 0
      vue/public/static/img/fileType/xls.png
  2. 227
      vue/public/static/live2d/waifu-tips.js
  3. 72
      vue/public/static/live2d/waifu-tips.json
  4. 6
      vue/public/static/live2d/waifu.css
  5. 2
      vue/src/components/ContextMenu/ContextMenuItem.vue
  6. 27
      vue/src/components/ContextMenu/index.vue
  7. 4
      vue/src/components/DialogForm/DialogFormItem.vue
  8. 4
      vue/src/components/DialogForm/index.vue
  9. 4
      vue/src/components/Guide/index.js
  10. 64
      vue/src/components/Guide/main.vue
  11. 2
      vue/src/components/LinerProgress/style.scss
  12. 2
      vue/src/components/PuzzleVerify/index.js
  13. 2
      vue/src/components/PuzzleVerify/style.scss
  14. 23
      vue/src/components/SearchForm/index.vue
  15. 2
      vue/src/components/SignautreBoard/index.js
  16. 2
      vue/src/components/Skeleton/PageSkeleton.vue
  17. 40
      vue/src/components/UploadFile/index.vue
  18. 2
      vue/src/components/UploadFile/style.scss
  19. 2
      vue/src/layout/components/Header.vue
  20. 2
      vue/src/layout/components/Main.vue
  21. 8
      vue/src/layout/components/Navbar/components/Breadcrumb.vue
  22. 3
      vue/src/layout/components/Navbar/index.vue
  23. 2
      vue/src/layout/components/Navbar/style.scss
  24. 6
      vue/src/layout/components/Sidebar/index.vue
  25. 2
      vue/src/layout/components/Sidebar/style.scss
  26. 5
      vue/src/layout/components/TagsView/index.vue
  27. 2
      vue/src/layout/components/TagsView/style.scss
  28. 22
      vue/src/mixins/guide/base.js
  29. 31
      vue/src/mixins/guide/data/index.js
  30. 15
      vue/src/mixins/guide/data/navbar.js
  31. 2
      vue/src/mixins/guide/index.js
  32. 291
      vue/src/plugin/live2d/index.js
  33. 4
      vue/src/router/constant/index.js
  34. 15
      vue/src/router/index.js
  35. 3
      vue/src/router/util.js
  36. 4
      vue/src/store/modules/iframe.js
  37. 6
      vue/src/store/modules/tagsView.js
  38. 36
      vue/src/utils/browser.js
  39. 2
      vue/src/utils/excel/xlsx.js
  40. 2
      vue/src/utils/index.js
  41. 2
      vue/src/utils/math.js
  42. 2
      vue/src/views/app/login/style.scss
  43. 2
      vue/src/views/example/components/skeletonExample.vue
  44. 81
      vue/src/views/example/cool/l2d.vue
  45. 11
      vue/src/views/example/developingTest/components/ImageCompressTest.vue
  46. 2
      vue/src/views/stock/current/DetailDialog.vue
  47. 2
      vue/src/views/system/role/components/RoleResource.vue
  48. 3
      vue/src/views/system/supplier/EditDialog.vue
  49. 3
      vue/src/views/system/supplier/index.vue
  50. 4
      vue/src/views/userCenter/components/Avatar.vue
  51. 4
      vue/vue.config.js

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

@ -1,227 +0,0 @@
/*
* Live2D Widget
* https://github.com/stevenjoezhang/live2d-widget
*/
function initWidget(waifuPath = "/waifu-tips.json", apiPath = "") {
sessionStorage.removeItem("waifu-text")
document.body.insertAdjacentHTML("beforeend",
`<div id="waifu">
<div id="waifu-tips"></div>
<canvas id="live2d" width="300" height="300"></canvas>
<div id="waifu-tool">
<span class="el-icon-s-promotion" title="打飞机"></span>
<span class="el-icon-refresh" title="换人"></span>
<span class="el-icon-s-operation" title="换装"></span>
<span class="el-icon-camera" title="拍照"></span>
<span class="el-icon-switch-button" title="关闭"></span>
</div>
</div>`)
setTimeout(() => {
document.getElementById("waifu").style.bottom = 0
}, 0)
function registerEventListener() {
document.querySelector("#waifu-tool .el-icon-s-promotion").addEventListener("click", () => {
if (window.Asteroids) {
if (!window.ASTEROIDSPLAYERS) window.ASTEROIDSPLAYERS = []
window.ASTEROIDSPLAYERS.push(new Asteroids())
}
else {
var script = document.createElement("script")
script.src = "https://cdn.jsdelivr.net/gh/GalaxyMimi/CDN/asteroids.js"
document.head.appendChild(script)
}
})
document.querySelector("#waifu-tool .el-icon-refresh").addEventListener("click", loadOtherModel)
document.querySelector("#waifu-tool .el-icon-s-operation").addEventListener("click", loadRandModel)
document.querySelector("#waifu-tool .el-icon-camera").addEventListener("click", () => {
showMessage("照好了嘛,是不是很可爱呢?", 6000, 9)
Live2D.captureName = "photo.png"
Live2D.captureFrame = true
})
document.querySelector("#waifu-tool .el-icon-switch-button").addEventListener("click", exit)
var devtools = () => ({})
console.log("%c", devtools)
devtools.toString = () => {
showMessage("哈哈,你打开了控制台,是想要看看我的小秘密吗?", 6000, 9)
}
window.addEventListener("visibilitychange", () => {
if (!document.hidden) showMessage("哇,你终于回来了~", 6000, 9)
})
}
registerEventListener()
function welcomeMessage() {
let text
if (location.pathname === "/") { // 如果是主页
let now = new Date().getHours()
if (now > 5 && now <= 7) text = "早上好!一日之计在于晨,美好的一天就要开始了。"
else if (now > 7 && now <= 11) text = "上午好!工作顺利嘛,不要久坐,多起来走动走动哦!"
else if (now > 11 && now <= 13) text = "中午了,工作了一个上午,现在是午餐时间!"
else if (now > 13 && now <= 17) text = "午后很容易犯困呢,今天的运动目标完成了吗?"
else if (now > 17 && now <= 19) text = "傍晚了!窗外夕阳的景色很美丽呢,最美不过夕阳红~"
else if (now > 19 && now <= 21) text = "晚上好,今天过得怎么样?"
else if (now > 21 && now <= 23) text = ["已经这么晚了呀,早点休息吧,晚安~", "深夜时要爱护眼睛呀!"]
else text = "你是夜猫子呀?这么晚还不睡觉,明天起的来嘛?"
}
else if (document.referrer !== "") {
let referrer = new URL(document.referrer),
domain = referrer.hostname.split(".")[1]
if (location.hostname === referrer.hostname) text = `欢迎阅读<span>「${document.title.split(" - ")[0]}」</span>`
else if (domain === "baidu") text = `Hello!来自 百度搜索 的朋友<br>你是搜索 <span>${referrer.search.split("&wd=")[1].split("&")[0]}</span> 找到的我吗?`
else if (domain === "so") text = `Hello!来自 360搜索 的朋友<br>你是搜索 <span>${referrer.search.split("&q=")[1].split("&")[0]}</span> 找到的我吗?`
else if (domain === "google") text = `Hello!来自 谷歌搜索 的朋友<br>欢迎阅读<span>「${document.title.split(" - ")[0]}」</span>`
else text = `Hello!来自 <span>${referrer.hostname}</span> 的朋友`
}
else {
text = `欢迎阅读<span>「${document.title.split(" - ")[0]}」</span>`
}
showMessage(text, 7000, 8)
}
welcomeMessage()
// 检测用户活动状态,并在空闲时显示消息
var userAction = false,
userActionTimer = null,
messageTimer = null,
messageArray = ["好久不见,日子过得好快呢……", "大坏蛋!你都多久没理人家了呀,嘤嘤嘤~", "嗨~快来逗我玩吧!", "拿小拳拳锤你胸口!", "记得把小家加入 Adblock 白名单哦!"]
window.addEventListener("mousemove", () => userAction = true)
window.addEventListener("keydown", () => userAction = true)
setInterval(() => {
if (userAction) {
userAction = false
clearInterval(userActionTimer)
userActionTimer = null
}
else if (!userActionTimer) {
userActionTimer = setInterval(() => {
showMessage(messageArray[Math.floor(Math.random() * messageArray.length)], 6000, 9)
}, 20000)
}
}, 1000)
function initModel() {
let modelId = localStorage.getItem("modelId"),
modelTexturesId = localStorage.getItem("modelTexturesId")
if (modelId == null) {
// 首次访问加载 指定模型 的 指定材质
modelId = 1 // 模型 ID
modelTexturesId = 53 // 材质 ID
}
loadModel(modelId, modelTexturesId)
fetch(waifuPath)
.then(response => response.json())
.then(result => {
result.mouseover.forEach(tips => {
window.addEventListener("mouseover", event => {
if (!event.target.matches(tips.selector)) return
var text = Array.isArray(tips.text) ? tips.text[Math.floor(Math.random() * tips.text.length)] : tips.text
text = text.replace("{text}", event.target.innerText)
showMessage(text, 4000, 8)
})
})
result.click.forEach(tips => {
window.addEventListener("click", event => {
if (!event.target.matches(tips.selector)) return
var text = Array.isArray(tips.text) ? tips.text[Math.floor(Math.random() * tips.text.length)] : tips.text
text = text.replace("{text}", event.target.innerText)
showMessage(text, 4000, 8)
})
})
result.seasons.forEach(tips => {
var now = new Date(),
after = tips.date.split("-")[0],
before = tips.date.split("-")[1] || after
if ((after.split("/")[0] <= now.getMonth() + 1 && now.getMonth() + 1 <= before.split("/")[0]) && (after.split("/")[1] <= now.getDate() && now.getDate() <= before.split("/")[1])) {
var text = Array.isArray(tips.text) ? tips.text[Math.floor(Math.random() * tips.text.length)] : tips.text
text = text.replace("{year}", now.getFullYear())
//showMessage(text, 7000, true);
messageArray.push(text)
}
})
})
}
initModel()
function loadModel(modelId, modelTexturesId) {
localStorage.setItem("modelId", modelId)
if (modelTexturesId === undefined) modelTexturesId = 0
localStorage.setItem("modelTexturesId", modelTexturesId)
loadlive2d("live2d", `${apiPath}/get/?id=${modelId}-${modelTexturesId}`, console.log(`Live2D 模型 ${modelId}-${modelTexturesId} 加载完成`))
}
//调用一言api
function showHitokoto() {
// 增加 hitokoto.cn 的 API
fetch("https://v1.hitokoto.cn")
.then(response => response.json())
.then(result => {
var text = `这句一言来自 <span>「${result.from}」</span>,是 <span>${result.creator}</span> 在 hitokoto.cn 投稿的。`
showMessage(result.hitokoto, 6000, 9)
setTimeout(() => {
showMessage(text, 4000, 9)
}, 6000)
})
}
//显示信息
function showMessage(text, timeout, priority) {
if (!text) return
if (!sessionStorage.getItem("waifu-text") || sessionStorage.getItem("waifu-text") <= priority) {
if (messageTimer) {
clearTimeout(messageTimer)
messageTimer = null
}
if (Array.isArray(text)) text = text[Math.floor(Math.random() * text.length)]
sessionStorage.setItem("waifu-text", priority)
var tips = document.getElementById("waifu-tips")
if (!tips) return
tips.innerHTML = text
tips.classList.add("waifu-tips-active")
messageTimer = setTimeout(() => {
sessionStorage.removeItem("waifu-text")
tips.classList.remove("waifu-tips-active")
}, timeout)
}
}
//换装
function loadRandModel() {
let modelId = localStorage.getItem("modelId"),
modelTexturesId = localStorage.getItem("modelTexturesId")
// 可选 "rand"(随机), "switch"(顺序)
fetch(`${apiPath}/rand_textures/?id=${modelId}-${modelTexturesId}`)
.then(response => response.json())
.then(result => {
if (result.textures.id == 1 && (modelTexturesId == 1 || modelTexturesId == 0)) showMessage("我还没有其他衣服呢!", 4000, 10)
else showMessage("我的新衣服好看嘛?", 4000, 10)
loadModel(modelId, result.textures.id)
})
}
//切换其他模型
function loadOtherModel() {
var modelId = localStorage.getItem("modelId")
fetch(`${apiPath}/switch/?id=${modelId}`)
.then(response => response.json())
.then(result => {
loadModel(result.model.id)
showMessage(result.model.message, 4000, 10)
})
}
//退出
function exit() {
showMessage("愿你有一天能与重要的人重逢。", 2000, 11)
const dom = document.getElementById("waifu")
dom.style.bottom = "-500px"
setTimeout(() => {
// dom.style.display = "none"
dom.remove()
}, 3000)
}
}

@ -60,28 +60,6 @@
"我们,还能再见面吗……", "我们,还能再见面吗……",
"哼,你会后悔的!" "哼,你会后悔的!"
] ]
},
{
"selector": ".menu-item-search",
"text": [
"找不到想看的内容?搜索看看吧!",
"在找什么东西呢,需要帮忙吗?"
]
},
{
"selector": "#qrcode",
"text": [
"手机扫一下就能继续看,很方便呢~",
"扫一扫,打开新世界的大门!"
]
},
{
"selector": ".back-to-top",
"text": [
"点它就可以回到顶部啦!",
"又回到最初的起点~",
"要回到开始的地方么?"
]
} }
], ],
"click": [ "click": [
@ -98,55 +76,5 @@
"别摸我,有什么好摸的!" "别摸我,有什么好摸的!"
] ]
} }
],
"seasons": [
{
"date": "01/01",
"text": "<span>元旦</span>了呢,新的一年又开始了,今年是{year}年~"
},
{
"date": "02/14",
"text": "又是一年<span>情人节</span>,{year}年找到对象了嘛~"
},
{
"date": "03/08",
"text": "今天是<span>国际妇女节</span>!"
},
{
"date": "03/12",
"text": "今天是<span>植树节</span>,要保护环境呀!"
},
{
"date": "04/01",
"text": "悄悄告诉你一个秘密~<span>今天是愚人节,不要被骗了哦~</span>"
},
{
"date": "05/01",
"text": "今天是<span>五一劳动节</span>,计划好假期去哪里了吗~"
},
{
"date": "06/01",
"text": "<span>儿童节</span>了呢,快活的时光总是短暂,要是永远长不大该多好啊…"
},
{
"date": "09/03",
"text": "<span>中国人民抗日战争胜利纪念日</span>,铭记历史、缅怀先烈、珍爱和平、开创未来。"
},
{
"date": "09/10",
"text": "<span>教师节</span>,在学校要给老师问声好呀~"
},
{
"date": "10/01",
"text": "<span>国庆节</span>到了,为祖国母亲庆生!"
},
{
"date": "11/05-11/12",
"text": "今年的<span>双十一</span>是和谁一起过的呢~"
},
{
"date": "12/20-12/31",
"text": "这几天是<span>圣诞节</span>,主人肯定又去剁手买买买了~"
}
] ]
} }

@ -12,12 +12,6 @@
transform: translateY(0); transform: translateY(0);
} }
@media (max-width: 768px) {
#waifu {
display: none;
}
}
#waifu-tips { #waifu-tips {
animation: shake 50s ease-in-out 5s infinite; animation: shake 50s ease-in-out 5s infinite;
background-color: rgba(236, 217, 188, .5); background-color: rgba(236, 217, 188, .5);

@ -5,7 +5,7 @@
functional: true, functional: true,
render(h, context) { render(h, context) {
return h('li', context.data, context.children) return <li class="contextmenu-item" {...context.data}>{context.children}</li>
} }
} }
</script> </script>

@ -9,16 +9,9 @@
name: "ContextMenu", name: "ContextMenu",
props: { props: {
value: { value: Boolean,
type: Boolean, left: Number,
default: false top: Number
},
left: {
type: Number
},
top: {
type: Number
}
}, },
data() { data() {
@ -31,7 +24,7 @@
watch: { watch: {
value(v) { value(v) {
document.body[v ? 'addEventListener' : 'removeEventListener']('click', this.closeContextMenu) document.body[v ? 'addEventListener' : 'removeEventListener']('click', this.closeContextMenu)
if (v) this.$nextTick(() => this.autoAdapt()) if (v) this.$nextTick(this.autoAdapt)
}, },
left(v) { left(v) {
if (!v) return if (!v) return
@ -56,24 +49,22 @@
if (this.$el.offsetHeight > document.body.clientHeight - v && v > this.$el.offsetHeight) { if (this.$el.offsetHeight > document.body.clientHeight - v && v > this.$el.offsetHeight) {
this.realTop = v - this.$el.offsetHeight + 'px' this.realTop = v - this.$el.offsetHeight + 'px'
} }
else { else this.realTop = v + 'px'
this.realTop = v + 'px'
}
}, },
autoAdaptLeft(v) { autoAdaptLeft(v) {
if (!this.value) return if (!this.value) return
if (this.$el.offsetWidth > document.body.clientWidth - v) { if (this.$el.offsetWidth > document.body.clientWidth - v) {
this.realLeft = v - this.$el.offsetWidth + 'px' this.realLeft = v - this.$el.offsetWidth + 'px'
} }
else { else this.realLeft = v + 'px'
this.realLeft = v + 'px'
}
} }
} }
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import "~@/assets/styles/variables.scss";
.contextmenu { .contextmenu {
margin: 0; margin: 0;
background: $menu-background; background: $menu-background;
@ -87,7 +78,7 @@
color: #fff; color: #fff;
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3); box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
li { &-item {
margin: 0; margin: 0;
padding: 7px 16px; padding: 7px 16px;
cursor: pointer; cursor: pointer;

@ -7,10 +7,12 @@
props: {full: Boolean, dense: Boolean, label: String, prop: String}, props: {full: Boolean, dense: Boolean, label: String, prop: String},
render(h, context) { render(h, context) {
let {full, dense, label, prop} = context.props const {full, dense, label, prop} = context.props
let attrs = {xs: 24, sm: 12, lg: 8} let attrs = {xs: 24, sm: 12, lg: 8}
if (full) attrs = {span: 24} if (full) attrs = {span: 24}
else if (dense) attrs.lg = 12 else if (dense) attrs.lg = 12
return ( return (
<el-col {...{attrs}}> <el-col {...{attrs}}>
<el-form-item label={label} prop={prop}> <el-form-item label={label} prop={prop}>

@ -1,10 +1,10 @@
<template> <template>
<el-dialog <el-dialog
v-drag-dialog v-drag-dialog
custom-class="dialog-form"
v-bind="$props" v-bind="$props"
:visible="value"
v-on="$listeners" v-on="$listeners"
:visible="value"
custom-class="dialog-form"
> >
<slot slot="title" name="title">{{title}}</slot> <slot slot="title" name="title">{{title}}</slot>

@ -14,7 +14,7 @@ const defaultOptions = {
prevBtnText: '上一步', prevBtnText: '上一步',
} }
const guide = function (start, steps, beforeExist) { const guide = function (start, steps, beforeExit) {
if (instance) instance.exit() if (instance) instance.exit()
else { else {
instance = new GuideConstructor({data: {options: defaultOptions}}) instance = new GuideConstructor({data: {options: defaultOptions}})
@ -23,7 +23,7 @@ const guide = function (start, steps, beforeExist) {
} }
instance.steps = steps instance.steps = steps
instance.beforeExist = beforeExist instance.beforeExit = beforeExit
this.$nextTick(() => instance.start(start)) this.$nextTick(() => instance.start(start))
} }

@ -5,19 +5,19 @@
<div class="guide-popover-action"> <div class="guide-popover-action">
<div class="action-close"> <div class="action-close">
<el-button v-show="hasDone" size="small" @click="exit"> <el-button v-if="hasDone" size="small" @click="exit">
{{step.doneBtnText}} {{step.doneBtnText}}
</el-button> </el-button>
<el-button v-show="!hasDone" size="small" @click="exit"> <el-button v-else size="small" @click="exit">
{{step.closeBtnText}} {{step.closeBtnText}}
</el-button> </el-button>
</div> </div>
<div class="action-step"> <div class="action-step">
<el-button v-show="showPrevBtn" class="prev-btn" size="small" @click="previous"> <el-button v-if="showPrevBtn" class="prev-btn" size="small" @click="previous">
{{step.prevBtnText}} {{step.prevBtnText}}
</el-button> </el-button>
<el-button v-show="showNextBtn" class="next-btn" size="small" @click="next"> <el-button v-if="showNextBtn" class="next-btn" size="small" @click="next">
{{step.nextBtnText}} {{step.nextBtnText}}
</el-button> </el-button>
</div> </div>
@ -26,9 +26,9 @@
<div slot="reference" v-show="showStage" id="guide-stage" :style="stageStyle"/> <div slot="reference" v-show="showStage" id="guide-stage" :style="stageStyle"/>
</el-popover> </el-popover>
<div v-show="showStage" id="guide-highlight-element-cover" :style="stageStyle" @click.prevent.stop/> <div v-if="showStage" id="guide-highlight-element-cover" :style="stageStyle" @click.prevent.stop/>
<div v-show="showOverlay" id="guide-overlay"/> <div v-if="showOverlay" id="guide-overlay"/>
</div> </div>
</template> </template>
@ -46,13 +46,7 @@
data() { data() {
return { return {
steps: [], steps: [],
options: { options: {},
stageBackground: '#ffffff',
doneBtnText: '完成',
closeBtnText: '关闭',
nextBtnText: '下一步',
prevBtnText: '上一步',
},
beforeExit: null, beforeExit: null,
isActive: false, isActive: false,
showStage: false, showStage: false,
@ -79,9 +73,12 @@
return this.currentStep === this.steps.length - 1 return this.currentStep === this.steps.length - 1
}, },
step() { step() {
if (!this.isActive) return {} if (!this.isActive
if (this.steps.length <= 0) return {} || this.steps.length <= 0
if (!this.steps[this.currentStep]) return {} || !this.steps[this.currentStep]) {
return {}
}
return { return {
...this.options, ...this.options,
...this.steps[this.currentStep], ...this.steps[this.currentStep],
@ -114,59 +111,72 @@
this.showStage = false this.showStage = false
this.$_highlight() this.$_highlight()
this.showOverlay = true this.showOverlay = true
this.showStage = true this.showStage = true
}, },
exit() { exit() {
if (!this.isActive) return if (!this.isActive) return
let done = this.hasDone
if (this.beforeExit) { if (this.beforeExit) {
let result = this.beforeExit(done) const result = this.beforeExit(this.hasDone)
if (result && result.then) { if (result && result.then) {
result.then(() => this.$_clear()) result.then(this.$_clear)
} }
if (result !== false) this.$_clear() else result !== false && this.$_clear()
return return
} }
this.$_clear() this.$_clear()
}, },
previous() { previous() {
if (!this.isActive || this.moving) return if (!this.isActive || this.moving) return
this.moving = true this.moving = true
if (this.step.onPrevious) { if (this.step.onPrevious) {
let result = this.step.onPrevious() const result = this.step.onPrevious()
if (result && result.then) result.then(() => this.$_movePrevious()) if (result && result.then) {
result.then(this.$_movePrevious)
}
else result !== false && this.$_movePrevious() else result !== false && this.$_movePrevious()
} }
else this.$_movePrevious() else this.$_movePrevious()
}, },
next() { next() {
if (!this.isActive || this.moving) return if (!this.isActive || this.moving) return
this.moving = true this.moving = true
if (this.step.onNext) { if (this.step.onNext) {
let result = this.step.onNext() const result = this.step.onNext()
if (result && result.then) result.then(() => this.$_moveNext()) if (result && result.then) {
result.then(this.$_moveNext)
}
else result !== false && this.$_moveNext() else result !== false && this.$_moveNext()
} }
else this.$_moveNext() else this.$_moveNext()
}, },
resize() { resize() {
if (!this.highlightedElement) return if (!this.highlightedElement) return
this.$_setStageStyle(getCalculatedPosition(this.highlightedElement)) this.$_setStageStyle(getCalculatedPosition(this.highlightedElement))
this.$nextTick(() => this.$refs.popover.updatePopper()) this.$nextTick(this.$refs.popover.updatePopper)
}, },
$_movePrevious() { $_movePrevious() {
if (!this.isActive) return if (!this.isActive) return
this.currentStep-- this.currentStep--
this.$_highlight() this.$_highlight()
}, },
$_moveNext() { $_moveNext() {
if (!this.isActive) return if (!this.isActive) return
this.currentStep++ this.currentStep++
this.$_highlight() this.$_highlight()
}, },
$_clear() { $_clear() {
if (!this.isActive) return if (!this.isActive) return
this.isActive = false this.isActive = false
@ -179,10 +189,11 @@
this.highlightedElement = null this.highlightedElement = null
this.lastHighlightedElement = null this.lastHighlightedElement = null
}, },
$_highlight() { $_highlight() {
if (isEmpty(this.step.element)) throw new Error(`step${this.currentStep}中element为空`) if (isEmpty(this.step.element)) throw new Error(`step${this.currentStep}中element为空`)
let el = document.querySelector(this.step.element) const el = document.querySelector(this.step.element)
if (!el) throw new Error(`${this.step.element} 没有该元素`) if (!el) throw new Error(`${this.step.element} 没有该元素`)
@ -204,6 +215,7 @@
addHighlightClasses(el) addHighlightClasses(el)
}, },
$_setStageStyle({top, left, right, bottom}) { $_setStageStyle({top, left, right, bottom}) {
const width = right - left const width = right - left
const height = bottom - top const height = bottom - top

@ -1,3 +1,5 @@
@import "~@/assets/styles/variables.scss";
.liner-progress { .liner-progress {
position: relative; position: relative;
height: 4px; height: 4px;

@ -8,12 +8,14 @@ let Constructor = Vue.extend(Main)
const PuzzleVerify = function ({left, top} = {}) { const PuzzleVerify = function ({left, top} = {}) {
const instance = new Constructor() const instance = new Constructor()
const position = getPosition({height: instance.height + 130, width: instance.width + 20, left, top}) const position = getPosition({height: instance.height + 130, width: instance.width + 20, left, top})
instance.positionTop = position.top instance.positionTop = position.top
instance.positionLeft = position.left instance.positionLeft = position.left
instance.$mount() instance.$mount()
document.body.appendChild(instance.$el) document.body.appendChild(instance.$el)
instance.$el.style.zIndex = PopupManager.nextZIndex() instance.$el.style.zIndex = PopupManager.nextZIndex()
instance.visible = true instance.visible = true
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
instance.resolve = resolve instance.resolve = resolve
instance.reject = reject instance.reject = reject

@ -1,3 +1,5 @@
@import "~@/assets/styles/variables.scss";
.puzzle-container { .puzzle-container {
position: absolute; position: absolute;
box-shadow: 0 0 10px #cccccc; box-shadow: 0 0 10px #cccccc;

@ -12,10 +12,10 @@
props: { props: {
labelWidth: {type: String, default: '120px'}, labelWidth: {type: String, default: '120px'},
xs: {type: Number, default: 24},// <768px xs: {type: Number, default: 1},// <768px
sm: {type: Number, default: 12},// >=768px sm: {type: Number, default: 2},// >=768px
md: {type: Number, default: 8}, // >=998px md: {type: Number, default: 3}, // >=998px
lg: {type: Number, default: 6} // >=1200px lg: {type: Number, default: 4} // >=1200px
}, },
data() { data() {
@ -35,13 +35,10 @@
getElementNumInRow() { getElementNumInRow() {
const vw = getElementInnerWidth(this.$el.parentNode) const vw = getElementInnerWidth(this.$el.parentNode)
let lineNum = this.lg if (vw < 768) return this.xs
else if (vw < 998) return this.sm
if (vw < 768) lineNum = this.xs else if (vw < 1200) return this.md
else if (vw < 998) lineNum = this.sm return this.lg
else if (vw < 1200) lineNum = this.md
return Math.floor(24 / lineNum)
}, },
resize() { resize() {
@ -78,7 +75,9 @@
const collapseSlot = this.$scopedSlots.collapse const collapseSlot = this.$scopedSlots.collapse
collapseChildren.push( collapseChildren.push(
collapseSlot ? collapseSlot({collapse: this.collapse, handle: this.handleCollapse}) : collapseSlot ?
collapseSlot({collapse: this.collapse, handle: this.handleCollapse})
:
<div class="searchForm__collapse"> <div class="searchForm__collapse">
<el-button <el-button
type="text" type="text"

@ -11,12 +11,14 @@ const signature = function ({image, lineWidth = 6, lineColor = '#000000', onConf
instance = new Constructor().$mount() instance = new Constructor().$mount()
document.body.appendChild(instance.$el) document.body.appendChild(instance.$el)
} }
instance.image = image instance.image = image
instance.lineWidth = lineWidth instance.lineWidth = lineWidth
instance.lineColor = lineColor instance.lineColor = lineColor
instance.onConfirm = onConfirm instance.onConfirm = onConfirm
instance.init() instance.init()
instance.visible = true instance.visible = true
return instance return instance
} }

@ -26,6 +26,8 @@
</script> </script>
<style lang="scss"> <style lang="scss">
@import "~@/assets/styles/variables.scss";
.page-skeleton-wrapper { .page-skeleton-wrapper {
margin: $page-view-margin; margin: $page-view-margin;
} }

@ -3,7 +3,7 @@
ref="upload" ref="upload"
:before-upload="beforeUpload" :before-upload="beforeUpload"
:class="{disabled: hideUploader}" :class="{disabled: hideUploader}"
:file-list="data" :file-list="tempData"
:http-request="httpRequest" :http-request="httpRequest"
:limit="limit" :limit="limit"
:multiple="multiple" :multiple="multiple"
@ -13,7 +13,7 @@
action="" action=""
list-type="picture-card" list-type="picture-card"
> >
<i slot="default" class="el-icon-plus"/> <i class="el-icon-plus"/>
<template v-slot:file="{file}"> <template v-slot:file="{file}">
<span <span
@ -64,6 +64,11 @@
import {preview, deleteUpload, download, upload, autoCompleteUrl} from "@/utils/file" import {preview, deleteUpload, download, upload, autoCompleteUrl} from "@/utils/file"
import {getContextPath} from "@/utils/browser" import {getContextPath} from "@/utils/browser"
const typeMapper = [
{test: isImage}, {test: isDoc, type: 'doc'}, {test: isPdf, type: 'pdf'}, {test: isPpt, type: 'ppt'},
{test: isRar, type: 'rar'}, {test: isXls, type: 'xls'}, {test: isTxt, type: 'txt'}, {test: isZip, type: 'zip'},
]
function parseMaxSize(maxSize) { function parseMaxSize(maxSize) {
if (typeof maxSize === 'number') { if (typeof maxSize === 'number') {
return maxSize return maxSize
@ -77,27 +82,17 @@
return parseInt(num) * (map[unit] || 1) return parseInt(num) * (map[unit] || 1)
} }
function isFileTypeSupported(fileType) {
return [isImage, isDoc, isPdf, isPpt, isRar, isXls, isTxt, isZip].some(i => i(fileType))
}
function getCoverImage(url, fileType) { function getCoverImage(url, fileType) {
if (isImage(fileType)) return url const mapper = typeMapper.find(({test}) => test(fileType))
else if (isDoc(fileType)) url = `${getContextPath()}static/img/fileType/doc.png`
else if (isPdf(fileType)) url = `${getContextPath()}static/img/fileType/pdf.png` return mapper && mapper.type ? `${getContextPath()}static/img/fileType/${mapper.type}.png` : url
else if (isPpt(fileType)) url = `${getContextPath()}static/img/fileType/ppt.png`
else if (isRar(fileType)) url = `${getContextPath()}static/img/fileType/rar.png`
else if (isXls(fileType)) url = `${getContextPath()}static/img/fileType/xls.png`
else if (isTxt(fileType)) url = `${getContextPath()}static/img/fileType/txt.png`
else if (isZip(fileType)) url = `${getContextPath()}static/img/fileType/zip.png`
return url
} }
export default { export default {
name: 'UploadFile', name: 'UploadFile',
props: { props: {
disabled: {type: Boolean, default: false}, disabled: Boolean,
multiple: {type: Boolean, default: true}, multiple: {type: Boolean, default: true},
fileList: {type: Array, default: () => []}, fileList: {type: Array, default: () => []},
limit: {type: Number, default: 10}, limit: {type: Number, default: 10},
@ -106,6 +101,7 @@
data() { data() {
return { return {
tempData: this.fileList,
data: this.fileList, data: this.fileList,
tooltipContent: null tooltipContent: null
} }
@ -127,14 +123,15 @@
fileList: { fileList: {
immediate: true, immediate: true,
handler(fileList) { handler(fileList) {
if (isEmpty(fileList)) { if (isEmpty(fileList)) this.data = []
return this.data = [] else {
}
this.data = [...this.fileList.map(file => { this.data = [...this.fileList.map(file => {
const downloadUrl = autoCompleteUrl(file.url) const downloadUrl = autoCompleteUrl(file.url)
return {...file, url: getCoverImage(downloadUrl, file.name), downloadUrl} return {...file, url: getCoverImage(downloadUrl, file.name), downloadUrl}
})] })]
} }
this.tempData = JSON.parse(JSON.stringify(this.data))
}
} }
}, },
@ -209,7 +206,7 @@
// //
beforeUpload(file) { beforeUpload(file) {
if (!isFileTypeSupported(file.name)) { if (!typeMapper.some(({test}) => test(file.name))) {
elError('只支持图片、word、pdf、ppt、rar、excel、txt、zip类型的文件') elError('只支持图片、word、pdf、ppt、rar、excel、txt、zip类型的文件')
return false return false
} }
@ -221,8 +218,7 @@
}, },
httpRequest({file, onProgress}) { httpRequest({file, onProgress}) {
const CancelToken = axios.CancelToken const source = axios.CancelToken.source()
const source = CancelToken.source()
const promise = upload(file, file.name, { const promise = upload(file, file.name, {
onUploadProgress(e) { onUploadProgress(e) {
if (e.total > 0) { if (e.total > 0) {

@ -1,3 +1,5 @@
@import "~@/assets/styles/variables.scss";
.disabled .el-upload--picture-card { .disabled .el-upload--picture-card {
display: none; display: none;
} }

@ -81,6 +81,8 @@
</script> </script>
<style lang="scss"> <style lang="scss">
@import "~@/assets/styles/variables.scss";
.has-tags-view .header-container { .has-tags-view .header-container {
height: calc(#{$nav-height} + #{$tags-view-height}); height: calc(#{$nav-height} + #{$tags-view-height});
} }

@ -74,6 +74,8 @@
</script> </script>
<style lang="scss"> <style lang="scss">
@import "~@/assets/styles/variables.scss";
.app-main { .app-main {
position: relative; position: relative;
overflow: hidden; overflow: hidden;

@ -10,11 +10,7 @@
<script> <script>
export default { export default {
data() { data: () => ({data: []}),
return {
data: null
}
},
watch: { watch: {
$route(route) { $route(route) {
@ -37,6 +33,8 @@
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import "~@/assets/styles/variables.scss";
.app-breadcrumb.el-breadcrumb { .app-breadcrumb.el-breadcrumb {
display: inline-block; display: inline-block;
line-height: 50px; line-height: 50px;

@ -26,7 +26,7 @@
<router-link to="/user/index"> <router-link to="/user/index">
<el-dropdown-item icon="el-icon-user">个人中心</el-dropdown-item> <el-dropdown-item icon="el-icon-user">个人中心</el-dropdown-item>
</router-link> </router-link>
<el-dropdown-item class="hidden-xs" icon="el-icon-guide" @click.native="$guide(0,steps)"> <el-dropdown-item class="hidden-xs" icon="el-icon-guide" @click.native="()=>$guide(0,guideSteps)">
新手指引 新手指引
</el-dropdown-item> </el-dropdown-item>
<router-link v-if="showSystemMonitor" to="/system/monitor"> <router-link v-if="showSystemMonitor" to="/system/monitor">
@ -66,7 +66,6 @@
data() { data() {
return { return {
fullscreen: false,
settingDrawer: false settingDrawer: false
} }
}, },

@ -1,3 +1,5 @@
@import "~@/assets/styles/variables.scss";
.navbar { .navbar {
height: $nav-height; height: $nav-height;
overflow: hidden; overflow: hidden;

@ -2,6 +2,7 @@
import {mapState} from 'vuex' import {mapState} from 'vuex'
import Logo from './components/Logo' import Logo from './components/Logo'
import SidebarItem from './components/SidebarItem' import SidebarItem from './components/SidebarItem'
import {isExternal} from "@/utils/validate"
import variables from '@/assets/styles/variables.scss' import variables from '@/assets/styles/variables.scss'
export default { export default {
@ -98,6 +99,11 @@
if (!jump) return if (!jump) return
//
if (isExternal(index)) {
return window.open(index)
}
if (this.$route.path === index) { if (this.$route.path === index) {
this.$store.commit('tagsView/delCachedView', this.$route) this.$store.commit('tagsView/delCachedView', this.$route)
this.$nextTick(() => this.$router.replace({path: '/redirect' + this.$route.fullPath})) this.$nextTick(() => this.$router.replace({path: '/redirect' + this.$route.fullPath}))

@ -1,3 +1,5 @@
@import "~@/assets/styles/variables.scss";
$iconSize: 17px; $iconSize: 17px;
.sidebar-container { .sidebar-container {

@ -169,6 +169,11 @@
} }
}, },
beforeDestroy() {
//fade
this.$store.commit('setting/transitionName', 'el-fade-in-linear')
},
mounted() { mounted() {
this.initTags() this.initTags()
this.addTags() this.addTags()

@ -1,3 +1,5 @@
@import "~@/assets/styles/variables.scss";
.tags-view-container { .tags-view-container {
height: $tags-view-height; height: $tags-view-height;
background: #f0f0f0; background: #f0f0f0;

@ -15,31 +15,39 @@ export default {
methods: { methods: {
$_prepareGuide(params) { $_prepareGuide(params) {
if (!['navbar', 'sidebar'].includes(this.$options.name)) return if (!['navbar', 'sidebar'].includes(this.$options.name)) return
if ('guide' in params) { if ('guide' in params) {
delAllUrlParam() delAllUrlParam()
if (params.navbar && this.$options.name === 'navbar') this.$guide(params.guide, this.steps) for (const key of ['navbar', 'sidebar']) {
else if (params.sidebar && this.$options.name === 'sidebar') this.$guide(params.guide, this.steps) if (params[key] && this.$options.name === key) {
return this.$guide(params.guide, this.guideSteps)
}
}
} }
} }
}, },
computed: { computed: {
params() { routeParams() {
return this.$route.params return this.$route.params
} }
}, },
watch: { watch: {
params(v) { routeParams(v) {
this.$_prepareGuide(v) this.$_prepareGuide(v)
} }
}, },
created() { created() {
transformGuideSteps(this, this.steps) transformGuideSteps(this, this.guideSteps)
}, },
activated() { activated() {
let params = this.$route.params const params = this.$route.params
if (!params.navbar && !params.sidebar && 'guide' in params) { if (!params.navbar && !params.sidebar && 'guide' in params) {
delAllUrlParam() delAllUrlParam()
this.$guide(params.guide, this.steps) this.$guide(params.guide, this.guideSteps)
} }
} }
} }

@ -1,31 +0,0 @@
/*
* 首页引导步骤
* */
const steps = [
{
element: '.radar-chart',
content: '雷达图',
forceShowPrevBtn: true,
prevBtnText: '上一阶段',
onPrevious() {
this.$router.push({
path: '/redirect/index',
query: {
params: JSON.stringify({name: 'index', params: {navbar: 1, guide: 'last'}})
}
})
return false
}
},
{
element: '.pie-chart',
content: '饼图'
},
{
element: '.bar-chart',
content: '柱状图'
},
]
export default steps

@ -7,10 +7,6 @@ const steps = [
element: '#header-search', element: '#header-search',
content: '这是搜索栏,可以根据关键字搜索菜单', content: '这是搜索栏,可以根据关键字搜索菜单',
}, },
{
element: '.fullscreen-btn.right-menu-item',
content: '这是全屏按钮',
},
{ {
element: '.setting-btn.right-menu-item', element: '.setting-btn.right-menu-item',
content: '这是个性设置按钮,可以根据自己喜好进行一些设置', content: '这是个性设置按钮,可以根据自己喜好进行一些设置',
@ -25,17 +21,6 @@ const steps = [
<p>ctrl + 可以进行tab页的左右切换</p> <p>ctrl + 可以进行tab页的左右切换</p>
<p>当tab过多时通过鼠标滚轮来滚动</p> <p>当tab过多时通过鼠标滚轮来滚动</p>
<p>双击可以关闭</p>`, <p>双击可以关闭</p>`,
/*forceShowNextBtn: true,
nextBtnText: '下一阶段',
onNext() {
this.$router.push({
path: '/redirect/index',
query: {
params: JSON.stringify({name: 'index', params: {guide: 'first'}})
}
})
return false
}*/
}, },
] ]

@ -7,7 +7,7 @@ const modules = modulesFiles.keys().reduce((modules, modulePath) => {
modules[moduleName] = { modules[moduleName] = {
data() { data() {
return { return {
steps: value.default guideSteps: value.default
} }
}, },
...baseMixin ...baseMixin

@ -0,0 +1,291 @@
/*
* Live2D Widget
* https://github.com/stevenjoezhang/live2d-widget
*
* API 后端可自行搭建参考 https://github.com/fghrsh/live2d_api
*/
export default class Waifu {
constructor(tipsPath, apiPath) {
this.tipsPath = tipsPath
this.apiPath = apiPath
this.setUserAction = this.setUserAction.bind(this)
this.visibilityChange = this.visibilityChange.bind(this)
this.userAction = false
this.userActionTimer = null
this.messageTimer = null
this.messageArray = [
"好久不见,日子过得好快呢……",
"大坏蛋!你都多久没理人家了呀,嘤嘤嘤~",
"嗨~快来逗我玩吧!",
"拿小拳拳锤你胸口!",
"记得把小家加入 Adblock 白名单哦!"
]
sessionStorage.removeItem("waifu-text")
this.insertWaifu()
this.addEventListener()
this.welcomeMessage()
this.detectUserAction()
this.initModel()
this.extra()
}
insertWaifu() {
document.body.insertAdjacentHTML("beforeend",
`
<div id="waifu">
<div id="waifu-tips"></div>
<canvas id="live2d" width="300" height="300"></canvas>
<div id="waifu-tool">
<span class="el-icon-s-promotion" title="打飞机"></span>
<span class="el-icon-refresh" title="换人"></span>
<span class="el-icon-s-operation" title="换装"></span>
<span class="el-icon-camera" title="拍照"></span>
<span class="el-icon-switch-button" title="关闭"></span>
</div>
</div>
`
)
setTimeout(() => document.getElementById("waifu").style.bottom = '0', 0)
}
addEventListener() {
document.querySelector("#waifu-tool .el-icon-s-promotion").addEventListener("click", this.startAsteroids)
document.querySelector("#waifu-tool .el-icon-refresh").addEventListener("click", this.loadOtherModel.bind(this))
document.querySelector("#waifu-tool .el-icon-s-operation").addEventListener("click", this.loadRandModel.bind(this))
document.querySelector("#waifu-tool .el-icon-camera").addEventListener("click", this.takePicture.bind(this))
document.querySelector("#waifu-tool .el-icon-switch-button").addEventListener("click", this.exit.bind(this))
window.addEventListener("mousemove", this.setUserAction)
window.addEventListener("keydown", this.setUserAction)
window.addEventListener("visibilitychange", this.visibilityChange)
}
removeEventListener() {
window.removeEventListener("mousemove", this.setUserAction)
window.removeEventListener("keydown", this.setUserAction)
window.removeEventListener("visibilitychange", this.visibilityChange)
}
detectUserAction() {
window.setInterval(() => {
if (this.userAction) {
this.userAction = false
window.clearInterval(this.userActionTimer)
this.userActionTimer = null
}
else if (!this.userActionTimer) {
this.userActionTimer = window.setInterval(() => {
this.showMessage(this.randomSelection(this.messageArray), 6000, 9)
}, 20000)
}
}, 1000)
}
setUserAction() {
this.userAction = true
}
startAsteroids() {
if (window.Asteroids) {
if (!window.ASTEROIDSPLAYERS) window.ASTEROIDSPLAYERS = []
window.ASTEROIDSPLAYERS.push(new window.Asteroids())
}
else {
const script = document.createElement("script")
script.src = "https://cdn.jsdelivr.net/gh/GalaxyMimi/CDN/asteroids.js"
document.head.appendChild(script)
}
}
takePicture() {
this.showMessage("照好了嘛,是不是很可爱呢?", 6000, 9)
window.Live2D.captureName = "photo.png"
window.Live2D.captureFrame = true
}
welcomeMessage() {
let text, now = new Date().getHours()
if (now > 5 && now <= 7) text = "早上好!一日之计在于晨,美好的一天就要开始了。"
else if (now > 7 && now <= 11) text = "上午好!工作顺利嘛,不要久坐,多起来走动走动哦!"
else if (now > 11 && now <= 13) text = "中午了,工作了一个上午,现在是午餐时间!"
else if (now > 13 && now <= 17) text = "午后很容易犯困呢,今天的运动目标完成了吗?"
else if (now > 17 && now <= 19) text = "傍晚了!窗外夕阳的景色很美丽呢,最美不过夕阳红~"
else if (now > 19 && now <= 21) text = "晚上好,今天过得怎么样?"
else if (now > 21 && now <= 23) text = ["已经这么晚了呀,早点休息吧,晚安~", "深夜时要爱护眼睛呀!"]
else text = "你是夜猫子呀?这么晚还不睡觉,明天起的来嘛?"
this.showMessage(text, 7000, 8)
}
visibilityChange() {
!document.hidden && this.showMessage("哇,你终于回来了~", 6000, 9)
}
randomSelection(array) {
return Array.isArray(array) ? array[Math.floor(Math.random() * array.length)] : array
}
initModel() {
let modelId = localStorage.getItem("modelId"),
modelTexturesId = localStorage.getItem("modelTexturesId")
if (modelId == null) {
// 首次访问加载 指定模型 的 指定材质
modelId = 1 // 模型 ID
modelTexturesId = 53 // 材质 ID
}
this.loadModel(modelId, modelTexturesId)
fetch(this.tipsPath)
.then(response => response.json())
.then(result => {
for (const key of ['mouseover', 'click']) {
window.addEventListener(key, event => {
for (const tips of result[key]) {
if (!event.target.matches(tips.selector)) continue
const text = this.randomSelection(tips.text).replace("{text}", event.target.innerText)
return this.showMessage(text, 4000, 8)
}
})
}
})
}
loadModel(modelId, modelTexturesId) {
localStorage.setItem("modelId", modelId)
if (modelTexturesId === undefined) modelTexturesId = 0
localStorage.setItem("modelTexturesId", modelTexturesId)
window.loadlive2d(
"live2d",
`${this.apiPath}/get/?id=${modelId}-${modelTexturesId}`,
console.log(`Live2D 模型 ${modelId}-${modelTexturesId} 加载完成`)
)
}
//调用一言api
showHitokoto() {
// 增加 hitokoto.cn 的 API
fetch("https://v1.hitokoto.cn")
.then(response => response.json())
.then(result => {
const text = `这句一言来自 <span>「${result.from}」</span>,是 <span>${result.creator}</span> 在 hitokoto.cn 投稿的。`
this.showMessage(result.hitokoto, 6000, 9)
setTimeout(() => this.showMessage(text, 4000, 9), 6000)
})
}
showMessage(text, timeout, priority) {
if (!text) return
if (!sessionStorage.getItem("waifu-text") ||
sessionStorage.getItem("waifu-text") <= priority) {
if (this.messageTimer) {
window.clearTimeout(this.messageTimer)
this.messageTimer = null
}
if (Array.isArray(text)) text = this.randomSelection(text)
sessionStorage.setItem("waifu-text", priority)
const tips = document.getElementById("waifu-tips")
if (!tips) return
tips.innerHTML = text
tips.classList.add("waifu-tips-active")
this.messageTimer = window.setTimeout(() => {
sessionStorage.removeItem("waifu-text")
tips.classList.remove("waifu-tips-active")
}, timeout)
}
}
//换装
loadRandModel() {
const modelId = localStorage.getItem("modelId"),
modelTexturesId = localStorage.getItem("modelTexturesId")
// 可选 "rand"(随机), "switch"(顺序)
fetch(`${this.apiPath}/rand_textures/?id=${modelId}-${modelTexturesId}`)
.then(response => response.json())
.then(result => {
if (result.textures.id === 1 &&
(modelTexturesId === '1' || modelTexturesId === '0')) {
this.showMessage("我还没有其他衣服呢!", 4000, 10)
}
else this.showMessage("我的新衣服好看嘛?", 4000, 10)
this.loadModel(modelId, result.textures.id)
})
}
//切换其他模型
loadOtherModel() {
const modelId = localStorage.getItem("modelId")
fetch(`${this.apiPath}/switch/?id=${modelId}`)
.then(response => response.json())
.then(result => {
this.loadModel(result.model.id)
this.showMessage(result.model.message, 4000, 10)
})
}
extra() {
const devtools = () => ({})
console.log("%c", devtools)
devtools.toString = () => this.showMessage("哈哈,你打开了控制台,是想要看看我的小秘密吗?", 6000, 9)
console.log(`
__,.ヘヽ. / ,
', !--i / /´
' L/
/ /, /| , , ',
/ /-‐/ L_ ! i
7 '-!| |
!,/7 '0' ´0i| |
|." _ ,,,, / |./ |
'| i.,,__ _,. / .i |
'| | / k_7_/レ', . |
| |/i 〈|/ i ,. | i |
.|/ / ! |
kヽ> _,. /!
!'〈//`T´', '7'ーr'
'ヽL__|___i,___,ンレ|
-,/ |___./
'ー' !_,.:
`)
}
exit() {
this.showMessage("愿你有一天能与重要的人重逢。", 2000, 11)
this.removeEventListener()
const dom = document.getElementById("waifu")
dom.style.bottom = "-500px"
setTimeout(() => dom.remove && dom.remove(), 3000)
}
}

@ -32,6 +32,7 @@ const routes = [
path: '/user', path: '/user',
component: Layout, component: Layout,
redirect: '/user/index', redirect: '/user/index',
hidden: true,
children: [ children: [
{ {
path: 'index', path: 'index',
@ -39,8 +40,7 @@ const routes = [
component: () => lazyLoadView(import('@/views/userCenter')), component: () => lazyLoadView(import('@/views/userCenter')),
meta: {title: '个人中心', noCache: true, icon: 'user'}, meta: {title: '个人中心', noCache: true, icon: 'user'},
} }
], ]
hidden: true
} }
] ]

@ -9,7 +9,7 @@
* 搜索选项显示name && meta.title * 搜索选项显示name && meta.title
* tab栏显示name && meta.title * tab栏显示name && meta.title
* tab栏固定显示meta.affix * tab栏固定显示meta.affix
* 页面不缓存!name || meta.noCache * 页面不缓存!name && !meta.isDetailPage || meta.noCache
* 打开iframemeta.iframe不会重复打开相同src的iframe * 打开iframemeta.iframe不会重复打开相同src的iframe
* */ * */
import Vue from 'vue' import Vue from 'vue'
@ -71,7 +71,7 @@ router.beforeEach(async (to, from, next) => {
//页面不需要鉴权或有访问权限时通过 //页面不需要鉴权或有访问权限时通过
if (!needAuth(to) || auth(to.path)) { if (!needAuth(to) || auth(to.path)) {
iframeControl(to) iframeControl(to, from)
return next() return next()
} }
@ -90,9 +90,14 @@ function initMenu() {
} }
//判断是否需要打开iframe //判断是否需要打开iframe
function iframeControl(route) { function iframeControl(to, from) {
const operate = route.meta.iframe ? 'open' : 'close' const isRefresh = to.path === '/redirect' + from.path
store.dispatch(`iframe/${operate}`, route.meta.iframe) let iframe = to.meta && to.meta.iframe
const operate = iframe ? 'open' : 'close'
if (isRefresh) iframe = from.meta && from.meta.iframe
return store.dispatch(`iframe/${operate}`, iframe)
} }
export default router export default router

@ -5,8 +5,7 @@ import PageSkeleton from "@/components/Skeleton/PageSkeleton"
//拼接页面标题 //拼接页面标题
export function getPageTitle(route) { export function getPageTitle(route) {
let pageTitle = route.meta && route.meta.title const pageTitle = route.meta && route.meta.title
if (typeof pageTitle === 'function') pageTitle = pageTitle(route)
return pageTitle ? `${pageTitle} - ${title}` : title return pageTitle ? `${pageTitle} - ${title}` : title
} }

@ -13,15 +13,13 @@ const mutations = {
state.list.push(src) state.list.push(src)
}, },
del(state, src) { del(state, src) {
if (!src) return const index = state.list.findIndex(i => i === src)
let index = state.list.findIndex(i => i === src)
index > -1 && state.list.splice(index, 1) index > -1 && state.list.splice(index, 1)
} }
} }
const actions = { const actions = {
open({commit}, src) { open({commit}, src) {
if (!src) return
commit('show', true) commit('show', true)
commit('current', src) commit('current', src)
commit('add', src) commit('add', src)

@ -8,7 +8,7 @@ const state = {
cachedViews: [], cachedViews: [],
//路由过渡动画名称 //路由过渡动画名称
transitionName: '' transitionName: 'el-fade-in-linear'
} }
const mutations = { const mutations = {
@ -22,9 +22,9 @@ const mutations = {
state.visitedViews.push({...view, title}) state.visitedViews.push({...view, title})
}, },
addCachedView(state, view) { addCachedView(state, view) {
const {noCache, iframe} = view.meta || {} const {noCache, iframe, isDetailPage} = view.meta || {}
if (noCache || iframe) return if (noCache || iframe || !view.name && !isDetailPage) return
const key = getCachedViewKey(view) const key = getCachedViewKey(view)

@ -42,3 +42,39 @@ export function getContextPath() {
const {protocol, host} = document.location const {protocol, host} = document.location
return `${protocol}//${host}${process.env.BASE_URL}` return `${protocol}//${host}${process.env.BASE_URL}`
} }
/**
* 加载js或css
*
* @param url
* @param type js|css
* @returns {Promise<String>} url
*/
export function loadExternalResource(url, type = 'js') {
return new Promise((resolve, reject) => {
let tag
if (type === "css") {
const links = Array.from(document.getElementsByTagName('link'))
if (links.some(link => link.getAttribute('href') === url)) return resolve()
tag = document.createElement("link")
tag.rel = "stylesheet"
tag.href = url
}
else if (type === "js") {
const scripts = Array.from(document.getElementsByTagName('script'))
if (scripts.some(script => script.getAttribute('src') === url)) return resolve()
tag = document.createElement("script")
tag.src = url
}
if (tag) {
tag.onload = () => resolve(url)
tag.onerror = () => reject(url)
document.head.appendChild(tag)
}
else reject(`没有这个东东,url:${url},type:${type}`)
})
}

@ -1,6 +1,6 @@
/** /**
* @deprecated * @deprecated
* xlsx问题多多准备全面转向excelJS * xlsx问题多多转向excelJS
*/ */
import {isEmpty} from "@/utils" import {isEmpty} from "@/utils"

@ -49,7 +49,7 @@ export function timeFormat(fmt, date = new Date()) {
fmt = fmt.replace(RegExp.$1, [...replace].join('')) fmt = fmt.replace(RegExp.$1, [...replace].join(''))
} }
for (let k in o) { for (const k in o) {
if (new RegExp(`(${k})`).test(fmt)) { if (new RegExp(`(${k})`).test(fmt)) {
const firstMatch = RegExp.$1 const firstMatch = RegExp.$1
const replace = firstMatch.length === 1 ? o[k] : ("00" + o[k]).substring(("" + o[k]).length) const replace = firstMatch.length === 1 ? o[k] : ("00" + o[k]).substring(("" + o[k]).length)

@ -1,6 +1,6 @@
/*基于decimal.js的运算封装*/
import Decimal from 'decimal.js' import Decimal from 'decimal.js'
/*基于decimal.js的运算封装*/
export function plus(...val) { export function plus(...val) {
if (val.length === 0) return 0 if (val.length === 0) return 0
else if (val.length === 1) return new Decimal(val[0]).toNumber() else if (val.length === 1) return new Decimal(val[0]).toNumber()

@ -1,3 +1,5 @@
@import "~@/assets/styles/variables.scss";
$bg: #283443; $bg: #283443;
$light_gray: #fff; $light_gray: #fff;
$dark_gray: #889aa4; $dark_gray: #889aa4;

@ -38,6 +38,8 @@
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import "~@/assets/styles/variables.scss";
.q-skeleton + .q-skeleton { .q-skeleton + .q-skeleton {
margin-top: 20px; margin-top: 20px;
} }

@ -9,81 +9,28 @@
</template> </template>
<script> <script>
import {getContextPath} from "@/utils/browser" import {getContextPath, loadExternalResource} from "@/utils/browser"
/**
* 加载js或css
* @param url
* @param type js|css
* @returns {Promise<String>} url
*/
function loadExternalResource(url, type = 'js') {
return new Promise((resolve, reject) => {
let tag
if (type === "css") {
const links = Array.from(document.getElementsByTagName('link'))
if (links.some(link => link.getAttribute('href') === url)) return resolve()
tag = document.createElement("link")
tag.rel = "stylesheet"
tag.href = url
}
else if (type === "js") {
const scripts = Array.from(document.getElementsByTagName('script'))
if (scripts.some(script => script.getAttribute('src') === url)) return resolve()
tag = document.createElement("script")
tag.src = url
}
if (tag) {
tag.onload = () => resolve(url)
tag.onerror = () => reject(url)
document.head.appendChild(tag)
}
else reject(`没有这个东东,url:${url},type:${type}`)
})
}
export default { export default {
name: "l2d", name: "l2d",
data: () => ({l2d: null}),
mounted() { mounted() {
//live2d_path 使 const path = `${getContextPath()}static/live2d/`
//const live2d_path = "https://cdn.jsdelivr.net/gh/stevenjoezhang/live2d-widget/"
const live2d_path = `${getContextPath()}static/live2d/`
// waifu.css live2d.min.js waifu-tips.js
Promise.all([ Promise.all([
loadExternalResource(live2d_path + "waifu.css", "css"), import('@/plugin/live2d'),
loadExternalResource(live2d_path + "live2d.min.js"), loadExternalResource(path + "waifu.css", "css"),
loadExternalResource(live2d_path + "waifu-tips.js") loadExternalResource(path + "live2d.min.js")
]) ])
.then(() => { .then(([_]) => {
// initWidget waifu-tips.json API this.l2d = new _.default(`${path}waifu-tips.json`, "https://live2d.fghrsh.net/api")
// API https://github.com/fghrsh/live2d_api
// waifu-tips.json
window.initWidget(live2d_path + "waifu-tips.json", "https://live2d.fghrsh.net/api")
console.log(`
__,.ヘヽ. / ,
', !--i / /´
' L/
/ /, /| , , ',
/ /-‐/ L_ ! i
7 '-!| |
!,/7 '0' ´0i| |
|." _ ,,,, / |./ |
'| i.,,__ _,. / .i |
'| | / k_7_/レ', . |
| |/i 〈|/ i ,. | i |
.|/ / ! |
kヽ> _,. /!
!'〈//`T´', '7'ーr'
'ヽL__|___i,___,ンレ|
-,/ |___./
'ー' !_,.:
`)
}) })
},
beforeDestroy() {
this.l2d && this.l2d.exit()
} }
} }
</script> </script>

@ -71,8 +71,6 @@
<script> <script>
import {elError, elSuccess} from "@/utils/message" import {elError, elSuccess} from "@/utils/message"
import compressJPG from '@/plugin/imageCompress/cjpeg'
import compressPNG from '@/plugin/imageCompress/pngquant'
import {sub, mul, div} from "@/utils/math" import {sub, mul, div} from "@/utils/math"
const commonData = () => ({ const commonData = () => ({
@ -146,12 +144,14 @@
reader.readAsArrayBuffer(this[type].input.file) reader.readAsArrayBuffer(this[type].input.file)
}, },
compressJPG(uint8Array, start) { compressJPG(uint8Array, start) {
compressJPG(uint8Array, this.jpg.quality) import('@/plugin/imageCompress/cjpeg')
.then(_ => _.default(uint8Array, this.jpg.quality))
.then(({data, time}) => this.compressSuccess({type: 'jpg', start, data, time})) .then(({data, time}) => this.compressSuccess({type: 'jpg', start, data, time}))
.finally(() => this.jpg.loading = false) .finally(() => this.jpg.loading = false)
}, },
compressPNG(uint8Array, start) { compressPNG(uint8Array, start) {
compressPNG(uint8Array, this.png.quality, this.png.speed) import('@/plugin/imageCompress/pngquant')
.then(_ => _.default(uint8Array, this.png.quality, this.png.speed))
.then(({data, time}) => this.compressSuccess({type: 'png', start, data, time})) .then(({data, time}) => this.compressSuccess({type: 'png', start, data, time}))
.finally(() => this.png.loading = false) .finally(() => this.png.loading = false)
}, },
@ -166,7 +166,10 @@
} }
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import "~@/assets/styles/variables.scss";
.container { .container {
max-width: 1200px; max-width: 1200px;
text-align: center; text-align: center;

@ -117,6 +117,8 @@
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import "~@/assets/styles/variables.scss";
.el-table { .el-table {
a { a {
color: $--color-primary; color: $--color-primary;

@ -45,6 +45,8 @@
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import "~@/assets/styles/variables.scss";
span { span {
.svg-icon { .svg-icon {
color: $--color-primary color: $--color-primary

@ -13,6 +13,7 @@
</el-form-item> </el-form-item>
<el-form-item label="行政区域:" prop="region_name"> <el-form-item label="行政区域:" prop="region_name">
<region-selector <region-selector
type="tree"
:value="form.region_name" :value="form.region_name"
:readonly="!canEdit" :readonly="!canEdit"
@clear="clearRegion" @clear="clearRegion"
@ -55,7 +56,7 @@
<script> <script>
import DialogForm from '@/components/DialogForm' import DialogForm from '@/components/DialogForm'
import RegionSelector from '@/components/RegionSelector/Tree' import RegionSelector from '@/components/RegionSelector'
import dialogMixin from "@/mixins/dialogMixin" import dialogMixin from "@/mixins/dialogMixin"
import {addSupplier, updateSupplier} from "@/api/system/supplier" import {addSupplier, updateSupplier} from "@/api/system/supplier"
import {isEmpty, mergeObj, resetObj} from '@/utils' import {isEmpty, mergeObj, resetObj} from '@/utils'

@ -6,6 +6,7 @@
</search-form-item> </search-form-item>
<search-form-item label="行政区域:"> <search-form-item label="行政区域:">
<region-selector <region-selector
type="tree"
:value="temp.region_name" :value="temp.region_name"
limit limit
:limit-api="getLimitRegion" :limit-api="getLimitRegion"
@ -83,7 +84,7 @@
<script> <script>
import SearchForm from "@/components/SearchForm" import SearchForm from "@/components/SearchForm"
import SearchFormItem from "@/components/SearchForm/SearchFormItem" import SearchFormItem from "@/components/SearchForm/SearchFormItem"
import RegionSelector from "@/components/RegionSelector/Tree" import RegionSelector from "@/components/RegionSelector"
import EditDialog from './EditDialog' import EditDialog from './EditDialog'
import {delSupplier, getLimitRegion, getSuppliers} from "@/api/system/supplier" import {delSupplier, getLimitRegion, getSuppliers} from "@/api/system/supplier"
import {isEmpty} from '@/utils' import {isEmpty} from '@/utils'

@ -125,8 +125,8 @@
} }
.img-wrapper { .img-wrapper {
height: 360px; height: 500px;
width: 640px; width: 100%;
display: inline-block; display: inline-block;
border: 1px solid #ebebeb; border: 1px solid #ebebeb;
} }

@ -81,9 +81,9 @@ module.exports = {
.options({symbolId: 'icon-[name]'}) .options({symbolId: 'icon-[name]'})
.end() .end()
}, },
css: { /*css: {
loaderOptions: { loaderOptions: {
sass: {prependData: `@import "src/assets/styles/variables.scss";`,} sass: {prependData: `@import "src/assets/styles/variables.scss";`,}
} }
} }*/
} }

Loading…
Cancel
Save