refactor: remove old demo pages and static menu logic

1. 删除大量旧的示例页面、组件示例和静态菜单配置
2. 新增菜单扁平数组转树形结构工具函数
3. 重构菜单加载逻辑,改为从后端动态获取并格式化
4. 新增全局权限检查方法和自定义权限指令
5. 优化侧边栏菜单路由跳转逻辑,自动跳转第一个有权限的子页面
6. 移除路由中对旧demo模块的引用
This commit is contained in:
sheng
2026-05-27 18:07:48 +08:00
parent 0f3b5d4371
commit 2cc8329695
96 changed files with 799 additions and 4985 deletions

View File

@@ -1,104 +0,0 @@
<template>
<d2-container
ref="container"
:type="containerType"
:better-scroll="betterScroll"
:scroll-delay="scrollDelay"
@scroll="({x, y}) => { scrollTop = y }">
<template slot="header">
<el-form
:inline="true"
size="mini">
<el-form-item
label="布局类型"
class="d2-mb-0">
<el-radio-group v-model="containerType">
<el-radio-button label="full"></el-radio-button>
<el-radio-button label="card"></el-radio-button>
<el-radio-button label="ghost"></el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item
label="滚动距离"
class="d2-mb-0">
<el-input
:value="scrollTop"
style="width: 130px;">
<template slot="append">px</template>
</el-input>
</el-form-item>
<el-form-item
v-if="!betterScroll"
label="事件延迟(ms)"
class="d2-mb-0">
<el-input-number
v-model="scrollDelay"
:min="10"
:max="2000"
:step="100"
style="width: 110px;"/>
</el-form-item>
<el-form-item class="d2-mb-0">
<el-button
v-if="scrollTop >= 55"
type="primary"
@click="$refs.container.scrollToTop">
回到顶部
</el-button>
</el-form-item>
</el-form>
</template>
<el-alert
type="success"
:title="`${betterScroll ? '此示例开启了 BetterScroll ' : ''}请向下滚动`"
class="d2-mb-10"
center/>
<d2-demo-article
v-for="i in 10"
:key="i"
:style="articleStyle"
long/>
<el-form
slot="footer"
:inline="true"
size="mini">
<el-form-item class="d2-mb-0">
<el-button @click="$refs.container.scrollBy(0, 30)">相对滚动 (0, 30) 像素</el-button>
</el-form-item>
<el-form-item class="d2-mb-0">
<el-button @click="$refs.container.scrollTo(0, 100)">滚动到 (0, 100) 像素位置</el-button>
</el-form-item>
<el-form-item class="d2-mb-0">
<el-button @click="$refs.container.scrollTop(100)">滚动到垂直位置 100</el-button>
</el-form-item>
</el-form>
</d2-container>
</template>
<script>
import d2DemoArticle from './components/d2-demo-article'
export default {
components: {
'd2-demo-article': d2DemoArticle
},
data () {
return {
containerType: 'full',
scrollDelay: 10,
scrollTop: 0
}
},
computed: {
// 是否开启 better scroll
betterScroll () {
return this.$route.query.bs === 'true'
},
// 根据滚动位置返回文章的样式
articleStyle () {
return {
opacity: this.scrollTop > 55 ? '1' : '.1'
}
}
}
}
</script>

View File

@@ -1,16 +0,0 @@
<template>
<d2-container type="card" better-scroll>
<template slot="header">Header</template>
<d2-demo-article/>
<template slot="footer">Footer</template>
</d2-container>
</template>
<script>
import d2DemoArticle from './components/d2-demo-article'
export default {
components: {
'd2-demo-article': d2DemoArticle
}
}
</script>

View File

@@ -1,16 +0,0 @@
<template>
<d2-container type="card">
<template slot="header">Header</template>
<d2-demo-article/>
<template slot="footer">Footer</template>
</d2-container>
</template>
<script>
import d2DemoArticle from './components/d2-demo-article'
export default {
components: {
'd2-demo-article': d2DemoArticle
}
}
</script>

View File

@@ -1,14 +0,0 @@
<template>
<d2-container type="card">
<d2-demo-article/>
</d2-container>
</template>
<script>
import d2DemoArticle from './components/d2-demo-article'
export default {
components: {
'd2-demo-article': d2DemoArticle
}
}
</script>

View File

@@ -1,50 +0,0 @@
<template>
<div class="d2-demo-article">
<div v-if="!long" class="d2-demo-article__control">
<el-switch
v-model="isLong"
active-text="长内容"
inactive-text="短内容"/>
</div>
<d2-markdown v-show="isLong" :source="sourceLong"/>
<d2-markdown v-show="!isLong" :source="sourceShort"/>
</div>
</template>
<script>
import sourceLong from '../md/long.md'
import sourceShort from '../md/short.md'
export default {
props: {
// 指定为长文本
long: {
type: Boolean,
required: false,
default: false
}
},
data () {
return {
sourceLong,
sourceShort,
isLong: false
}
},
created () {
this.isLong = this.long
}
}
</script>
<style lang="scss" scoped>
.d2-demo-article {
transition: opacity .3s;
.d2-demo-article__control {
padding: 8px 16px;
margin-bottom: 10px;
box-sizing: border-box;
border-radius: 4px;
background-color: #f4f4f5;
}
}
</style>

View File

@@ -1,16 +0,0 @@
<template>
<d2-container better-scroll>
<template slot="header">Header</template>
<d2-demo-article/>
<template slot="footer">Header</template>
</d2-container>
</template>
<script>
import d2DemoArticle from './components/d2-demo-article'
export default {
components: {
'd2-demo-article': d2DemoArticle
}
}
</script>

View File

@@ -1,16 +0,0 @@
<template>
<d2-container>
<template slot="header">Header</template>
<d2-demo-article/>
<template slot="footer">Footer</template>
</d2-container>
</template>
<script>
import d2DemoArticle from './components/d2-demo-article'
export default {
components: {
'd2-demo-article': d2DemoArticle
}
}
</script>

View File

@@ -1,14 +0,0 @@
<template>
<d2-container>
<d2-demo-article/>
</d2-container>
</template>
<script>
import d2DemoArticle from './components/d2-demo-article'
export default {
components: {
'd2-demo-article': d2DemoArticle
}
}
</script>

View File

@@ -1,20 +0,0 @@
<template>
<d2-container type="ghost" better-scroll>
<template slot="header">Header</template>
<div class="d2-pt d2-pb">
<el-card shadow="never" class="d2-card" style="width: 400px;">
<d2-demo-article/>
</el-card>
</div>
<template slot="footer">Footer</template>
</d2-container>
</template>
<script>
import d2DemoArticle from './components/d2-demo-article'
export default {
components: {
'd2-demo-article': d2DemoArticle
}
}
</script>

View File

@@ -1,20 +0,0 @@
<template>
<d2-container type="ghost">
<template slot="header">Header</template>
<div class="d2-pt d2-pb">
<el-card shadow="never" class="d2-card" style="width: 400px;">
<d2-demo-article/>
</el-card>
</div>
<template slot="footer">Footer</template>
</d2-container>
</template>
<script>
import d2DemoArticle from './components/d2-demo-article'
export default {
components: {
'd2-demo-article': d2DemoArticle
}
}
</script>

View File

@@ -1,18 +0,0 @@
<template>
<d2-container type="ghost">
<div class="d2-pt d2-pb">
<el-card shadow="never" class="d2-card" style="width: 400px;">
<d2-demo-article/>
</el-card>
</div>
</d2-container>
</template>
<script>
import d2DemoArticle from './components/d2-demo-article'
export default {
components: {
'd2-demo-article': d2DemoArticle
}
}
</script>

View File

@@ -1,53 +0,0 @@
## vue.js
**易用**
已经会了 HTML、CSS、JavaScript即刻阅读指南开始构建应用
**灵活**
不断繁荣的生态系统,可以在一个库和一套完整框架之间自如伸缩。
**高效**
20kB min+gzip 运行大小
超快虚拟 DOM
最省心的优化
**Vue.js 是什么**
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层不仅易于上手还便于与第三方库或既有项目整合。另一方面当与现代化的工具链以及各种支持类库结合使用时Vue 也完全能够为复杂的单页应用提供驱动。
如果你已经是有经验的前端开发者,想知道 Vue 与其它库/框架有哪些区别,请查看对比其它框架。
## Element
Element一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库
**一致性** Consistency
- 与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念;
- 在界面中一致:所有的元素和结构需保持一致,比如:设计样式、图标和文本、元素的位置等。
**反馈** Feedback
- 控制反馈:通过界面样式和交互动效让用户可以清晰的感知自己的操作;
- 页面反馈:操作后,通过页面元素的变化清晰地展现当前状态。
**效率** Efficiency
- 简化流程:设计简洁直观的操作流程;
- 清晰明确:语言表达清晰且表意明确,让用户快速理解进而作出决策;
- 帮助用户识别:界面简单直白,让用户快速识别而非回忆,减少用户记忆负担。
**可控** Controllability
- 用户决策:根据场景可给予用户操作建议或安全提示,但不能代替用户进行决策;
- 结果可控:用户可以自由的进行操作,包括撤销、回退和终止当前操作等。

View File

@@ -1,17 +0,0 @@
## vue.js
**易用**
已经会了 HTML、CSS、JavaScript即刻阅读指南开始构建应用
**灵活**
不断繁荣的生态系统,可以在一个库和一套完整框架之间自如伸缩。
**高效**
20kB min+gzip 运行大小
超快虚拟 DOM
最省心的优化

View File

@@ -1,94 +0,0 @@
<template>
<d2-container type="card" class="page">
<template slot="header">数字动画组件</template>
<el-row :gutter="20">
<el-col :span="6">
<el-card shadow="never" class="d2-card d2-mb">
<p slot="title">只设置目标数字</p>
<div class="group">
<d2-count-up :end="100"/>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card shadow="never" class="d2-card d2-mb">
<p slot="title">设置起止数值</p>
<div class="group">
<d2-count-up :start="14" :end="100"/>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card shadow="never" class="d2-card d2-mb">
<p slot="title">小数位数</p>
<div class="group">
<d2-count-up :end="100" :decimals="2"/>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card shadow="never" class="d2-card d2-mb">
<p slot="title">动画时长</p>
<div class="group">
<d2-count-up :end="100" :duration="6"/>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card shadow="never" class="d2-card">
<p slot="title">回调函数</p>
<div class="group">
<d2-count-up :end="100" :callback="() => {className = 'end'}" :class="className"/>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card shadow="never" class="d2-card d2-mb-0">
<p slot="title">结束一秒后更新数值</p>
<div class="group">
<d2-count-up :end="end" :callback="update"/>
</div>
</el-card>
</el-col>
</el-row>
</d2-container>
</template>
<script>
export default {
data () {
return {
// 回调函数使用
className: '',
// 更新数值用
end: 50
}
},
methods: {
update () {
setTimeout(() => {
this.end = 100
}, 1000)
}
}
}
</script>
<style lang="scss" scoped>
.page {
.group {
display: flex;
justify-content: center;
align-items: center;
span {
font-size: 60px;
&.end {
padding: 0px 20px;
border-radius: 4px;
background-color: $color-success;
color: #FFF;
}
}
}
}
</style>

View File

@@ -1,49 +0,0 @@
<template>
<d2-container>
<d2-quill
style="min-height: 200px; margin-bottom: 20px;"
v-model="value"
@text-change="textChangeHandler"
@selection-change="selectionChangeHandler"
@editor-change="editorChangeHandler"/>
<el-button
type="primary"
@click="handleAddRow">
添加一行
</el-button>
<el-card shadow="never" class="d2-card d2-mt">
<d2-highlight :code="value" format-html/>
</el-card>
</d2-container>
</template>
<script>
import value from './value'
export default {
data () {
return {
value
}
},
methods: {
handleAddRow () {
this.value += '<p style="color: #409EFF;">我是新增的行</p>'
},
textChangeHandler (delta, oldDelta, source) {
// console.group('QuillEditor textChangeHandler')
// console.log(delta, oldDelta, source)
// console.groupEnd()
},
selectionChangeHandler (range, oldRange, source) {
// console.group('QuillEditor selectionChangeHandler')
// console.log(range, oldRange, source)
// console.groupEnd()
},
editorChangeHandler (eventName, ...args) {
// console.group('QuillEditor editorChangeHandler')
// console.log(eventName, args)
// console.groupEnd()
}
}
}
</script>

View File

@@ -1,6 +0,0 @@
export default `<p>
<a href="https://github.com/d2-projects/d2-admin" target="_blank" class="ql-size-large" style="color: rgb(65, 184, 131);"><strong>D2 Admin</strong></a>
<strong style="color: rgb(65, 184, 131);"></strong>
by
<a href="https://cn.vuejs.org/" target="_blank" class="ql-size-large" style="color: rgb(65, 184, 131);"><strong>vue.js</strong></a>
</p>`

View File

@@ -1,33 +0,0 @@
<template>
<d2-container type="card">
<el-row :gutter="20">
<el-col :span="14">
<d2-ueditor v-model="text"/>
</el-col>
<el-col :span="10">
<el-card v-if="text" shadow="never" style="border: 1px solid #d4d4d4;">
<template slot="header">Result</template>
<div v-html="text" style="margin: -20px 0px;"></div>
</el-card>
</el-col>
</el-row>
<template slot="footer">
<el-button type="primary" @click="text += text">
<d2-icon name="copy"/> 当前内容 x2
</el-button>
<el-button type="danger" @click="text = ''">
<d2-icon name="trash-o"/> 清空
</el-button>
</template>
</d2-container>
</template>
<script>
export default {
data () {
return {
text: '<p>Hello World</p>'
}
}
}
</script>

View File

@@ -1,8 +0,0 @@
export default `body {
background-color: aliceblue;
height: 100%;
}
.my-card {
height: 300px;
width: 300px;
}`

View File

@@ -1,8 +0,0 @@
export default `<ul>
<li class="li-1"><p>Hello</p></li>
<li>
<span style="color: red;">
Hello
</span>
</li>
</ul>`

View File

@@ -1,3 +0,0 @@
export default `[].forEach.call($$("*"), a => {
a.style.outline="1px solid #"+(~~(Math.random()*(1<<24))).toString(16)
})`

View File

@@ -1,8 +0,0 @@
export default `body {
background-color: aliceblue;
height: 100%;
.my-card {
height: 300px;
width: 300px;
}
}`

View File

@@ -1,38 +0,0 @@
<template>
<d2-container>
<template slot="header">代码高亮组件</template>
<el-card shadow="never" class="d2-mb">
<p slot="title">javascript</p>
<d2-highlight :code="codeJavascript"/>
</el-card>
<el-card shadow="never" class="d2-mb">
<p slot="title">css</p>
<d2-highlight :code="codeCSS"/>
</el-card>
<el-card shadow="never" class="d2-mb">
<p slot="title">scss</p>
<d2-highlight :code="codeSCSS"/>
</el-card>
<el-card shadow="never">
<p slot="title">html</p>
<d2-highlight :code="codeHTML"/>
</el-card>
</d2-container>
</template>
<script>
import codeJavascript from './code/javascript'
import codeCSS from './code/css'
import codeSCSS from './code/scss'
import codeHTML from './code/html'
export default {
data () {
return {
codeJavascript,
codeCSS,
codeSCSS,
codeHTML
}
}
}
</script>

View File

@@ -1,82 +0,0 @@
<template>
<div>
<el-popover
ref="pop"
placement="right"
:title="icon"
width="300"
trigger="click">
<div class="icon-group">
<i :class="'fa fa-' + icon"></i>
</div>
<el-row :gutter="10">
<el-col :span="8">
<el-tooltip effect="dark" :content="iconClass" placement="top">
<el-button @click="copy(iconClass)" style="width: 100%;">Class</el-button>
</el-tooltip>
</el-col>
<el-col :span="8">
<el-tooltip effect="dark" :content="iconHtml" placement="top">
<el-button @click="copy(iconHtml)" style="width: 100%;">HTML</el-button>
</el-tooltip>
</el-col>
<el-col :span="8">
<el-tooltip effect="dark" :content="iconComponent" placement="top">
<el-button @click="copy(iconComponent)" style="width: 100%;">组件</el-button>
</el-tooltip>
</el-col>
</el-row>
</el-popover>
<span v-popover:pop>
<el-tag type="info" class="icon-tag">
<i :class="'fa fa-' + icon"></i>
</el-tag>
<span style="font-size: 10px;">{{icon}}</span>
</span>
</div>
</template>
<script>
import * as clipboard from 'clipboard-polyfill'
export default {
props: {
icon: {
type: String,
required: false,
default: ''
}
},
computed: {
iconClass () {
return `fa fa-${this.icon}`
},
iconHtml () {
return `<i class="fa fa-${this.icon}" aria-hidden="true"></i>`
},
iconComponent () {
return `<d2-icon name="${this.icon}"/>`
}
},
methods: {
copy (text) {
clipboard.writeText(text)
this.$message({
message: `${text} 复制到剪贴板`,
type: 'success'
})
}
}
}
</script>
<style lang="scss" scoped>
.icon-group {
text-align: center;
font-size: 200px;
}
.icon-tag {
width: 32px;
text-align: center;
margin-right: 5px;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -1,42 +0,0 @@
<template>
<d2-container>
<template slot="header">SVG图标组件</template>
<el-row>
<el-col class="icon-card" :span="4" v-for="(icon, index) in $IconSvg" :key="index">
<d2-icon-svg class="icon" :name="icon"/>
<div class="icon-title">
<span>{{icon}}</span>
</div>
</el-col>
</el-row>
</d2-container>
</template>
<style lang="scss" scoped>
.icon-card {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
height: 150px;
&:hover {
.icon {
transform: scale(1.1);
}
.icon-title {
color: $color-text-main;
}
}
}
.icon {
height: 80px;
width: 80px;
transition: all .3s;
cursor: pointer;
}
.icon-title {
font-size: 12px;
margin-top: 10px;
color: $color-text-normal;
}
</style>

View File

@@ -1,22 +0,0 @@
<template>
<d2-container>
<template slot="header">图标组件</template>
<d2-icon class="d2-mr-10"/>
<d2-icon name="github" class="d2-mr-10"/>
<d2-icon name="github" style="font-size: 100px;" class="d2-mr-10"/>
<d2-icon name="github" class="icon-demo"/>
</d2-container>
</template>
<style lang="scss" scoped>
.icon-demo {
transition: all .3s;
font-size: 100px;
color: #409EFF;
@extend %unable-select;
&:hover{
color: #F56C6C;
transform: scale(1.2) rotate(30deg);
}
}
</style>

View File

@@ -1,46 +0,0 @@
<template>
<d2-container>
<template slot="header">
<el-radio-group v-model="showIndex" size="mini">
<el-radio-button
v-for="(item, index) in radioOptions"
:key="index"
:label="item.value">
{{item.label}}
</el-radio-button>
</el-radio-group>
</template>
<el-row style="margin: -10px;">
<el-alert title="点击图标复制代码" type="info" class="d2-m-10" style="width: auto;"/>
<el-col v-for="(iconItem, iconIndex) in iconShow.icon" :key="iconIndex" :span="6" class="d2-p-10">
<d2-icon-cell :icon="iconItem"/>
</el-col>
</el-row>
</d2-container>
</template>
<script>
import icon from './data/index'
export default {
components: {
'd2-icon-cell': () => import('./components/d2-icon-cell')
},
data () {
return {
icon,
showIndex: 12
}
},
computed: {
iconShow () {
return this.icon[this.showIndex]
},
radioOptions () {
return this.icon.map((e, index) => ({
label: e.title,
value: index
}))
}
}
}
</script>

View File

@@ -1,24 +0,0 @@
<template>
<d2-container>
<template slot="header">svg 图标选择器</template>
<div class="d2-mb">
<p class="d2-mt-0 d2-mb-10">一般用法 | {{icon || '未选择'}}</p>
<d2-icon-svg-select v-model="icon"/>
</div>
<div class="d2-mb">
<p class="d2-mt-0 d2-mb-10">用户可以输入 | {{icon2 || '未选择'}}</p>
<d2-icon-svg-select v-model="icon2" :user-input="true"/>
</div>
</d2-container>
</template>
<script>
export default {
data () {
return {
icon: '',
icon2: ''
}
}
}
</script>

View File

@@ -1,56 +0,0 @@
<template>
<d2-container>
<template slot="header">图标选择器</template>
<div class="title-group">
<p class="title">一般用法</p>
<p class="sub-title">
<template v-if="icon">
选择的图标 {{icon}}
<i :class="'fa fa-' + icon"></i>
</template>
<template v-else>未选择</template>
</p>
</div>
<d2-icon-select v-model="icon"/>
<div class="title-group">
<p class="title">用户可以输入</p>
<p class="sub-title">
<template v-if="icon2">
选择的图标 {{icon2}}
<i :class="'fa fa-' + icon2"></i>
</template>
<template v-else>未选择</template>
</p>
</div>
<d2-icon-select v-model="icon2" :user-input="true"/>
</d2-container>
</template>
<script>
export default {
data () {
return {
icon: '',
icon2: ''
}
}
}
</script>
<style lang="scss" scoped>
.title-group {
margin-top: 20px;
margin-bottom: 10px;
&:first-child {
margin-top: 0px;
}
.title {
margin: 0px;
}
.sub-title {
margin: 0px;
color: $color-text-sub;
font-size: 10px;
}
}
</style>

View File

@@ -1,21 +0,0 @@
<template>
<d2-container type="ghost">
<d2-module-index-banner slot="header" v-bind="banner"/>
<d2-module-index-menu :menu="menu"/>
</d2-container>
</template>
<script>
import menu from '@/menu/modules/demo-components'
export default {
data () {
return {
menu,
banner: {
title: 'COMPONENTS',
subTitle: 'D2Admin 为你提供了一些上手即用的组件'
}
}
}
}
</script>

View File

@@ -1,24 +0,0 @@
<template>
<d2-container>
<tree-view :data="packJson" :options="options"/>
</d2-container>
</template>
<script>
import Vue from 'vue'
import vueJsonTreeView from 'vue-json-tree-view'
import packJson from '../../../../../package.json'
Vue.use(vueJsonTreeView)
export default {
data () {
return {
options: {
maxDepth: 10,
rootObjectKey: 'package.json',
modifiable: false
},
packJson
}
}
}
</script>

View File

@@ -1,122 +0,0 @@
<template>
<d2-container type="full" class="page">
<d2-grid-layout
v-bind="layout"
@layout-updated="layoutUpdatedHandler">
<d2-grid-item
v-for="(item, index) in layout.layout"
:key="index"
v-bind="item"
@resize="resizeHandler"
@move="moveHandler"
@resized="resizedHandler"
@moved="movedHandler">
<el-card shadow="never" class="page_card">
<el-tag size="mini" type="info" slot="header">Card {{item.i}}</el-tag>
<template v-if="item.i === '0'">
<div class="d2-mb">拖拽卡片调整位置</div>
<div class="d2-mb">拖拽卡片右下角的手柄调整卡片大小</div>
<div class="d2-mb">在控制台打印出数据变化</div>
</template>
</el-card>
</d2-grid-item>
</d2-grid-layout>
</d2-container>
</template>
<script>
import Vue from 'vue'
import { GridLayout, GridItem } from 'vue-grid-layout'
Vue.component('d2-grid-layout', GridLayout)
Vue.component('d2-grid-item', GridItem)
export default {
data () {
return {
layout: {
layout: [
{ x: 0, y: 0, w: 4, h: 10, i: '0' },
{ x: 4, y: 0, w: 2, h: 5, i: '1' },
{ x: 6, y: 0, w: 4, h: 5, i: '2' },
{ x: 10, y: 0, w: 2, h: 10, i: '3' },
{ x: 4, y: 5, w: 4, h: 5, i: '4' },
{ x: 8, y: 5, w: 2, h: 5, i: '5' },
{ x: 0, y: 10, w: 8, h: 5, i: '6' },
{ x: 8, y: 10, w: 4, h: 5, i: '7' }
],
colNum: 12,
rowHeight: 30,
isDraggable: true,
isResizable: true,
isMirrored: false,
verticalCompact: true,
margin: [10, 10],
useCssTransforms: true
}
}
},
mounted () {
// 加载完成后显示提示
this.showInfo()
},
methods: {
log (arg1 = 'log', ...logs) {
if (logs.length === 0) {
console.log(arg1)
} else {
console.group(arg1)
logs.forEach(e => {
console.log(e)
})
console.groupEnd()
}
},
// 显示提示
showInfo () {
this.$notify({
title: '提示',
message: '你可以按住卡片拖拽改变位置;或者在每个卡片的右下角拖动,调整卡片大小'
})
},
// 测试代码
layoutUpdatedHandler (newLayout) {
console.group('layoutUpdatedHandler')
newLayout.forEach(e => {
console.log(`{'x': ${e.x}, 'y': ${e.y}, 'w': ${e.w}, 'h': ${e.h}, 'i': '${e.i}'},`)
})
console.groupEnd()
},
resizeHandler (i, newH, newW) {
this.log('resizeHandler', `i: ${i}, newH: ${newH}, newW: ${newW}`)
},
moveHandler (i, newX, newY) {
this.log('moveHandler', `i: ${i}, newX: ${newX}, newY: ${newY}`)
},
resizedHandler (i, newH, newW, newHPx, newWPx) {
this.log('resizedHandler', `i: ${i}, newH: ${newH}, newW: ${newW}, newHPx: ${newHPx}, newWPx: ${newWPx}`)
},
movedHandler (i, newX, newY) {
this.log('movedHandler', `i: ${i}, newX: ${newX}, newY: ${newY}`)
}
}
}
</script>
<style lang="scss" scoped>
.page {
.vue-grid-layout {
background-color: $color-bg;
border-radius: 4px;
margin: -10px;
.page_card {
height: 100%;
@extend %unable-select;
}
.vue-resizable-handle {
opacity: .3;
&:hover{
opacity: 1;
}
}
}
}
</style>

View File

@@ -1,37 +0,0 @@
<template>
<d2-container type="card">
<template slot="header">区域划分</template>
<div style="height: 400px; margin: -16px;">
<SplitPane :min-percent='20' :default-percent='30' split="vertical">
<template slot="paneL"><div style="margin: 10px;"></div></template>
<template slot="paneR">
<SplitPane split="horizontal">
<template slot="paneL"><div style="margin: 10px;">右上</div></template>
<template slot="paneR"><div style="margin: 10px;">右下</div></template>
</SplitPane>
</template>
</SplitPane>
</div>
</d2-container>
</template>
<script>
import Vue from 'vue'
import SplitPane from 'vue-splitpane'
Vue.component('SplitPane', SplitPane)
export default {
mounted () {
// 加载完成后显示提示
this.showInfo()
},
methods: {
// 显示提示
showInfo () {
this.$notify({
title: '提示',
message: '在横向或者纵向的分割线上拖拽调整分区大小'
})
}
}
}
</script>

View File

@@ -1,38 +0,0 @@
# 一级标题
| ID | Name | Email |
| --- | --- | --- |
| 0001 | FairyEver | 1711467488@qq.com |
```
// 注释
[].forEach.call($$("*"), a => {
a.style.outline="1px solid #"+(~~(Math.random()*(1<<24))).toString(16)
})
```
```
<div>
<p>Hello World</p>
</div>
```
```
body {
background-color: #333;
}
```
一般引用
> 引用文字
分享一个我很早前的一副设计作品 [in Lofter](http://fairyever.lofter.com/post/16ff00_6796fe8) 借此演示百度云链接的显示优化
> https://pan.baidu.com/s/1kW6uUwB
设计源文件
> 链接: https://pan.baidu.com/s/1ggFW21l 密码: 877y
[https://github.com/d2-projects](https://github.com/d2-projects)

View File

@@ -1,17 +0,0 @@
<template>
<d2-container>
<template slot="header">指定资源</template>
<d2-markdown :source="doc" highlight/>
</d2-container>
</template>
<script>
import doc from './md/doc.md'
export default {
data () {
return {
doc
}
}
}
</script>

View File

@@ -1,6 +0,0 @@
<template>
<d2-container>
<template slot="header">异步加载文件</template>
<d2-markdown url="markdown/demo.md"/>
</d2-container>
</template>

View File

@@ -1,5 +0,0 @@
<template>
<d2-container type="card">
<p>src/views/demo/playground/add-routes/alternates/1.vue</p>
</d2-container>
</template>

View File

@@ -1,5 +0,0 @@
<template>
<d2-container type="card">
<p>src/views/demo/playground/add-routes/alternates/2.vue</p>
</d2-container>
</template>

View File

@@ -1,5 +0,0 @@
<template>
<d2-container type="card">
<p>src/views/demo/playground/add-routes/alternates/3.vue</p>
</d2-container>
</template>

View File

@@ -1,109 +0,0 @@
<template>
<d2-container>
<el-alert
title="由于演示功能特殊,请注意在需要时刷新您的浏览器(以重置路由设置)查看效果"
type="warning"
show-icon/>
<d2-highlight :code="dataView"/>
<el-form label-position="top">
<el-form-item label="创建路由(你可以假设上面是接口数据)">
<el-button-group>
<el-button
v-for="item in setting"
:key="item.component"
@click="onClick(item)">
{{item.title}}
</el-button>
</el-button-group>
</el-form-item>
</el-form>
</d2-container>
</template>
<script>
import { cloneDeep } from 'lodash'
import { mapState, mapMutations } from 'vuex'
import { frameInRoutes } from '@/router/routes'
import layoutHeaderAside from '@/layout/header-aside'
export default {
data () {
return {
title: '',
setting: [
{ title: '追加页面 1', name: 'add-routes-1', path: 'add-routes/1', component: '1' },
{ title: '追加页面 2', name: 'add-routes-2', path: 'add-routes/2', component: '2' },
{ title: '追加页面 3', name: 'add-routes-3', path: 'add-routes/3', component: '3' }
]
}
},
computed: {
...mapState('d2admin/menu', [
'header'
]),
dataView () {
return JSON.stringify(this.setting, null, 2)
}
},
methods: {
...mapMutations({
pageInit: 'd2admin/page/init',
headerSet: 'd2admin/menu/headerSet'
}),
onClick ({ title, name, path, component }) {
// vue router 的设计暂时不能支持在路由示例上访问动态添加的路由
// 目前可行的解决方法是自行维护一个存储路由数据的位置
// https://github.com/vuejs/vue-router/issues/1234
// https://github.com/vuejs/vue-router/issues/1859
// https://github.com/vuejs/vue-router/issues/1955
// https://github.com/vuejs/vue-router/issues/2454
// https://github.com/vuejs/vue-router/issues/2280
// 所以暂时先不做对路由已经存在的判断
const route = [
{
path: '/demo/playground',
component: layoutHeaderAside,
children: [
{
path,
name,
component: () => import('@/views/demo/playground/add-routes/alternates/' + component + '.vue'),
meta: {
title
}
}
]
}
]
this.$router.addRoutes(route)
// 更新标签页池
this.pageInit([
...frameInRoutes,
...route
])
// 演示更新菜单
const menuGroup = {
title: '临时菜单',
icon: 'plus-square',
children: []
}
const menu = {
path: `/demo/playground/${path}`,
title,
icon: 'file-o'
}
const header = cloneDeep(this.header)
const menuGroupIndex = header.findIndex(e => e.title === menuGroup.title)
// 如果顶栏菜单已经有这个组,就在组里添加项目,反之新建一个菜单组
if (menuGroupIndex >= 0) {
header[menuGroupIndex].children.push(menu)
} else {
menuGroup.children.push(menu)
header.push(menuGroup)
}
this.headerSet(header)
// 跳转
this.$router.push({ name })
}
}
}
</script>

View File

@@ -1,33 +0,0 @@
<template>
<d2-container>
<template slot="header">
<el-alert
type="success"
:closable="false"
title="这个页面展示的是全部数据的存储结构,包括系统区域和存储区域,涵盖所有用户,也就是整个 D2Admin 的数据存储结构"/>
</template>
<d2-highlight :code="dbData"/>
<el-button slot="footer" type="primary" @click="load">
重新获取本地数据
</el-button>
</d2-container>
</template>
<script>
import util from '@/libs/util'
export default {
data () {
return {
dbData: ''
}
},
mounted () {
this.load()
},
methods: {
load () {
this.dbData = JSON.stringify(util.db.value(), null, 2)
}
}
}
</script>

View File

@@ -1,127 +0,0 @@
<template>
<d2-container>
<template slot="header">
<el-alert
type="success"
:closable="false"
title="路由存储指当前路由的存储区域,
不同路由之间存储不会相互干扰,
使用 await this.$store.dispatch('d2admin/db/databasePage') 获得存储实例进行操作,
不同路由条件下获取的存储实例指向位置不同,
可以指定路由区分依据 name | path | fullPath
默认根据路由的 name 区分不同的路由"/>
</template>
<el-row>
<el-col :span="12">
<p class="d2-mt-0">增加不重复字段</p>
<el-button @click="handleSetRandom">增加</el-button>
<p>增加自定义字段</p>
<el-input v-model="keyNameToSet" placeholder="字段名" class="d2-mr-5" style="width: 100px;"/>
<el-input v-model="valueToSet" placeholder="值" class="d2-mr-5" style="width: 100px;"/>
<el-button @click="handleSet">增加</el-button>
<p>删除字段</p>
<el-select
v-model="keyNameToDelete"
placeholder="请选择要删除的 key">
<el-option
v-for="item in keyNameList"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<p>清空当前用户数据</p>
<el-button @click="handleClear">清空</el-button>
</el-col>
<el-col :span="12">
<d2-highlight :code="dataDisplay"/>
</el-col>
</el-row>
</d2-container>
</template>
<script>
import { uniqueId } from 'lodash'
import { mapActions } from 'vuex'
export default {
data () {
return {
dataDisplay: '',
keyNameToSet: '',
valueToSet: '',
keyNameList: [],
keyNameToDelete: ''
}
},
watch: {
keyNameToDelete (value) {
if (value) {
this.handleDelete(value)
}
}
},
mounted () {
this.load()
},
methods: {
...mapActions('d2admin/db', [
'databasePage',
'databasePageClear'
]),
/**
* 加载本地数据
*/
async load () {
const db = await this.databasePage()
this.dataDisplay = JSON.stringify(db.value(), null, 2)
this.keyNameList = Object.keys(db.value()).map(k => ({
value: k,
label: k
}))
},
/**
* 删除一个字段
*/
async handleDelete (name) {
const db = await this.databasePage()
db
.unset(name)
.write()
this.load()
this.keyNameToDelete = ''
},
/**
* 清空当前用户的数据
*/
async handleClear () {
await this.databasePageClear()
this.load()
},
/**
* 添加一个数据
*/
async handleSet () {
if (this.keyNameToSet === '') {
this.$message.error('字段名不能为空')
return
}
const db = await this.databasePage()
db
.set(this.keyNameToSet, this.valueToSet)
.write()
this.load()
},
/**
* 添加一个随机数据
*/
async handleSetRandom () {
const id = uniqueId()
const db = await this.databasePage()
db
.set(`uniqueKey${id}`, `value${id}`)
.write()
this.load()
}
}
}
</script>

View File

@@ -1,114 +0,0 @@
<template>
<d2-container>
<template slot="header">
<el-alert
type="success"
:closable="false"
title="路由快照相当于路由存储一种快捷操作,
会将传入的 vue instance 携带的 $data 全部持久化,
下面的表单来自 Element 的表单示例,
在 D2Admin 的本页示例中你可以随意填写这个表单,
表单内容会自动实时持久化,
无论是切换标签页、重新打开标签页、刷新浏览器、重开浏览器、重开浏览器标签页等,
该页面数据都会自动恢复到上次填写的状态,
这些都只需要你使用 D2Admin 提供的两个方法,
总共只需要多写十几行代码"/>
</template>
<el-form ref="form" :model="form" label-width="80px" style="max-width: 600px; margin: 0px auto;">
<el-form-item label="活动名称">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="form.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="活动时间">
<el-col :span="11">
<el-date-picker type="date" placeholder="选择日期" v-model="form.date1" style="width: 100%;"></el-date-picker>
</el-col>
<el-col :span="2" style="text-align: center;">-</el-col>
<el-col :span="11">
<el-time-picker type="fixed-time" placeholder="选择时间" v-model="form.date2" style="width: 100%;"></el-time-picker>
</el-col>
</el-form-item>
<el-form-item label="即时配送">
<el-switch v-model="form.delivery"></el-switch>
</el-form-item>
<el-form-item label="活动性质">
<el-checkbox-group v-model="form.type">
<el-checkbox label="线上活动" name="type"></el-checkbox>
<el-checkbox label="地推活动" name="type"></el-checkbox>
<el-checkbox label="线下活动" name="type"></el-checkbox>
<el-checkbox label="品牌曝光" name="type"></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="特殊资源">
<el-radio-group v-model="form.resource">
<el-radio label="线上品牌商赞助"></el-radio>
<el-radio label="线下场地免费"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="活动形式">
<el-input type="textarea" v-model="form.desc"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary">立即创建</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
<el-button
slot="footer"
type="danger"
@click="handleClear">
<d2-icon name="trash-o"/>
删除当前页面快照
</el-button>
</d2-container>
</template>
<script>
import { mapActions } from 'vuex'
export default {
data () {
return {
form: {
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
}
}
},
async created () {
const data = await this.pageGet({ instance: this })
for (const key in data) {
this[key] = data[key]
}
},
watch: {
$data: {
handler () {
this.pageSet({ instance: this })
},
deep: true
}
},
methods: {
...mapActions('d2admin/db', [
'pageSet',
'pageGet',
'pageClear'
]),
async handleClear () {
await this.pageClear({ instance: this })
this.$message.success('此页面快照已经删除,请重新进入该页面或者关闭选项卡重新打开')
}
}
}
</script>

View File

@@ -1,114 +0,0 @@
<template>
<d2-container>
<template slot="header">
<el-alert
type="success"
:closable="false"
title="私有路由快照相当于私有路由存储一种快捷操作,
会将传入的 vue instance 携带的 $data 全部根据用户区分持久化,
下面的表单来自 Element 的表单示例,
在 D2Admin 的本页示例中你可以随意填写这个表单,
表单内容会自动实时持久化,
无论是切换标签页、重新打开标签页、刷新浏览器、重开浏览器、重开浏览器标签页等,
该页面数据都会自动恢复到上次填写的状态,
这些都只需要你使用 D2Admin 提供的两个方法,
总共只需要多写十几行代码"/>
</template>
<el-form ref="form" :model="form" label-width="80px" style="max-width: 600px; margin: 0px auto;">
<el-form-item label="活动名称">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="form.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="活动时间">
<el-col :span="11">
<el-date-picker type="date" placeholder="选择日期" v-model="form.date1" style="width: 100%;"></el-date-picker>
</el-col>
<el-col :span="2" style="text-align: center;">-</el-col>
<el-col :span="11">
<el-time-picker type="fixed-time" placeholder="选择时间" v-model="form.date2" style="width: 100%;"></el-time-picker>
</el-col>
</el-form-item>
<el-form-item label="即时配送">
<el-switch v-model="form.delivery"></el-switch>
</el-form-item>
<el-form-item label="活动性质">
<el-checkbox-group v-model="form.type">
<el-checkbox label="线上活动" name="type"></el-checkbox>
<el-checkbox label="地推活动" name="type"></el-checkbox>
<el-checkbox label="线下活动" name="type"></el-checkbox>
<el-checkbox label="品牌曝光" name="type"></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="特殊资源">
<el-radio-group v-model="form.resource">
<el-radio label="线上品牌商赞助"></el-radio>
<el-radio label="线下场地免费"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="活动形式">
<el-input type="textarea" v-model="form.desc"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary">立即创建</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
<el-button
slot="footer"
type="danger"
@click="handleClear">
<d2-icon name="trash-o"/>
删除当前页面快照
</el-button>
</d2-container>
</template>
<script>
import { mapActions } from 'vuex'
export default {
data () {
return {
form: {
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
}
}
},
async created () {
const data = await this.pageGet({ instance: this, user: true })
for (const key in data) {
this[key] = data[key]
}
},
watch: {
$data: {
handler () {
this.pageSet({ instance: this, user: true })
},
deep: true
}
},
methods: {
...mapActions('d2admin/db', [
'pageSet',
'pageGet',
'pageClear'
]),
async handleClear () {
await this.pageClear({ instance: this, user: true })
this.$message.success('此页面快照已经删除,请重新进入该页面或者关闭选项卡重新打开')
}
}
}
</script>

View File

@@ -1,139 +0,0 @@
<template>
<d2-container>
<template slot="header">
<el-alert
type="success"
:closable="false"
title="私有路由存储指当前路由的存储区域,
并且同时还根据用户区分,
相当于结合了 “路由存储” 和 “私有存储”,
不同路由以及不同用户之间存储不会相互干扰,
使用 await this.$store.dispatch('d2admin/db/databasePage', { user: true }) 获得存储实例进行操作,
不同路由和用户条件下获取的存储实例指向位置不同,
可以指定路由区分依据 name | path | fullPath
默认根据路由的 name 区分不同的路由"/>
</template>
<el-row>
<el-col :span="12">
<p class="d2-mt-0">增加不重复字段</p>
<el-button @click="handleSetRandom">增加</el-button>
<p>增加自定义字段</p>
<el-input v-model="keyNameToSet" placeholder="字段名" class="d2-mr-5" style="width: 100px;"/>
<el-input v-model="valueToSet" placeholder="值" class="d2-mr-5" style="width: 100px;"/>
<el-button @click="handleSet">增加</el-button>
<p>删除字段</p>
<el-select
v-model="keyNameToDelete"
placeholder="请选择要删除的 key">
<el-option
v-for="item in keyNameList"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<p>清空当前用户数据</p>
<el-button @click="handleClear">清空</el-button>
</el-col>
<el-col :span="12">
<d2-highlight :code="dataDisplay"/>
</el-col>
</el-row>
</d2-container>
</template>
<script>
import { uniqueId } from 'lodash'
import { mapActions } from 'vuex'
export default {
data () {
return {
dataDisplay: '',
keyNameToSet: '',
valueToSet: '',
keyNameList: [],
keyNameToDelete: ''
}
},
watch: {
keyNameToDelete (value) {
if (value) {
this.handleDelete(value)
}
}
},
mounted () {
this.load()
},
methods: {
...mapActions('d2admin/db', [
'databasePage',
'databasePageClear'
]),
/**
* 加载本地数据
*/
async load () {
const db = await this.databasePage({
user: true
})
this.dataDisplay = JSON.stringify(db.value(), null, 2)
this.keyNameList = Object.keys(db.value()).map(k => ({
value: k,
label: k
}))
},
/**
* 删除一个字段
*/
async handleDelete (name) {
const db = await this.databasePage({
user: true
})
db
.unset(name)
.write()
this.load()
this.keyNameToDelete = ''
},
/**
* 清空当前用户的数据
*/
async handleClear () {
await this.databasePageClear({
user: true
})
this.load()
},
/**
* 添加一个数据
*/
async handleSet () {
if (this.keyNameToSet === '') {
this.$message.error('字段名不能为空')
return
}
const db = await this.databasePage({
user: true
})
db
.set(this.keyNameToSet, this.valueToSet)
.write()
this.load()
},
/**
* 添加一个随机数据
*/
async handleSetRandom () {
const id = uniqueId()
const db = await this.databasePage({
user: true
})
db
.set(`uniqueKey${id}`, `value${id}`)
.write()
this.load()
}
}
}
</script>

View File

@@ -1,123 +0,0 @@
<template>
<d2-container>
<template slot="header">
<el-alert
type="success"
:closable="false"
title="公用存储指所有用户共用的存储区域,
使用 await this.$store.dispatch('d2admin/db/database') 获得存储实例进行操作"/>
</template>
<el-row>
<el-col :span="12">
<p class="d2-mt-0">增加不重复字段</p>
<el-button @click="handleSetRandom">增加</el-button>
<p>增加自定义字段</p>
<el-input v-model="keyNameToSet" placeholder="字段名" class="d2-mr-5" style="width: 100px;"/>
<el-input v-model="valueToSet" placeholder="值" class="d2-mr-5" style="width: 100px;"/>
<el-button @click="handleSet">增加</el-button>
<p>删除字段</p>
<el-select
v-model="keyNameToDelete"
placeholder="请选择要删除的 key">
<el-option
v-for="item in keyNameList"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<p>清空当前用户数据</p>
<el-button @click="handleClear">清空</el-button>
</el-col>
<el-col :span="12">
<d2-highlight :code="dataDisplay"/>
</el-col>
</el-row>
</d2-container>
</template>
<script>
import { uniqueId } from 'lodash'
import { mapActions } from 'vuex'
export default {
data () {
return {
dataDisplay: '',
keyNameToSet: '',
valueToSet: '',
keyNameList: [],
keyNameToDelete: ''
}
},
watch: {
keyNameToDelete (value) {
if (value) {
this.handleDelete(value)
}
}
},
mounted () {
this.load()
},
methods: {
...mapActions('d2admin/db', [
'database',
'databaseClear'
]),
/**
* 加载本地数据
*/
async load () {
const db = await this.database()
this.dataDisplay = JSON.stringify(db.value(), null, 2)
this.keyNameList = Object.keys(db.value()).map(k => ({
value: k,
label: k
}))
},
/**
* 删除一个字段
*/
async handleDelete (name) {
const db = await this.database()
db
.unset(name)
.write()
this.load()
this.keyNameToDelete = ''
},
/**
* 清空当前用户的数据
*/
async handleClear () {
await this.databaseClear()
this.load()
},
/**
* 添加一个数据
*/
async handleSet () {
if (this.keyNameToSet === '') {
this.$message.error('字段名不能为空')
return
}
const db = await this.database()
db
.set(this.keyNameToSet, this.valueToSet)
.write()
this.load()
},
/**
* 添加一个随机数据
*/
async handleSetRandom () {
const id = uniqueId()
const db = await this.database()
db
.set(`uniqueKey${id}`, `value${id}`)
.write()
this.load()
}
}
}
</script>

View File

@@ -1,125 +0,0 @@
<template>
<d2-container>
<template slot="header">
<el-alert
type="success"
:closable="false"
title="私有存储指当前用户专用的存储区域,
不同用户之间存储不会相互干扰,
使用 await this.$store.dispatch('d2admin/db/database', { user: true }) 获得存储实例进行操作,
不同用户条件下获取的存储实例指向位置不同"/>
</template>
<el-row>
<el-col :span="12">
<p class="d2-mt-0">增加不重复字段</p>
<el-button @click="handleSetRandom">增加</el-button>
<p>增加自定义字段</p>
<el-input v-model="keyNameToSet" placeholder="字段名" class="d2-mr-5" style="width: 100px;"/>
<el-input v-model="valueToSet" placeholder="值" class="d2-mr-5" style="width: 100px;"/>
<el-button @click="handleSet">增加</el-button>
<p>删除字段</p>
<el-select
v-model="keyNameToDelete"
placeholder="请选择要删除的 key">
<el-option
v-for="item in keyNameList"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<p>清空当前用户数据</p>
<el-button @click="handleClear">清空</el-button>
</el-col>
<el-col :span="12">
<d2-highlight :code="dataDisplay"/>
</el-col>
</el-row>
</d2-container>
</template>
<script>
import { uniqueId } from 'lodash'
import { mapActions } from 'vuex'
export default {
data () {
return {
dataDisplay: '',
keyNameToSet: '',
valueToSet: '',
keyNameList: [],
keyNameToDelete: ''
}
},
watch: {
keyNameToDelete (value) {
if (value) {
this.handleDelete(value)
}
}
},
mounted () {
this.load()
},
methods: {
...mapActions('d2admin/db', [
'database',
'databaseClear'
]),
/**
* 加载本地数据
*/
async load () {
const db = await this.database({ user: true })
this.dataDisplay = JSON.stringify(db.value(), null, 2)
this.keyNameList = Object.keys(db.value()).map(k => ({
value: k,
label: k
}))
},
/**
* 删除一个字段
*/
async handleDelete (name) {
const db = await this.database({ user: true })
db
.unset(name)
.write()
this.load()
this.keyNameToDelete = ''
},
/**
* 清空当前用户的数据
*/
async handleClear () {
await this.databaseClear({ user: true })
this.load()
},
/**
* 添加一个数据
*/
async handleSet () {
if (this.keyNameToSet === '') {
this.$message.error('字段名不能为空')
return
}
const db = await this.database({ user: true })
db
.set(this.keyNameToSet, this.valueToSet)
.write()
this.load()
},
/**
* 添加一个随机数据
*/
async handleSetRandom () {
const id = uniqueId()
const db = await this.database({ user: true })
db
.set(`uniqueKey${id}`, `value${id}`)
.write()
this.load()
}
}
}
</script>

View File

@@ -1,16 +0,0 @@
<template>
<d2-container type="card">
<template slot="header">process.env</template>
<d2-highlight :code="env"/>
</d2-container>
</template>
<script>
export default {
data () {
return {
env: JSON.stringify(process.env, null, 2)
}
}
}
</script>

View File

@@ -1,3 +0,0 @@
<template>
<d2-container-frame src="https://d2.pub/doc/d2-admin"/>
</template>

View File

@@ -1,3 +0,0 @@
<template>
<d2-container-frame :src="`${$baseUrl}html/demo.html`"/>
</template>

View File

@@ -1,3 +0,0 @@
<template>
<d2-container-frame :src="`${$baseUrl}report.html`"/>
</template>

View File

@@ -1,21 +0,0 @@
<template>
<d2-container type="ghost">
<d2-module-index-banner slot="header" v-bind="banner"/>
<d2-module-index-menu :menu="menu"/>
</d2-container>
</template>
<script>
import menu from '@/menu/modules/demo-playground'
export default {
data () {
return {
menu,
banner: {
title: 'PLAYGROUND',
subTitle: '在这里可以测试一些 D2Admin 的系统功能'
}
}
}
}
</script>

View File

@@ -1,22 +0,0 @@
<template>
<d2-container>
<p class="d2-mt-0">
<el-radio-group v-model="$i18n.locale">
<el-radio-button
v-for="language in $languages"
:key="language.value"
:label="language.value">
{{ language.label }}
</el-radio-button>
</el-radio-group>
</p>
<el-alert
:title="$t('page.demo.playground.locales.text')"
type="success">
</el-alert>
<d2-link-btn
slot="footer"
title="文档"
link="https://d2.pub/doc/d2-admin/locales"/>
</d2-container>
</template>

View File

@@ -1,20 +0,0 @@
<template>
<d2-container>
<template slot="header">Ajax 错误</template>
<p class="d2-mt-0">请打开浏览器控制台然后点击下面的按钮尝试访问一个不存在的网络地址</p>
<el-button type="danger" @click="handleClick">请求错误的地址</el-button>
<p>此错误已经被记录在日志页面并在页面右上"日志按钮"区域显示提示信息</p>
</d2-container>
</template>
<script>
import { DEMO_LOG_AJAX } from '@/api/demo.js'
export default {
methods: {
handleClick () {
DEMO_LOG_AJAX()
}
}
}
</script>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

View File

@@ -1,67 +0,0 @@
<template>
<d2-container class="page">
<p class="d2-mt-0">$log.capsule</p>
<el-button size="small" type="primary" @click="$log.capsule('title', 'primary')">
$log.capsule('title', 'primary')
</el-button>
<el-button size="small" type="success" @click="$log.capsule('title', 'success', 'success')">
$log.capsule('title', 'success', 'success')
</el-button>
<el-button size="small" type="warning" @click="$log.capsule('title', 'warning', 'warning')">
$log.capsule('title', 'warning', 'warning')
</el-button>
<el-button size="small" type="danger" @click="$log.capsule('title', 'danger', 'danger')">
$log.capsule('title', 'danger', 'danger')
</el-button>
<p>$log.colorful</p>
<el-button size="small" @click="handleColorful">
colorful
</el-button>
<p>$log.default | primary | success | warning | danger</p>
<el-button size="small" @click="$log.default('default style')">
$log.default('default style')
</el-button>
<el-button size="small" type="primary" @click="$log.primary('primary style')">
$log.primary('primary style')
</el-button>
<el-button size="small" type="success" @click="$log.success('success style')">
$log.success('success style')
</el-button>
<el-button size="small" type="warning" @click="$log.warning('warning style')">
$log.warning('warning style')
</el-button>
<el-button size="small" type="danger" @click="$log.danger('danger style')">
$log.danger('danger style')
</el-button>
<p>效果 ( Chrome )</p>
<img
class="page__image-demo"
src="./image/demo.png">
</d2-container>
</template>
<script>
export default {
methods: {
handleColorful () {
this.$log.colorful([
{ text: 'H', type: 'default' },
{ text: 'e', type: 'primary' },
{ text: 'l', type: 'success' },
{ text: 'l', type: 'warning' },
{ text: 'o', type: 'danger' }
])
}
}
}
</script>
<style lang="scss" scoped>
.page {
.page__image-demo {
border-radius: 4px;
width: 260px;
border: 1px solid $color-border-1;
}
}
</style>

View File

@@ -1,18 +0,0 @@
<template>
<d2-container>
<template slot="header">捕获错误信息</template>
<p class="d2-mt-0">请打开浏览器控制台然后点击下面的按钮</p>
<el-button type="danger" @click="handleNewError">触发一个错误</el-button>
<p>此错误已经被记录在日志页面并在页面右上"日志按钮"区域显示提示信息</p>
</d2-container>
</template>
<script>
export default {
methods: {
handleNewError () {
console.log(a) // eslint-disable-line
}
}
}
</script>

View File

@@ -1,28 +0,0 @@
<template>
<d2-container>
<template slot="header">记录日志内容</template>
<p class="d2-mt-0">在下方输入你要记录的日志然后点击记录按钮</p>
<el-input
v-model="text"
placeholder="日志内容"
class="d2-mr-10"
style="width: 200px;"/>
<el-button type="primary" @click="handleAdd">记录</el-button>
<p>此信息已经被记录在日志页面并在页面右上"日志按钮"区域显示提示信息</p>
</d2-container>
</template>
<script>
export default {
data () {
return {
text: 'some text'
}
},
methods: {
handleAdd () {
this.$log.push(this.text)
}
}
}
</script>

View File

@@ -1,16 +0,0 @@
<template>
<d2-container type="card">
<h2 class="d2-mt-0">$route.params.username: {{$route.params.username}}</h2>
<h2>$route.query.userid: {{$route.query.userid}}</h2>
<p>你可以尝试返回发送数据页面修改数据重新发送或者切换到其它页面后刷新浏览器再返回本业观察参数保留</p>
<el-button type="primary" @click="$router.push({ name: 'demo-playground-page-argu-send' })">返回发送数据的页面</el-button>
</d2-container>
</template>
<script>
export default {
mounted () {
console.log('this.$route', this.$route)
}
}
</script>

View File

@@ -1,55 +0,0 @@
<template>
<d2-container type="card">
<el-form :model="sendForm" :rules="rules" label-position="top" ref="sendForm">
<el-form-item label="username 通过动态路由匹配发送" prop="username">
<el-input v-model="sendForm.username" style="width: 300px;"/>
</el-form-item>
<el-form-item label="userid 通过参数发送" prop="userid">
<el-input v-model="sendForm.userid" style="width: 300px;"/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSubmit('sendForm')">跳转到接收页面</el-button>
</el-form-item>
</el-form>
</d2-container>
</template>
<script>
export default {
data () {
return {
sendForm: {
username: 'FairyEver',
userid: '001'
},
rules: {
username: [
{ required: true, message: '请输入要发送的用户名', trigger: 'blur' }
],
userid: [
{ required: true, message: '请输入要发送的用户ID', trigger: 'blur' }
]
}
}
},
methods: {
handleSubmit (formName) {
this.$refs[formName].validate(valid => {
if (valid) {
this.$router.push({
name: 'demo-playground-page-argu-get',
params: {
username: this.sendForm.username
},
query: {
userid: this.sendForm.userid
}
})
} else {
return false
}
})
}
}
}
</script>

View File

@@ -1,17 +0,0 @@
<template>
<d2-container type="card">
<template slot="header">这个页面不会被 keep-alive</template>
<p class="d2-mt-0">在下面的输入框输入任意字符后切换到其它页面再回到此页时输入框文字消失证明没有被缓存</p>
<el-input v-model="value" placeholder="input here"></el-input>
</d2-container>
</template>
<script>
export default {
data () {
return {
value: ''
}
}
}
</script>

View File

@@ -1,18 +0,0 @@
<template>
<d2-container type="card">
<template slot="header">这个页面会被 keep-alive</template>
<p class="d2-mt-0">在下面的输入框输入任意字符后切换到其它页面再回到此页时输入框文字保留证明被缓存</p>
<el-input v-model="value" placeholder="input here"></el-input>
</d2-container>
</template>
<script>
export default {
name: 'demo-playground-page-cache-on',
data () {
return {
value: ''
}
}
}
</script>

View File

@@ -1,42 +0,0 @@
<template>
<d2-container type="card">
<template slot="header">
<el-button
size="mini"
type="primary">
props.id = {{id}}
</el-button>
</template>
<p class="d2-mt-0">在下面的输入框输入任意字符后切换到其它页面再回到此页时输入框文字保留证明被缓存</p>
<p>注意此页面根据不同 params 打开后数据不会混淆</p>
<el-row :gutter="10">
<el-col :span="12">
<p>el-input</p>
<el-input v-model="data.value" placeholder="input here" />
</el-col>
<el-col :span="12">
<p>html input</p>
<div class="el-input el-input--default">
<input v-model="data.value" placeholder="input here" class="el-input__inner" />
</div>
</el-col>
</el-row>
</d2-container>
</template>
<script>
export default {
name: 'demo-playground-page-cache-params',
props: {
id: {
type: String,
required: true
}
},
data () {
return {
data: { value: '' }
}
}
}
</script>

View File

@@ -1,19 +0,0 @@
<template>
<d2-container type="card" class="page-demo-playground-fullscreen">
<template slot="header">全屏</template>
<el-button type="primary" @click="toggle">
toggle 切换全屏
</el-button>
</d2-container>
</template>
<script>
import { mapActions } from 'vuex'
export default {
methods: {
...mapActions('d2admin/fullscreen', [
'toggle'
])
}
}
</script>

View File

@@ -1,87 +0,0 @@
<template>
<d2-container type="card" class="page">
<template slot="header">
<div class="colorful">{{grayActive ? 'GRAY' : 'COLORFUL'}}</div>
</template>
<el-button-group>
<el-button @click="grayToggle">切换灰度模式</el-button>
<el-button @click="graySet(true)">打开灰度模式</el-button>
<el-button @click="graySet(false)">关闭灰度模式</el-button>
<el-button @click="dialogVisible = true">模拟报错提示框</el-button>
</el-button-group>
<el-dialog
title="错误"
:visible.sync="dialogVisible"
:append-to-body="true"
width="30%"
@open="handleDialogOpen"
@closed="handleDialogClosed">
<div
style="
text-align: center;
line-height: 100px;
color: #FFF;
font-size: 64px;
font-weight: bold;
border-radius: 4px;
background-color: #F56C6C;
margin: -20px 0px;
">
Error
</div>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="dialogVisible = false" style="width: 100%;">
我看到后面的内容已经变为灰度模式
</el-button>
</span>
</el-dialog>
</d2-container>
</template>
<script>
import { mapState, mapMutations } from 'vuex'
export default {
data () {
return {
dialogVisible: false
}
},
computed: {
...mapState('d2admin/gray', {
grayActive: 'active'
})
},
methods: {
...mapMutations('d2admin/gray', {
grayToggle: 'toggle',
graySet: 'set'
}),
handleDialogOpen () {
this.graySet(true)
},
handleDialogClosed () {
this.graySet(false)
}
}
}
</script>
<style lang="scss" scoped>
.page {
.colorful {
@extend %unable-select;
line-height: 300px;
font-size: 100px;
font-weight: bold;
color: #FFF;
text-align: center;
border-radius: 4px;
border: 1px solid #333;
background-color: #ffff00;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100%25' height='100%25' viewBox='0 0 1200 800'%3E%3Cdefs%3E%3CradialGradient id='a' cx='0' cy='800' r='800' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='0' stop-color='%23ff8000'/%3E%3Cstop offset='1' stop-color='%23ff8000' stop-opacity='0'/%3E%3C/radialGradient%3E%3CradialGradient id='b' cx='1200' cy='800' r='800' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='0' stop-color='%2300ff19'/%3E%3Cstop offset='1' stop-color='%2300ff19' stop-opacity='0'/%3E%3C/radialGradient%3E%3CradialGradient id='c' cx='600' cy='0' r='600' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='0' stop-color='%239900ff'/%3E%3Cstop offset='1' stop-color='%239900ff' stop-opacity='0'/%3E%3C/radialGradient%3E%3CradialGradient id='d' cx='600' cy='800' r='600' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='0' stop-color='%23ffff00'/%3E%3Cstop offset='1' stop-color='%23ffff00' stop-opacity='0'/%3E%3C/radialGradient%3E%3CradialGradient id='e' cx='0' cy='0' r='800' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='0' stop-color='%23FF0000'/%3E%3Cstop offset='1' stop-color='%23FF0000' stop-opacity='0'/%3E%3C/radialGradient%3E%3CradialGradient id='f' cx='1200' cy='0' r='800' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='0' stop-color='%230CF'/%3E%3Cstop offset='1' stop-color='%230CF' stop-opacity='0'/%3E%3C/radialGradient%3E%3C/defs%3E%3Crect fill='url(%23a)' width='1200' height='800'/%3E%3Crect fill='url(%23b)' width='1200' height='800'/%3E%3Crect fill='url(%23c)' width='1200' height='800'/%3E%3Crect fill='url(%23d)' width='1200' height='800'/%3E%3Crect fill='url(%23e)' width='1200' height='800'/%3E%3Crect fill='url(%23f)' width='1200' height='800'/%3E%3C/svg%3E");
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
}
</style>

View File

@@ -1,148 +0,0 @@
<template>
<d2-container>
<el-tabs>
<el-tab-pane label="顶栏菜单">
<el-button-group class="d2-mb">
<el-button @click="handleHeaderSet">设置顶栏空菜单</el-button>
<el-button @click="headerReset">恢复顶栏菜单</el-button>
</el-button-group>
<d2-highlight :code="JSON.stringify(header, null, 2)"/>
</el-tab-pane>
<el-tab-pane label="侧栏菜单">
<el-button-group class="d2-mb">
<el-button @click="handleAsideSet">设置侧栏空菜单</el-button>
<el-button @click="asideReset">恢复侧栏菜单</el-button>
<el-button @click="asideTransitionToggle()">{{`${asideTransition ? '关闭' : '开启'}侧栏动画效果`}}</el-button>
</el-button-group>
<d2-highlight :code="JSON.stringify(aside, null, 2)"/>
</el-tab-pane>
</el-tabs>
</d2-container>
</template>
<script>
import { cloneDeep } from 'lodash'
import { mapState, mapMutations, mapActions } from 'vuex'
export default {
data () {
return {
menuEmpty: [
{
title: '空菜单演示',
icon: 'folder-o',
children: [
{
title: '空菜单 1',
children: [
{ title: '空菜单 1-1' },
{ title: '空菜单 1-2' }
]
},
{ title: '空菜单 2' },
{ title: '空菜单 3' }
]
}
],
headerChanged: false,
asideChanged: false,
headerBak: [],
asideBak: []
}
},
computed: {
...mapState('d2admin/menu', [
'header',
'aside',
'asideTransition'
])
},
created () {
this.headerBak = cloneDeep(this.header)
this.asideBak = cloneDeep(this.aside)
},
beforeDestroy () {
if (this.headerChanged && this.asideChanged) {
this.headerSet(this.headerBak)
this.asideSet(this.asideBak)
this.$notify({
title: '菜单恢复',
message: '对侧边栏和顶栏菜单的修改已经复原',
type: 'success'
})
return
}
if (this.headerChanged) {
this.headerSet(this.headerBak)
this.$notify({
title: '菜单恢复',
message: '对顶栏菜单的修改已经复原',
type: 'success'
})
return
}
if (this.asideChanged) {
this.asideSet(this.asideBak)
this.$notify({
title: '菜单恢复',
message: '对侧边栏菜单的修改已经复原',
type: 'success'
})
}
},
methods: {
...mapMutations('d2admin/menu', [
'headerSet',
'asideSet'
]),
...mapActions('d2admin/menu', [
'asideTransitionToggle'
]),
/**
* 修改顶栏菜单
*/
handleHeaderSet () {
this.headerChanged = true
this.headerSet(this.menuEmpty)
this.$notify({
title: '菜单修改',
message: '对顶栏菜单的修改已经生效',
type: 'success'
})
},
/**
* 修改侧边栏菜单
*/
handleAsideSet () {
this.asideChanged = true
this.asideSet(this.menuEmpty)
this.$notify({
title: '菜单修改',
message: '对侧边栏菜单的修改已经生效',
type: 'success'
})
},
/**
* 恢复顶栏菜单
*/
headerReset () {
this.headerSet(this.headerBak)
this.$notify({
title: '菜单恢复',
message: '对顶栏菜单的修改已经复原',
type: 'success'
})
},
/**
* 恢复侧边栏菜单
*/
asideReset () {
this.asideSet(this.asideBak)
this.$notify({
title: '菜单恢复',
message: '对侧边栏菜单的修改已经复原',
type: 'success'
})
}
}
}
</script>

View File

@@ -1,98 +0,0 @@
<template>
<d2-container type="card">
<!-- 证明有缓存 -->
<p class="d2-mt-0">在下面的输入框输入任意字符后切换到其它页面再回到此页时输入框文字保留证明被缓存</p>
<el-input v-model="value" placeholder="input here"></el-input>
<!-- 页签操作 -->
<p>关闭标签页</p>
<el-button-group>
<el-button @click="handleCloseCurrent">
<d2-icon name="times"/> 当前
</el-button>
<el-button @click="handleCloseLeft">
<d2-icon name="arrow-left"/> 左侧
</el-button>
<el-button @click="handleCloseRight">
右侧 <d2-icon name="arrow-right"/>
</el-button>
<el-button @click="handleCloseOther">
其它 <d2-icon name="times"/>
</el-button>
<el-button @click="closeAll">
全部 <d2-icon name="times-circle"/>
</el-button>
</el-button-group>
<p>刷新</p>
<el-button-group>
<el-button @click="handleCleanCacheAndRefreshCurrent">
<d2-icon name="refresh"/>
清空当前页缓存并刷新
</el-button>
<el-button @click="handleCleanCacheAndRefreshAll">
<d2-icon name="refresh"/>
清空所有缓存并刷新
</el-button>
</el-button-group>
</d2-container>
</template>
<script>
import { mapMutations, mapActions } from 'vuex'
export default {
name: 'demo-playground-store-page',
data () {
return {
value: ''
}
},
methods: {
...mapMutations('d2admin/page', [
'keepAliveRemove',
'keepAliveClean'
]),
...mapActions('d2admin/page', [
'close',
'closeLeft',
'closeRight',
'closeOther',
'closeAll'
]),
// 关闭当前
handleCloseCurrent () {
this.close({
tagName: this.$route.fullPath
})
},
// 关闭左侧
handleCloseLeft () {
this.closeLeft({
tagName: this.$route.fullPath
})
},
// 关闭右侧
handleCloseRight () {
this.closeRight({
tagName: this.$route.fullPath
})
},
// 关闭其他
handleCloseOther () {
this.closeOther({
tagName: this.$route.fullPath
})
},
// 清空当前页缓存并刷新此页面
async handleCleanCacheAndRefreshCurrent () {
this.keepAliveRemove(this.$route.name)
await this.$nextTick()
this.$router.replace('/refresh')
},
// 清空所有的缓存并刷新此页面
async handleCleanCacheAndRefreshAll () {
this.keepAliveClean()
await this.$nextTick()
this.$router.replace('/refresh')
}
}
}
</script>

View File

@@ -1,39 +0,0 @@
<template>
<d2-container type="card">
<el-radio-group v-model="currentValue" @change="set">
<el-radio-button label="default"></el-radio-button>
<el-radio-button label="medium"></el-radio-button>
<el-radio-button label="small"></el-radio-button>
<el-radio-button label="mini"></el-radio-button>
</el-radio-group>
</d2-container>
</template>
<script>
import { mapState, mapActions } from 'vuex'
export default {
data () {
return {
currentValue: ''
}
},
computed: {
...mapState('d2admin/size', [
'value'
])
},
watch: {
value: {
handler (val) {
this.currentValue = val
},
immediate: true
}
},
methods: {
...mapActions('d2admin/size', [
'set'
])
}
}
</script>

View File

@@ -1,74 +0,0 @@
<template>
<d2-container type="card" class="page">
<template slot="header">主题</template>
<el-table :data="list" v-bind="table">
<el-table-column prop="name" align="center" width="260"/>
<el-table-column label="预览" width="120">
<div
slot-scope="scope"
class="theme-preview"
:style="{'backgroundImage': `url(${$baseUrl}${scope.row.preview})`}">
</div>
</el-table-column>
<el-table-column prop="address" align="center">
<template slot-scope="scope">
<el-button v-if="activeName === scope.row.name" type="success" icon="el-icon-check" round>已激活</el-button>
<el-button v-else round @click="handleSelectTheme(scope.row.name)">使用</el-button>
</template>
</el-table-column>
</el-table>
<div>
<p>尝试激活一个不存在的主题主题不存在 <d2-icon name="arrow-right"/> 默认主题</p>
<el-button type="danger" @click="handleSelectTheme('err-theme')">
<d2-icon name="hand-o-right" class="d2-mr-10"/>
尝试激活主题 'err-theme'
</el-button>
</div>
<el-button
slot="footer"
type="primary"
size="small">
当前激活主题 {{activeName}}
</el-button>
</d2-container>
</template>
<script>
import { mapState, mapActions } from 'vuex'
export default {
data () {
return {
table: {
showHeader: false,
border: true
}
}
},
computed: {
...mapState('d2admin/theme', [
'list',
'activeName'
])
},
methods: {
...mapActions('d2admin/theme', [
'set'
]),
handleSelectTheme (name) {
this.set(name)
}
}
}
</script>
<style lang="scss" scoped>
.page {
.theme-preview {
height: 50px;
width: 100px;
border-radius: 4px;
background-size: cover;
border: 1px solid $color-border-1;
}
}
</style>

View File

@@ -1,26 +0,0 @@
<template>
<d2-container type="card">
<template slot="header">
当前状态 {{active ? '开启过渡动画' : '关闭过渡动画'}}
</template>
<el-button type="primary" @click="set(!active)">
{{active ? '关闭页面过渡动画' : '打开页面过渡动画'}}
</el-button>
</d2-container>
</template>
<script>
import { mapState, mapActions } from 'vuex'
export default {
computed: {
...mapState('d2admin/transition', [
'active'
])
},
methods: {
...mapActions('d2admin/transition', [
'set'
])
}
}
</script>

View File

@@ -1,23 +0,0 @@
<template>
<d2-container>
<p class="d2-mt-0">useragent</p>
<el-input :value="uaData.ua"></el-input>
<p>格式化数据 in vuex: state.d2admin.ua.data</p>
<d2-highlight :code="uaStr"/>
</d2-container>
</template>
<script>
import { mapState } from 'vuex'
export default {
computed: {
...mapState('d2admin/ua', {
uaData: 'data'
}),
uaStr () {
const { browser, engine, os, device, cpu } = this.uaData
return JSON.stringify({ browser, engine, os, device, cpu }, null, 2)
}
}
}
</script>

View File

@@ -1,82 +0,0 @@
<template>
<d2-container>
<template slot="header">剪贴板访问</template>
<el-row :gutter="10">
<el-col :span="12">
<div class="d2-mb">
<el-input v-model="text" style="width: 200px;"></el-input>
<el-button class="d2-ml" @click="copyText()">将左侧输入框内的文字复制进剪贴板</el-button>
</div>
<el-button @click="copyHtml()"> <span v-html="html"></span> 连带样式一起复制进剪贴板然后去 Word 文档内粘贴</el-button>
</el-col>
<el-col :span="12">
<el-alert
class="d2-mb"
title="在 IE 浏览器或者高版本 Chrome 下你才可以通过下面这两个按钮获取剪贴板数据"
type="warning"
show-icon>
</el-alert>
<div class="d2-mb">
<el-tooltip content="需要 IE 浏览器" placement="top">
<el-button @click="readText">readText( )</el-button>
</el-tooltip>
<el-tooltip content="需要 IE 浏览器" placement="top">
<el-button @click="read">read( )</el-button>
</el-tooltip>
</div>
<el-input type="textarea" placeholder="在这里检验你的剪贴板 ( text/plain 数据 )"></el-input>
</el-col>
</el-row>
</d2-container>
</template>
<script>
import * as clipboard from 'clipboard-polyfill'
export default {
data () {
return {
text: 'Hello ~',
html: '<span style="background-color: #19be6b; color: #f8f8f9;">Hello</span><span style="background-color: #495060; color: #f8f8f9;">World</span>'
}
},
methods: {
copyText () {
clipboard.writeText(this.text)
},
copyHtml () {
var dt = new clipboard.DT()
dt.setData('text/html', this.html)
clipboard.write(dt)
},
readText () {
clipboard.readText().then((res) => {
this.$message({
message: '读取成功 返回结果请查看控制台',
type: 'success'
})
}, err => {
console.log(err)
this.$message({
message: '错误信息已经打印到控制台',
type: 'error'
})
})
},
read () {
clipboard.read().then((res) => {
console.log(res)
this.$message({
message: '读取成功 返回结果请查看控制台',
type: 'success'
})
}, (err) => {
console.log(err)
this.$message({
message: '错误信息已经打印到控制台',
type: 'error'
})
})
}
}
}
</script>

View File

@@ -1,73 +0,0 @@
<template>
<d2-container>
<template slot="header">日期计算</template>
<h1 class="d2-mt-0">解析</h1>
<el-row :gutter="20" class="d2-mt">
<el-col :span="6"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// 当前时间\ndayjs()`"/>{{dayjs()}}</el-card></el-col>
<el-col :span="6"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// 时间字符串\ndayjs('1995-12-25')`"/>{{dayjs('1995-12-25')}}</el-card></el-col>
<el-col :span="6"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// Unix 时间戳 (毫秒)\ndayjs(1318781876406)`"/>{{dayjs(1318781876406)}}</el-card></el-col>
<el-col :span="6"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// Date 对象\ndayjs(new Date(2018, 8, 18))`"/>{{dayjs(new Date(2018, 8, 18))}}</el-card></el-col>
<el-col :span="6"><el-card shadow="never"><d2-highlight slot="header" :code="`// 复制\ndayjs().clone()`"/>{{dayjs().clone()}}</el-card></el-col>
<el-col :span="6"><el-card shadow="never"><d2-highlight slot="header" :code="`// 检测是否是一个有效的时间\ndayjs().isValid()`"/>{{dayjs().isValid()}}</el-card></el-col>
</el-row>
<h1>获取</h1>
<el-row :gutter="20" class="d2-mt">
<el-col :span="6"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// 获取年\ndayjs().year()`"/>{{dayjs().year()}}</el-card></el-col>
<el-col :span="6"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// 获取月\ndayjs().month()`"/>{{dayjs().month()}}</el-card></el-col>
<el-col :span="6"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// 获取日\ndayjs().date()`"/>{{dayjs().date()}}</el-card></el-col>
<el-col :span="6"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// 获取星期\ndayjs().day()`"/>{{dayjs().day()}}</el-card></el-col>
<el-col :span="6"><el-card shadow="never"><d2-highlight slot="header" :code="`// 获取小时\ndayjs().hour()`"/>{{dayjs().hour()}}</el-card></el-col>
<el-col :span="6"><el-card shadow="never"><d2-highlight slot="header" :code="`// 获取分钟\ndayjs().minute()`"/>{{dayjs().minute()}}</el-card></el-col>
<el-col :span="6"><el-card shadow="never"><d2-highlight slot="header" :code="`// 获取秒\ndayjs().second()`"/>{{dayjs().second()}}</el-card></el-col>
<el-col :span="6"><el-card shadow="never"><d2-highlight slot="header" :code="`// 获取毫秒\ndayjs().millisecond()`"/>{{dayjs().millisecond()}}</el-card></el-col>
</el-row>
<h1>设置</h1>
<el-row :gutter="20" class="d2-mt">
<el-col :span="8"><el-card shadow="never"><d2-highlight slot="header" :code="`// 设置月份\ndayjs().set('month', 6).month()`"/>{{dayjs().set('month', 6).month()}}</el-card></el-col>
<el-col :span="8"><el-card shadow="never"><d2-highlight slot="header" :code="`// 设置秒\ndayjs().set('second', 30).second()`"/>{{dayjs().set('second', 30).second()}}</el-card></el-col>
<el-col :span="8"><el-card shadow="never"><d2-highlight slot="header" :code="`// 设置小时\ndayjs().set('hour', 4).hour()`"/>{{dayjs().set('hour', 4).hour()}}</el-card></el-col>
</el-row>
<h1>操作</h1>
<el-row :gutter="20" class="d2-mt">
<el-col :span="12"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// 增加\ndayjs().add(1, 'day').format('YYYY年M月D日 HH:mm:ss')`"/>{{dayjs().add(1, 'day').format('YYYY年M月D日 HH:mm:ss')}}</el-card></el-col>
<el-col :span="12"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// 减少\ndayjs().subtract(7, 'year').format('YYYY年M月D日 HH:mm:ss')`"/>{{dayjs().subtract(7, 'year').format('YYYY年M月D日 HH:mm:ss')}}</el-card></el-col>
<el-col :span="12"><el-card shadow="never"><d2-highlight slot="header" :code="`// 开头时间\ndayjs().startOf('year').format('YYYY年M月D日 HH:mm:ss')`"/>{{dayjs().startOf('year').format('YYYY年M月D日 HH:mm:ss')}}</el-card></el-col>
<el-col :span="12"><el-card shadow="never"><d2-highlight slot="header" :code="`// 末尾时间\ndayjs().endOf('month').format('YYYY年M月D日 HH:mm:ss')`"/>{{dayjs().endOf('month').format('YYYY年M月D日 HH:mm:ss')}}</el-card></el-col>
</el-row>
<h1>显示</h1>
<el-row :gutter="20" class="d2-mt">
<el-col :span="12"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// 格式化\ndayjs().format('YYYY-M-D HH:mm:ss')`"/>{{dayjs().format('YYYY-M-D HH:mm:ss')}}</el-card></el-col>
<el-col :span="12"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// 时间差\ndayjs().diff(dayjs().subtract(1, 'day'), 'days')`"/>{{dayjs().diff(dayjs().subtract(1, 'day'), 'days')}}</el-card></el-col>
<el-col :span="12"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// Unix 时间戳 (毫秒)\ndayjs().valueOf()`"/>{{dayjs().valueOf()}}</el-card></el-col>
<el-col :span="12"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// Unix 时间戳 (秒)\ndayjs().unix()`"/>{{dayjs().unix()}}</el-card></el-col>
<el-col :span="12"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// 天数 (月)\ndayjs().daysInMonth()`"/>{{dayjs().daysInMonth()}}</el-card></el-col>
<el-col :span="12"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// Date 对象\ndayjs().toDate()`"/>{{dayjs().toDate()}}</el-card></el-col>
<!-- <el-col :span="12"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// 数组\ndayjs().toArray()`"/>{{dayjs().toArray()}}</el-card></el-col> -->
<el-col :span="12"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// 序列化 Dayjs 对象时会返回 ISO 8601 格式的字符串\ndayjs().toJSON()`"/>{{dayjs().toJSON()}}</el-card></el-col>
<el-col :span="12"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// ISO 8601 字符串\ndayjs().toISOString()`"/>{{dayjs().toISOString()}}</el-card></el-col>
<el-col :span="12"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// 字符串\ndayjs().toString()`"/>{{dayjs().toString()}}</el-card></el-col>
<!-- <el-col :span="24"><el-card shadow="never"><d2-highlight slot="header" :code="`// 对象\ndayjs().toObject()`"/>{{dayjs().toObject()}}</el-card></el-col> -->
</el-row>
<h1>查询</h1>
<el-row :gutter="20" class="d2-mt">
<el-col :span="12"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// 是否之前\ndayjs().isBefore(dayjs().add(1, 'day'))`"/>{{dayjs().isBefore(dayjs().add(1, 'day'))}}</el-card></el-col>
<el-col :span="12"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// 是否之前\ndayjs().isBefore(dayjs().subtract(1, 'day'))`"/>{{dayjs().isBefore(dayjs().subtract(1, 'day'))}}</el-card></el-col>
<el-col :span="12"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// 是否相同\ndayjs().isSame(dayjs())`"/>{{dayjs().isSame(dayjs())}}</el-card></el-col>
<el-col :span="12"><el-card shadow="never" class="d2-mb"><d2-highlight slot="header" :code="`// 是否相同\ndayjs().isSame(dayjs().add(1, 'day'))`"/>{{dayjs().isSame(dayjs().add(1, 'day'))}}</el-card></el-col>
<el-col :span="12"><el-card shadow="never"><d2-highlight slot="header" :code="`// 是否之后\ndayjs().isAfter(dayjs().add(1, 'day'))`"/>{{dayjs().isAfter(dayjs().add(1, 'day'))}}</el-card></el-col>
<el-col :span="12"><el-card shadow="never"><d2-highlight slot="header" :code="`// 是否之后\ndayjs().isAfter(dayjs().subtract(1, 'day'))`"/>{{dayjs().isAfter(dayjs().subtract(1, 'day'))}}</el-card></el-col>
</el-row>
<d2-link-btn slot="footer" title="依赖" link="https://github.com/iamkun/dayjs"/>
</d2-container>
</template>
<script>
import dayjs from 'dayjs'
export default {
data () {
return {
dayjs
}
}
}
</script>

View File

@@ -1,72 +0,0 @@
<template>
<d2-container type="card">
<template slot="header">导出表格</template>
<div class="d2-mb">
<el-button type="primary" @click="exportCsv">
<d2-icon name="download"/>
导出 CSV
</el-button>
<el-button type="primary" @click="exportExcel">
<d2-icon name="download"/>
导出 Excel
</el-button>
</div>
<el-table v-bind="table" style="width: 100%">
<el-table-column
v-for="(item, index) in table.columns"
:key="index"
:prop="item.prop"
:label="item.label">
</el-table-column>
</el-table>
</d2-container>
</template>
<script>
import Vue from 'vue'
import pluginExport from '@d2-projects/vue-table-export'
Vue.use(pluginExport)
export default {
data () {
return {
table: {
columns: [
{ label: 'ID', prop: 'id' },
{ label: '名称', prop: 'name' },
{ label: '创建日期', prop: 'creatDate' },
{ label: '地址', prop: 'address' },
{ label: '邮编', prop: 'zip' }
],
data: [
{ id: 1, name: 'Lucy', creatDate: '2020-05-07', address: 'Address', zip: '000000' }
],
size: 'mini',
stripe: true,
border: true
}
}
},
methods: {
exportCsv (params = {}) {
this.$export.csv({
columns: this.table.columns,
data: this.table.data
})
.then(() => {
this.$message('导出CSV成功')
})
},
exportExcel () {
this.$export.excel({
columns: this.table.columns,
data: this.table.data,
header: '导出 Excel',
merges: ['A1', 'E1']
})
.then(() => {
this.$message('导出表格成功')
})
}
}
}
</script>

View File

@@ -1,47 +0,0 @@
<template>
<d2-container type="card">
<template slot="header">导出文本</template>
<el-input
type="textarea"
:autosize="{minRows: 2, maxRows: 4}"
placeholder="请输入内容 然后点击保存按钮导出文本文档"
v-model="text">
</el-input>
<div class="d2-mt">
<el-button type="primary" @click="exportTxt">
<d2-icon name="download"/>
保存为 txt
</el-button>
</div>
</d2-container>
</template>
<script>
import Vue from 'vue'
import pluginExport from '@d2-projects/vue-table-export'
Vue.use(pluginExport)
export default {
data () {
return {
text: ''
}
},
methods: {
exportTxt () {
// 校验是不是空
if (this.text === '') {
this.$message('虽然可以为空 但是出于体验不建议这样 还是写点东西吧')
return
}
// 导出
this.$export.txt({
text: this.text,
title: '文本'
})
.then(() => {
this.$message('导出文本成功')
})
}
}
}
</script>

View File

@@ -1,62 +0,0 @@
<template>
<d2-container type="card">
<template slot="header">
<el-button @click="download">
<d2-icon name="download"/>
下载演示 .csv 表格
</el-button>
</template>
<div class="d2-mb">
<el-upload :before-upload="handleUpload" action="default">
<el-button type="success">
<d2-icon name="file-o"/>
选择要导入的 .csv 表格
</el-button>
</el-upload>
</div>
<el-table v-bind="table">
<el-table-column
v-for="(item, index) in table.columns"
:key="index"
:prop="item.prop"
:label="item.label">
</el-table-column>
</el-table>
</d2-container>
</template>
<script>
import Vue from 'vue'
import pluginImport from '@d2-projects/vue-table-import'
Vue.use(pluginImport)
export default {
data () {
return {
table: {
columns: [],
data: [],
size: 'mini',
stripe: true,
border: true
}
}
},
methods: {
handleUpload (file) {
this.$import.csv(file)
.then(res => {
this.table.columns = Object.keys(res.data[0]).map(e => ({
label: e,
prop: e
}))
this.table.data = res.data
})
return false
},
download () {
this.$open('https://file.d2.pub/document/d2-admin/demo-csv.csv')
}
}
}
</script>

View File

@@ -1,64 +0,0 @@
<template>
<d2-container type="card">
<template slot="header">
<el-button @click="download">
<d2-icon name="download"/>
下载演示 .xlsx 表格
</el-button>
</template>
<div class="d2-mb">
<el-upload :before-upload="handleUpload" action="default">
<el-button type="success">
<d2-icon name="file-o"/>
选择要导入的 .xlsx 表格
</el-button>
</el-upload>
</div>
<el-table v-bind="table">
<el-table-column
v-for="(item, index) in table.columns"
:key="index"
:prop="item.prop"
:label="item.label">
</el-table-column>
</el-table>
</d2-container>
</template>
<script>
import Vue from 'vue'
import pluginImport from '@d2-projects/vue-table-import'
Vue.use(pluginImport)
export default {
data () {
return {
table: {
columns: [],
data: [],
size: 'mini',
stripe: true,
border: true
}
}
},
methods: {
handleUpload (file) {
this.$import.xlsx(file)
.then(({ header, results }) => {
this.table.columns = header.map(e => {
return {
label: e,
prop: e
}
})
this.table.data = results
})
return false
},
download () {
this.$open('https://file.d2.pub/document/d2-admin/demo-table.xlsx')
}
}
}
</script>

View File

@@ -1,21 +0,0 @@
<template>
<d2-container type="ghost">
<d2-module-index-banner slot="header" v-bind="banner"/>
<d2-module-index-menu :menu="menu"/>
</d2-container>
</template>
<script>
import menu from '@/menu/modules/demo-plugins'
export default {
data () {
return {
menu,
banner: {
title: 'PLUGIN',
subTitle: 'D2Admin 集成了许多实用插件'
}
}
}
}
</script>

View File

@@ -1,54 +0,0 @@
<template>
<d2-container>
<template slot="header">
<div class="d2-mb">Cookie 读写</div>
<el-alert
title="建议"
type="warning"
description="建议使用 util 内的 cookies 对象,这样会在存储和读取时统一增加前缀,方便对 cookie 统一管理"
show-icon>
</el-alert>
</template>
<p class="d2-mt-0">基本读写删</p>
<el-button type="primary" @click="set('demo-user-name', 'demo-user')">set('demo-user-name', 'normalValue')</el-button>
<el-button type="info" @click="get('demo-user-name')">get('demo-user-name')</el-button>
<el-button type="error" @click="remove('demo-user-name')">remove('demo-user-name')</el-button>
<p>设置有效期</p>
<el-button type="primary" @click="setExpires('demo-user-pwd', '123456789', 1)">设置 'demo-user-pwd' 有效期为一天</el-button>
<el-button type="info" @click="get('demo-user-pwd')">get('demo-user-pwd')</el-button>
<el-button type="error" @click="remove('demo-user-pwd')">remove('demo-user-pwd')</el-button>
<p>获取所有可以获得的数据</p>
<el-button type="info" @click="getAll">getAll</el-button>
</d2-container>
</template>
<script>
import util from '@/libs/util.js'
export default {
methods: {
set (name = 'default-name', value = 'default-value') {
util.cookies.set(name, value)
this.$message.info(`设置数据 ${name} = ${value}`)
},
setExpires (name = 'default-name', value = 'default-value', expires = 1) {
util.cookies.set(name, value, {
expires
})
this.$message.info(`设置数据 ${name} = ${value} 有效期 ${expires}`)
},
get (name = 'default-name') {
const value = util.cookies.get(name)
this.$message.info(`获取数据 ${name} = ${value}`)
},
getAll () {
const value = util.cookies.getAll()
console.log(value)
this.$message.info('结果已经打印到控制台')
},
remove (name = 'default-name') {
util.cookies.remove(name)
this.$message.info(`删除数据 ${name}`)
}
}
}
</script>