2025-05-17

This commit is contained in:
lcc
2025-05-17 18:31:02 +08:00
parent 0430096017
commit 41aa927097
129 changed files with 846 additions and 14120 deletions
+3 -1
View File
@@ -1 +1,3 @@
VUE_APP_API_BASE_URL=http://agent.admin.haodian.cn/api
VUE_APP_API_BASE_URL=/api
URL = http://agent.admin.haodian.cn
PORT = 8100
+22
View File
@@ -0,0 +1,22 @@
import request from '@/utils/request';
export async function pageBrand(params) {
const res = await request.get('/common/autoBrand', {
params
});
return res.data;
}
export async function pageSeries(params) {
const res = await request.get('/common/autoSeries', {
params
});
return res.data;
}
export async function pageAutoCar(params) {
const res = await request.get('/common/autoCar', {
params
});
return res.data;
}
+214
View File
@@ -0,0 +1,214 @@
<template>
<div class="car-model-selector">
<el-form-item label="品牌">
<el-select
v-model="form.brandId"
filterable
clearable
placeholder="请输入品牌名称搜索"
:loading="brandLoading"
@change="handleBrandChange"
@filter-change="handleBrandFilter"
>
<el-option
v-for="item in brandList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
<template v-if="type !== 'brand'">
-
<el-select
v-model="form.seriesId"
placeholder="请选择车系"
clearable
:disabled="!form.brandId"
:loading="seriesLoading"
@change="handleSeriesChange"
>
<el-option
v-for="item in seriesList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</template>
<template v-if="!type">
-
<el-select
v-model="form.modelId"
placeholder="请选择车型"
clearable
:disabled="!form.seriesId"
:loading="modelLoading"
@change="handleModelChange"
>
<el-option
v-for="item in modelList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</template>
</el-form-item>
</div>
</template>
<script>
import { pageBrand, pageSeries, pageAutoCar } from '@/api/auto';
export default {
name: 'CarModelSelector',
props: {
modelValue: {
type: Object,
default: () => ({
brandId: null,
seriesId: null,
modelId: null
})
},
type: {
type: String,
validator: (type) => {
return !type || ['brandSeries', 'brand'].includes(type);
}
}
},
data() {
return {
form: {
brandId: null,
seriesId: null,
modelId: null
},
brandList: [],
seriesList: [],
modelList: [],
brandLoading: false,
seriesLoading: false,
modelLoading: false,
brandFilter: ''
};
},
watch: {
modelValue: {
deep: true,
handler(newVal) {
this.form = { ...newVal };
this.syncFormWithProps();
}
},
'$props.modelValue': {
handler() {
this.syncFormWithProps();
}
},
'form.brandId'(val) {
this.emitValue();
if (!val) {
this.seriesList = [];
this.modelList = [];
this.form.seriesId = null;
this.form.modelId = null;
}
},
'form.seriesId'(val) {
this.emitValue();
if (!val) this.modelList = this.form.modelId = null;
},
'form.modelId': {
handler() {
this.emitValue();
},
immediate: true
}
},
created() {
this.loadBrands();
this.syncFormWithProps();
},
methods: {
async loadBrands(filter = '') {
this.brandLoading = true;
try {
const res = await pageBrand({ nameLike: filter });
this.brandList = res;
} catch (error) {
this.$message.error('品牌加载失败');
} finally {
this.brandLoading = false;
}
},
async loadSeriesList(brandId) {
this.seriesLoading = true;
try {
const res = await pageSeries({ brandId });
this.seriesList = res;
this.form.seriesId = null;
} catch (error) {
this.$message.error('车系加载失败');
} finally {
this.seriesLoading = false;
}
},
async loadModelList(seriesId) {
this.modelLoading = true;
try {
const res = await pageAutoCar({ seriesId });
this.modelList = res;
this.form.modelId = null;
} catch (error) {
this.$message.error('车型加载失败');
} finally {
this.modelLoading = false;
}
},
handleBrandChange(brandId) {
if (brandId) this.loadSeriesList(brandId);
},
handleSeriesChange(seriesId) {
if (seriesId) this.loadModelList(seriesId);
},
handleModelChange() {},
handleBrandFilter(filter) {
this.brandFilter = filter;
this.loadBrands(filter);
},
emitValue() {
this.$emit('update:modelValue', {
brandId: this.form.brandId,
seriesId: this.form.seriesId,
modelId: this.form.modelId
});
},
syncFormWithProps() {
// 重置所有数据
this.brandList = [];
this.seriesList = [];
this.modelList = [];
const { brandId, seriesId, modelId } = this.modelValue;
this.form = { brandId, seriesId, modelId };
if (brandId) {
this.loadSeriesList(brandId);
if (seriesId) {
this.loadModelList(seriesId);
}
}
}
}
};
</script>
<style scoped></style>
@@ -39,6 +39,11 @@
class="ele-fluid"
/>
</el-form-item>
<car-model-selector
type="brandSeries"
v-model="form.selectedCar"
@update:modelValue="handleCarChange"
/>
<el-form-item label="有效期:" prop="dateRange">
<el-date-picker
v-model="form.dateRange"
@@ -108,11 +113,13 @@
import { listDictionaryData } from '@/api/system/dictionary-data';
import UploadImg from '@/components/UploadImg/index.vue';
import RegionsSelect from '@/components/RegionsSelect/index.vue';
import CarModelSelector from '@/components/CarSelector/index.vue';
export default {
components: {
UploadImg,
RegionsSelect
RegionsSelect,
CarModelSelector
},
props: {
// 弹窗是否打开
@@ -133,7 +140,12 @@
secondLevelClues: '',
firstLevelDeal: '',
secondLevelDeal: '',
crowdProfiling: []
crowdProfiling: [],
selectedCar: {
brandId: null,
seriesId: null,
modelId: null
}
};
return {
editVersion: false,
@@ -185,10 +197,6 @@
});
},
methods: {
/* 添加海报描述 */
addShareTitle() {
this.form.shareTitle.push('');
},
/* 保存编辑 */
save() {
this.$refs.form.validate((valid) => {
@@ -213,6 +221,9 @@
});
});
},
handleCarChange(carInfo) {
this.form.selectedCar = carInfo;
},
/* 更新visible */
updateVisible(value) {
this.$emit('update:visible', value);
+31 -7
View File
@@ -13,6 +13,14 @@
/>
</el-form-item>
</el-col>
<el-col :md="24" :sm="24">
<car-model-selector
type="brandSeries"
v-model="this.where.selectedCar"
@update:modelValue="handleCarChange"
:key="componentKey"
/>
</el-col>
<el-col :md="6" :sm="12">
<div class="ele-form-actions">
<el-button
@@ -107,14 +115,20 @@
updateProductStatus
} from '@/api/car/product';
import edit from './components/edit.vue';
import CarModelSelector from '@/components/CarSelector/index.vue';
export default {
name: 'carProduct',
components: { edit },
components: { CarModelSelector, edit },
data() {
return {
where: {
title: ''
title: '',
selectedCar: {
brandId: '',
seriesId: '',
modelId: ''
}
},
// 门店数据
organizationList: [],
@@ -186,12 +200,11 @@
showEditDraw: false,
showEditVisitTag: false,
// 是否显示二维码弹窗
showCode: false
showCode: false,
componentKey: 0
};
},
created() {
//this.organizationQuery();
},
created() {},
methods: {
edit(row) {
this.current = row;
@@ -259,7 +272,18 @@
},
/* 重置搜索 */
reset() {
this.where = {};
this.where = {
selectedCar: {
brandId: null,
seriesId: null,
modelId: null
}
};
// 更新 key 强制组件重新渲染
this.componentKey = Date.now();
},
handleCarChange(carInfo) {
this.where.selectedCar = carInfo;
}
}
};
+10
View File
@@ -2,6 +2,16 @@ const CompressionWebpackPlugin = require('compression-webpack-plugin');
const { transformElementScss } = require('ele-admin/lib/utils/dynamic-theme');
module.exports = {
devServer: {
port: process.env.PORT || 8100,
proxy: {
'/api': {
target: process.env.URL,
changeOrigin: true,
pathRewrite: { '^/api/common': '/common' } //路由重写调用公共方法
}
}
},
productionSourceMap: false,
transpileDependencies: ['element-ui', 'ele-admin', 'vue-i18n'],
configureWebpack: {
+1 -1
View File
@@ -1,2 +1,2 @@
VUE_APP_NAME=Ele Admin
VUE_APP_NAME=易客来
VUE_APP_API_BASE_URL=https://v2.eleadmin.com/api
+4 -1
View File
@@ -1 +1,4 @@
VUE_APP_API_BASE_URL=http://agent.admin.haodian.cn/api
VUE_APP_NAME=易客来
VUE_APP_API_BASE_URL=/pingan
URL = http://agent.admin.haodian.cn
PORT = 8200
+22
View File
@@ -24,3 +24,25 @@ export async function getCaptcha() {
}
return Promise.reject(new Error(res.data.message));
}
/**
* 获取短信验证码
*/
export async function getCode(data) {
const res = await request.get('/login/code', data);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 注册
*/
export async function register(data) {
const res = await request.post('/register', data);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
+15
View File
@@ -0,0 +1,15 @@
<template>
<div class="copyright">Copyright © 2022 好店云(厦门)科技有限公司</div>
</template>
<style lang="scss" scoped>
/* 底部版权 */
.copyright {
position: fixed;
bottom: 0;
width: 100%;
color: #eee;
text-align: center;
padding: 50px 0;
z-index: 100;
}
</style>
+1 -1
View File
@@ -18,7 +18,7 @@ export const HIDE_FOOTERS = [
export const REPEATABLE_TABS = [];
// 不需要登录的路由
export const WHITE_LIST = ['/login', '/forget'];
export const WHITE_LIST = ['/login', '/register'];
// 开启 KeepAlive 后仍然不需要缓存的路由地址
export const KEEP_ALIVE_EXCLUDES = [];
@@ -26,7 +26,7 @@
<el-dropdown @command="onUserDropClick">
<div class="ele-admin-header-avatar">
<el-avatar :src="loginUser.avatar" />
<span class="hidden-xs-only">{{ loginUser.nickname }}</span>
<span class="hidden-xs-only">{{ loginUser.username }}</span>
<i class="el-icon-arrow-down"></i>
</div>
<template v-slot:dropdown>
@@ -34,9 +34,6 @@
<el-dropdown-item command="profile" icon="el-icon-user">
{{ $t('layout.header.profile') }}
</el-dropdown-item>
<el-dropdown-item command="password" icon="el-icon-key">
{{ $t('layout.header.password') }}
</el-dropdown-item>
<el-dropdown-item
command="logout"
icon="el-icon-switch-button"
@@ -61,14 +58,14 @@
<script>
// import HeaderNotice from './header-notice.vue';
import PasswordModal from './password-modal.vue';
// import PasswordModal from './password-modal.vue';
import SettingDrawer from './setting-drawer.vue';
// import I18nIcon from './i18n-icon.vue';
import { logout } from '@/utils/page-tab-util';
export default {
// components: { HeaderNotice, PasswordModal, SettingDrawer, I18nIcon },
components: { PasswordModal, SettingDrawer },
components: { SettingDrawer },
props: {
// 是否是全屏
fullscreen: Boolean
+8 -3
View File
@@ -13,10 +13,15 @@ export const routes = [
component: () => import('@/views/login/index.vue'),
meta: { title: '登录' }
},
// {
// path: '/forget',
// component: () => import('@/views/forget/index.vue'),
// meta: { title: '忘记密码' }
// },
{
path: '/forget',
component: () => import('@/views/forget/index.vue'),
meta: { title: '忘记密码' }
path: '/register',
component: () => import('@/views/register/index.vue'),
meta: { title: '账号绑定' }
},
// 404
{
@@ -1,73 +0,0 @@
<template>
<el-card shadow="never" header="热门搜索">
<v-chart
ref="hotSearchChart"
style="height: 303px"
:option="hotSearchChartOption"
/>
</el-card>
</template>
<script>
import { use } from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers';
import { TooltipComponent } from 'echarts/components';
import VChart from 'vue-echarts';
import 'echarts-wordcloud';
import { wordCloudColor } from 'ele-admin';
import { getWordCloudList } from '@/api/dashboard/analysis';
import { echartsMixin } from '@/utils/echarts-mixin';
use([CanvasRenderer, TooltipComponent]);
export default {
components: { VChart },
mixins: [echartsMixin(['hotSearchChart'])],
data() {
return {
// 词云图表配置
hotSearchChartOption: {}
};
},
created() {
this.getWordCloudData();
},
methods: {
/* 获取词云数据 */
getWordCloudData() {
getWordCloudList()
.then((data) => {
this.hotSearchChartOption = {
tooltip: {
show: true,
confine: true,
borderWidth: 1
},
series: [
{
type: 'wordCloud',
width: '100%',
height: '100%',
sizeRange: [12, 24],
gridSize: 6,
textStyle: {
color: wordCloudColor
},
emphasis: {
textStyle: {
shadowBlur: 8,
shadowColor: 'rgba(0, 0, 0, .15)'
}
},
data: data
}
]
};
})
.catch((e) => {
this.$message.error(e.message);
});
}
}
};
</script>
@@ -1,210 +0,0 @@
<template>
<el-card shadow="never" body-style="padding: 0;">
<div class="ele-cell demo-monitor-tool">
<div class="ele-cell-content">
<el-tabs
v-model="saleSearch.type"
class="demo-monitor-tabs"
@tab-click="onSaleTypeChange"
>
<el-tab-pane label="销售额" name="saleroom" />
<el-tab-pane label="访问量" name="visits" />
</el-tabs>
</div>
<div :class="['ele-inline-block', { 'hidden-xs-only': styleResponsive }]">
<el-radio-group v-model="saleSearch.dateType" size="small">
<el-radio-button :label="0">今天</el-radio-button>
<el-radio-button :label="1">本周</el-radio-button>
<el-radio-button :label="2">本月</el-radio-button>
<el-radio-button :label="3">本年</el-radio-button>
</el-radio-group>
</div>
<div
:class="['ele-inline-block', { 'hidden-sm-and-down': styleResponsive }]"
style="width: 260px; margin-left: 10px"
>
<el-date-picker
unlink-panels
type="daterange"
class="ele-fluid"
end-placeholder="结束日期"
start-placeholder="开始日期"
v-model="saleSearch.datetime"
range-separator=""
size="small"
/>
</div>
</div>
<el-divider />
<el-row>
<el-col v-bind="styleResponsive ? { lg: 18, md: 16 } : { span: 18 }">
<div class="demo-monitor-title">
<span v-if="saleSearch.type === 'saleroom'">销售额趋势</span>
<span v-else>访问量趋势</span>
</div>
<v-chart
ref="saleChart"
style="height: 285px"
:option="saleChartOption"
/>
</el-col>
<el-col v-bind="styleResponsive ? { lg: 6, md: 8 } : { span: 6 }">
<div class="demo-monitor-title" style="display: flex">
<div>门店</div>
<div>
<span v-if="saleSearch.type === 'saleroom'">销售额</span>
<span v-else>访问量</span>
</div>
<div>排名</div>
</div>
<div
v-for="(item, index) in saleroomRankData"
:key="index"
class="demo-monitor-rank-item ele-cell"
style="margin-bottom: 15px"
>
<el-tag
size="mini"
type="info"
:effect="index < 3 ? 'dark' : 'light'"
:color="index < 3 ? '#314659' : 'hsla(0, 0%, 60%, .2)'"
style="border-color: transparent"
class="ele-tag-round"
>
{{ index + 1 }}
</el-tag>
<div class="ele-cell-content">{{ item.name }}</div>
<div class="ele-text-secondary">{{ item.value }}</div>
</div>
</el-col>
</el-row>
</el-card>
</template>
<script>
import { use } from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers';
import { BarChart } from 'echarts/charts';
import { GridComponent, TooltipComponent } from 'echarts/components';
import VChart from 'vue-echarts';
import { getSaleroomList } from '@/api/dashboard/analysis';
import { echartsMixin } from '@/utils/echarts-mixin';
use([CanvasRenderer, BarChart, GridComponent, TooltipComponent]);
export default {
components: { VChart },
mixins: [echartsMixin(['saleChart'])],
data() {
return {
// 销售量搜索参数
saleSearch: {
type: 'saleroom',
dateType: 0,
datetime: ''
},
// 销售量趋势数据
saleroomData1: [],
// 访问量趋势数据
saleroomData2: [],
// 门店排名数据
saleroomRankData: [
{ name: '工专路 1 号店', value: '323,234' },
{ name: '工专路 2 号店', value: '323,234' },
{ name: '工专路 3 号店', value: '323,234' },
{ name: '工专路 4 号店', value: '323,234' },
{ name: '工专路 5 号店', value: '323,234' },
{ name: '工专路 6 号店', value: '323,234' },
{ name: '工专路 7 号店', value: '323,234' }
],
// 销售额柱状图配置
saleChartOption: {}
};
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
},
created() {
this.getSaleroomData();
},
methods: {
/* 获取销售量数据 */
getSaleroomData() {
getSaleroomList()
.then((data) => {
this.saleroomData1 = data.list1;
this.saleroomData2 = data.list2;
this.onSaleTypeChange();
})
.catch((e) => {
this.$message.error(e.message);
});
},
/* 销售量tab选择改变事件 */
onSaleTypeChange() {
const isSale = this.saleSearch.type === 'saleroom';
const data = isSale ? this.saleroomData1 : this.saleroomData2;
this.saleChartOption = {
tooltip: {
trigger: 'axis'
},
xAxis: [
{
type: 'category',
data: data.map((d) => d.month)
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
type: 'bar',
data: data.map((d) => d.value)
}
]
};
}
}
};
</script>
<style lang="scss" scoped>
/* 销售额、访问量工具栏 */
.demo-monitor-tool {
padding: 0 20px;
.demo-monitor-tabs {
height: 51px;
}
:deep(.el-tabs__item) {
height: 51px;
line-height: 51px;
font-size: 15px;
}
:deep(.el-tabs__nav-wrap:after) {
display: none;
}
}
/* 小标题 */
.demo-monitor-title {
padding: 0 20px;
margin: 15px 0 5px 0;
}
/* 排名 item */
.demo-monitor-rank-item {
padding: 0 20px;
line-height: 20px;
margin-top: 18px;
}
</style>
@@ -1,243 +0,0 @@
<!-- 统计卡片 -->
<template>
<el-row :gutter="15">
<el-col v-bind="styleResponsive ? { lg: 6, md: 12 } : { span: 6 }">
<el-card class="analysis-chart-card" shadow="never">
<template v-slot:header>
<div class="ele-cell">
<div class="ele-cell-content">总销售额</div>
<el-tooltip content="指标说明" placement="top">
<i
class="el-icon-_question ele-text-placeholder"
style="cursor: pointer"
>
</i>
</el-tooltip>
</div>
</template>
<div class="analysis-chart-card-num ele-text-heading">¥ 126,560</div>
<div class="analysis-chart-card-content" style="padding-top: 18px">
<span class="ele-action">
<span>周同比12%</span>
<i class="el-icon-caret-top ele-text-danger"></i>
</span>
<span class="ele-action">
<span>日同比11%</span>
<i class="el-icon-caret-bottom ele-text-success"></i>
</span>
</div>
<el-divider />
<div class="analysis-chart-card-text">日销售额 ¥12,423</div>
</el-card>
</el-col>
<el-col v-bind="styleResponsive ? { lg: 6, md: 12 } : { span: 6 }">
<el-card class="analysis-chart-card" shadow="never">
<template v-slot:header>
<div class="ele-cell">
<div class="ele-cell-content">访问量</div>
<el-tag size="mini" type="danger"></el-tag>
</div>
</template>
<div class="analysis-chart-card-num ele-text-heading">8,846</div>
<div class="analysis-chart-card-content">
<v-chart
ref="visitChart"
style="height: 40px"
:option="visitChartOption"
/>
</div>
<el-divider />
<div class="analysis-chart-card-text">日访问量 1,234</div>
</el-card>
</el-col>
<el-col v-bind="styleResponsive ? { lg: 6, md: 12 } : { span: 6 }">
<el-card class="analysis-chart-card" shadow="never">
<template v-slot:header>
<div class="ele-cell">
<div class="ele-cell-content">支付笔数</div>
<el-tag size="mini"></el-tag>
</div>
</template>
<div class="analysis-chart-card-num ele-text-heading">6,560</div>
<div class="analysis-chart-card-content">
<v-chart
ref="payNumChart"
style="height: 40px"
:option="payNumChartOption"
/>
</div>
<el-divider />
<div class="analysis-chart-card-text">转化率 60%</div>
</el-card>
</el-col>
<el-col v-bind="styleResponsive ? { lg: 6, md: 12 } : { span: 6 }">
<el-card class="analysis-chart-card" shadow="never">
<template v-slot:header>
<div class="ele-cell">
<div class="ele-cell-content">运营活动效果</div>
<el-tag size="mini" type="success"></el-tag>
</div>
</template>
<div class="analysis-chart-card-num ele-text-heading">78%</div>
<div class="analysis-chart-card-content" style="padding-top: 25px">
<el-progress
:percentage="78"
:show-text="false"
:stroke-width="10"
color="#13c2c2"
/>
</div>
<el-divider />
<div class="analysis-chart-card-text">
<span class="ele-action">
<span>周同比12%</span>
<i class="el-icon-caret-top ele-text-danger"></i>
</span>
<span class="ele-action">
<span>日同比11%</span>
<i class="el-icon-caret-bottom ele-text-success"></i>
</span>
</div>
</el-card>
</el-col>
</el-row>
</template>
<script>
import { use } from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers';
import { LineChart, BarChart } from 'echarts/charts';
import { GridComponent, TooltipComponent } from 'echarts/components';
import VChart from 'vue-echarts';
import { getPayNumList } from '@/api/dashboard/analysis';
import { echartsMixin } from '@/utils/echarts-mixin';
use([CanvasRenderer, LineChart, BarChart, GridComponent, TooltipComponent]);
export default {
components: { VChart },
mixins: [echartsMixin(['visitChart', 'payNumChart'])],
data() {
return {
// 访问量折线图配置
visitChartOption: {},
// 支付笔数柱状图配置
payNumChartOption: {}
};
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
},
created() {
this.getPayNumData();
},
methods: {
/* 获取数据 */
getPayNumData() {
getPayNumList()
.then((data) => {
this.visitChartOption = {
color: '#975fe5',
tooltip: {
trigger: 'axis',
formatter:
'<i class="ele-chart-dot" style="background: #975fe5;"></i>{b0}: {c0}'
},
grid: {
top: 10,
bottom: 0,
left: 0,
right: 0
},
xAxis: [
{
show: false,
type: 'category',
boundaryGap: false,
data: data.map((d) => d.date)
}
],
yAxis: [
{
show: false,
type: 'value',
splitLine: {
show: false
}
}
],
series: [
{
type: 'line',
smooth: true,
symbol: 'none',
areaStyle: {
opacity: 0.5
},
data: data.map((d) => d.value)
}
]
};
//
this.payNumChartOption = {
tooltip: {
trigger: 'axis',
formatter:
'<i class="ele-chart-dot" style="background: #5b8ff9;"></i>{b0}: {c0}'
},
grid: {
top: 10,
bottom: 0,
left: 0,
right: 0
},
xAxis: [
{
show: false,
type: 'category',
data: data.map((d) => d.date)
}
],
yAxis: [
{
show: false,
type: 'value',
splitLine: {
show: false
}
}
],
series: [
{
type: 'bar',
data: data.map((d) => d.value)
}
]
};
})
.catch((e) => {
this.$message.error(e.message);
});
}
}
};
</script>
<style lang="scss" scoped>
.analysis-chart-card-num {
font-size: 30px;
}
.analysis-chart-card-content {
height: 40px;
box-sizing: border-box;
margin-bottom: 12px;
}
.analysis-chart-card-text {
padding-top: 12px;
}
</style>
@@ -1,103 +0,0 @@
<template>
<el-card
shadow="never"
header="最近1小时访问情况"
body-style="padding: 14px 5px 0 0;"
>
<v-chart
ref="visitHourChart"
style="height: 323px"
:option="visitHourChartOption"
/>
</el-card>
</template>
<script>
import { use } from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers';
import { LineChart } from 'echarts/charts';
import {
GridComponent,
TooltipComponent,
LegendComponent
} from 'echarts/components';
import VChart from 'vue-echarts';
import { getVisitHourList } from '@/api/dashboard/analysis';
import { echartsMixin } from '@/utils/echarts-mixin';
use([
CanvasRenderer,
LineChart,
GridComponent,
TooltipComponent,
LegendComponent
]);
export default {
components: { VChart },
mixins: [echartsMixin(['visitHourChart'])],
data() {
return {
// 最近1小时访问情况折线图配置
visitHourChartOption: {}
};
},
created() {
this.getVisitHourData();
},
methods: {
/* 获取最近1小时访问情况数据 */
getVisitHourData() {
getVisitHourList()
.then((data) => {
this.visitHourChartOption = {
tooltip: {
trigger: 'axis'
},
legend: {
data: ['浏览量', '访问量'],
right: 20
},
xAxis: [
{
type: 'category',
boundaryGap: false,
data: data.map((d) => d.time)
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
name: '浏览量',
type: 'line',
smooth: true,
symbol: 'none',
areaStyle: {
opacity: 0.5
},
data: data.map((d) => d.views)
},
{
name: '访问量',
type: 'line',
smooth: true,
symbol: 'none',
areaStyle: {
opacity: 0.5
},
data: data.map((d) => d.visits)
}
]
};
})
.catch((e) => {
this.$message.error(e.message);
});
}
}
};
</script>
@@ -1,37 +0,0 @@
<template>
<div class="ele-body ele-body-card">
<statistics-card />
<sale-card />
<el-row :gutter="15">
<el-col v-bind="styleResponsive ? { lg: 18, md: 16 } : { span: 18 }">
<visit-hour />
</el-col>
<el-col v-bind="styleResponsive ? { lg: 6, md: 8 } : { span: 6 }">
<hot-search />
</el-col>
</el-row>
</div>
</template>
<script>
import StatisticsCard from './components/statistics-card.vue';
import SaleCard from './components/sale-card.vue';
import VisitHour from './components/visit-hour.vue';
import HotSearch from './components/hot-search.vue';
export default {
name: 'DashboardAnalysis',
components: {
StatisticsCard,
SaleCard,
VisitHour,
HotSearch
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
}
};
</script>
@@ -1,71 +0,0 @@
<template>
<el-card shadow="never" header="浏览器分布" body-style="padding: 0 10px;">
<v-chart
ref="browserChart"
style="height: 240px"
:option="browserChartOption"
/>
</el-card>
</template>
<script>
import { use } from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers';
import { PieChart } from 'echarts/charts';
import { TooltipComponent, LegendComponent } from 'echarts/components';
import VChart from 'vue-echarts';
import { getBrowserCountList } from '@/api/dashboard/monitor';
import { echartsMixin } from '@/utils/echarts-mixin';
use([CanvasRenderer, PieChart, TooltipComponent, LegendComponent]);
export default {
components: { VChart },
mixins: [echartsMixin(['browserChart'])],
data() {
return {
// 浏览器分布饼图配置
browserChartOption: {}
};
},
created() {
this.getBrowserCountData();
},
methods: {
/* 获取用户浏览器分布数据 */
getBrowserCountData() {
getBrowserCountList()
.then((data) => {
this.browserChartOption = {
tooltip: {
trigger: 'item',
confine: true,
borderWidth: 1
},
legend: {
bottom: 5,
itemWidth: 10,
itemHeight: 10,
icon: 'circle',
data: data.map((d) => d.name)
},
series: [
{
type: 'pie',
radius: ['45%', '70%'],
center: ['50%', '43%'],
label: {
show: false
},
data: data
}
]
};
})
.catch((e) => {
this.$message.error(e.message);
});
}
}
};
</script>
@@ -1,149 +0,0 @@
<template>
<el-card shadow="never" header="用户分布">
<el-row>
<el-col v-bind="styleResponsive ? { sm: 18 } : { span: 18 }">
<v-chart
ref="userCountMapChart"
style="height: 444px"
:option="userCountMapOption"
/>
</el-col>
<el-col v-bind="styleResponsive ? { sm: 6 } : { span: 6 }">
<div style="padding: 10px 5px 0 0">
<div
v-for="(item, index) in userCountDataRank"
:key="index"
class="monitor-user-count-item ele-cell"
>
<div>{{ item.name }}</div>
<div class="ele-cell-content">
<el-progress
:stroke-width="10"
:show-text="false"
:percentage="item.percent"
/>
</div>
<div>{{ item.value }}</div>
</div>
</div>
</el-col>
</el-row>
</el-card>
</template>
<script>
import { use, registerMap } from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers';
import { MapChart } from 'echarts/charts';
import {
VisualMapComponent,
GeoComponent,
TooltipComponent
} from 'echarts/components';
import VChart from 'vue-echarts';
import { getChinaMapData, getUserCountList } from '@/api/dashboard/monitor';
import { echartsMixin } from '@/utils/echarts-mixin';
use([
CanvasRenderer,
MapChart,
VisualMapComponent,
GeoComponent,
TooltipComponent
]);
export default {
components: { VChart },
mixins: [echartsMixin(['userCountMapChart'])],
data() {
return {
// 用户分布地图配置
userCountMapOption: {},
// 用户分布前10名
userCountDataRank: []
};
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
},
created() {
this.registerChinaMap();
},
methods: {
/* 获取中国地图数据并注册地图 */
registerChinaMap() {
getChinaMapData()
.then((data) => {
registerMap('china', data);
this.getUserCountData();
})
.catch((e) => {
this.$message.error(e.message);
});
},
/* 获取用户分布数据 */
getUserCountData() {
getUserCountList()
.then((data) => {
const temp = data.sort((a, b) => b.value - a.value);
const min = temp[temp.length - 1].value || 0;
const max = temp[0].value || 1;
//
const list = temp.length > 10 ? temp.slice(0, 15) : temp;
this.userCountDataRank = list.map((d) => {
return {
name: d.name,
value: d.value,
percent: (d.value / max) * 100
};
});
//
this.userCountMapOption = {
tooltip: {
trigger: 'item',
borderWidth: 1
},
visualMap: {
min: min,
max: max,
text: ['高', '低'],
calculable: true
},
series: [
{
name: '用户数',
label: {
show: true
},
type: 'map',
map: 'china',
data: data
}
]
};
})
.catch((e) => {
this.$message.error(e.message);
});
}
}
};
</script>
<style lang="scss" scoped>
/* 人数分布排名 */
.monitor-user-count-item {
margin-bottom: 8px;
:deep(.el-progress-bar__outer) {
background: none;
}
.ele-cell-content {
padding-right: 10px;
}
}
</style>
@@ -1,93 +0,0 @@
<template>
<el-card shadow="never" header="在线人数">
<div
:class="[
'monitor-online-num-card',
{ 'monitor-online-num-responsive': styleResponsive }
]"
>
<div class="monitor-online-num-text">{{ currentTime }}</div>
<div class="monitor-online-num-title ele-text-heading">
<vue-count-up :end-val="onlineNum" />
</div>
<div class="monitor-online-num-text">在线总人数</div>
<ele-dot :text="updateTimeText" />
</div>
</el-card>
</template>
<script>
import VueCountUp from 'vue-countup-v2';
export default {
components: { VueCountUp },
data() {
return {
// 在线总人数倒计时
updateTime: 10,
// 当前时间
currentTime: '20:58:22',
// 在线人数
onlineNum: 228,
// 在线人数更新定时器
onlineNumTimer: null
};
},
computed: {
// 在线人数倒计时文字
updateTimeText() {
return this.updateTime + ' 秒后更新';
},
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
},
created() {
this.startUpdateOnlineNum();
},
methods: {
/* 在线人数更新倒计时 */
startUpdateOnlineNum() {
this.currentTime = this.$util.toDateString(new Date(), 'HH:mm:ss');
this.onlineNumTimer = setInterval(() => {
this.currentTime = this.$util.toDateString(new Date(), 'HH:mm:ss');
if (this.updateTime === 1) {
this.updateTime = 10;
this.onlineNum = 100 + Math.round(Math.random() * 900);
} else {
this.updateTime--;
}
}, 1000);
}
},
beforeDestroy() {
// 销毁定时器
if (this.onlineNumTimer) {
clearInterval(this.onlineNumTimer);
}
}
};
</script>
<style lang="scss" scoped>
.monitor-online-num-card {
text-align: center;
padding: 5px 0;
}
.monitor-online-num-text {
margin-bottom: 5px;
}
.monitor-online-num-title {
font-size: 48px;
margin-bottom: 10px;
}
@media screen and (max-width: 1200px) {
.monitor-online-num-responsive.monitor-online-num-card {
padding: 42px 0;
}
}
</style>
@@ -1,163 +0,0 @@
<!-- 统计卡片 -->
<template>
<el-row :gutter="15">
<el-col v-bind="styleResponsive ? { md: 6, sm: 12 } : { span: 6 }">
<el-card shadow="never" class="monitor-count-card">
<el-tag size="large" class="ele-tag-round">
<i class="el-icon-s-custom"></i>
</el-tag>
<div class="monitor-count-card-num ele-text-heading">21.2 k</div>
<div class="monitor-count-card-text ele-text-secondary">
总访问人数
</div>
<ele-avatar-list :data="visitUsers" :size="22" :max="4" />
</el-card>
</el-col>
<el-col v-bind="styleResponsive ? { md: 6, sm: 12 } : { span: 6 }">
<el-card shadow="never" class="monitor-count-card">
<el-tag size="large" type="warning" class="ele-tag-round">
<i class="el-icon-_sent"></i>
</el-tag>
<div class="monitor-count-card-num ele-text-heading">1.6 k</div>
<div class="monitor-count-card-text ele-text-secondary">
点击量 (近30天)
</div>
<div class="monitor-count-card-trend ele-text-success">
<i class="el-icon-arrow-up"></i>
<span>110.5%</span>
</div>
<el-tooltip content="指标说明" placement="top">
<i
class="el-icon-_question ele-text-placeholder monitor-count-card-tips"
>
</i>
</el-tooltip>
</el-card>
</el-col>
<el-col v-bind="styleResponsive ? { md: 6, sm: 12 } : { span: 6 }">
<el-card shadow="never" class="monitor-count-card">
<el-tag size="large" type="danger" class="ele-tag-round">
<i class="el-icon-s-flag"></i>
</el-tag>
<div class="monitor-count-card-num ele-text-heading">826.0</div>
<div class="monitor-count-card-text ele-text-secondary">
到达量 (近30天)
</div>
<div class="monitor-count-card-trend ele-text-danger">
<i class="el-icon-arrow-down"></i>
<span>15.5%</span>
</div>
</el-card>
</el-col>
<el-col v-bind="styleResponsive ? { md: 6, sm: 12 } : { span: 6 }">
<el-card shadow="never" class="monitor-count-card">
<el-tag size="large" type="success" class="ele-tag-round">
<i class="el-icon-_flash-solid"></i>
</el-tag>
<div class="monitor-count-card-num ele-text-heading">28.8 %</div>
<div class="monitor-count-card-text">转化率 (近30天)</div>
<div class="monitor-count-card-trend ele-text-success">
<i class="el-icon-arrow-up"></i>
<span>65.8%</span>
</div>
<el-tooltip content="指标说明" placement="top">
<i
class="el-icon-_question ele-text-placeholder monitor-count-card-tips"
>
</i>
</el-tooltip>
</el-card>
</el-col>
</el-row>
</template>
<script>
export default {
data() {
return {
// 访问人数
visitUsers: [
{
name: 'SunSmile',
avatar:
'https://cdn.eleadmin.com/20200609/c184eef391ae48dba87e3057e70238fb.jpg'
},
{
name: '你的名字很好听',
avatar:
'https://cdn.eleadmin.com/20200609/b6a811873e704db49db994053a5019b2.jpg'
},
{
name: '全村人的希望',
avatar:
'https://cdn.eleadmin.com/20200609/948344a2a77c47a7a7b332fe12ff749a.jpg'
},
{
name: 'Jasmine',
avatar:
'https://cdn.eleadmin.com/20200609/f6bc05af944a4f738b54128717952107.jpg'
},
{
name: '酷酷的大叔',
avatar:
'https://cdn.eleadmin.com/20200609/2d98970a51b34b6b859339c96b240dcd.jpg'
},
{
name: '管理员',
avatar: 'https://cdn.eleadmin.com/20200610/avatar.jpg'
}
]
};
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
}
};
</script>
<style lang="scss" scoped>
.monitor-count-card {
:deep(.el-card__body) {
padding-top: 18px;
text-align: center;
position: relative;
}
:deep(.el-tag) {
border-color: transparent;
font-size: 15px;
}
.monitor-count-card-num {
font-weight: 500;
font-size: 32px;
margin-top: 12px;
}
.monitor-count-card-text {
font-size: 12px;
margin: 10px 0;
}
.monitor-count-card-trend {
font-weight: 600;
padding: 6px 0;
& > i {
font-size: 12px;
font-weight: 600;
margin-right: 5px;
}
}
.monitor-count-card-tips {
position: absolute;
top: 15px;
right: 15px;
cursor: pointer;
}
}
</style>
@@ -1,266 +0,0 @@
<template>
<el-row :gutter="15">
<el-col v-bind="styleResponsive ? { lg: 8 } : { span: 8 }">
<el-card shadow="never" header="用户评价">
<div class="ele-cell ele-cell-align-bottom">
<div class="ele-text-heading" style="font-size: 48px">4.5</div>
<div class="ele-cell-content" style="padding-bottom: 8px">
<el-rate
v-model="userRate"
disabled
show-score
text-color="#F7BA2A"
score-template="很棒"
/>
</div>
</div>
<div class="ele-cell" style="margin: 15px 0">
<div style="font-size: 29px" class="ele-text-placeholder">-0%</div>
<div class="ele-cell-content ele-text-small ele-text-secondary">
当前没有评价波动
</div>
</div>
<div class="ele-cell">
<div class="ele-cell-content">
<el-progress :percentage="60" :show-text="false" status="success" />
</div>
<div
style="width: 80px; white-space: nowrap"
class="ele-text-secondary"
>
<span><s></s><i class="el-icon-star-on"></i></span>
<span> 5 : 368</span>
</div>
</div>
<div class="ele-cell">
<div class="ele-cell-content">
<el-progress :percentage="40" :show-text="false" />
</div>
<div
style="width: 80px; white-space: nowrap"
class="ele-text-secondary"
>
<span><s></s><i class="el-icon-star-on"></i></span>
<span> 4 : 256</span>
</div>
</div>
<div class="ele-cell">
<div class="ele-cell-content">
<el-progress :percentage="20" :show-text="false" status="warning" />
</div>
<div
style="width: 80px; white-space: nowrap"
class="ele-text-secondary"
>
<span><s></s><i class="el-icon-star-on"></i></span>
<span> 3 : 49</span>
</div>
</div>
<div class="ele-cell">
<div class="ele-cell-content">
<el-progress
:percentage="10"
:show-text="false"
status="exception"
/>
</div>
<div
style="width: 80px; white-space: nowrap"
class="ele-text-secondary"
>
<span><s></s><i class="el-icon-star-on"></i></span>
<span> 2 : 14</span>
</div>
</div>
<div class="ele-cell">
<div class="ele-cell-content">
<el-progress :percentage="0" :show-text="false" />
</div>
<div
style="width: 80px; white-space: nowrap"
class="ele-text-secondary"
>
<span><s></s><i class="el-icon-star-on"></i></span>
<span> 1 : 0</span>
</div>
</div>
</el-card>
</el-col>
<el-col v-bind="styleResponsive ? { lg: 8, md: 12 } : { span: 8 }">
<el-card shadow="never" header="用户满意度">
<div class="ele-cell" style="margin: 15px 0">
<div
class="ele-cell-content ele-text-center ele-text-heading"
style="font-size: 24px"
>
856
</div>
<div class="ele-cell-content ele-text-center">
<div class="monitor-face-smile">
<span></span>
</div>
<div class="ele-text-secondary" style="margin-top: 5px">
正面评论
</div>
</div>
<h2 class="ele-cell-content ele-text-success ele-text-center">
82%
</h2>
</div>
<el-divider />
<div class="ele-cell" style="margin: 15px 0 12px 0">
<div
class="ele-cell-content ele-text-center ele-text-heading"
style="font-size: 24px"
>
60
</div>
<div class="ele-cell-content ele-text-center">
<div class="monitor-face-cry">
<span></span>
</div>
<div class="ele-text-secondary" style="margin-top: 5px">
负面评论
</div>
</div>
<h2 class="ele-cell-content ele-text-danger ele-text-center">9%</h2>
</div>
</el-card>
</el-col>
<el-col v-bind="styleResponsive ? { lg: 8, md: 12 } : { span: 8 }">
<el-card shadow="never" header="用户活跃度">
<div class="ele-cell" style="padding: 35px 0; justify-content: center">
<div class="monitor-progress-group">
<el-progress
type="circle"
:percentage="70"
status="success"
:show-text="false"
:width="140"
/>
<el-progress
type="circle"
:percentage="60"
:show-text="false"
:width="115"
:stroke-width="5"
/>
<el-progress
type="circle"
:percentage="35"
status="exception"
:show-text="false"
:width="90"
:stroke-width="4"
/>
</div>
<div class="monitor-progress-legends" style="padding-left: 12px">
<div class="ele-text-small">
<ele-dot :ripple="false" text="活跃率: 70%" />
</div>
<div class="ele-text-small">
<ele-dot type="success" :ripple="false" text="留存率: 60%" />
</div>
<div class="ele-text-small">
<ele-dot type="danger" :ripple="false" text="跳出率: 35%" />
</div>
</div>
</div>
</el-card>
</el-col>
</el-row>
</template>
<script>
export default {
data() {
return {
// 用户评分
userRate: 4.5
};
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
}
};
</script>
<style lang="scss" scoped>
/* 笑脸、哭脸 */
.monitor-face-smile,
.monitor-face-cry {
width: 50px;
height: 50px;
display: inline-block;
background-color: #fbd971;
border-radius: 50%;
position: relative;
}
.monitor-face-smile > span,
.monitor-face-smile:before,
.monitor-face-smile:after,
.monitor-face-cry > span,
.monitor-face-cry:before,
.monitor-face-cry:after {
width: 22px;
height: 22px;
border-radius: 50%;
transform: rotate(225deg);
border: 3px solid #f0c419;
border-right-color: transparent !important;
border-bottom-color: transparent !important;
position: absolute;
bottom: 8px;
left: 11px;
}
.monitor-face-smile:before,
.monitor-face-smile:after,
.monitor-face-cry:before,
.monitor-face-cry:after {
content: '';
width: 6px;
height: 6px;
left: 8px;
top: 14px;
border-color: #f29c1f;
transform: rotate(45deg);
}
.monitor-face-smile:after,
.monitor-face-cry:after {
left: auto;
right: 8px;
}
.monitor-face-cry > span {
transform: rotate(45deg);
bottom: -6px;
}
/* 圆形进度条组合 */
.monitor-progress-group {
position: relative;
display: inline-block;
.el-progress:not(:first-child) {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
margin-top: -1px;
}
:deep(.el-progress-circle__track) {
stroke: hsla(0deg, 0%, 60%, 0.15);
}
}
.monitor-progress-legends > div + div {
margin-top: 8px;
}
</style>
@@ -1,50 +0,0 @@
<template>
<div class="ele-body ele-body-card">
<statistics-card />
<el-row :gutter="15">
<el-col v-bind="styleResponsive ? { lg: 18 } : { span: 18 }">
<map-card />
</el-col>
<el-col v-bind="styleResponsive ? { lg: 6 } : { span: 6 }">
<el-row :gutter="15">
<el-col
v-bind="styleResponsive ? { lg: 24, md: 12, sm: 24 } : { span: 24 }"
>
<online-num />
</el-col>
<el-col
v-bind="styleResponsive ? { lg: 24, md: 12, sm: 24 } : { span: 24 }"
>
<browser-card />
</el-col>
</el-row>
</el-col>
</el-row>
<user-rate />
</div>
</template>
<script>
import StatisticsCard from './components/statistics-card.vue';
import MapCard from './components/map-card.vue';
import OnlineNum from './components/online-num.vue';
import BrowserCard from './components/browser-card.vue';
import UserRate from './components/user-rate.vue';
export default {
name: 'DashboardMonitor',
components: {
StatisticsCard,
MapCard,
OnlineNum,
BrowserCard,
UserRate
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
}
};
</script>
@@ -1,128 +0,0 @@
<template>
<el-card shadow="never" body-style="padding: 6px 0;">
<template v-slot:header>
<span>{{ title }}</span>
<more-icon @remove="onRemove" @edit="onEdit" />
</template>
<el-scrollbar
style="height: 326px"
wrapStyle="overflow-x: hidden;"
viewStyle="padding: 14px 10px;"
>
<el-timeline :reverse="false" class="ele-timeline ele-timeline-act">
<el-timeline-item
v-for="(item, index) in activities"
:key="index"
:timestamp="item.timestamp"
:type="item.type"
>
{{ item.title }}
</el-timeline-item>
</el-timeline>
</el-scrollbar>
</el-card>
</template>
<script>
import MoreIcon from './more-icon.vue';
export default {
components: { MoreIcon },
props: {
title: String
},
data() {
return {
activities: []
};
},
created() {
this.queryActivities();
},
methods: {
queryActivities() {
this.activities = [
{
title: 'SunSmile 解决了bug 登录提示操作失败',
timestamp: '20:30'
},
{
title: 'Jasmine 解决了bug 按钮颜色与设计不符',
timestamp: '19:30'
},
{
title: '项目经理 指派了任务 解决项目一的bug',
timestamp: '18:30',
type: 'primary'
},
{
title: '项目经理 指派了任务 解决项目二的bug',
timestamp: '17:30',
type: 'primary'
},
{
title: '项目经理 指派了任务 解决项目三的bug',
timestamp: '16:30',
type: 'primary'
},
{
title: '项目经理 指派了任务 解决项目四的bug',
timestamp: '15:30'
},
{
title: '项目经理 指派了任务 解决项目五的bug',
timestamp: '14:30'
},
{
title: '项目经理 指派了任务 解决项目六的bug',
timestamp: '12:30'
},
{
title: '项目经理 指派了任务 解决项目七的bug',
timestamp: '11:30',
type: 'primary'
},
{
title: '项目经理 指派了任务 解决项目八的bug',
timestamp: '10:30'
},
{
title: '项目经理 指派了任务 解决项目九的bug',
timestamp: '09:30'
},
{
title: '项目经理 指派了任务 解决项目十的bug',
timestamp: '08:30'
}
];
},
onRemove() {
this.$emit('remove');
},
onEdit() {
this.$emit('edit');
}
}
};
</script>
<style lang="scss" scoped>
.ele-timeline-act {
padding-left: 50px;
:deep(.el-timeline-item__timestamp) {
margin: 0;
position: absolute;
top: 3px;
left: -45px;
}
:deep(.el-timeline-item) {
padding-bottom: 19px;
&:last-child {
padding-bottom: 0;
}
}
}
</style>
@@ -1,70 +0,0 @@
<template>
<el-card shadow="never">
<template v-slot:header>
<span>{{ title }}</span>
<more-icon @remove="onRemove" @edit="onEdit" />
</template>
<div class="workplace-goal-wrap">
<div class="workplace-goal-group">
<el-progress
:width="170"
:percentage="80"
type="dashboard"
:format="() => ''"
/>
<div class="workplace-goal-content">
<el-tag size="large" class="ele-tag-round">
<i class="el-icon-s-data"></i>
</el-tag>
<div class="workplace-goal-num ele-text-heading">285</div>
</div>
<div class="workplace-goal-text">恭喜, 本月目标已达标!</div>
</div>
</div>
</el-card>
</template>
<script>
import MoreIcon from './more-icon.vue';
export default {
components: { MoreIcon },
props: {
title: String
},
methods: {
onRemove() {
this.$emit('remove');
},
onEdit() {
this.$emit('edit');
}
}
};
</script>
<style lang="scss" scoped>
.workplace-goal-wrap {
height: 304px;
display: flex;
flex-direction: column;
justify-content: center;
}
.workplace-goal-group {
text-align: center;
position: relative;
.workplace-goal-content {
position: absolute;
top: 48px;
left: 0;
width: 100%;
}
.workplace-goal-num {
font-size: 40px;
margin-top: 15px;
}
}
</style>
@@ -1,143 +0,0 @@
<!-- 快捷方式 -->
<template>
<vue-draggable
tag="el-row"
v-model="data"
:component-data="{ props: { gutter: 15 } }"
:animation="300"
:set-data="() => void 0"
@end="onEnd"
>
<el-col
v-for="item in data"
:key="item.url"
v-bind="styleResponsive ? { lg: 3, md: 6, sm: 6, xs: 12 } : { span: 3 }"
>
<el-card shadow="hover" body-style="padding: 0;">
<router-link :to="item.url" class="app-link-block">
<i
:class="['app-link-icon', item.icon]"
:style="{ color: item.color }"
>
</i>
<div class="app-link-title">{{ item.title }}</div>
</router-link>
</el-card>
</el-col>
</vue-draggable>
</template>
<script>
import VueDraggable from 'vuedraggable';
export default {
components: { VueDraggable },
data() {
// 默认布局
const defaultData = [
{
icon: 'el-icon-user',
title: '用户',
url: '/system/user'
},
{
icon: 'el-icon-data-line',
title: '分析',
url: '/dashboard/analysis',
color: '#95de64'
},
{
icon: 'el-icon-shopping-cart-2',
title: '商品',
url: '/list/card/project',
color: '#ff9c6e'
},
{
icon: 'el-icon-tickets',
title: '订单',
url: '/list/basic',
color: '#b37feb'
},
{
icon: 'el-icon-bank-card',
title: '票据',
url: '/list/advanced',
color: '#ffd666'
},
{
icon: 'el-icon-message',
title: '消息',
url: '/user/message',
color: '#5cdbd3'
},
{
icon: 'el-icon-discount',
title: '标签',
url: '/extension/tag',
color: '#ff85c0'
},
{
icon: 'el-icon-s-operation',
title: '配置',
url: '/user/profile',
color: '#ffc069'
}
];
// 获取缓存顺序
const cache = (() => {
const str = localStorage.getItem('workplace-links');
try {
return str ? JSON.parse(str) : null;
} catch (e) {
return null;
}
})();
return {
defaultData,
data: [...(cache ?? defaultData)]
};
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
},
methods: {
/* 排序改变 */
onEnd() {
this.cacheData();
},
/* 重置布局 */
reset() {
this.data = [...this.defaultData];
this.cacheData();
},
/* 缓存布局 */
cacheData() {
localStorage.setItem('workplace-links', JSON.stringify(this.data));
}
}
};
</script>
<style lang="scss" scoped>
.app-link-block {
display: block;
color: inherit;
padding: 15px 0;
text-align: center;
text-decoration: none;
cursor: pointer;
.app-link-icon {
color: #69c0ff;
font-size: 30px;
margin-top: 5px;
}
.app-link-title {
margin-top: 8px;
}
}
</style>
@@ -1,41 +0,0 @@
<template>
<el-dropdown class="card-more-icon" @command="onCommand">
<i class="el-icon-more ele-text-secondary"></i>
<template v-slot:dropdown>
<el-dropdown-menu>
<el-dropdown-item icon="el-icon-edit" command="edit">
编辑
</el-dropdown-item>
<el-dropdown-item icon="el-icon-circle-close" command="remove">
删除
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
<script>
export default {
methods: {
onCommand(command) {
this.$emit(command);
}
}
};
</script>
<style lang="scss" scoped>
.card-more-icon {
padding: 0 8px 0 0;
position: absolute;
right: 8px;
top: 50%;
margin-top: -8px;
cursor: pointer;
.el-icon-more {
transform: rotate(90deg);
display: block;
}
}
</style>
@@ -1,115 +0,0 @@
<!-- 用户信息 -->
<template>
<el-card shadow="never" body-style="padding: 20px;">
<div
:class="[
'ele-cell',
'workplace-user-card',
{ 'workplace-user-responsive': styleResponsive }
]"
>
<div class="ele-cell-content ele-cell">
<el-avatar :size="68" :src="loginUser.avatar" />
<div class="ele-cell-content">
<h4 class="ele-elip">
早安, {{ loginUser.nickname }} , 开始您一天的工作吧!
</h4>
<div class="ele-text-secondary ele-elip" style="margin-top: 8px">
<i class="el-icon-heavy-rain"></i>
<em>今日阴转小雨, 22 - 32 , 出门记得带伞哦</em>
</div>
</div>
</div>
<div class="workplace-count-group">
<div class="workplace-count-item">
<div class="workplace-count-header">
<el-tag size="small" class="ele-tag-round">
<i class="el-icon-menu"></i>
</el-tag>
<span class="workplace-count-name">项目数</span>
</div>
<div class="workplace-count-num ele-text-heading">3</div>
</div>
<div class="workplace-count-item">
<div class="workplace-count-header">
<el-tag type="warning" size="small" class="ele-tag-round">
<i class="el-icon-finished"></i>
</el-tag>
<span class="workplace-count-name">待办项</span>
</div>
<div class="workplace-count-num ele-text-heading">6 / 24</div>
</div>
<div class="workplace-count-item">
<div class="workplace-count-header">
<el-tag type="success" size="small" class="ele-tag-round">
<i class="el-icon-bell"></i>
</el-tag>
<span class="workplace-count-name">消息</span>
</div>
<div class="workplace-count-num ele-text-heading">1,689</div>
</div>
</div>
</div>
</el-card>
</template>
<script>
export default {
computed: {
// 当前登录用户信息
loginUser() {
return this.$store.state.user.info;
},
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
}
};
</script>
<style lang="scss" scoped>
.workplace-user-card {
.ele-cell-content {
overflow: hidden;
}
.workplace-count-group {
white-space: nowrap;
}
.workplace-count-item {
padding: 0 5px 0 25px;
box-sizing: border-box;
display: inline-block;
text-align: right;
}
.workplace-count-name {
padding-left: 8px;
}
.workplace-count-num {
font-size: 24px;
margin-top: 6px;
}
}
@media screen and (max-width: 992px) {
.workplace-user-responsive .workplace-count-item {
padding: 0 5px 0 10px;
}
}
@media screen and (max-width: 768px) {
.workplace-user-responsive.workplace-user-card {
display: block;
.workplace-count-group {
display: block;
margin-top: 15px;
text-align: right;
}
}
}
</style>
@@ -1,156 +0,0 @@
<template>
<el-card
shadow="never"
body-style="padding: 11px;"
class="workplace-table-card"
>
<template v-slot:header>
<span>{{ title }}</span>
<more-icon @remove="onRemove" @edit="onEdit" />
</template>
<el-table :data="projectList" :height="316">
<el-table-column type="index" width="35" min-width="35" align="right" />
<el-table-column label="项目名称" min-width="110" show-overflow-tooltip>
<template v-slot="{ row }">
<el-link type="primary" :underline="false">
{{ row.projectName }}
</el-link>
</template>
</el-table-column>
<el-table-column
label="开始时间"
prop="startDate"
width="95"
min-width="80"
align="center"
show-overflow-tooltip
/>
<el-table-column
prop="endDate"
label="结束时间"
width="95"
min-width="80"
align="center"
show-overflow-tooltip
/>
<el-table-column
label="状态"
width="70"
min-width="60"
align="center"
show-overflow-tooltip
>
<template v-slot="{ row }">
<span
:class="
[
'ele-text-success',
'ele-text-danger',
'ele-text-warning',
'ele-text-info ele-text-delete'
][row.status]
"
>
{{ ['进行中', '已延期', '未开始', '已结束'][row.status] }}
</span>
</template>
</el-table-column>
<el-table-column label="进度" width="160" min-width="100" align="center">
<template v-slot="{ row }">
<el-progress :percentage="row.progress" class="ele-text-small" />
</template>
</el-table-column>
</el-table>
</el-card>
</template>
<script>
import MoreIcon from './more-icon.vue';
export default {
components: { MoreIcon },
props: {
title: String
},
data() {
return {
projectList: []
};
},
created() {
this.queryProjectList();
},
methods: {
queryProjectList() {
this.projectList = [
{
id: 1,
projectName: '项目0000001',
status: 0,
startDate: '2020-03-01',
endDate: '2020-06-01',
progress: 30
},
{
id: 2,
projectName: '项目0000002',
status: 0,
startDate: '2020-03-01',
endDate: '2020-08-01',
progress: 10
},
{
id: 3,
projectName: '项目0000003',
status: 1,
startDate: '2020-01-01',
endDate: '2020-05-01',
progress: 60
},
{
id: 4,
projectName: '项目0000004',
status: 1,
startDate: '2020-06-01',
endDate: '2020-10-01',
progress: 0
},
{
id: 5,
projectName: '项目0000005',
status: 2,
startDate: '2020-01-01',
endDate: '2020-03-01',
progress: 100
},
{
id: 6,
projectName: '项目0000006',
status: 3,
startDate: '2020-01-01',
endDate: '2020-03-01',
progress: 100
}
];
},
onRemove() {
this.$emit('remove');
},
onEdit() {
this.$emit('edit');
}
}
};
</script>
<style lang="scss" scoped>
.workplace-table-card {
:deep(.el-table tbody > .el-table__row:last-child td) {
border-bottom: none;
}
:deep(.el-table:before) {
display: none;
}
}
</style>
@@ -1,156 +0,0 @@
<template>
<el-card
shadow="never"
body-style="padding: 0;height: 338px;overflow: hidden;"
class="workplace-table-card"
>
<template v-slot:header>
<span>{{ title }}</span>
<more-icon @remove="onRemove" @edit="onEdit" />
</template>
<table class="ele-table" style="table-layout: fixed">
<colgroup>
<col width="38" />
<col width="65" />
<col />
<col width="70" />
</colgroup>
<thead>
<tr style="background: none">
<th></th>
<th>优先级</th>
<th class="ele-elip">任务名称</th>
<th style="text-align: center">状态</th>
</tr>
</thead>
<vue-draggable
tag="tbody"
:animation="300"
v-model="taskList"
handle=".sort-handle"
:set-data="() => void 0"
>
<tr v-for="d in taskList" :key="d.id">
<td style="text-align: center">
<i class="sort-handle el-icon-_nav ele-text-placeholder"></i>
</td>
<td>
<el-tag
size="mini"
class="ele-tag-round"
:type="['danger', 'warning', 'primary'][d.priority - 1]"
>
{{ d.priority }}
</el-tag>
</td>
<td class="ele-elip">
<el-link type="primary" :underline="false" class="ele-inline">
{{ d.taskName }}
</el-link>
</td>
<td style="text-align: center">
<span
:class="
['ele-text-warning', 'ele-text-success', 'ele-text-info'][
d.status
]
"
>
{{ ['未开始', '进行中', '已完成'][d.status] }}
</span>
</td>
</tr>
</vue-draggable>
</table>
</el-card>
</template>
<script>
import VueDraggable from 'vuedraggable';
import MoreIcon from './more-icon.vue';
export default {
components: { VueDraggable, MoreIcon },
props: {
title: String
},
data() {
return {
taskList: []
};
},
created() {
this.queryTaskList();
},
methods: {
queryTaskList() {
this.taskList = [
{
id: 1,
priority: 1,
taskName: '解决项目一的bug',
status: 0
},
{
id: 2,
priority: 2,
taskName: '解决项目二的bug',
status: 0
},
{
id: 3,
priority: 2,
taskName: '解决项目三的bug',
status: 1
},
{
id: 4,
priority: 3,
taskName: '解决项目四的bug',
status: 1
},
{
id: 5,
priority: 3,
taskName: '解决项目五的bug',
status: 2
},
{
id: 6,
priority: 3,
taskName: '解决项目六的bug',
status: 2
}
];
},
onRemove() {
this.$emit('remove');
},
onEdit() {
this.$emit('edit');
}
}
};
</script>
<style lang="scss" scoped>
.ele-table tbody > tr:last-child td {
border-bottom: none;
}
.ele-table {
td {
padding-top: 11px;
padding-bottom: 11px;
}
tr.sortable-chosen {
background: hsla(0, 0%, 60%, 0.1);
}
}
.workplace-table-card .sort-handle {
cursor: move;
font-size: 18px;
}
</style>
@@ -1,102 +0,0 @@
<template>
<el-card shadow="never" body-style="padding: 2px 0;">
<template v-slot:header>
<span>{{ title }}</span>
<more-icon @remove="onRemove" @edit="onEdit" />
</template>
<div
v-for="(item, index) in userList"
:key="index"
class="ele-cell user-list-item"
>
<el-avatar :size="40" :src="item.avatar" />
<div class="ele-cell-content" style="overflow: hidden">
<div class="ele-cell-title ele-elip">{{ item.name }}</div>
<div class="ele-cell-desc ele-elip">{{ item.introduction }}</div>
</div>
<el-tag size="mini" :type="['success', 'danger'][item.status]">
{{ ['在线', '离线'][item.status] }}
</el-tag>
</div>
</el-card>
</template>
<script>
import MoreIcon from './more-icon.vue';
export default {
components: { MoreIcon },
props: {
title: String
},
data() {
return {
userList: []
};
},
created() {
this.queryUserList();
},
methods: {
queryUserList() {
this.userList = [
{
name: 'SunSmile',
introduction: 'UI设计师、交互专家',
status: 0,
avatar:
'https://cdn.eleadmin.com/20200609/c184eef391ae48dba87e3057e70238fb.jpg'
},
{
name: '你的名字很好听',
introduction: '前端工程师',
status: 0,
avatar:
'https://cdn.eleadmin.com/20200609/b6a811873e704db49db994053a5019b2.jpg'
},
{
name: '全村人的希望',
introduction: '前端工程师',
status: 0,
avatar:
'https://cdn.eleadmin.com/20200609/948344a2a77c47a7a7b332fe12ff749a.jpg'
},
{
name: 'Jasmine',
introduction: '产品经理、项目经理',
status: 1,
avatar:
'https://cdn.eleadmin.com/20200609/f6bc05af944a4f738b54128717952107.jpg'
},
{
name: '酷酷的大叔',
introduction: '组长、后端工程师',
status: 1,
avatar:
'https://cdn.eleadmin.com/20200609/2d98970a51b34b6b859339c96b240dcd.jpg'
}
];
},
onRemove() {
this.$emit('remove');
},
onEdit() {
this.$emit('edit');
}
}
};
</script>
<style lang="scss" scoped>
.user-list-item {
padding: 13px 18px;
& + .user-list-item {
border-top: 1px solid hsla(0, 0%, 60%, 0.15);
}
.ele-cell-desc {
margin-top: 2px;
}
}
</style>
@@ -1,237 +0,0 @@
<template>
<div class="ele-body ele-body-card">
<profile-card />
<link-card ref="linkCard" />
<vue-draggable
tag="el-row"
v-model="data"
handle=".el-card__header"
:component-data="{ props: { gutter: 15 } }"
:animation="300"
:set-data="() => void 0"
@end="onEnd"
>
<el-col
v-for="(d, i) in data"
:key="d.name"
v-bind="styleResponsive ? { md: d.md, sm: d.sm } : { span: d.md }"
>
<component
:is="d.name"
:title="d.title"
@remove="onRemove(i)"
@edit="onEdit(i)"
/>
</el-col>
</vue-draggable>
<el-card shadow="never" body-style="padding: 0;">
<div class="ele-cell" style="line-height: 42px">
<div
class="ele-cell-content ele-text-primary workplace-bottom-btn"
@click="add"
>
<i class="el-icon-circle-plus-outline"></i> 添加视图
</div>
<el-divider direction="vertical" />
<div
class="ele-cell-content ele-text-primary workplace-bottom-btn"
@click="reset"
>
<i class="el-icon-refresh-left"></i> 重置布局
</div>
</div>
</el-card>
<!-- 编辑弹窗 -->
<ele-modal width="680px" :visible.sync="visible" title="未添加的视图">
<el-row :gutter="15" style="margin-bottom: -15px">
<el-col v-for="item in notAddedData" :key="item.name" :md="8" :sm="24">
<div
class="workplace-card-item ele-border-lighter"
@click="addView(item)"
>
<div class="workplace-card-header ele-border-lighter">
{{ item.title }}
</div>
<div class="workplace-card-body ele-text-placeholder">
<i class="el-icon-plus"></i>
</div>
</div>
</el-col>
</el-row>
<ele-empty v-if="!notAddedData.length" text="已添加所有视图" />
</ele-modal>
</div>
</template>
<script>
import VueDraggable from 'vuedraggable';
import ProfileCard from './components/profile-card.vue';
import LinkCard from './components/link-card.vue';
import ActivitiesCard from './components/activities-card.vue';
import TaskCard from './components/task-card.vue';
import GoalCard from './components/goal-card.vue';
import ProjectCard from './components/project-card.vue';
import UserList from './components/user-list.vue';
export default {
name: 'DashboardWorkplace',
components: {
VueDraggable,
ProfileCard,
LinkCard,
ActivitiesCard,
TaskCard,
GoalCard,
ProjectCard,
UserList
},
data() {
// 默认布局
const defaultData = [
{
name: 'activities-card',
title: '最新动态',
md: 8,
sm: 24
},
{
name: 'task-card',
title: '我的任务',
md: 8,
sm: 24
},
{
name: 'goal-card',
title: '本月目标',
md: 8,
sm: 24
},
{
name: 'project-card',
title: '项目进度',
md: 16,
sm: 24
},
{
name: 'user-list',
title: '小组成员',
md: 8,
sm: 24
}
];
// 获取缓存布局
const cache = (() => {
const str = localStorage.getItem('workplace-layout');
try {
return str ? JSON.parse(str) : null;
} catch (e) {
return null;
}
})();
return {
defaultData,
data: [...(cache ?? defaultData)],
visible: false
};
},
computed: {
// 未添加的数据
notAddedData() {
return this.defaultData.filter(
(d) => !this.data.some((t) => t.name === d.name)
);
},
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
},
methods: {
/* 添加 */
add() {
this.visible = true;
},
/* 重置布局 */
reset() {
this.data = [...this.defaultData];
this.cacheData();
this.$refs.linkCard.reset();
this.$message.success('已重置');
},
/* 缓存布局 */
cacheData() {
localStorage.setItem('workplace-layout', JSON.stringify(this.data));
},
/* 删除视图 */
onRemove(index) {
this.data = this.data.filter((_d, i) => i !== index);
this.cacheData();
},
/* 编辑视图 */
onEdit(index) {
console.log('index:', index);
this.$message.info('点击了编辑');
},
/* 添加视图 */
addView(item) {
this.data.push(item);
this.cacheData();
this.$message.success('已添加');
},
/* 排序改变 */
onEnd() {
this.cacheData();
}
}
};
</script>
<style lang="scss" scoped>
.ele-body {
:deep(.el-card__header) {
cursor: move;
position: relative;
}
:deep(.el-row > .el-col.sortable-chosen > .el-card) {
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.2);
}
}
.workplace-bottom-btn {
text-align: center;
cursor: pointer;
transition: background-color 0.2s;
&:hover {
background: hsla(0, 0%, 60%, 0.05);
}
}
/* 添加弹窗 */
.workplace-card-item {
margin-bottom: 15px;
border-width: 1px;
border-style: solid;
border-radius: 4px;
position: relative;
cursor: pointer;
transition: box-shadow 0.3s;
&:hover {
box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.15);
}
.workplace-card-header {
border-bottom-width: 1px;
border-bottom-style: solid;
padding: 8px;
}
}
.workplace-card-body {
font-size: 24px;
padding: 40px 10px;
text-align: center;
}
</style>
-150
View File
@@ -1,150 +0,0 @@
<template>
<div class="ele-body" style="padding-bottom: 71px">
<el-card shadow="never">
<el-row :gutter="15">
<el-col v-bind="styleResponsive ? { md: 12 } : { span: 12 }">
<!-- 未选择的班级数据表格 -->
<ele-pro-table
:datasource="unChooseClass"
:columns="columns"
sub-title="未选班级:"
height="535px"
emptyText="已全部选择"
:toolkit="[]"
layout="total, prev, pager, next, jumper"
>
<template v-slot:toolkit>
<el-button size="mini" class="ele-btn-icon" @click="addAll">
全部添加
</el-button>
</template>
<template v-slot:action="{ row }">
<el-button size="mini" @click="add(row)">添加</el-button>
</template>
</ele-pro-table>
</el-col>
<el-col v-bind="styleResponsive ? { md: 12 } : { span: 12 }">
<!-- 已选择的班级数据表格 -->
<ele-pro-table
:datasource="chooseClasses"
:columns="columns"
sub-title="已选班级:"
height="535px"
emptyText="未选择班级"
:toolkit="[]"
layout="total, prev, pager, next, jumper"
>
<template v-slot:toolkit>
<el-button
size="mini"
type="danger"
plain
class="ele-btn-icon"
@click="removeAll"
>
全部移除
</el-button>
</template>
<template v-slot:action="{ row }">
<el-button type="danger" plain size="mini" @click="remove(row)">
移除
</el-button>
</template>
</ele-pro-table>
</el-col>
</el-row>
</el-card>
</div>
</template>
<script>
import { getAllClasses } from '@/api/example/choose';
export default {
name: 'ExampleChoose',
data() {
return {
// 加载状态
loading: false,
// 全部实训班级
classes: [],
// 已选择的班级数据
chooseClasses: [],
// 表格列配置
columns: [
{
columnKey: 'action',
label: '操作',
width: 100,
align: 'center',
slot: 'action'
},
{
prop: 'classesName',
label: '班级名称',
showOverflowTooltip: true,
minWidth: 110,
sortable: 'custom'
},
{
prop: 'major',
label: '专业',
showOverflowTooltip: true,
minWidth: 110,
sortable: 'custom'
},
{
prop: 'college',
label: '学院',
showOverflowTooltip: true,
minWidth: 110,
sortable: 'custom'
}
]
};
},
computed: {
/* 未选择的班级数据 */
unChooseClass() {
return this.classes.filter((d) => this.chooseClasses.indexOf(d) === -1);
},
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
},
created() {
this.query();
},
methods: {
/* 获取全部实训班级 */
query() {
getAllClasses()
.then((data) => {
this.classes = data;
})
.catch((e) => {
this.$message.error(e.message);
});
},
/* 添加 */
add(row) {
this.chooseClasses.push(row);
},
/* 移除 */
remove(row) {
this.chooseClasses.splice(this.chooseClasses.indexOf(row), 1);
},
/* 添加全部 */
addAll() {
this.unChooseClass.forEach((d) => {
this.chooseClasses.push(d);
});
},
/* 移除所有 */
removeAll() {
this.chooseClasses.splice(0, this.chooseClasses.length);
}
}
};
</script>
@@ -1,341 +0,0 @@
<template>
<ele-modal
top="5vh"
width="1100px"
:visible="visible"
title="卷内文件调整"
custom-class="demo-file-sort-dialog"
@update:visible="updateVisible"
>
<el-row :gutter="15">
<el-col v-bind="styleResponsive ? { md: 8 } : { span: 8 }">
<ele-pro-table
ref="docTable"
sub-title="案卷列表"
:datasource="documents"
:columns="columns1"
highlight-current-row
height="400px"
:toolkit="[]"
:need-page="false"
:current.sync="current"
class="demo-file-sort-table"
:tool-style="{ lineHeight: '28px' }"
@done="onDocTbDone"
>
</ele-pro-table>
</el-col>
<el-col v-bind="styleResponsive ? { md: 8 } : { span: 8 }">
<ele-pro-table
ref="fileTable"
:loading="loading"
sub-title="卷内列表"
:datasource="data1"
:columns="columns2"
height="400px"
:selection.sync="selection1"
:need-page="false"
:toolkit="[]"
>
<template v-slot:toolkit>
<el-button
type="primary"
icon="el-icon-top"
class="ele-btn-icon"
size="mini"
@click="moveUp"
>
上移
</el-button>
<el-button
type="primary"
icon="el-icon-bottom"
class="ele-btn-icon"
size="mini"
@click="moveDown"
>
下移
</el-button>
<el-button
type="primary"
icon="el-icon-top-right"
class="ele-btn-icon"
size="mini"
@click="moveOut"
>
调出
</el-button>
</template>
</ele-pro-table>
</el-col>
<el-col v-bind="styleResponsive ? { md: 8 } : { span: 8 }">
<ele-pro-table
:loading="loading"
sub-title="未归档列表"
:datasource="data2"
:columns="columns2"
height="400px"
:selection.sync="selection2"
:need-page="false"
:toolkit="[]"
>
<template v-slot:toolkit>
<el-button
type="primary"
icon="el-icon-top-left"
class="ele-btn-icon"
size="mini"
@click="moveIn"
>
调入
</el-button>
</template>
</ele-pro-table>
</el-col>
</el-row>
<template v-slot:footer>
<div>
<el-button @click="close">取消</el-button>
<el-button type="primary" @click="save">保存</el-button>
</div>
</template>
</ele-modal>
</template>
<script>
import { getArchiveList } from '@/api/example/document';
export default {
props: {
// 弹窗是否打开
visible: Boolean,
// 案卷列表
documents: {
type: Array,
required: true
}
},
data() {
return {
// 加载loading
loading: true,
// 案卷表格列配置
columns1: [
{
prop: 'title',
label: '案卷题名',
width: 110,
showOverflowTooltip: true
},
{
prop: 'piece_no',
label: '案卷档号',
showOverflowTooltip: true
}
],
// 卷内表格列配置
columns2: [
{
columnKey: 'selection',
type: 'selection',
width: 45,
align: 'center'
},
{
prop: 'title',
label: '文件题名',
width: 110,
showOverflowTooltip: true
},
{
prop: 'archive_no',
label: '文件档号',
showOverflowTooltip: true
}
],
// 案卷下的全部文件列表
data: [],
// 选中案卷
current: null,
// 卷内列表选中数据
selection1: [],
// 未归档列表选中数据
selection2: []
};
},
computed: {
// 选中案卷的卷内文件
data1() {
if (!this.current) {
return [];
}
return this.data.filter((d) => d.piece_no === this.current.piece_no);
},
// 未归档的卷内文件
data2() {
return this.data.filter((d) => !d.piece_no);
},
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
},
methods: {
onDocTbDone() {
if (this.documents.length) {
this.$refs.docTable.setCurrentRow(this.documents[0]);
}
},
/* 查询所选案卷的卷内文件 */
query() {
this.loading = true;
getArchiveList({
pieceNoIn: this.documents.map((d) => d.piece_no)
})
.then((data) => {
this.loading = false;
this.data = data;
})
.catch((e) => {
this.loading = false;
this.$message.error(e.message);
});
},
/* 上移 */
moveUp() {
if (!this.selection1.length) {
this.$message.error('请选择一条数据');
return;
}
if (this.selection1.length > 1) {
this.$message.error('只能选择一条数据');
return;
}
if (this.data1.indexOf(this.selection1[0]) === 0) {
return;
}
const index = this.data.indexOf(this.selection1[0]);
const temp = this.data[index - 1];
this.$set(this.data, index - 1, this.selection1[0]);
this.$set(this.data, index, temp);
this.$nextTick(() => {
this.$refs.fileTable.toggleRowSelection(this.data[index - 1], true);
});
},
/* 下移 */
moveDown() {
if (!this.selection1.length) {
this.$message.error('请选择一条数据');
return;
}
if (this.selection1.length > 1) {
this.$message.error('只能选择一条数据');
return;
}
if (this.data1.indexOf(this.selection1[0]) === this.data1.length - 1) {
return;
}
const index = this.data.indexOf(this.selection1[0]);
const temp = this.data[index + 1];
this.$set(this.data, index + 1, this.selection1[0]);
this.$set(this.data, index, temp);
this.$nextTick(() => {
this.$refs.fileTable.toggleRowSelection(this.data[index + 1], true);
});
},
/* 调出 */
moveOut() {
if (!this.selection1.length) {
this.$message.error('请至少选择一条数据');
return;
}
this.selection1.forEach((d) => {
d.piece_no = '';
});
},
/* 调入 */
moveIn() {
if (!this.current) {
return;
}
if (!this.selection2.length) {
this.$message.error('请至少选择一条数据');
return;
}
this.selection2.forEach((d) => {
d.piece_no = this.current.piece_no;
});
},
/* 保存 */
save() {
const result = this.data.map((d) => {
return {
archive_no: d.archive_no,
piece_no: d.piece_no
};
});
console.log(result);
this.updateVisible(false);
},
/* 关闭弹窗 */
close() {
this.updateVisible(false);
},
/* 更新visible */
updateVisible(value) {
this.$emit('update:visible', value);
}
},
watch: {
visible(visible) {
if (visible) {
this.query();
} else {
this.data = [];
}
}
}
};
</script>
<style lang="scss" scoped>
:deep(.demo-file-sort-dialog) {
margin-bottom: 5vh;
.el-dialog__body {
padding-top: 15px;
padding-bottom: 0;
& > .el-row > .el-col {
margin-bottom: 15px;
}
}
}
.demo-file-sort-table {
:deep(.el-table__row) {
cursor: pointer;
}
:deep(.el-table__row > td:last-child) {
&:after {
content: '\e6e0';
font-family: element-icons !important;
font-style: normal;
font-variant: normal;
text-transform: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
line-height: 1;
position: absolute;
right: 10px;
top: 50%;
margin-top: -7px;
}
.cell {
padding-right: 20px;
}
}
}
</style>
-164
View File
@@ -1,164 +0,0 @@
<template>
<div class="ele-body">
<el-card shadow="never">
<ele-pro-table
ref="table"
:columns="columns"
:datasource="datasource"
:selection.sync="selection"
:show-summary="true"
:summary-method="getSummaries"
:height="fixedHeight ? 'calc(100vh - 344px)' : void 0"
>
<template v-slot:toolbar>
<el-button
size="small"
type="primary"
icon="el-icon-sort"
class="ele-btn-icon"
@click="openFileSortDialog"
>
卷内文件调整
</el-button>
<span>&emsp;固定高度&nbsp;</span>
<el-switch v-model="fixedHeight" @change="destroyTable" />
</template>
</ele-pro-table>
</el-card>
<!-- 卷内文件调整弹窗 -->
<file-sort :visible.sync="showFileSort" :documents="fileSortChoose" />
</div>
</template>
<script>
import FileSort from './components/file-sort.vue';
import { getPieceList } from '@/api/example/document';
export default {
name: 'ExampleDocument',
components: { FileSort },
data() {
return {
// 表格列配置
columns: [
{
columnKey: 'selection',
type: 'selection',
width: 45,
align: 'center',
fixed: 'left'
},
{
columnKey: 'index',
type: 'index',
width: 45,
align: 'center',
fixed: 'left'
},
{
prop: 'piece_no',
label: '案卷档号',
width: 215,
minWidth: 110,
showOverflowTooltip: true
},
{
prop: 'title',
label: '案卷题名',
minWidth: 110,
showOverflowTooltip: true
},
{
prop: 'year',
label: '年度',
minWidth: 110,
showOverflowTooltip: true
},
{
prop: 'retention',
label: '保管期限',
minWidth: 110,
showOverflowTooltip: true
},
{
prop: 'secret',
label: '密级',
minWidth: 110,
showOverflowTooltip: true
},
{
prop: 'type',
label: '档案类别',
minWidth: 110,
showOverflowTooltip: true
},
{
prop: 'carrier',
label: '载体规格',
minWidth: 110,
showOverflowTooltip: true
},
{
prop: 'amount',
label: '件数',
minWidth: 110,
showOverflowTooltip: true
}
],
// 是否显示卷内文件调整弹窗
showFileSort: false,
// 列表选中数据
selection: [],
// 选中的案卷
fileSortChoose: [],
// 表格固定高度
fixedHeight: false
};
},
methods: {
/* 列表数据源 */
datasource({ page, limit, where, order }) {
return getPieceList({ ...where, ...order, page, limit });
},
/* 打开卷内文件调整弹窗 */
openFileSortDialog() {
if (this.selection.length < 2) {
this.$message.error('请至少选择两条数据');
return;
}
// 实际项目用这一行
/*this.fileSortChoose = this.selection.map(d => {
return { ...d };
});*/
// 演示强制选前三个演示
this.fileSortChoose = this.$refs.table.tableData.slice(0, 3);
this.showFileSort = true;
},
/* 表格合计行 */
getSummaries({ columns, data }) {
const sums = [];
columns.forEach((column, index) => {
if (index === 2) {
sums[index] = '合计';
} else if (column.property === 'amount') {
sums[index] = data
.map((item) => Number(item[column.property]))
.reduce((prev, curr) => {
const value = Number(curr);
if (!isNaN(value)) {
return prev + curr;
} else {
return prev;
}
}, 0);
}
});
return sums;
},
/* 销毁表格 */
destroyTable() {
this.$refs.table.reRenderTable();
}
}
};
</script>
@@ -1,134 +0,0 @@
<template>
<div class="ele-body">
<el-card shadow="never" header="修改菜单徽章数据">
<el-form label-width="90px" style="max-width: 360px; padding-top: 20px">
<el-form-item label="菜单:">
<ele-tree-select
clearable
v-model="path"
:data="treeData"
default-expand-all
placeholder="请选择菜单"
/>
</el-form-item>
<el-form-item label="徽章值:">
<el-input
v-model="badge"
placeholder="请输入徽章值"
clearable
:maxlength="20"
/>
</el-form-item>
<el-form-item label="徽章颜色:">
<el-select
v-model="color"
placeholder="请选择徽章颜色"
clearable
class="ele-fluid"
>
<el-option label="primary" value="primary" />
<el-option label="success" value="success" />
<el-option label="warning" value="warning" />
<el-option label="danger" value="danger" />
<el-option label="info" value="info" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="setBadge">更新</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card shadow="never" header="分组菜单">
<div>
<el-button type="primary" @click="toMenuGroup1">
一级菜单变为分组形式
</el-button>
</div>
<div style="margin-top: 16px">
<el-button type="primary" @click="toMenuGroup2">
二级菜单变为分组形式
</el-button>
</div>
<div class="ele-text-secondary" style="margin-top: 6px">
二级菜单可查看列表页面/卡片列表的效果
</div>
</el-card>
</div>
</template>
<script>
import { formatTreeData } from 'ele-admin';
export default {
name: 'ExampleMenuBadge',
data() {
return {
path: '',
badge: '',
color: '',
orgMenus: JSON.parse(JSON.stringify(this.$store.state.user.menus))
};
},
computed: {
treeData() {
return formatTreeData(this.$store.state.user.menus, (m) => {
return {
...m,
value: m.path,
label: m.meta.title
};
});
}
},
methods: {
setBadge() {
if (!this.path) {
this.$message.error('请选择菜单');
return;
}
this.$store.dispatch('user/setMenuBadge', {
path: this.path,
value: this.badge,
color: this.color || undefined
});
},
/* 一级菜单变为分组形式 */
toMenuGroup1() {
this.$store.dispatch(
'user/setMenus',
this.orgMenus.map((m) => {
return {
...m,
meta: {
...m.meta,
group: true
}
};
})
);
},
/* 二级菜单变为分组形式 */
toMenuGroup2() {
this.$store.dispatch(
'user/setMenus',
this.orgMenus.map((m) => {
return {
...m,
children: m.children
? m.children.map((c) => {
return {
...c,
meta: {
...c.meta,
group: true
}
};
})
: void 0
};
})
);
}
}
};
</script>
@@ -1,93 +0,0 @@
<template>
<el-card shadow="never">
<!-- 数据表格 -->
<ele-pro-table
ref="table"
row-key="userId"
title="设置默认排序和筛选"
:columns="columns"
:datasource="datasource"
:default-sort="{ prop: 'username', order: 'ascending' }"
size="mini"
/>
</el-card>
</template>
<script>
import { pageUsers } from '@/api/system/user';
export default {
data() {
return {
// 表格列配置
columns: [
{
columnKey: 'index',
type: 'index',
width: 45,
align: 'center',
showOverflowTooltip: true,
fixed: 'left'
},
{
prop: 'username',
label: '用户账号',
sortable: 'custom',
showOverflowTooltip: true,
minWidth: 110
},
{
prop: 'nickname',
label: '用户名',
sortable: 'custom',
showOverflowTooltip: true,
minWidth: 110
},
{
columnKey: 'sexName',
prop: 'sexName',
label: '性别',
sortable: 'custom',
showOverflowTooltip: true,
minWidth: 80,
filterMultiple: false,
filters: [
{
text: '男',
value: '男'
},
{
text: '女',
value: '女'
}
],
filteredValue: ['男']
},
{
prop: 'phone',
label: '手机号',
sortable: 'custom',
showOverflowTooltip: true,
minWidth: 110
},
{
prop: 'createTime',
label: '创建时间',
sortable: 'custom',
showOverflowTooltip: true,
minWidth: 110,
formatter: (_row, _column, cellValue) => {
return this.$util.toDateString(cellValue);
}
}
]
};
},
methods: {
/* 表格数据源 */
datasource({ page, limit, order, filterValue }) {
return pageUsers({ ...order, ...filterValue, page, limit });
}
}
};
</script>
@@ -1,85 +0,0 @@
<template>
<el-card shadow="never">
<!-- 数据表格 -->
<ele-pro-table
ref="table"
row-key="menuId"
title="树形表格懒加载"
:columns="columns"
:datasource="datasource"
:need-page="false"
:lazy="true"
size="mini"
>
<!-- 标题列 -->
<template v-slot:title="{ row }">
<i :class="row.icon"></i> {{ row.title }}
</template>
</ele-pro-table>
</el-card>
</template>
<script>
import { listMenus } from '@/api/system/menu';
export default {
data() {
return {
// 表格列配置
columns: [
{
columnKey: 'index',
type: 'index',
width: 45,
align: 'center',
showOverflowTooltip: true
},
{
prop: 'title',
label: '菜单名称',
showOverflowTooltip: true,
minWidth: 110,
slot: 'title'
},
{
prop: 'path',
label: '路由地址',
showOverflowTooltip: true,
minWidth: 110
},
{
prop: 'component',
label: '组件路径',
showOverflowTooltip: true,
minWidth: 110
},
{
prop: 'sortNumber',
label: '排序',
align: 'center',
showOverflowTooltip: true,
width: 60
},
{
prop: 'createTime',
label: '创建时间',
showOverflowTooltip: true,
minWidth: 110,
formatter: (_row, _column, cellValue) => {
return this.$util.toDateString(cellValue);
}
}
]
};
},
methods: {
/* 表格数据源 */
datasource({ where, parent }) {
return listMenus({
...where,
parentId: parent?.menuId ?? 0
});
}
}
};
</script>
@@ -1,68 +0,0 @@
<template>
<el-card shadow="never">
<!-- 数据表格 -->
<ele-pro-table
ref="table"
row-key="id"
title="合并单元格"
:columns="columns"
:datasource="datasource"
:span-method="spanMethod"
size="mini"
/>
</el-card>
</template>
<script>
import { pageUserScores } from '@/api/example/table';
export default {
data() {
return {
// 表格列配置
columns: [
{
columnKey: 'index',
type: 'index',
width: 45,
align: 'center',
showOverflowTooltip: true,
fixed: 'left'
},
{
columnKey: 'userName',
prop: 'userName',
label: '姓名',
showOverflowTooltip: true,
minWidth: 110
},
{
prop: 'courseName',
label: '课程',
showOverflowTooltip: true,
minWidth: 110
},
{
prop: 'score',
label: '得分',
showOverflowTooltip: true,
minWidth: 110
}
]
};
},
methods: {
/* 表格数据源 */
datasource() {
return pageUserScores();
},
/* 合并表格单元格 */
spanMethod({ row, column }) {
if (column.columnKey === 'userName') {
return [row.userNameRowSpan, 1];
}
return [1, 1];
}
}
};
</script>
@@ -1,113 +0,0 @@
<template>
<el-card shadow="never">
<!-- 数据表格 -->
<ele-pro-table
ref="table"
row-key="userId"
title="可控的排序和筛选"
:columns="columns"
:datasource="datasource"
size="mini"
>
<template #toolkit>
<el-button size="small" type="primary" @click="setSorter">
设置用户名排序
</el-button>
<el-button size="small" type="primary" @click="resetAll">
重置排序和筛选
</el-button>
<div style="padding: 0 10px">
<el-divider direction="vertical" />
</div>
</template>
</ele-pro-table>
</el-card>
</template>
<script>
import { pageUsers } from '@/api/system/user';
export default {
data() {
return {
// 表格列配置
columns: [
{
columnKey: 'index',
type: 'index',
width: 45,
align: 'center',
showOverflowTooltip: true,
fixed: 'left'
},
{
prop: 'username',
label: '用户账号',
sortable: 'custom',
showOverflowTooltip: true,
minWidth: 110
},
{
prop: 'nickname',
label: '用户名',
sortable: 'custom',
showOverflowTooltip: true,
minWidth: 110
},
{
columnKey: 'sexName',
prop: 'sexName',
label: '性别',
sortable: 'custom',
showOverflowTooltip: true,
minWidth: 80,
filterMultiple: false,
filters: [
{
text: '男',
value: '男'
},
{
text: '女',
value: '女'
}
]
},
{
prop: 'phone',
label: '手机号',
sortable: 'custom',
showOverflowTooltip: true,
minWidth: 110
},
{
prop: 'createTime',
label: '创建时间',
sortable: 'custom',
showOverflowTooltip: true,
minWidth: 110,
formatter: (_row, _column, cellValue) => {
return this.$util.toDateString(cellValue);
}
}
]
};
},
methods: {
/* 表格数据源 */
datasource({ page, limit, order, filterValue }) {
return pageUsers({ ...order, ...filterValue, page, limit });
},
/* 设置排序 */
setSorter() {
this.$refs.table.sort('nickname', 'descending');
},
/* 重置排序和筛选 */
resetAll() {
this.$refs.table.clearSort();
this.$refs.table.clearFilter();
this.$refs.table.reload({ orders: {}, filters: {} });
}
}
};
</script>
-20
View File
@@ -1,20 +0,0 @@
<template>
<div class="ele-body">
<lazy-tree-table />
<default-sorter />
<reset-sorter />
<merge-cell />
</div>
</template>
<script>
import LazyTreeTable from './components/lazy-tree-table.vue';
import DefaultSorter from './components/default-sorter.vue';
import ResetSorter from './components/reset-sorter.vue';
import MergeCell from './components/merge-cell.vue';
export default {
name: 'ExampleTable',
components: { LazyTreeTable, DefaultSorter, ResetSorter, MergeCell }
};
</script>
@@ -1,113 +0,0 @@
<template>
<div class="ele-body">
<el-card shadow="never" header="条形码" style="overflow: visible">
<div ref="printRef" class="demo-barcode-images ele-bg-white">
<ele-bar-code :value="text" :tag="tag" :options="options" />
</div>
<el-form label-width="88px" style="max-width: 340px">
<el-form-item label="条码类型: ">
<el-radio-group :value="options.format" @input="updateFormat">
<el-radio label="CODE128">CODE128</el-radio>
<el-radio label="EAN13">EAN13</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="渲染方式: ">
<el-radio-group v-model="tag">
<el-radio label="svg">svg</el-radio>
<el-radio label="img">img</el-radio>
<el-radio label="canvas">canvas</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="条码文本: ">
<el-select
v-if="options.format === 'EAN13'"
v-model="text"
class="ele-fluid"
>
<el-option value="1234567890128" label="1234567890128" />
<el-option value="6971872201359" label="6971872201359" />
<el-option value="6954531770199" label="6954531770199" />
<el-option value="6923644240318" label="6923644240318" />
</el-select>
<el-input v-else v-model="text" :maxlength="20" />
</el-form-item>
<el-form-item label="高度: ">
<el-slider v-model="options.height" :min="40" :max="160" :step="10" />
</el-form-item>
<el-form-item label="宽度: ">
<el-slider v-model="options.width" :min="1" :max="6" />
</el-form-item>
<el-form-item label="间距: ">
<el-slider v-model="options.margin" :min="0" :max="40" />
</el-form-item>
<el-form-item label="显示文本: ">
<el-switch v-model="options.displayValue" />
</el-form-item>
<el-form-item v-if="options.displayValue" label="文本大小: ">
<el-slider v-model="options.fontSize" :min="12" :max="36" :step="2" />
</el-form-item>
<el-form-item
v-if="options.displayValue && options.format === 'CODE128'"
label="文本位置: "
>
<el-radio-group v-model="options.textPosition">
<el-radio label="bottom">bottom</el-radio>
<el-radio label="top">top</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item>
<div>
<el-button type="primary" @click="print">打印</el-button>
</div>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script>
import EleBarCode from 'ele-admin/es/ele-bar-code';
import { printElement } from 'ele-admin';
export default {
name: 'ExtensionBarCode',
components: { EleBarCode },
data() {
return {
text: '1234567890',
tag: 'svg',
options: {
height: 60,
width: 2,
margin: 2,
displayValue: true,
textPosition: 'bottom',
fontSize: 14,
format: 'CODE128'
}
};
},
methods: {
updateFormat(value) {
if (value === 'EAN13') {
this.text = '1234567890128';
}
this.options.format = value;
},
print() {
printElement(this.$refs.printRef);
}
}
};
</script>
<style lang="scss" scoped>
.demo-barcode-images {
padding-bottom: 16px;
margin-bottom: 4px;
position: sticky;
top: 0;
overflow: auto;
z-index: 1002;
}
</style>
@@ -1,62 +0,0 @@
<template>
<div class="ele-body">
<el-card shadow="never" header="滚动数字">
<h1 style="padding-left: 10px">
<vue-count-up
:delay="0"
:end-val="demoNum"
:options="option"
@ready="onReady"
/>
</h1>
<div style="margin-top: 15px">
<el-button size="mini" @click="restart">重新开始</el-button>
<el-button size="mini" @click="update">更新数字</el-button>
</div>
</el-card>
</div>
</template>
<script>
import VueCountUp from 'vue-countup-v2';
export default {
name: 'ExtensionCountUp',
components: { VueCountUp },
data() {
return {
// 值
demoNum: 2345,
// 配置
option: {
useEasing: true,
useGrouping: true,
separator: ',',
decimal: '.',
prefix: '',
suffix: ''
},
// 实例
instance: null
};
},
methods: {
/* 渲染完成 */
onReady(ins) {
this.instance = ins;
},
/* 重新开始 */
restart() {
if (!this.instance) {
return;
}
this.instance.reset();
this.instance.start();
},
/* 更新 */
update() {
this.demoNum += 100 + Math.round(Math.random() * 300);
}
}
};
</script>
@@ -1,41 +0,0 @@
<template>
<div class="ele-body">
<el-card shadow="never" header="基本用法">
<ele-dashboard type="success" style="margin-right: 18px">
<div style="line-height: 1">
<span style="font-size: 48px">100</span>
<span style="font-size: 12px; margin-left: 4px"></span>
</div>
<div style="margin-top: 4px">安全</div>
</ele-dashboard>
<ele-dashboard type="warning" style="margin-right: 18px">
<div style="line-height: 1">
<span style="font-size: 48px">70</span>
<span style="font-size: 12px; margin-left: 4px"></span>
</div>
<div style="margin-top: 4px">待优化</div>
</ele-dashboard>
<ele-dashboard type="danger">
<div style="line-height: 1">
<span style="font-size: 48px">40</span>
<span style="font-size: 12px; margin-left: 4px"></span>
</div>
<div style="margin-top: 4px">高风险</div>
</ele-dashboard>
</el-card>
<el-card shadow="never" header="自定义颜色和尺寸">
<ele-dashboard color="#722ED1" style="margin-right: 18px">
<div style="font-size: 48px">100</div>
</ele-dashboard>
<ele-dashboard size="116px" space="12px">
<div style="font-size: 38px">100</div>
</ele-dashboard>
</el-card>
</div>
</template>
<script>
export default {
name: 'ExtensionDashboard'
};
</script>
@@ -1,14 +0,0 @@
<template>
<div></div>
</template>
<script>
export default {
created() {
console.log('弹窗内组件创建');
},
destroyed() {
console.log('弹窗内组件销毁');
}
};
</script>
@@ -1,220 +0,0 @@
<template>
<el-card shadow="never" header="可拖拽、拉伸、全屏弹窗">
<el-form label-width="140px" style="max-width: 360px">
<el-form-item label="是否可拖出边界:">
<el-select class="ele-block" v-model="moveOut">
<el-option label="不可拖出边界" :value="0" />
<el-option label="可以拖出边界" :value="1" />
<el-option label="只可右下方向拖出边界" :value="2" />
</el-select>
</el-form-item>
<el-form-item label="是否可拉伸大小:">
<el-select class="ele-block" v-model="resizable">
<el-option label="不可拉伸大小" value="false" />
<el-option label="可以拉伸大小" value="true" />
<el-option label="只可横向拉伸" value="horizontal" />
<el-option label="只可纵向拉伸" value="vertical" />
</el-select>
</el-form-item>
<el-form-item label="最大化切换按钮:">
<el-switch v-model="maxable" />
</el-form-item>
<!-- <el-form-item label="是否垂直居中:">
<el-switch v-model="centered" />
</el-form-item> -->
<el-form-item label="关闭后重置位置:">
<el-switch v-model="resetOnClose" />
</el-form-item>
<el-form-item label="限制在主体区域:">
<el-switch v-model="inner" />
</el-form-item>
<el-form-item label="默认位置:">
<el-select clearable class="ele-block" v-model="position">
<el-option label="顶部" value="top" />
<el-option label="底部" value="bottom" />
<el-option label="左边" value="left" />
<el-option label="右边" value="right" />
<el-option label="左上角" value="leftTop" />
<el-option label="左下角" value="leftBottom" />
<el-option label="右上角" value="rightTop" />
<el-option label="右下角" value="rightBottom" />
<el-option label="正中间" value="center" />
</el-select>
</el-form-item>
<el-form-item label="destroy-on-close:">
<el-switch v-model="destroyOnClose" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="openDialog">打开可拖拽弹窗</el-button>
</el-form-item>
</el-form>
<ele-modal
width="400px"
title="拖拽弹窗"
:visible.sync="visible"
:move-out="moveOut > 0"
:move-out-positive="moveOut === 2"
:resizable="modalResizable"
:maxable="maxable"
:inner="inner"
:centered="centered"
:reset-on-close="resetOnClose"
:append-to-body="true"
:destroy-on-close="destroyOnClose"
:mask-keep-alive="inner || !destroyOnClose"
:position="position"
@closed="cancel"
>
<el-form ref="form" :model="form" :rules="rules" label-width="82px">
<el-form-item label="用户名:" prop="nickname">
<el-input
clearable
v-model="form.nickname"
placeholder="请输入用户名"
/>
</el-form-item>
<el-form-item label="性别:" prop="sex">
<el-select
clearable
class="ele-fluid"
v-model="form.sex"
placeholder="请选择性别"
:popper-append-to-body="false"
>
<el-option label="" value="" />
<el-option label="" value="" />
</el-select>
</el-form-item>
<el-form-item label="手机号:" prop="phone">
<el-input clearable v-model="form.phone" placeholder="请输入手机号" />
</el-form-item>
<el-form-item label="邮箱:" prop="email">
<el-input clearable v-model="form.email" placeholder="请输入邮箱" />
</el-form-item>
<el-form-item label="个人简介:">
<el-input
:rows="4"
clearable
type="textarea"
v-model="form.introduction"
placeholder="请输入个人简介"
/>
</el-form-item>
</el-form>
<component-test />
<template v-slot:footer>
<el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="save">保存</el-button>
</template>
</ele-modal>
</el-card>
</template>
<script>
import ComponentTest from './component-test.vue';
export default {
components: { ComponentTest },
data() {
return {
// 弹窗是否打开
visible: false,
// 是否允许拖出边界
moveOut: 0,
// 是否可拉伸
resizable: 'false',
// 是否显示最大化切换按钮
maxable: true,
// 关闭后重置位置
resetOnClose: true,
// 限制在主体区域
inner: false,
// 垂直居中
centered: false,
// 表单数据
form: {
nickname: '',
sex: undefined,
phone: '',
email: '',
introduction: ''
},
// 表单验证规则
rules: {
nickname: [
{
required: true,
message: '请输入用户名',
type: 'string'
}
],
sex: [
{
required: true,
message: '请选择性别',
type: 'string'
}
],
phone: [
{
required: true,
message: '请输入手机号',
type: 'string'
}
],
email: [
{
required: true,
message: '请输入邮箱',
type: 'string'
}
]
},
// 弹窗关闭后是否销毁
destroyOnClose: false,
// 默认位置
position: undefined
};
},
computed: {
modalResizable() {
return this.resizable === 'true'
? true
: this.resizable === 'false'
? false
: this.resizable;
}
},
methods: {
/* 打开弹窗 */
openDialog() {
if (!this.visible) {
this.visible = true;
}
},
/* 弹窗关闭回调 */
cancel() {
this.form = {
nickname: '',
sex: undefined,
phone: '',
email: '',
introduction: ''
};
this.$nextTick(() => {
this.$refs.form.clearValidate();
});
this.visible = false;
},
/* 保存编辑 */
save() {
this.$refs.form.validate((valid) => {
if (!valid) {
return false;
}
this.$message.success('保存成功');
});
}
}
};
</script>
@@ -1,84 +0,0 @@
<template>
<el-card shadow="never" header="同时打开多个弹窗">
<div>
<el-button type="primary" @click="openDialog1">打开弹窗1</el-button>
<el-button type="primary" @click="openDialog2">打开弹窗2</el-button>
<el-button type="primary" @click="openDialog3">打开弹窗3</el-button>
</div>
<p style="margin-top: 20px">同时打开多个弹窗时点击会自动置顶</p>
<ele-modal
width="400px"
title="弹窗1"
:visible.sync="visible1"
:resizable="true"
:maxable="true"
:multiple="true"
:move-out="true"
:move-out-positive="true"
position="center"
>
<div style="padding: 20px 0">弹窗1</div>
<template v-slot:footer>
<el-button @click="visible1 = false">取消</el-button>
<el-button type="primary">确定</el-button>
</template>
</ele-modal>
<ele-modal
width="400px"
title="弹窗2"
:visible.sync="visible2"
:resizable="true"
:maxable="true"
:multiple="true"
:move-out="true"
:move-out-positive="true"
position="rightTop"
>
<div style="padding: 20px 0">弹窗2</div>
<template v-slot:footer>
<el-button @click="visible2 = false">取消</el-button>
<el-button type="primary">确定</el-button>
</template>
</ele-modal>
<ele-modal
width="400px"
title="弹窗3"
:visible.sync="visible3"
:resizable="true"
:maxable="true"
:multiple="true"
:move-out="true"
:move-out-positive="true"
position="rightBottom"
>
<div style="padding: 20px 0">弹窗3</div>
<template v-slot:footer>
<el-button @click="visible3 = false">取消</el-button>
<el-button type="primary">确定</el-button>
</template>
</ele-modal>
</el-card>
</template>
<script>
export default {
data() {
return {
visible1: false,
visible2: false,
visible3: false
};
},
methods: {
openDialog1() {
this.visible1 = true;
},
openDialog2() {
this.visible2 = true;
},
openDialog3() {
this.visible3 = true;
}
}
};
</script>
@@ -1,19 +0,0 @@
<template>
<div class="ele-body ele-body-card">
<demo-modal />
<multiple-modal />
</div>
</template>
<script>
import DemoModal from './components/demo-modal.vue';
import MultipleModal from './components/multiple-modal.vue';
export default {
name: 'ExtensionDialog',
components: {
DemoModal,
MultipleModal
}
};
</script>
@@ -1,157 +0,0 @@
<template>
<el-row :gutter="15">
<el-col v-bind="styleResponsive ? { md: 8 } : { span: 8 }">
<el-card shadow="never" header="宫格拖拽排序">
<div class="demo-drag-grid">
<vue-draggable
v-model="grid"
animation="300"
:set-data="() => void 0"
>
<div
class="demo-drag-grid-item"
v-for="item in grid"
:key="item.id"
>
{{ item.name }}
</div>
</vue-draggable>
</div>
</el-card>
</el-col>
<el-col v-bind="styleResponsive ? { md: 16 } : { span: 16 }">
<el-card shadow="never" header="宫格相互拖拽">
<el-row :gutter="15">
<el-col :span="12">
<div class="demo-drag-grid">
<vue-draggable
v-model="grid1"
group="project2"
animation="300"
:set-data="() => void 0"
>
<div
class="demo-drag-grid-item"
v-for="item in grid1"
:key="item.id"
>
{{ item.name }}
</div>
</vue-draggable>
</div>
</el-col>
<el-col :span="12">
<div class="demo-drag-grid">
<vue-draggable
v-model="grid2"
group="project2"
animation="300"
:set-data="() => void 0"
>
<div
class="demo-drag-grid-item"
v-for="item in grid2"
:key="item.id"
>
{{ item.name }}
</div>
</vue-draggable>
</div>
</el-col>
</el-row>
</el-card>
</el-col>
</el-row>
</template>
<script>
import VueDraggable from 'vuedraggable';
export default {
components: { VueDraggable },
data() {
return {
grid: [
{ id: 1, name: '项目0000001' },
{ id: 2, name: '项目0000002' },
{ id: 3, name: '项目0000003' },
{ id: 4, name: '项目0000004' },
{ id: 5, name: '项目0000005' }
],
grid1: [
{ id: 1, name: '项目0000001' },
{ id: 2, name: '项目0000002' },
{ id: 3, name: '项目0000003' },
{ id: 4, name: '项目0000004' },
{ id: 5, name: '项目0000005' }
],
grid2: [
{ id: 6, name: '项目0000006' },
{ id: 7, name: '项目0000007' },
{ id: 8, name: '项目0000008' },
{ id: 9, name: '项目0000009' },
{ id: 10, name: '项目0000010' }
]
};
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
}
};
</script>
<style lang="scss" scoped>
/* 宫格样式 */
.demo-drag-grid {
position: relative;
& > div {
border: 1px solid hsla(0, 0%, 60%, 0.2);
border-right: none;
border-bottom: none;
display: grid;
grid-template-columns: repeat(3, 33.33%);
min-height: 201px;
}
&:before,
&:after {
content: '';
position: absolute;
background: hsla(0, 0%, 60%, 0.2);
bottom: 0;
right: 0;
}
&:before {
width: 1px;
top: 0;
}
&:after {
height: 1px;
left: 0;
}
}
.demo-drag-grid-item {
cursor: move;
border: 1px solid hsla(0, 0%, 60%, 0.2);
border-top: none;
border-left: none;
height: 100px;
line-height: 100px;
white-space: nowrap;
word-break: break-all;
overflow: hidden;
text-overflow: ellipsis;
text-align: center;
}
.demo-drag-grid-item.sortable-chosen {
background: hsla(0, 0%, 60%, 0.1);
}
</style>
@@ -1,129 +0,0 @@
<template>
<el-row :gutter="15">
<el-col v-bind="styleResponsive ? { md: 8 } : { span: 8 }">
<el-card shadow="never" header="列表拖拽排序">
<div class="demo-drag-list">
<vue-draggable v-model="list" handle=".sort-handle" animation="300">
<div
class="demo-drag-list-item ele-cell"
v-for="item in list"
:key="item.id"
>
<div class="ele-cell-content">{{ item.name }}</div>
<i class="sort-handle el-icon-rank ele-text-secondary"></i>
</div>
</vue-draggable>
</div>
</el-card>
</el-col>
<el-col v-bind="styleResponsive ? { md: 16 } : { span: 16 }">
<el-card shadow="never" header="列表相互拖拽">
<el-row :gutter="15">
<el-col :span="12">
<div class="demo-drag-list">
<vue-draggable
v-model="list1"
handle=".sort-handle"
group="project1"
animation="300"
:set-data="() => void 0"
>
<div
class="demo-drag-list-item ele-cell"
v-for="item in list1"
:key="item.id"
>
<div class="ele-cell-content">{{ item.name }}</div>
<i class="sort-handle el-icon-rank ele-text-secondary"></i>
</div>
</vue-draggable>
</div>
</el-col>
<el-col :span="12">
<div class="demo-drag-list">
<vue-draggable
v-model="list2"
handle=".sort-handle"
group="project1"
animation="300"
:set-data="() => void 0"
>
<div
class="demo-drag-list-item ele-cell"
v-for="item in list2"
:key="item.id"
>
<div class="ele-cell-content">{{ item.name }}</div>
<i class="sort-handle el-icon-rank ele-text-secondary"></i>
</div>
</vue-draggable>
</div>
</el-col>
</el-row>
</el-card>
</el-col>
</el-row>
</template>
<script>
import VueDraggable from 'vuedraggable';
export default {
components: { VueDraggable },
data() {
return {
list: [
{ id: 1, name: '项目0000001' },
{ id: 2, name: '项目0000002' },
{ id: 3, name: '项目0000003' },
{ id: 4, name: '项目0000004' },
{ id: 5, name: '项目0000005' }
],
list1: [
{ id: 1, name: '项目0000001' },
{ id: 2, name: '项目0000002' },
{ id: 3, name: '项目0000003' },
{ id: 4, name: '项目0000004' },
{ id: 5, name: '项目0000005' }
],
list2: [
{ id: 6, name: '项目0000006' },
{ id: 7, name: '项目0000007' },
{ id: 8, name: '项目0000008' },
{ id: 9, name: '项目0000009' },
{ id: 10, name: '项目0000010' }
]
};
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
}
};
</script>
<style lang="scss" scoped>
/* 列表样式 */
.demo-drag-list {
border: 1px solid hsla(0, 0%, 60%, 0.2);
}
.demo-drag-list-item {
padding: 10px 15px;
& + .demo-drag-list-item {
border-top: 1px solid hsla(0, 0%, 60%, 0.2);
}
&.sortable-chosen {
background-color: hsla(0, 0%, 60%, 0.1);
}
.sort-handle {
cursor: move;
font-size: 16px;
}
}
</style>
@@ -1,117 +0,0 @@
<template>
<el-card shadow="never" header="表格拖拽排序">
<el-row :gutter="15">
<el-col
v-for="(item, index) in taskList"
:key="index"
v-bind="styleResponsive ? { md: 8 } : { span: 8 }"
>
<table class="ele-table ele-table-border ele-table-medium">
<colgroup>
<col width="40" />
<col />
<col width="80" />
</colgroup>
<thead>
<tr>
<th></th>
<th>任务名称</th>
<th style="text-align: center">状态</th>
</tr>
</thead>
<vue-draggable
tag="tbody"
:value="item"
:animation="300"
group="demoDragTable"
handle=".demo-table-drag-handle"
:set-data="() => void 0"
@input="(value) => updateModelValue(value, index)"
>
<tr v-for="d in item" :key="d.id">
<td style="text-align: center">
<i
class="demo-table-drag-handle el-icon-rank ele-text-secondary"
style="cursor: move"
></i>
</td>
<td>{{ d.taskName }}</td>
<td style="text-align: center">
<span
:class="
['ele-text-warning', 'ele-text-success', 'ele-text-info'][
d.status
]
"
>
{{ ['未开始', '进行中', '已完成'][d.status] }}
</span>
</td>
</tr>
<template v-slot:footer>
<tr v-if="!item.length" style="background: none">
<td colspan="3" style="text-align: center">暂无数据</td>
</tr>
</template>
</vue-draggable>
</table>
</el-col>
</el-row>
</el-card>
</template>
<script>
import VueDraggable from 'vuedraggable';
export default {
components: { VueDraggable },
data() {
return {
taskList: [],
result: '',
visible: false
};
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
},
methods: {
/* 更新数据 */
updateModelValue(value, index) {
//this.taskList[index] = value;
this.$set(this.taskList, index, value);
},
/* 查看数据 */
viewData() {
this.result = JSON.stringify(this.taskList, null, 4);
this.visible = true;
}
},
created() {
// 处理数据
const temp = [];
for (let i = 0; i < 18; i++) {
const index = parseInt(String(i / 6));
if (temp[index] == null) {
temp[index] = [];
}
temp[index].push({
id: i,
taskName: '测试任务' + (i + 1),
status: 0
});
}
this.taskList = temp;
}
};
</script>
<style lang="scss" scoped>
/* 表格行拖拽按下去样式 */
.ele-table tr.sortable-chosen {
background: hsla(0, 0%, 60%, 0.1);
}
</style>
@@ -1,18 +0,0 @@
<template>
<div class="ele-body ele-body-card">
<demo-list />
<demo-grid />
<demo-table />
</div>
</template>
<script>
import DemoList from './components/demo-list.vue';
import DemoGrid from './components/demo-grid.vue';
import DemoTable from './components/demo-table.vue';
export default {
name: 'ExtensionDragSort',
components: { DemoList, DemoGrid, DemoTable }
};
</script>
-109
View File
@@ -1,109 +0,0 @@
<template>
<div class="ele-body">
<el-card shadow="never">
<!-- 操作按钮 -->
<div class="ele-table-tool">
<el-button size="small" @click="editContent">修改内容</el-button>
<el-button size="small" @click="showViewContent = true">
获取html
</el-button>
<el-button
size="small"
class="hidden-xs-only"
@click="showViewText = true"
>
获取文本
</el-button>
<el-button size="small" class="hidden-xs-only" @click="toggleDisabled">
{{ disabled ? '启用' : '禁用' }}
</el-button>
</div>
<!-- 编辑器 -->
<tinymce-editor
ref="editor"
v-model="value"
:init="option"
:disabled="disabled"
/>
</el-card>
<!-- 内容弹窗 -->
<ele-modal width="400px" title="编辑器内容" :visible.sync="showViewContent">
<div>{{ value }}</div>
</ele-modal>
<!-- 纯文本弹窗 -->
<ele-modal width="400px" title="编辑器纯文本" :visible.sync="showViewText">
<div>{{ value | htmlToText }}</div>
</ele-modal>
</div>
</template>
<script>
import TinymceEditor from '@/components/TinymceEditor/index.vue';
export default {
name: 'ExtensionEditor',
components: { TinymceEditor },
data() {
return {
option: {
height: 520,
// 自定义文件上传(这里使用把选择的文件转成 blob 演示)
file_picker_callback: (callback, _value, meta) => {
const input = document.createElement('input');
input.setAttribute('type', 'file');
// 设定文件可选类型
if (meta.filetype === 'image') {
input.setAttribute('accept', 'image/*');
} else if (meta.filetype === 'media') {
input.setAttribute('accept', 'video/*');
}
input.onchange = () => {
const file = input.files?.[0];
if (!file) {
return;
}
if (meta.filetype === 'media') {
if (!file.type.startsWith('video/')) {
this.$refs.editor.alert({ content: '只能选择视频文件' });
return;
}
}
if (file.size / 1024 / 1024 > 20) {
this.$refs.editor.alert({ content: '大小不能超过 20MB' });
return;
}
const reader = new FileReader();
reader.onload = (e) => {
if (e.target?.result != null) {
const blob = new Blob([e.target.result], { type: file.type });
callback(URL.createObjectURL(blob));
}
};
reader.readAsArrayBuffer(file);
};
input.click();
}
},
value: '',
showViewContent: false,
showViewText: false,
disabled: false
};
},
methods: {
/* 修改编辑器内容 */
editContent() {
this.value = [
'<div style="text-align: center;color: #fff;background-image: linear-gradient( 135deg, #2AFADF 10%, #4C83FF 100%);padding: 20px;">',
' <div style="font-size: 28px;margin-bottom: 10px;">EleAdmin后台管理模板</div>',
' <div style="font-size: 18px">通用型后台管理模板,界面美观、开箱即用,拥有丰富的组件和模板</div>',
'</div><br/>'
].join('');
},
/* 禁用启用切换 */
toggleDisabled() {
this.disabled = !this.disabled;
}
}
};
</script>
@@ -1,28 +0,0 @@
<template>
<div class="ele-body">
<el-card shadow="never" header="默认效果">
<ele-empty></ele-empty>
</el-card>
<el-card shadow="never" header="自定义图标">
<ele-empty>
<template v-slot:icon>
<i class="el-icon-_retrieve-solid"></i>
</template>
</ele-empty>
</el-card>
<el-card shadow="never" header="自定义操作按钮">
<ele-empty text="还没有添加过数据~">
<div style="margin-top: 20px">
<el-button size="mini">添加数据</el-button>
<el-button type="primary" size="mini">重新加载</el-button>
</div>
</ele-empty>
</el-card>
</div>
</template>
<script>
export default {
name: 'ExtensionEmpty'
};
</script>
@@ -1,261 +0,0 @@
<template>
<el-card shadow="never" header="导出 Excel">
<ele-pro-table
size="mini"
:columns="columns"
:datasource="users"
:selection.sync="select"
:toolkit="['size', 'columns', 'fullscreen']"
:need-page="false"
>
<template v-slot:toolbar>
<el-button type="primary" size="small" @click="exportBas">
导出
</el-button>
<el-button type="primary" size="small" @click="exportAdv">
导出带表头合并
</el-button>
<el-button type="primary" size="small" @click="exportSel">
导出选中
</el-button>
</template>
</ele-pro-table>
</el-card>
</template>
<script>
import { utils, writeFile } from 'xlsx';
export default {
data() {
return {
// 表格列配置
columns: [
{
columnKey: 'selection',
type: 'selection',
width: 45,
align: 'center'
},
{
columnKey: 'index',
type: 'index',
width: 45,
align: 'center'
},
{
prop: 'username',
label: '用户名',
align: 'center',
showOverflowTooltip: true
},
{
prop: 'addressGroup',
label: '地址',
align: 'center',
showOverflowTooltip: true,
children: [
{
prop: 'province',
label: '省',
align: 'center',
showOverflowTooltip: true
},
{
prop: 'city',
label: '市',
align: 'center',
showOverflowTooltip: true
},
{
prop: 'zone',
label: '区',
align: 'center',
showOverflowTooltip: true
},
{
prop: 'street',
label: '街道',
align: 'center',
showOverflowTooltip: true
},
{
prop: 'address',
label: '详细地址',
align: 'center',
showOverflowTooltip: true
}
]
},
{
prop: 'amount',
label: '金额',
align: 'center',
showOverflowTooltip: true
}
],
// 表格数据
users: [
{
key: 1,
username: '张小三',
amount: 18,
province: '浙江',
city: '杭州',
zone: '西湖区',
street: '西溪街道',
address: '西溪花园30栋1单元'
},
{
key: 2,
username: '李小四',
amount: 39,
province: '江苏',
city: '苏州',
zone: '姑苏区',
street: '丝绸路',
address: '天墅之城9幢2单元'
},
{
key: 3,
username: '王小五',
amount: 8,
province: '江西',
city: '南昌',
zone: '青山湖区',
street: '艾溪湖办事处',
address: '中兴和园1幢3单元'
},
{
key: 4,
username: '赵小六',
amount: 16,
province: '福建',
city: '泉州',
zone: '丰泽区',
street: '南洋街道',
address: '南洋村6幢1单元'
},
{
key: 5,
username: '孙小七',
amount: 12,
province: '湖北',
city: '武汉',
zone: '武昌区',
street: '武昌大道',
address: '两湖花园16幢2单元'
},
{
key: 6,
username: '周小八',
amount: 11,
province: '安徽',
city: '黄山',
zone: '黄山区',
street: '汤口镇',
address: '温泉村21号'
}
],
// 选中数据
select: []
};
},
methods: {
/* 导出 excel */
exportBas() {
const array = [
['用户名', '省', '市', '区', '街道', '详细地址', '金额']
];
this.users.forEach((d) => {
array.push([
d.username,
d.province,
d.city,
d.zone,
d.street,
d.address,
d.amount
]);
});
const sheetName = 'Sheet1';
const workbook = {
SheetNames: [sheetName],
Sheets: {}
};
const sheet = utils.aoa_to_sheet(array);
workbook.Sheets[sheetName] = sheet;
// 设置列宽
sheet['!cols'] = [
{ wch: 10 },
{ wch: 10 },
{ wch: 10 },
{ wch: 10 },
{ wch: 20 },
{ wch: 40 },
{ wch: 10 }
];
writeFile(workbook, '用户数据.xlsx');
},
/* 导出带单元格合并 */
exportAdv() {
const array = [
['用户名', '地址', null, null, null, null, '金额'],
[null, '省', '市', '区', '街道', '详细地址', null]
];
this.users.forEach((d) => {
array.push([
d.username,
d.province,
d.city,
d.zone,
d.street,
d.address,
d.amount
]);
});
const sheet = utils.aoa_to_sheet(array);
sheet['!merges'] = [
{ s: { r: 0, c: 1 }, e: { r: 0, c: 5 } }, // 合并第 0 行第 1 列到第 0 行第 5 列
{ s: { r: 0, c: 0 }, e: { r: 1, c: 0 } }, // 合并第 0 行第 0 列到第 1 行第 0 列
{ s: { r: 0, c: 6 }, e: { r: 1, c: 6 } } // 合并第 0 行第 6 列到第 1 行第 6 列
];
const sheetName = 'Sheet1';
const workbook = {
SheetNames: [sheetName],
Sheets: {}
};
workbook.Sheets[sheetName] = sheet;
writeFile(workbook, '用户数据.xlsx');
},
/* 导出选中数据 */
exportSel() {
if (this.select.length === 0) {
this.$message.error('请至少选择一条数据');
return;
}
const array = [
['用户名', '省', '市', '区', '街道', '详细地址', '金额']
];
this.select.forEach((d) => {
array.push([
d.username,
d.province,
d.city,
d.zone,
d.street,
d.address,
d.amount
]);
});
const sheetName = 'Sheet1';
const workbook = {
SheetNames: [sheetName],
Sheets: {}
};
workbook.Sheets[sheetName] = utils.aoa_to_sheet(array);
writeFile(workbook, '用户数据.xlsx');
}
}
};
</script>
@@ -1,305 +0,0 @@
<template>
<el-card shadow="never" header="导入 Excel">
<!-- 操作按钮 -->
<div style="display: flex; margin-bottom: 12px">
<el-upload
action=""
:show-file-list="false"
:before-upload="importFile"
accept=".xls,.xlsx"
class="ele-action"
>
<el-button type="primary" size="small" class="hidden-xs-only">
导入
</el-button>
</el-upload>
<el-upload
action=""
:show-file-list="false"
:before-upload="importFile2"
accept=".xls,.xlsx"
class="ele-action"
>
<el-button type="primary" size="small">导入拆分合并</el-button>
</el-upload>
<el-upload
action=""
:show-file-list="false"
:before-upload="importFile3"
accept=".xls,.xlsx"
class="ele-action"
>
<el-button type="primary" size="small">导入保持合并</el-button>
</el-upload>
</div>
<!-- 数据表格 -->
<el-table
size="mini"
:border="true"
:data="importData"
style="width: 100%"
:span-method="spanMethod"
>
<el-table-column type="index" width="45" align="center" />
<el-table-column
v-for="(key, index) in importTitle"
:key="index"
:prop="key"
:label="key"
align="center"
show-overflow-tooltip
/>
</el-table>
<el-row :gutter="30">
<el-col v-bind="styleResponsive ? { md: 12 } : { span: 12 }">
<div style="padding: 15px 0">二维数组格式数据:</div>
<pre style="max-height: 300px; overflow: auto">{{
JSON.stringify(importDataAoa, null, 4)
}}</pre>
</el-col>
<el-col v-bind="styleResponsive ? { md: 12 } : { span: 12 }">
<div style="padding: 15px 0">JSON格式数据:</div>
<pre style="max-height: 300px; overflow: auto">{{
JSON.stringify(importData, null, 4)
}}</pre>
</el-col>
</el-row>
</el-card>
</template>
<script>
import { utils, read } from 'xlsx';
export default {
data() {
return {
// 导入数据
importData: [],
// 导入数据的列
importTitle: ['A', 'B', 'C', 'D', 'E', 'F', 'G'],
// 导入数据二维数组形式
importDataAoa: []
};
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
},
methods: {
/* 导入本地 excel 文件 */
importFile(file) {
if (
![
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
].includes(file.type)
) {
this.$message.error('只能选择 excel 文件');
return false;
}
if (file.size / 1024 / 1024 > 20) {
this.$message.error('大小不能超过 20MB');
return false;
}
const reader = new FileReader();
reader.onload = (e) => {
const data = new Uint8Array(e.target.result);
const workbook = read(data, { type: 'array' });
const sheetNames = workbook.SheetNames;
const worksheet = workbook.Sheets[sheetNames[0]];
// 解析成二维数组
const aoa = utils.sheet_to_json(worksheet, { header: 1 });
// 生成表格需要的数据
const list = [];
let maxCols = 0;
const title = [];
aoa.forEach((d) => {
if (d.length > maxCols) {
maxCols = d.length;
}
const row = {};
for (let i = 0; i < d.length; i++) {
row[this.getCharByIndex(i)] = d[i];
}
list.push(row);
});
for (let i = 0; i < maxCols; i++) {
title.push(this.getCharByIndex(i));
}
this.importTitle = title;
this.importData = list;
this.importDataAoa = aoa;
};
reader.readAsArrayBuffer(file);
return false;
},
/* 导入本地 excel 文件 */
importFile2(file) {
if (
![
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
].includes(file.type)
) {
this.$message.error('只能选择 excel 文件');
return false;
}
if (file.size / 1024 / 1024 > 20) {
this.$message.error('大小不能超过 20MB');
return false;
}
const reader = new FileReader();
reader.onload = (e) => {
const data = new Uint8Array(e.target.result);
const workbook = read(data, { type: 'array' });
const sheetNames = workbook.SheetNames;
const worksheet = workbook.Sheets[sheetNames[0]];
// 解析成二维数组
const aoa = utils.sheet_to_json(worksheet, { header: 1 });
// 拆分合并单元格
if (worksheet['!merges']) {
worksheet['!merges'].forEach((m) => {
for (let r = m.s.r; r <= m.e.r; r++) {
for (let c = m.s.c; c <= m.e.c; c++) {
aoa[r][c] = aoa[m.s.r][m.s.c];
}
}
});
}
// 生成表格需要的数据
const list = [];
let maxCols = 0;
const title = [];
aoa.forEach((d) => {
if (d.length > maxCols) {
maxCols = d.length;
}
const row = {};
for (let i = 0; i < d.length; i++) {
row[this.getCharByIndex(i)] = d[i];
}
list.push(row);
});
for (let i = 0; i < maxCols; i++) {
title.push(this.getCharByIndex(i));
}
this.importTitle = title;
this.importData = list;
this.importDataAoa = aoa;
};
reader.readAsArrayBuffer(file);
return false;
},
/* 导入本地 excel 文件 */
importFile3(file) {
if (
![
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
].includes(file.type)
) {
this.$message.error('只能选择 excel 文件');
return false;
}
if (file.size / 1024 / 1024 > 20) {
this.$message.error('大小不能超过 20MB');
return false;
}
const reader = new FileReader();
reader.onload = (e) => {
const data = new Uint8Array(e.target.result);
const workbook = read(data, { type: 'array' });
const sheetNames = workbook.SheetNames;
const worksheet = workbook.Sheets[sheetNames[0]];
// 解析成二维数组
const aoa = utils.sheet_to_json(worksheet, { header: 1 });
// 生成表格需要的数据
const list = [];
let maxCols = 0;
const title = [];
aoa.forEach((d) => {
if (d.length > maxCols) {
maxCols = d.length;
}
const row = {};
for (let i = 0; i < d.length; i++) {
row[this.getCharByIndex(i)] = d[i];
}
list.push(row);
});
for (let i = 0; i < maxCols; i++) {
title.push(this.getCharByIndex(i));
}
// 记录合并单元格
if (worksheet['!merges']) {
worksheet['!merges'].forEach((m) => {
for (let r = m.s.r; r <= m.e.r; r++) {
for (let c = m.s.c; c <= m.e.c; c++) {
const cc = this.getCharByIndex(c);
list[r]['__colspan__' + cc] = 0;
list[r]['__rowspan__' + cc] = 0;
}
}
const char = this.getCharByIndex(m.s.c);
list[m.s.r]['__colspan__' + char] = m.e.c - m.s.c + 1;
list[m.s.r]['__rowspan__' + char] = m.e.r - m.s.r + 1;
});
}
this.importTitle = title;
this.importData = list;
this.importDataAoa = aoa;
};
reader.readAsArrayBuffer(file);
return false;
},
/* 生成 Excel 列字母序号 */
getCharByIndex(index) {
const chars = [
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z'
];
if (index < chars.length) {
return chars[index];
}
const n = parseInt(index / chars.length),
m = index % chars.length;
return chars[n] + chars[m];
},
/* 合并表格单元格 */
spanMethod({ row, column }) {
if (!column.label) {
return [1, 1];
}
const r = row['__rowspan__' + column.label],
c = row['__colspan__' + column.label];
return [r == null ? 1 : r, c == null ? 1 : c];
}
}
};
</script>
@@ -1,16 +0,0 @@
<template>
<div class="ele-body">
<excel-export />
<excel-import />
</div>
</template>
<script>
import ExcelExport from './components/excel-export.vue';
import ExcelImport from './components/excel-import.vue';
export default {
name: 'ExtensionExcel',
components: { ExcelExport, ExcelImport }
};
</script>
@@ -1,103 +0,0 @@
<!-- 文件目录面包屑 -->
<template>
<div class="ele-file-breadcrumb-group ele-cell">
<div class="ele-cell-content ele-cell">
<div
v-if="directorys.length"
class="ele-file-breadcrumb-back ele-text-primary"
@click="goBack"
>
返回上一级
</div>
<div class="ele-file-breadcrumb-list ele-cell-content ele-cell">
<div
:class="[
'ele-file-breadcrumb-item ele-cell',
{ 'ele-text-primary': directorys.length }
]"
@click="goRoot"
>
<div class="ele-file-breadcrumb-item-title">全部文件</div>
<i
v-if="directorys.length"
class="el-icon-arrow-right ele-text-secondary"
></i>
</div>
<div
v-for="(item, i) in directorys"
:key="item.id"
:class="[
'ele-file-breadcrumb-item ele-cell',
{ 'ele-text-primary': i !== directorys.length - 1 }
]"
@click="goDirectory(i)"
>
<div class="ele-file-breadcrumb-item-title">{{ item.name }}</div>
<i
v-if="i !== directorys.length - 1"
class="el-icon-arrow-right ele-text-secondary"
></i>
</div>
</div>
</div>
<div class="hidden-xs-only">已全部加载, {{ total }}</div>
</div>
</template>
<script>
export default {
props: {
// 文件夹数据
directorys: Array,
// 总文件数
total: Number
},
methods: {
/* 回到上级 */
goBack() {
this.$emit(
'update:directorys',
this.directorys.slice(0, this.directorys.length - 1)
);
},
/* 回到根目录 */
goRoot() {
if (this.directorys.length) {
this.$emit('update:directorys', []);
}
},
/* 回到指定目录 */
goDirectory(index) {
if (index !== this.directorys.length - 1) {
this.$emit('update:directorys', this.directorys.slice(0, index + 1));
}
}
}
};
</script>
<style lang="scss" scoped>
/* 文件目录面包屑 */
.ele-file-breadcrumb-group {
font-size: 13px;
padding: 2px 0 6px 0;
line-height: 1;
}
.ele-file-breadcrumb-back {
padding-right: 10px;
border-right: 2px solid hsla(0, 0%, 60%, 0.2);
&:hover {
text-decoration: underline;
cursor: pointer;
}
}
.ele-file-breadcrumb-item.ele-text-primary:hover {
& > .ele-file-breadcrumb-item-title {
text-decoration: underline;
cursor: pointer;
}
}
</style>
@@ -1,216 +0,0 @@
<!-- 文件展示列表 -->
<template>
<div class="demo-file-list-group">
<ele-file-list
v-if="data.length"
:data="data"
:grid="grid"
:sort="sort"
:order="order"
:checked="checked"
:style="{ minHeight: '400px', minWidth: grid ? 'auto' : '456px' }"
@item-click="onItemClick"
@sort-change="onSortChange"
@update:checked="updateChecked"
@item-context-menu="onCtxMenuClick"
:icons="icons"
:sm-icons="smIcons"
>
<template v-slot:context-menu="{ item }">
<el-dropdown-item command="open">打开</el-dropdown-item>
<el-dropdown-item
v-if="!item.isDirectory"
command="download"
icon="el-icon-download"
divided
>
下载
</el-dropdown-item>
<el-dropdown-item
command="edit"
icon="el-icon-edit"
:divided="item.isDirectory"
>
重命名
</el-dropdown-item>
<el-dropdown-item command="move" icon="el-icon-rank" divided>
移动到
</el-dropdown-item>
<el-dropdown-item command="remove" icon="el-icon-delete">
删除
</el-dropdown-item>
</template>
</ele-file-list>
<div v-else class="demo-file-list-empty">
<ele-empty />
</div>
<!-- 用于图片预览 -->
<div style="display: none">
<el-image
ref="previewRef"
v-if="previewOption.visible"
:src="previewOption.current"
:preview-src-list="previewImages"
/>
</div>
<!-- 文件重命名弹窗 -->
<name-edit
:visible.sync="nameEditVisible"
:data="nameEditData"
@done="onDone"
/>
</div>
</template>
<script>
import EleFileList from 'ele-admin/es/ele-file-list';
import NameEdit from './name-edit.vue';
import { removeUserFile } from '@/api/system/user-file';
import { icons, smIcons } from 'ele-admin/es/ele-file-list/icons';
export default {
components: { EleFileList, NameEdit },
props: {
// 父级 id
parentId: Number,
// 文件列表数据
data: Array,
// 排序字段
sort: String,
// 排序方式
order: String,
// 选中数据
checked: Array,
// 是否网格展示
grid: Boolean
},
data() {
return {
icons: icons.map((d) => {
return {
...d,
icon: d.icon.replace(
'https://cdn.eleadmin.com/20200609/',
'/ele-file-list/'
)
};
}),
smIcons: smIcons.map((d) => {
return {
...d,
icon: d.icon.replace(
'https://cdn.eleadmin.com/20200609/',
'/ele-file-list/'
)
};
}),
// 图片预览列表
previewImages: [],
// 图片预览配置
previewOption: {
visible: false,
current: null
},
// 文件重命名弹窗是否打开
nameEditVisible: false,
// 文件重命名的数据
nameEditData: null
};
},
methods: {
/* 文件列表排序方式改变 */
onSortChange(option) {
this.$emit('sort-change', option);
},
/* 更新选中数据 */
updateChecked(value) {
this.$emit('update:checked', value);
},
/* item 点击事件 */
onItemClick(item) {
if (item.isDirectory) {
// 进入文件夹
this.$emit('go-directory', item);
} else if (this.isImageFile(item)) {
// 预览图片文件
this.previewItemImage(item);
} else {
// 选中或取消选中文件
this.updateChecked(
this.checked.includes(item)
? this.checked.filter((d) => d !== item)
: [...this.checked, item]
);
}
},
/* 右键菜单点击事件 */
onCtxMenuClick({ key, item }) {
if (key === 'open') {
// 打开文件
if (item.isDirectory || this.isImageFile(item)) {
this.onItemClick(item);
} else {
window.open(item.url);
}
} else if (key === 'download') {
// 下载文件
if (typeof item.downloadUrl === 'string') {
window.open(item.downloadUrl);
}
} else if (key === 'edit') {
// 重命名
this.nameEditData = item;
this.nameEditVisible = true;
} else if (key === 'remove') {
// 删除文件
this.removeItem(item);
}
},
/* 删除 */
removeItem(item) {
this.$confirm('确定要删除此文件吗?', '提示', {
type: 'warning'
})
.then(() => {
const loading = this.$messageLoading('请求中..');
removeUserFile(item.id)
.then((msg) => {
loading.close();
this.$message.success(msg);
this.onDone();
})
.catch((e) => {
loading.close();
this.$message.error(e.message);
});
})
.catch(() => {});
},
/* 完成刷新列表数据 */
onDone() {
this.$emit('done');
},
/* 判断是否是图片文件 */
isImageFile(item) {
return (
typeof item.contentType === 'string' &&
item.contentType.startsWith('image/') &&
item.url
);
},
/* 预览图片文件 */
previewItemImage(item) {
this.previewImages = this.data
.filter((d) => this.isImageFile(d))
.map((d) => d.url);
this.previewOption.current = item.url;
this.previewOption.visible = true;
this.$nextTick(() => {
if (this.$refs.previewRef) {
this.$refs.previewRef.showViewer = true;
}
});
}
}
};
</script>
@@ -1,211 +0,0 @@
<template>
<ele-toolbar theme="none">
<el-upload
action=""
:show-file-list="false"
:before-upload="onUpload"
class="ele-action ele-inline-block"
>
<el-button
size="small"
type="primary"
class="ele-btn-icon"
icon="el-icon-upload2"
>
上传
</el-button>
</el-upload>
<el-button
size="small"
class="ele-btn-icon"
icon="el-icon-folder-add"
@click="openFolderAdd"
>
新建文件夹
</el-button>
<el-button
size="small"
type="danger"
icon="el-icon-delete"
class="ele-btn-icon hidden-xs-only"
:disabled="!checked.length"
@click="removeBatch"
>
删除
</el-button>
<template v-slot:action>
<!-- 搜索框 -->
<div
:class="['ele-file-tool-search', { 'hidden-xs-only': styleResponsive }]"
>
<el-input size="small" v-model="search" placeholder="搜索您的文件">
<template v-slot:append>
<el-button icon="el-icon-search" />
</template>
</el-input>
</div>
<!-- 显示方式切换 -->
<i
v-if="grid"
class="ele-file-tool-btn el-icon-_menu"
@click="toggleShowType"
></i>
<i
v-else
class="ele-file-tool-btn el-icon-_nav"
@click="toggleShowType"
></i>
</template>
<!-- 新建文件夹弹窗 -->
<folder-add
:visible.sync="folderAddVisible"
:parent-id="parentId"
@done="onDone"
/>
</ele-toolbar>
</template>
<script>
import { uploadFile } from '@/api/system/file';
import { addUserFile, removeUserFiles } from '@/api/system/user-file';
import FolderAdd from './folder-add.vue';
export default {
components: { FolderAdd },
props: {
// 是否网格展示
grid: Boolean,
// 选中数据
checked: Array,
// 父级 id
parentId: Number
},
data() {
return {
// 搜索关键字
search: '',
// 新建文件夹弹窗是否打开
folderAddVisible: false
};
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
},
methods: {
/* 上传 */
onUpload(file) {
if (file.size / 1024 / 1024 > 100) {
this.$message.error('大小不能超过 100MB');
return false;
}
const loading = this.$messageLoading('上传中..');
uploadFile(file)
.then((data) => {
addUserFile({
name: data.name,
isDirectory: 0,
parentId: this.parentId,
path: data.path,
length: data.length,
contentType: data.contentType
})
.then(() => {
loading.close();
this.$message.success('上传成功');
this.onDone();
})
.catch((e) => {
loading.close();
this.$message.error(e.message);
});
})
.catch((e) => {
loading.close();
this.$message.error(e.message);
});
return false;
},
/* 打开新建文件夹弹窗 */
openFolderAdd() {
this.folderAddVisible = true;
},
/* 批量删除 */
removeBatch() {
this.$confirm('确定要删除选中的文件吗?', '提示', {
type: 'warning'
})
.then(() => {
const loading = this.$messageLoading('请求中..');
removeUserFiles(this.checked.map((d) => d.id))
.then((msg) => {
loading.close();
this.$message.success(msg);
this.onDone();
})
.catch((e) => {
loading.close();
this.$message.error(e.message);
});
})
.catch(() => {});
},
/* 完成刷新列表数据 */
onDone() {
this.$emit('done');
},
/* 显示方式切换 */
toggleShowType() {
this.$emit('update:grid', !this.grid);
}
}
};
</script>
<style lang="scss" scoped>
/* 图标按钮 */
.ele-file-tool-btn {
cursor: pointer;
font-size: 22px;
display: inline-block;
vertical-align: middle;
margin-left: 10px;
}
/* 搜索框 */
.ele-file-tool-search {
display: inline-block;
vertical-align: middle;
background-color: hsla(0, 0%, 60%, 0.15);
border-radius: 32px;
:deep(.el-input-group__append),
:deep(.el-input__inner) {
background-color: transparent;
border: none;
}
:deep(.el-input-group__append) {
padding: 0;
}
:deep(.el-input-group__append .el-button) {
margin: 0;
padding: 7px 16px 7px 10px;
border: none;
}
:deep(.el-input-group__append .el-button > i) {
font-size: 16px;
font-weight: 600;
}
:deep(.el-input__inner) {
width: 200px;
padding-right: 0;
box-sizing: border-box;
}
}
</style>
@@ -1,99 +0,0 @@
<template>
<ele-modal
width="460px"
:visible="visible"
:append-to-body="true"
:close-on-click-modal="true"
custom-class="ele-dialog-form"
title="新建文件夹"
@update:visible="updateVisible"
>
<el-form ref="form" :model="form" :rules="rules" label-width="102px">
<el-form-item label="文件夹名称:" prop="name">
<el-input
clearable
:maxlength="20"
v-model="form.name"
placeholder="请输入文件夹名称"
/>
</el-form-item>
</el-form>
<template v-slot:footer>
<el-button @click="updateVisible(false)">取消</el-button>
<el-button type="primary" :loading="loading" @click="save">
保存
</el-button>
</template>
</ele-modal>
</template>
<script>
import { addUserFile } from '@/api/system/user-file';
export default {
props: {
// 弹窗是否打开
visible: Boolean,
// 父级 id
parentId: Number
},
data() {
return {
// 表单数据
form: {
name: ''
},
// 表单验证规则
rules: {
name: [
{
required: true,
message: '请输入文件夹名称',
trigger: 'blur'
}
]
},
// 提交状态
loading: false
};
},
methods: {
/* 保存编辑 */
save() {
this.$refs.form.validate((valid) => {
if (!valid) {
return false;
}
this.loading = true;
addUserFile({
...this.form,
parentId: this.parentId,
isDirectory: 1
})
.then((msg) => {
this.loading = false;
this.$message.success(msg);
this.updateVisible(false);
this.$emit('done');
})
.catch((e) => {
this.loading = false;
this.$message.error(e.message);
});
});
},
/* 更新 visible */
updateVisible(value) {
this.$emit('update:visible', value);
}
},
watch: {
visible(visible) {
if (!visible) {
this.$refs.form.clearValidate();
this.form.name = '';
}
}
}
};
</script>
@@ -1,97 +0,0 @@
<template>
<ele-modal
width="460px"
:visible="visible"
:append-to-body="true"
:close-on-click-modal="true"
custom-class="ele-dialog-form"
title="重命名"
@update:visible="updateVisible"
>
<el-form ref="form" :model="form" :rules="rules" label-width="102px">
<el-form-item label="文件/夹名称:" prop="name">
<el-input
clearable
:maxlength="20"
v-model="form.name"
placeholder="请输入文件夹名称"
/>
</el-form-item>
</el-form>
<template v-slot:footer>
<el-button @click="updateVisible(false)">取消</el-button>
<el-button type="primary" :loading="loading" @click="save">
保存
</el-button>
</template>
</ele-modal>
</template>
<script>
import { updateUserFile } from '@/api/system/user-file';
export default {
props: {
// 弹窗是否打开
visible: Boolean,
// 文件数据
data: Object
},
data() {
return {
// 表单数据
form: {
name: ''
},
// 表单验证规则
rules: {
name: [
{
required: true,
message: '请输入文件/夹名称',
trigger: 'blur'
}
]
},
// 提交状态
loading: false
};
},
methods: {
/* 保存编辑 */
save() {
this.$refs.form.validate((valid) => {
if (!valid) {
return false;
}
this.loading = true;
updateUserFile({ ...this.form, id: this.data?.id })
.then((msg) => {
this.loading = false;
this.$message.success(msg);
this.updateVisible(false);
this.$emit('done');
})
.catch((e) => {
this.loading = false;
this.$message.error(e.message);
});
});
},
/* 更新 visible */
updateVisible(value) {
this.$emit('update:visible', value);
}
},
watch: {
visible(visible) {
if (!visible) {
this.$refs.form.clearValidate();
this.form.name = '';
} else if (this.data) {
this.form.name = this.data.name;
}
}
}
};
</script>
-131
View File
@@ -1,131 +0,0 @@
<template>
<div class="ele-body">
<el-card shadow="never" body-style="padding: 0;">
<div style="padding: 16px 16px 12px 16px">
<file-toolbar
:grid.sync="grid"
:checked="checked"
:parentId="parentId"
@done="onDone"
/>
<file-header
:total="total"
:directorys="directorys"
@update:directorys="updateDirectorys"
/>
</div>
<div v-loading="loading">
<file-list
:grid="grid"
:data="data"
:sort="sort"
:order="order"
:parentId="parentId"
:checked.sync="checked"
@sort-change="onSortChange"
@go-directory="onGoDirectory"
@done="onDone"
/>
</div>
</el-card>
</div>
</template>
<script>
import FileToolbar from './components/file-toolbar.vue';
import FileHeader from './components/file-header.vue';
import FileList from './components/file-list.vue';
import { listUserFiles } from '@/api/system/user-file';
export default {
name: 'ExtensionFile',
components: { FileToolbar, FileHeader, FileList },
data() {
return {
// 加载状态
loading: true,
// 文件列表数据
data: [],
// 排序字段
sort: '',
// 排序方式
order: '',
// 选中数据
checked: [],
// 文件夹数据
directorys: [],
// 总文件数
total: 0,
// 是否网格展示
grid: true,
// 父级 id
parentId: 0
};
},
created() {
this.query();
},
methods: {
/* 查询文件列表 */
query() {
this.data = [];
this.checked = [];
this.loading = true;
listUserFiles({
sort: this.order ? this.sort : '',
order: this.order,
parentId: this.parentId
})
.then((list) => {
this.loading = false;
this.data = list.map((d) => {
return Object.assign({ name: d.name }, d, {
isDirectory: d.isDirectory === 1 ? true : false,
length: this.formatLength(d.length)
});
});
this.total = list.length;
})
.catch((e) => {
this.loading = false;
this.$message.error(e.message);
});
},
/* 刷新列表数据 */
onDone() {
this.query();
},
/* 文件列表排序方式改变 */
onSortChange(option) {
this.order = option.order;
this.sort = option.sort;
this.query();
},
/* 进入文件夹 */
onGoDirectory(item) {
this.updateDirectorys([...this.directorys, item]);
},
/* 更新文件夹数据 */
updateDirectorys(values) {
this.directorys = values;
this.parentId = this.directorys[this.directorys.length - 1]?.id ?? 0;
this.query();
},
/* 格式化文件大小 */
formatLength(length) {
if (length == null) {
return '-';
}
if (length < 1024) {
return length + 'B';
} else if (length < 1024 * 1024) {
return (length / 1024).toFixed(1) + 'KB';
} else if (length < 1024 * 1024 * 1024) {
return (length / 1024 / 1024).toFixed(1) + 'M';
} else {
return (length / 1024 / 1024 / 1024).toFixed(1) + 'G';
}
}
}
};
</script>
-227
View File
@@ -1,227 +0,0 @@
<template>
<div :class="['ele-body', { 'demo-icon-responsive': styleResponsive }]">
<el-alert
show-icon
type="info"
:title="tips"
:closable="true"
class="ele-alert-border"
style="margin-bottom: 10px"
/>
<el-card shadow="never" body-style="padding: 0;" style="overflow: visible">
<div class="demo-icon-header ele-bg-white">
<el-tabs
:value="active"
class="demo-icon-tabs"
@tab-click="onTabChange"
>
<el-tab-pane
v-for="(item, index) in data"
:key="index"
:label="item.title"
:name="String(index)"
/>
</el-tabs>
<div class="demo-icon-search">
<el-input
clearable
size="small"
v-model="keywords"
suffix-icon="el-icon-search"
placeholder="输入关键词搜索"
@input="onSearchChange"
/>
</div>
</div>
<div style="padding: 15px">
<el-row v-if="result.length" class="demo-icon">
<el-col
v-for="(d, i) in result"
:key="i"
v-bind="styleResponsive ? { md: 4, sm: 6, xs: 8 } : { span: 4 }"
class="demo-icon-item"
v-clipboard:copy="d"
v-clipboard:error="onError"
v-clipboard:success="onCopy"
>
<div class="demo-icon-content">
<i :class="d"></i>
</div>
<div class="demo-icon-text ele-text-secondary">{{ d }}</div>
<div class="demo-icon-tip ele-bg-primary">点击复制</div>
</el-col>
</el-row>
<ele-empty v-else />
</div>
</el-card>
</div>
</template>
<script>
import icons from 'ele-admin/es/ele-icon-picker/icons';
export default {
name: 'ExtensionIcon',
data() {
let elNum = 0;
let eleNum = 0;
icons.forEach((item) => {
item.icons.forEach((d) => {
if (d.indexOf('el-icon-_') === 0) {
eleNum++;
} else {
elNum++;
}
});
});
const total = elNum + eleNum;
return {
// 图标数据
data: icons,
// 搜索关键字
keywords: '',
// 当前显示的图标
result: icons[0]?.icons,
// 页签选中
active: '0',
// 提示文字
tips: `新增 ${eleNum} 个图标 + Element UI ${elNum} 个图标, 共计 ${total} 个图标`
};
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
},
methods: {
/* 页签切换事件 */
onTabChange(obj) {
if (this.active !== obj.name) {
this.active = obj.name;
const temp = this.data[this.active].icons;
if (this.keywords) {
this.result = temp.filter((d) => d.includes(this.keywords));
} else {
this.result = temp;
}
}
},
/* 输入框改变事件 */
onSearchChange() {
for (let i = 0; i < this.data.length; i++) {
const temp = this.data[i].icons;
const result = temp.filter((d) => d.includes(this.keywords));
if (result.length) {
this.active = String(i);
this.result = result;
return;
}
}
this.result = [];
},
/* 复制成功 */
onCopy() {
this.$message.success('复制成功');
},
/* 复制失败 */
onError() {
this.$message.error('复制失败');
}
}
};
</script>
<style lang="scss" scoped>
.demo-icon-header {
position: sticky;
top: 0;
border-radius: 4px;
z-index: 1;
}
/* 选项卡 */
.demo-icon-tabs {
:deep(.el-tabs__nav-scroll) {
padding: 0 0 0 30px;
}
:deep(.el-tabs__item) {
height: 48px;
line-height: 48px;
padding: 0 30px 0 0 !important;
}
:deep(.el-tabs__item:focus.is-active.is-focus:not(:active)) {
box-shadow: none;
}
}
/* 搜索框 */
.demo-icon-search {
position: absolute;
top: 8px;
right: 15px;
width: 180px;
z-index: 1;
}
@media screen and (max-width: 660px) {
.demo-icon-responsive .demo-icon-search {
width: auto;
position: static;
margin: 10px 10px 0 10px;
}
}
/* 图标 */
.demo-icon {
border-top: 1px solid hsla(0, 0%, 60%, 0.15);
border-left: 1px solid hsla(0, 0%, 60%, 0.15);
}
.demo-icon-item {
text-align: center;
padding: 24px 0;
border-right: 1px solid hsla(0, 0%, 60%, 0.15);
border-bottom: 1px solid hsla(0, 0%, 60%, 0.15);
position: relative;
overflow: hidden;
cursor: pointer;
& > .demo-icon-content > i {
font-size: 38px;
}
& > .demo-icon-text {
padding: 0 5px;
font-size: 14px;
margin-top: 8px;
white-space: nowrap;
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
}
& > .demo-icon-tip {
position: absolute;
left: 0;
right: 0;
bottom: -30px;
color: #fff;
padding: 4px 0;
font-size: 12px;
transition: bottom 0.2s;
}
&:hover > .demo-icon-tip {
bottom: 0;
}
}
:deep(.ele-admin-fixed-header:not(.ele-admin-fixed-body)) {
.demo-icon-header {
top: 100px;
}
}
</style>
@@ -1,100 +0,0 @@
<template>
<el-card shadow="never" header="官网底部地图">
<div ref="locationMap" style="max-width: 800px; height: 300px"></div>
</el-card>
</template>
<script>
import AMapLoader from '@amap/amap-jsapi-loader';
import { MAP_KEY } from '@/config/setting';
export default {
data() {
return {
// 官网底部地图的实例
mapInsLocation: null
};
},
computed: {
// 是否是暗黑模式
darkMode() {
return this.$store?.state?.theme?.darkMode;
}
},
mounted() {
this.renderLocationMap();
},
methods: {
/* 渲染官网底部地图 */
renderLocationMap() {
AMapLoader.load({
key: MAP_KEY,
version: '2.0',
plugins: ['AMap.InfoWindow', 'AMap.Marker']
})
.then((AMap) => {
// 渲染地图
const option = {
zoom: 13, // 初缩放级别
center: [114.346084, 30.511215 + 0.005] // 初始中心点
};
if (this.darkMode) {
option.mapStyle = 'amap://styles/dark';
}
this.mapInsLocation = new AMap.Map(this.$refs.locationMap, option);
// 创建信息窗体
const infoWindow = new AMap.InfoWindow({
content: `
<div style="color: #333;">
<div style="padding: 5px;font-size: 16px;">武汉易云智科技有限公司</div>
<div style="padding: 0 5px;">地址: 湖北省武汉市洪山区雄楚大道222号</div>
<div style="padding: 0 5px;">电话: 020-123456789</div>
</div>
<a
style="padding: 8px 5px 0;text-decoration: none;display: inline-block;"
href="//uri.amap.com/marker?position=114.346084,30.511215&name=武汉易云智科技有限公司"
class="ele-text-primary"
target="_blank"
>到这里去→</a>
`
});
infoWindow.open(this.mapInsLocation, [114.346084, 30.511215]);
const icon = new AMap.Icon({
size: new AMap.Size(25, 34),
image:
'//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-red.png',
imageSize: new AMap.Size(25, 34)
});
const marker = new AMap.Marker({
icon: icon,
position: [114.346084, 30.511215],
offset: new AMap.Pixel(-12, -28)
});
marker.setMap(this.mapInsLocation);
marker.on('click', () => {
infoWindow.open(this.mapInsLocation);
});
})
.catch((e) => {
console.error(e);
});
}
},
watch: {
darkMode(value) {
if (this.mapInsLocation) {
if (value) {
this.mapInsLocation.setMapStyle('amap://styles/dark');
} else {
this.mapInsLocation.setMapStyle('amap://styles/normal');
}
}
}
},
unmounted() {
if (this.mapInsLocation) {
this.mapInsLocation.destroy();
}
}
};
</script>
@@ -1,76 +0,0 @@
<template>
<el-card shadow="never" header="地图位置选择器">
<div style="display: flex; align-items: center">
<div style="width: 140px; margin-right: 12px">
<el-select size="small" class="ele-fluid" v-model="searchType">
<el-option label="POI检索模式" :value="0" />
<el-option label="关键字检索模式" :value="1" />
</el-select>
</div>
<el-button size="small" class="ele-btn-icon" @click="openMapPicker">
打开地图位置选择器
</el-button>
</div>
<div style="margin-top: 12px">选择位置: {{ result.location }}</div>
<div style="margin-top: 12px">详细地址: {{ result.address }}</div>
<div style="margin-top: 12px"> : {{ result.coordinate }}</div>
<!-- 地图位置选择弹窗 -->
<ele-map-picker
:need-city="true"
:show.sync="visible"
:lock-scroll="false"
:close-on-click-modal="false"
:search-type="searchType"
:dark-mode="darkMode"
@done="onChoose"
/>
</el-card>
</template>
<script>
import EleMapPicker from 'ele-admin/es/ele-map-picker';
export default {
components: { EleMapPicker },
data() {
return {
// 是否显示地图选择弹窗
visible: false,
// 地点检索类型
searchType: 0,
// 选择结果
result: {
location: '',
address: '',
coordinate: ''
}
};
},
computed: {
// 是否是暗黑模式
darkMode() {
return this.$store?.state?.theme?.darkMode;
}
},
methods: {
/* 地图选择后回调 */
onChoose(location) {
console.log(location);
this.result = {
location: [
location.city.province,
location.city.city,
location.city.district
].join('/'),
address: location.name + ' ' + location.address,
coordinate: location.lng + ',' + location.lat
};
this.visible = false;
},
/* 打开地图选择弹窗 */
openMapPicker() {
this.visible = true;
}
}
};
</script>
@@ -1,151 +0,0 @@
<template>
<el-card shadow="never" header="轨迹回放">
<div ref="trackMap" style="max-width: 800px; height: 300px"></div>
<div style="margin-top: 15px">
<el-button size="small" @click="startTrackAnim">开始移动</el-button>
<el-button size="small" @click="pauseTrackAnim">暂停移动</el-button>
<el-button size="small" @click="resumeTrackAnim">继续移动</el-button>
</div>
</el-card>
</template>
<script>
import AMapLoader from '@amap/amap-jsapi-loader';
import { MAP_KEY } from '@/config/setting';
export default {
data() {
return {
// 小车轨迹地图的实例
mapInsTrack: null,
// 小车的 marker
carMarker: null,
// 轨迹路线
lineData: [
[116.478935, 39.997761],
[116.478939, 39.997825],
[116.478912, 39.998549],
[116.478912, 39.998549],
[116.478998, 39.998555],
[116.478998, 39.998555],
[116.479282, 39.99856],
[116.479658, 39.998528],
[116.480151, 39.998453],
[116.480784, 39.998302],
[116.480784, 39.998302],
[116.481149, 39.998184],
[116.481573, 39.997997],
[116.481863, 39.997846],
[116.482072, 39.997718],
[116.482362, 39.997718],
[116.483633, 39.998935],
[116.48367, 39.998968],
[116.484648, 39.999861]
]
};
},
computed: {
// 是否是暗黑模式
darkMode() {
return this.$store?.state?.theme?.darkMode;
}
},
mounted() {
this.renderTrackMap();
},
methods: {
/* 渲染轨迹回放地图 */
renderTrackMap() {
AMapLoader.load({
key: MAP_KEY,
version: '2.0',
plugins: ['AMap.MoveAnimation', 'AMap.Marker', 'AMap.Polyline']
})
.then((AMap) => {
// 渲染地图
const option = {
zoom: 17,
center: [116.478935, 39.997761]
};
if (this.darkMode) {
option.mapStyle = 'amap://styles/dark';
}
this.mapInsTrack = new AMap.Map(this.$refs.trackMap, option);
// 创建小车 marker
this.carMarker = new AMap.Marker({
map: this.mapInsTrack,
position: [116.478935, 39.997761],
icon: 'https://a.amap.com/jsapi_demos/static/demo-center-v2/car.png',
offset: new AMap.Pixel(-13, -26)
});
// 绘制轨迹
new AMap.Polyline({
map: this.mapInsTrack,
path: this.lineData,
showDir: true,
strokeColor: '#28F', // 线颜色
strokeOpacity: 1, // 线透明度
strokeWeight: 6 // 线宽
//strokeStyle: 'solid' // 线样式
});
// 通过的轨迹
const passedPolyline = new AMap.Polyline({
map: this.mapInsTrack,
showDir: true,
strokeColor: '#4B5', // 线颜色
strokeOpacity: 1, // 线透明度
strokeWeight: 6 // 线宽
});
// 小车移动回调
this.carMarker.on('moving', function (e) {
passedPolyline.setPath(e.passedPath);
});
// 地图自适应
this.mapInsTrack.setFitView();
})
.catch((e) => {
console.error(e);
});
},
/* 开始轨迹回放动画 */
startTrackAnim() {
if (this.carMarker) {
this.carMarker.stopMove();
this.carMarker.moveAlong(this.lineData, {
duration: 200,
autoRotation: true
});
}
},
/* 暂停轨迹回放动画 */
pauseTrackAnim() {
if (this.carMarker) {
this.carMarker.pauseMove();
}
},
/* 继续开始轨迹回放动画 */
resumeTrackAnim() {
if (this.carMarker) {
this.carMarker.resumeMove();
}
}
},
watch: {
darkMode(value) {
if (this.mapInsTrack) {
if (value) {
this.mapInsTrack.setMapStyle('amap://styles/dark');
} else {
this.mapInsTrack.setMapStyle('amap://styles/normal');
}
}
}
},
unmounted() {
if (this.mapInsTrack) {
this.mapInsTrack.destroy();
}
this.carMarker = null;
}
};
</script>
-18
View File
@@ -1,18 +0,0 @@
<template>
<div class="ele-body">
<demo-picker />
<demo-map />
<demo-track />
</div>
</template>
<script>
import DemoPicker from './components/demo-picker.vue';
import DemoMap from './components/demo-map.vue';
import DemoTrack from './components/demo-track.vue';
export default {
name: 'ExtensionMap',
components: { DemoPicker, DemoMap, DemoTrack }
};
</script>
@@ -1,103 +0,0 @@
<template>
<div class="ele-body">
<el-card shadow="never">
<!-- 按钮 -->
<div style="margin-bottom: 16px">
<el-button size="small" @click="setContent">修改内容</el-button>
<el-button size="small" @click="showText">获取内容</el-button>
</div>
<!-- 编辑器 -->
<byte-md-editor
:value="content"
:locale="zh_Hans"
:plugins="plugins"
:editorConfig="{ lineNumbers: true }"
class="ele-bytemd-wrap"
@change="handleChange"
/>
</el-card>
<!-- 内容弹窗 -->
<ele-modal width="400px" title="编辑器内容" :visible.sync="showViewContent">
<div>{{ content }}</div>
</ele-modal>
</div>
</template>
<script>
import { Editor as ByteMdEditor } from '@bytemd/vue';
// 中文语言文件
import zh_Hans from 'bytemd/lib/locales/zh_Hans.json';
// 链接、删除线、复选框、表格等的插件
import gfm from '@bytemd/plugin-gfm';
// 插件的中文语言文件
import zh_HansGfm from '@bytemd/plugin-gfm/lib/locales/zh_Hans.json';
// 编辑器css
import 'bytemd/dist/index.min.css';
// 预览界面的样式,这里用的github的markdown主题
import 'github-markdown-css/github-markdown-light.css';
export default {
name: 'ExtensionMarkdown',
components: { ByteMdEditor },
data() {
return {
zh_Hans,
// 编辑器内容
content: '',
// 插件
plugins: [
gfm({
locale: zh_HansGfm
})
],
showViewContent: false
};
},
methods: {
/* 更新内容 */
handleChange(value) {
this.content = value;
},
/* 修改编辑器内容 */
setContent() {
this.content = '> **EleAdminPro**后台管理模板';
},
/* 获取编辑器内容 */
showText() {
this.showViewContent = true;
}
}
};
</script>
<style lang="scss" scoped>
// 修改编辑器高度
.ele-bytemd-wrap :deep(.bytemd) {
height: calc(100vh - 290px);
// 修改全屏的 zIndex
&.bytemd-fullscreen {
z-index: 999;
}
// 去掉默认的最大宽度限制
.CodeMirror .CodeMirror-lines {
max-width: 100%;
}
pre.CodeMirror-line,
pre.CodeMirror-line-like {
padding: 0 24px;
}
.markdown-body {
max-width: 100%;
padding: 16px 24px;
}
// 去掉 github 图标
.bytemd-toolbar-right > .bytemd-toolbar-icon:last-child {
display: none;
}
}
</style>
-150
View File
@@ -1,150 +0,0 @@
<template>
<div class="ele-body">
<el-card shadow="never" header="水平导航">
<el-radio-group v-model="dark" size="small">
<el-radio-button :label="false">Light</el-radio-button>
<el-radio-button :label="true">Dark</el-radio-button>
</el-radio-group>
<div
style="margin: 15px 0 5px 0; overflow: auto"
class="ele-scrollbar-hide"
>
<div style="max-width: 600px" class="demo-menu-wrap">
<el-menu mode="horizontal" :class="themeClass" default-active="1-1">
<el-submenu index="1">
<template v-slot:title>
<i class="el-icon-s-tools"></i>
<span>系统管理</span>
</template>
<el-menu-item index="1-1">用户管理</el-menu-item>
<el-menu-item index="1-2">角色管理</el-menu-item>
<el-menu-item index="1-3">权限管理</el-menu-item>
</el-submenu>
<el-submenu index="2">
<template v-slot:title>
<i class="el-icon-s-opportunity"></i>
<span>日志管理</span>
</template>
<el-menu-item index="2-1">登录日志</el-menu-item>
<el-menu-item index="2-2">操作日志</el-menu-item>
<el-menu-item index="2-3">错误日志</el-menu-item>
</el-submenu>
<el-submenu index="3">
<template v-slot:title>
<i class="el-icon-s-order"></i>
<span>订单管理</span>
</template>
<el-menu-item index="3-1">
<i class="el-icon-s-opportunity"></i>
<span>订单查询</span>
</el-menu-item>
<el-menu-item index="3-2">
<i class="el-icon-s-opportunity"></i>
<span>退款记录</span>
</el-menu-item>
<el-menu-item index="3-3">
<i class="el-icon-s-opportunity"></i>
<span>订单报表</span>
</el-menu-item>
</el-submenu>
<el-menu-item index="4">
<i class="el-icon-s-opportunity"></i>
<span>订单报表</span>
</el-menu-item>
</el-menu>
</div>
</div>
</el-card>
<el-card shadow="never" header="垂直导航">
<el-radio-group v-model="collapse" size="small">
<el-radio-button :label="false">展开</el-radio-button>
<el-radio-button :label="true">折叠</el-radio-button>
</el-radio-group>
<div style="max-width: 200px; margin: 15px 0 5px 0">
<el-menu
mode="vertical"
default-active="4"
:class="themeClass"
:collapse="collapse"
>
<el-submenu index="1" :popper-class="themeClass">
<template v-slot:title>
<i class="el-icon-s-tools"></i>
<span>系统管理</span>
</template>
<el-menu-item index="1-1">用户管理</el-menu-item>
<el-menu-item index="1-2">角色管理</el-menu-item>
<el-menu-item index="1-3">权限管理</el-menu-item>
</el-submenu>
<el-submenu index="2" :popper-class="themeClass">
<template v-slot:title>
<i class="el-icon-s-opportunity"></i>
<span>日志管理</span>
</template>
<el-menu-item index="2-1">登录日志</el-menu-item>
<el-menu-item index="2-2">操作日志</el-menu-item>
<el-menu-item index="2-3">错误日志</el-menu-item>
</el-submenu>
<el-submenu index="3" :popper-class="themeClass">
<template v-slot:title>
<i class="el-icon-s-order"></i>
<span>订单管理</span>
</template>
<el-menu-item index="3-1">
<i class="el-icon-s-opportunity"></i>
<span>订单查询</span>
</el-menu-item>
<el-menu-item index="3-2">
<i class="el-icon-s-opportunity"></i>
<span>退款记录</span>
</el-menu-item>
<el-menu-item index="3-3">
<i class="el-icon-s-opportunity"></i>
<span>订单报表</span>
</el-menu-item>
</el-submenu>
<el-menu-item index="4">
<i class="el-icon-s-opportunity"></i>
<template v-slot:title>
<span>订单报表</span>
</template>
</el-menu-item>
</el-menu>
</div>
</el-card>
</div>
</template>
<script>
export default {
name: 'ExtensionMenu',
data() {
return {
dark: false,
collapse: false
};
},
computed: {
themeClass() {
return this.dark ? 'ele-menu-dark' : '';
}
}
};
</script>
<style lang="scss" scoped>
/* 水平菜单超出不换行显示横向滚动条 */
.demo-menu-wrap {
overflow-x: auto;
overflow-y: hidden;
:deep(.el-menu) {
white-space: nowrap;
& > li {
float: none;
display: inline-block;
}
}
}
</style>
@@ -1,201 +0,0 @@
<template>
<div class="ele-body">
<el-card shadow="never" header="消息提示">
<div style="margin: 0 0 10px 0">边框风格</div>
<div class="ele-action-group">
<el-button size="small" @click="showSuccessMessage(true)">
成功
</el-button>
<el-button size="small" @click="showWarningMessage(true)">
警告
</el-button>
<el-button size="small" @click="showErrorMessage(true)">错误</el-button>
<el-button size="small" @click="showInfoMessage(true)">消息</el-button>
</div>
<div style="margin: 20px 0 10px 0">清新风格</div>
<div class="ele-action-group">
<el-button size="small" @click="showSuccessMessage(false)">
成功
</el-button>
<el-button size="small" @click="showWarningMessage(false)">
警告
</el-button>
<el-button size="small" @click="showErrorMessage(false)">
错误
</el-button>
<el-button size="small" @click="showInfoMessage(false)">消息</el-button>
</div>
<div>
<div style="margin: 20px 0 10px 0">loading</div>
<div class="ele-action-group">
<el-button size="small" @click="showLoadingMessage1">
Loading
</el-button>
<el-button size="small" @click="showLoadingMessage2">
加遮罩层
</el-button>
<el-button size="small" @click="showLoadingMessage3">
居中显示
</el-button>
</div>
</div>
</el-card>
<el-card
shadow="never"
header="警告组件"
body-style="padding: 20px 20px 0 20px;"
>
<el-row :gutter="20">
<el-col
v-bind="styleResponsive ? { md: 6, sm: 12, xs: 24 } : { span: 6 }"
>
<el-alert
show-icon
type="success"
title="Success Tips"
class="ele-alert-border"
/>
<el-alert
show-icon
type="success"
title="Success Tips"
class="ele-alert-border"
description="Detailed description and advice about successful copywriting."
/>
</el-col>
<el-col
v-bind="styleResponsive ? { md: 6, sm: 12, xs: 24 } : { span: 6 }"
>
<el-alert
show-icon
type="info"
class="ele-alert-border"
title="Informational Notes"
/>
<el-alert
show-icon
type="info"
class="ele-alert-border"
title="Informational Notes"
description="Additional description and information about copywriting."
/>
</el-col>
<el-col
v-bind="styleResponsive ? { md: 6, sm: 12, xs: 24 } : { span: 6 }"
>
<el-alert
show-icon
type="warning"
title="Warning"
class="ele-alert-border"
/>
<el-alert
show-icon
type="warning"
title="Warning"
class="ele-alert-border"
description="This is a warning notice about copywriting."
/>
</el-col>
<el-col
v-bind="styleResponsive ? { md: 6, sm: 12, xs: 24 } : { span: 6 }"
>
<el-alert
show-icon
type="error"
title="Error"
class="ele-alert-border"
/>
<el-alert
show-icon
type="error"
title="Error"
class="ele-alert-border"
description="This is an error message about copywriting."
/>
</el-col>
</el-row>
</el-card>
</div>
</template>
<script>
export default {
name: 'ExtensionMessage',
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
},
methods: {
showSuccessMessage(border) {
this.$message({
type: 'success',
message: '这是一条成功的提示',
customClass: border ? 'ele-message-border' : ''
});
},
showWarningMessage(border) {
this.$message({
type: 'warning',
message: '这是一条警告的提示',
customClass: border ? 'ele-message-border' : ''
});
},
showErrorMessage(border) {
if (border) {
this.$message({
type: 'error',
message: '这是一条错误的提示',
customClass: 'ele-message-border'
});
} else {
this.$message.error('这是一条错误的提示');
}
},
showInfoMessage(border) {
if (border) {
this.$message({
type: 'info',
message: '这是一条普通的提示',
customClass: 'ele-message-border'
});
} else {
this.$message.info('这是一条普通的提示');
}
},
showLoadingMessage1() {
const loading = this.$messageLoading('正在加载中..');
setTimeout(() => {
loading.close();
}, 3000);
},
showLoadingMessage2() {
const loading = this.$messageLoading({
message: '正在加载中..',
background: true
});
setTimeout(() => {
loading.close();
}, 3000);
},
showLoadingMessage3() {
const loading = this.$messageLoading({
message: '正在加载中..',
background: true,
center: true
});
setTimeout(() => {
loading.close();
}, 3000);
}
}
};
</script>
<style lang="scss" scoped>
.ele-alert-border {
margin-bottom: 20px;
}
</style>
@@ -1,82 +0,0 @@
<template>
<el-card shadow="never" header="基础演示">
<!-- 操作按钮 -->
<div style="margin-bottom: 10px" class="ele-action-group">
<el-button size="mini" :disabled="!ready" @click="play">播放</el-button>
<el-button size="mini" :disabled="!ready" @click="pause">暂停</el-button>
<el-button size="mini" :disabled="!ready" @click="replay">
重新播放
</el-button>
<el-button size="mini" :disabled="!ready" @click="changeSrc">
切换视频源
</el-button>
</div>
<!-- 播放器 -->
<xgplayer :config="config" @player="onPlayer" />
</el-card>
</template>
<script>
import Xgplayer from 'xgplayer-vue';
export default {
components: { Xgplayer },
data() {
return {
// 视频播放器配置
config: {
id: 'demoPlayer1',
lang: 'zh-cn',
// 宽度 100%
fluid: true,
// 视频地址
url: 'https://s1.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/xgplayer-demo.mp4',
// 封面
poster:
'https://imgcache.qq.com/open_proj/proj_qcloud_v2/gateway/solution/general-video/css/img/scene/1.png',
// 开启倍速播放
playbackRate: [0.5, 1, 1.5, 2],
// 开启画中画
pip: true
},
// 视频播放器实例
player: null,
// 视频播放器是否实例化完成
ready: false
};
},
methods: {
/* 播放器渲染完成 */
onPlayer(e) {
this.player = e;
this.player.on('play', () => {
this.ready = true;
});
},
/* 播放 */
play() {
if (this.player.paused) {
this.player.play();
}
},
/* 暂停 */
pause() {
if (!this.player.paused) {
this.player.pause();
}
},
/* 重新播放 */
replay() {
this.player.replay();
},
/* 切换视频源 */
changeSrc() {
this.player.src =
'https://blz-videos.nosdn.127.net/1/OverWatch/AnimatedShots/Overwatch_TheatricalTeaser_WeAreOverwatch_zhCN.mp4';
if (this.player.paused) {
this.player.play();
}
}
}
};
</script>
@@ -1,243 +0,0 @@
<template>
<el-card shadow="never" header="弹幕功能">
<!-- 操作按钮 -->
<div style="margin-bottom: 10px" class="ele-action-group">
<div style="display: inline-block; width: 160px" class="ele-action">
<el-input
v-model="text"
placeholder="请输入弹幕内容"
size="mini"
:disabled="!ready"
/>
</div>
<el-button size="mini" :disabled="!ready" @click="shoot">发射</el-button>
</div>
<!-- 播放器 -->
<xgplayer :config="config" @player="onPlayer" />
</el-card>
</template>
<script>
import Xgplayer from 'xgplayer-vue';
export default {
components: { Xgplayer },
data() {
return {
// 视频播放器配置
config: {
id: 'demoPlayer2',
lang: 'zh-cn',
fluid: true,
url: 'https://blz-videos.nosdn.127.net/1/OverWatch/AnimatedShots/Overwatch_TheatricalTeaser_WeAreOverwatch_zhCN.mp4',
poster:
'https://imgcache.qq.com/open_proj/proj_qcloud_v2/gateway/solution/general-video/css/img/scene/1.png',
danmu: {
comments: [
{
id: '1',
start: 0,
txt: '空降',
duration: 15000,
color: true,
style: {
color: '#ffcd08',
fontSize: '20px'
}
},
{
id: '2',
start: 1500,
txt: '前方高能',
duration: 15000,
color: true,
style: {
color: '#ffcd08',
fontSize: '20px'
}
},
{
id: '3',
start: 3500,
txt: '弹幕护体',
duration: 15000,
color: true,
style: {
color: '#ffcd08',
fontSize: '20px'
}
},
{
id: '4',
start: 4500,
txt: '弹幕护体',
duration: 15000,
color: true,
style: {
color: '#ffcd08',
fontSize: '20px'
}
},
{
id: '5',
start: 6000,
txt: '前方高能',
duration: 15000,
color: true,
style: {
color: '#ffcd08',
fontSize: '20px'
}
},
{
id: '6',
start: 8500,
txt: '弹幕护体',
duration: 15000,
color: true,
style: {
color: '#ffcd08',
fontSize: '20px'
}
},
{
id: '7',
start: 10000,
txt: '666666666',
duration: 15000,
color: true,
style: {
color: '#ffcd08',
fontSize: '20px'
}
},
{
id: '8',
start: 12500,
txt: '前方高能',
duration: 15000,
color: true,
style: {
color: '#ffcd08',
fontSize: '20px'
}
},
{
id: '9',
start: 15500,
txt: '666666666',
duration: 15000,
color: true,
style: {
color: '#ffcd08',
fontSize: '20px'
}
},
{
id: '10',
start: 16500,
txt: '666666666',
duration: 15000,
color: true,
style: {
color: '#ffcd08',
fontSize: '20px'
}
},
{
id: '11',
start: 18000,
txt: '关弹幕, 保智商',
duration: 15000,
color: true,
style: {
color: '#ffcd08',
fontSize: '20px'
}
},
{
id: '12',
start: 20500,
txt: '关弹幕, 保智商',
duration: 15000,
color: true,
style: {
color: '#ffcd08',
fontSize: '20px'
}
},
{
id: '13',
start: 22000,
txt: '666666666',
duration: 15000,
color: true,
style: {
color: '#ffcd08',
fontSize: '20px'
}
},
{
id: '14',
start: 25500,
txt: '666666666',
duration: 15000,
color: true,
style: {
color: '#ffcd08',
fontSize: '20px'
}
},
{
id: '15',
start: 26000,
txt: '前方高能',
duration: 15000,
color: true,
style: {
color: '#ffcd08',
fontSize: '20px'
}
}
]
}
},
// 视频播放器实例
player: null,
// 视频播放器是否实例化完成
ready: false,
// 弹幕输入内容
text: ''
};
},
methods: {
/* 播放器渲染完成 */
onPlayer(e) {
this.player = e;
this.player.on('play', () => {
this.ready = true;
});
},
/* 发射弹幕 */
shoot() {
if (!this.text) {
this.$message.error('请输入弹幕内容');
return;
}
this.player.danmu.sendComment({
id: new Date().getTime(),
duration: 15000,
color: true,
start: this.player.currentTime * 1000,
txt: this.text,
style: {
color: '#fa1f41',
fontSize: '20px',
border: 'solid 1px #fa1f41'
}
});
this.text = '';
}
}
};
</script>
@@ -1,34 +0,0 @@
<template>
<div class="ele-body ele-body-card">
<el-row :gutter="15">
<el-col v-bind="styleResponsive ? { md: 12 } : { span: 12 }">
<demo-basic />
</el-col>
<el-col v-bind="styleResponsive ? { md: 12 } : { span: 12 }">
<demo-danmu />
</el-col>
</el-row>
</div>
</template>
<script>
import DemoBasic from './components/demo-basic.vue';
import DemoDanmu from './components/demo-danmu.vue';
export default {
name: 'ExtensionPlayer',
components: { DemoBasic, DemoDanmu },
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
}
};
</script>
<style>
.xgplayer-skin-default .xgplayer-pip {
margin: -1px 0 0 10px;
}
</style>
@@ -1,211 +0,0 @@
<template>
<el-card shadow="never" header="进阶示例">
<el-button size="small" @click="printDataTable">打印数据表格</el-button>
<el-button size="small" @click="printAnyTable">打印复杂表格</el-button>
<el-button size="small" @click="printPdfUrl">打印 pdf</el-button>
</el-card>
</template>
<script>
import { printHtml, printPdf, makeTable } from 'ele-admin';
export default {
data() {
return {
users: [
{
key: 1,
username: '张小三',
amount: 18,
province: '浙江',
city: '杭州',
zone: '西湖区',
street: '西溪街道',
address: '西溪花园30栋1单元'
},
{
key: 2,
username: '李小四',
amount: 39,
province: '江苏',
city: '苏州',
zone: '姑苏区',
street: '丝绸路',
address: '天墅之城9幢2单元'
},
{
key: 3,
username: '王小五',
amount: 8,
province: '江西',
city: '南昌',
zone: '青山湖区',
street: '艾溪湖办事处',
address: '中兴和园1幢3单元'
},
{
key: 4,
username: '赵小六',
amount: 16,
province: '福建',
city: '泉州',
zone: '丰泽区',
street: '南洋街道',
address: '南洋村6幢1单元'
},
{
key: 5,
username: '孙小七',
amount: 12,
province: '湖北',
city: '武汉',
zone: '武昌区',
street: '武昌大道',
address: '两湖花园16幢2单元'
},
{
key: 6,
username: '周小八',
amount: 11,
province: '安徽',
city: '黄山',
zone: '黄山区',
street: '汤口镇',
address: '温泉村21号'
}
]
};
},
methods: {
/* 打印数据表格 */
printDataTable() {
const html = makeTable(this.users, [
[
{
field: 'username',
width: 150,
rowspan: 2,
title: '联系人'
},
{
align: 'center',
colspan: 3,
title: '地址'
},
{
field: 'amount',
width: 120,
rowspan: 2,
title: '金额',
align: 'center'
}
],
[
{
field: 'province',
width: 120,
title: '省'
},
{
field: 'city',
width: 120,
title: '市'
},
{
width: 200,
title: '区',
templet: (d) => {
return `<span style="color: red;">${d.zone}</span>`;
}
}
]
]);
printHtml({
html: '<p>提供数据和cols配置自动生成复杂表格, 非常的方便</p>' + html,
loading: false
});
},
/* 打印自定义表格 */
printAnyTable() {
const html = `
<h2 style="text-align: center;color: #333;">XXXXX班级课程表</h2>
<table class="ele-printer-table">
<colgroup>
<col width="130px"/>
</colgroup>
<tr>
<th style="position: relative;">
<div style="position: absolute;right: 20px;top: 10px;line-height: normal;">星期</div>
<div style="position: absolute;left: 20px;bottom: 10px;line-height: normal;">时间</div>
<div
style="border-top: 1px solid #000; width:141px;height: 0;position: absolute;left: 0;top: 0;transform: rotate(22deg);transform-origin: 0 0;">
</div>
</th>
<th>周一</th>
<th>周二</th>
<th>周三</th>
<th>周四</th>
<th>周五</th>
</tr>
<tr>
<td>8:00-10:00</td>
<td>HTML5网页设计<br/>曲丽丽 - 441教室</td>
<td>数据库原理及应用<br/>严良 - 716机房</td>
<td>JavaSE初级程序设计<br/>肖萧 - 715机房</td>
<td></td>
<td>JavaScript程序设计<br/>董娜 - 733机房</td>
</tr>
<tr>
<td>10:30-12:30</td>
<td></td>
<td>JavaScript程序设计<br/>董娜 - 733机房</td>
<td></td>
<td>锋利的jQuery<br/>程咏 - 303教室</td>
<td>JavaEE应用开发<br/>周星 - 303教室</td>
</tr>
<tr>
<td colspan="6" style="height: auto;">午休</td>
</tr>
<tr>
<td>13:30-15:30</td>
<td>JavaSE初级程序设计<br/>肖萧 - 715机房</td>
<td></td>
<td>HTML5网页设计<br/>曲丽丽 - 441教室</td>
<td></td>
<td></td>
</tr>
<tr>
<td>16:00-18:00</td>
<td></td>
<td>JavaEE应用开发<br/>周星 - 303教室</td>
<td></td>
<td>数据库原理及应用<br/>严良 - 716机房</td>
<td></td>
</tr>
</table>
<style>
th, td {
text-align: center;
line-height: 35px;
}
td {
height: 100px;
}
</style>
`;
printHtml({
html: html,
horizontal: true,
title: '.',
loading: false
});
},
/* 打印pdf */
printPdfUrl() {
printPdf({
url: 'https://cdn.eleadmin.com/20200610/20200708224450.pdf'
});
}
}
};
</script>
@@ -1,73 +0,0 @@
<template>
<el-card shadow="never" header="打印指定区域">
<div ref="printRef" class="demo-print-group">
<div class="demo-print-div">
<div>示例示例示例示例示例</div>
<div class="demo-hide-2" style="font-size: 12px; margin-top: 8px">
此段内容不打印
</div>
</div>
<div class="demo-print-right ele-bg-white">
<div>
<el-tag size="mini">示例</el-tag>
<el-tag size="mini" type="success">示例</el-tag>
<el-tag size="mini" type="warning">示例</el-tag>
</div>
<div style="margin-top: 12px">
<el-input v-model="value" />
</div>
</div>
</div>
<div style="margin-top: 20px">
<el-button size="small" @click="print">打印</el-button>
</div>
</el-card>
</template>
<script>
import { printElement } from 'ele-admin';
export default {
data() {
return {
value: '示例示例示例'
};
},
methods: {
print() {
printElement(this.$refs.printRef, { hide: ['.demo-hide-2'] });
}
}
};
</script>
<style lang="scss" scoped>
.demo-print-group {
display: flex;
align-items: center;
}
.demo-print-div {
background: #096dd9;
color: #fff;
font-size: 18px;
text-align: center;
padding: 40px 0;
flex: 1;
border: 2px solid #096dd9;
height: 120px;
box-sizing: border-box;
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
}
.demo-print-right {
flex: 1;
padding: 20px;
border: 2px solid #096dd9;
height: 120px;
box-sizing: border-box;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
}
</style>
@@ -1,75 +0,0 @@
<template>
<el-card shadow="never" header="打印任意内容">
<el-form label-width="64px">
<el-form-item label="loading">
<el-radio-group v-model="option.loading">
<el-radio :label="false">不显示</el-radio>
<el-radio :label="true">显示</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<el-button size="small" @click="printAnyHtml">打印任意内容</el-button>
<el-button size="small" @click="printAddHeader">设置页眉页脚</el-button>
<el-button size="small" @click="printImage">打印图片</el-button>
</el-card>
</template>
<script>
import { printHtml } from 'ele-admin';
export default {
data() {
return {
// 打印任意内容参数
option: {
loading: false
}
};
},
methods: {
/* 打印任意内容 */
printAnyHtml() {
printHtml({
...this.option,
html: [
'<h1 style="color: #1890ff;">EleAdmin 后台管理模板</h1>',
'<div style="color: #F51D2C;">通用型后台管理模板, 界面美观、开箱即用</div>'
].join('')
});
},
/* 打印设置页眉页脚 */
printAddHeader() {
printHtml({
...this.option,
margin: 0,
html: [
'<div style="padding: 0 60px;">',
Array(38).join('<h3>EleAdmin 后台管理模板</h3>'),
'</div>'
].join(''),
header: `
<div style="display: flex;font-size: 12px;padding: 15px 30px 25px;">
<div>我是页眉左侧</div>
<div style="flex: 1;text-align: center;">我是页眉</div>
<div>我是页眉右侧</div>
</div>`,
footer: `
<div style="display: flex;font-size: 12px;padding: 15px 30px 25px;">
<div>我是页脚左侧</div>
<div style="flex: 1;text-align: center;">我是页脚</div>
<div>我是页脚右侧</div>
</div>`,
style: '<style> h3 {color: red;} </style>'
});
},
/* 打印图片 */
printImage() {
printHtml({
...this.option,
margin: 0,
html: '<img src="https://cdn.eleadmin.com/20200610/LrCTN2j94lo9N7wEql7cBr1Ux4rHMvmZ.jpg" style="width: 100%;"/>'
});
}
}
};
</script>
@@ -1,57 +0,0 @@
<template>
<el-card shadow="never" header="分页打印">
<el-button size="small" @click="printAnyPage">分页打印</el-button>
<el-button size="small" @click="printPageAddHeader">设置页眉页脚</el-button>
</el-card>
</template>
<script>
import { printPage } from 'ele-admin';
export default {
methods: {
/* 分页打印 */
printAnyPage() {
printPage({
pages: [
'<h3>我是第一页</h3>',
'<h3>我是第二页</h3>',
'<h3>我是第三页</h3>',
'<h3>我是第四页</h3>',
'<h3>我是第五页</h3>'
],
style: '<style> h3 { color: red; } </style>',
loading: false
});
},
/* 分页打印设置页眉页脚 */
printPageAddHeader() {
printPage({
pages: [
'<h3>我是第一页</h3>',
'<h3>我是第二页</h3>',
'<h3>我是第三页</h3>',
'<h3>我是第四页</h3>',
'<h3>我是第五页</h3>'
],
margin: 0,
padding: '20px 60px',
header: `
<div style="display: flex;font-size: 12px;padding: 15px 30px;">
<div>我是页眉左侧</div>
<div style="flex: 1;text-align: center;">我是页眉</div>
<div>我是页眉右侧</div>
</div>`,
footer: `
<div style="display: flex;font-size: 12px;padding: 15px 30px;">
<div>我是页脚左侧</div>
<div style="flex: 1;text-align: center;">我是页脚</div>
<div>我是页脚右侧</div>
</div>`,
style: '<style> h3 { color: red; } </style>',
loading: false
});
}
}
};
</script>
@@ -1,72 +0,0 @@
<template>
<el-card shadow="never" header="打印当前页面">
<el-form label-width="80px" size="small" style="max-width: 320px">
<el-form-item label="纸张方向">
<el-select
clearable
class="ele-block"
v-model="option.horizontal"
placeholder="不设置"
>
<el-option label="横向" :value="true" />
<el-option label="纵向" :value="false" />
</el-select>
</el-form-item>
<el-form-item label="页面间距">
<el-select
clearable
class="ele-block"
v-model="option.margin"
placeholder="不设置"
>
<el-option label="0px" value="0px" />
<el-option label="50px" value="50px" />
<el-option label="100px" value="100px" />
</el-select>
</el-form-item>
<el-form-item label="页面标题">
<el-input clearable v-model="option.title" placeholder="不设置" />
</el-form-item>
</el-form>
<el-button size="small" @click="print">打印</el-button>
<el-button size="small" @click="printHide">打印隐藏指定内容</el-button>
<div style="margin-top: 15px">
<span class="ele-text-primary ele-printer-hide">
此段内容在所有打印时隐藏, 打印完复原
</span>
<span class="ele-text-danger demo-hide-1">
此段内容在指定打印时才隐藏
</span>
</div>
</el-card>
</template>
<script>
import { printThis } from 'ele-admin';
export default {
data() {
return {
// 打印当前页面参数
option: {
horizontal: null,
margin: null,
title: ''
}
};
},
methods: {
/* 打印当前页面 */
print() {
printThis(this.option1);
},
/* 打印隐藏指定内容 */
printHide() {
printThis({
...this.option1,
hide: ['.demo-hide-1']
});
}
}
};
</script>
@@ -1,28 +0,0 @@
<template>
<div class="ele-body">
<print-this />
<print-div />
<print-html />
<print-page />
<print-advanced />
</div>
</template>
<script>
import PrintThis from './components/print-this.vue';
import PrintDiv from './components/print-div.vue';
import PrintHtml from './components/print-html.vue';
import PrintPage from './components/print-page.vue';
import PrintAdvanced from './components/print-advanced.vue';
export default {
name: 'ExtensionPrinter',
components: {
PrintThis,
PrintDiv,
PrintHtml,
PrintPage,
PrintAdvanced
}
};
</script>
@@ -1,193 +0,0 @@
<template>
<div class="ele-body">
<el-card shadow="never" header="二维码" style="overflow: visible">
<div ref="printRef" class="demo-qrcode-images ele-bg-white">
<div class="demo-qrcode-image-item">
<div class="demo-qr-code-title">canvas 渲染</div>
<ele-qr-code
:value="text"
:size="size"
:level="level"
:margin="margin"
:image-settings="image"
/>
</div>
<div class="demo-qrcode-image-item">
<div class="demo-qr-code-title">svg 渲染</div>
<ele-qr-code-svg
:value="text"
:size="size"
:level="level"
:margin="margin"
:image-settings="image"
/>
</div>
</div>
<el-form label-width="88px" style="max-width: 340px">
<el-form-item label="二维码内容">
<el-input v-model="text" :maxlength="150" />
</el-form-item>
<el-form-item label="容错等级">
<el-select v-model="level" class="ele-fluid">
<el-option value="L" label="L" />
<el-option value="M" label="M" />
<el-option value="Q" label="Q" />
<el-option value="H" label="H" />
</el-select>
</el-form-item>
<el-form-item label="尺寸">
<el-slider v-model="size" :min="80" :max="280" :step="40" />
</el-form-item>
<el-form-item label="间距">
<el-slider v-model="margin" :min="0" :max="20" />
</el-form-item>
<el-form-item label="自定义图片">
<el-switch v-model="showImage" @change="onShowImageChange" />
</el-form-item>
<template v-if="showImage">
<el-form-item label="图片地址">
<el-input v-model="image.src" :maxlength="400" />
</el-form-item>
<el-form-item label="图片宽高">
<div class="ele-cell">
<div style="width: 80px; margin-right: 20px">
<el-input-number
v-model="image.width"
size="mini"
:min="0"
:max="size"
controls-position="right"
class="ele-fluid"
/>
</div>
<div style="width: 80px">
<el-input-number
v-model="image.height"
size="mini"
:min="0"
:max="size"
controls-position="right"
class="ele-fluid"
/>
</div>
</div>
</el-form-item>
<el-form-item label="位置居中">
<div class="ele-cell" style="min-height: 36px">
<el-switch v-model="center" @change="onCenterChange" />
<template v-if="!center">
<div style="padding: 0 10px">x</div>
<div style="width: 80px">
<el-input-number
v-model="image.x"
size="mini"
:min="0"
:max="size"
controls-position="right"
class="ele-fluid"
/>
</div>
<div style="padding: 0 10px">y</div>
<div style="width: 80px">
<el-input-number
v-model="image.y"
size="mini"
:min="0"
:max="size"
controls-position="right"
class="ele-fluid"
/>
</div>
</template>
</div>
</el-form-item>
<el-form-item label="背景擦除">
<el-switch v-model="image.excavate" />
</el-form-item>
<el-form-item>
<div>
<el-button type="primary" @click="print">打印</el-button>
</div>
</el-form-item>
</template>
</el-form>
</el-card>
</div>
</template>
<script>
import EleQrCode from 'ele-admin/es/ele-qr-code';
import EleQrCodeSvg from 'ele-admin/es/ele-qr-code-svg';
import { printElement } from 'ele-admin';
const IMAGE_SRC = 'https://cdn.eleadmin.com/20200610/logo-radius.png';
export default {
name: 'ExtensionQrCode',
components: { EleQrCode, EleQrCodeSvg },
data() {
return {
text: 'https://eleadmin.com',
level: 'L',
size: 120,
margin: 0,
showImage: true,
image: {
src: IMAGE_SRC,
width: 28,
height: 28,
x: undefined,
y: undefined,
excavate: false
},
center: true
};
},
methods: {
onShowImageChange(checked) {
if (checked) {
this.image.src = IMAGE_SRC;
} else {
this.image.src = undefined;
}
},
onCenterChange(checked) {
if (checked) {
this.image.x = undefined;
this.image.y = undefined;
} else {
this.image.x = 0;
this.image.y = 0;
}
},
print() {
printElement(this.$refs.printRef);
}
}
};
</script>
<style lang="scss" scoped>
.demo-qrcode-images {
display: flex;
padding-bottom: 16px;
margin-bottom: 4px;
position: sticky;
top: 0;
overflow: auto;
z-index: 1002;
.demo-qrcode-image-item {
padding: 0 20px;
.demo-qr-code-title {
margin-bottom: 6px;
}
}
}
@media screen and (max-width: 768px) {
.demo-qrcode-images .demo-qrcode-image-item {
padding: 0 10px;
}
}
</style>
@@ -1,60 +0,0 @@
<template>
<div class="ele-body">
<el-card shadow="never" header="省市区级联选择">
<div style="max-width: 280px">
<regions-select
v-model="city"
placeholder="请选择省市区"
class="ele-fluid"
/>
</div>
</el-card>
<el-card shadow="never" header="省市级联选择">
<div style="max-width: 280px">
<regions-select
v-model="provinceCity"
placeholder="请选择省市"
type="provinceCity"
class="ele-fluid"
/>
</div>
</el-card>
<el-card shadow="never" header="省选择">
<div style="max-width: 280px">
<regions-select
v-model="province"
placeholder="请选择省"
type="province"
class="ele-fluid"
/>
</div>
</el-card>
<el-card shadow="never" header="可多选">
<div style="max-width: 280px">
<regions-select
v-model="citys"
placeholder="请选择省市区"
:props="{ multiple: true }"
class="ele-fluid"
/>
</div>
</el-card>
</div>
</template>
<script>
import RegionsSelect from '@/components/RegionsSelect/index.vue';
export default {
name: 'ExtensionRegions',
components: { RegionsSelect },
data() {
return {
city: [],
provinceCity: [],
province: [],
citys: []
};
}
};
</script>
-179
View File
@@ -1,179 +0,0 @@
<template>
<div class="ele-body">
<el-card shadow="never" header="基本用法">
<div class="option-item">
<div>显示折叠按钮:</div>
<div class="option-item-body">
<el-radio-group v-model="allowCollapse">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
</div>
</div>
<div class="option-item">
<div>支持自由拉伸:</div>
<div class="option-item-body">
<el-radio-group v-model="resizable">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
</div>
</div>
<div class="option-item">
<div>上下布局模式:</div>
<div class="option-item-body">
<el-radio-group v-model="vertical">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
</div>
</div>
<div class="option-item">
<div>反转布局方向:</div>
<div class="option-item-body">
<el-radio-group v-model="reverse">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
</div>
</div>
<ele-split-layout
space="0px"
:allow-collapse="allowCollapse"
:resizable="resizable"
:vertical="vertical"
:reverse="reverse"
:min-size="40"
:left-style="{
background: 'rgba(185, 182, 229, .4)',
overflow: 'hidden'
}"
:right-style="{
background: 'rgba(125, 226, 252, .4)',
overflow: 'hidden'
}"
style="height: 480px; margin-top: 12px"
>
<div>边栏</div>
<template #content>
<div>内容</div>
</template>
</ele-split-layout>
</el-card>
<el-card shadow="never" header="组合使用">
<div style="margin: 0 0 8px 0">先左右再上下</div>
<ele-split-layout
space="0px"
:resizable="true"
:min-size="40"
:max-size="-40"
:left-style="{
background: 'rgba(185, 182, 229, .4)',
overflow: 'hidden'
}"
:right-style="{ overflow: 'hidden' }"
:responsive="false"
style="height: 400px"
>
<div>边栏</div>
<template #content>
<ele-split-layout
space="0px"
width="240px"
:min-size="40"
:max-size="-40"
:resizable="true"
:vertical="true"
:left-style="{
background: 'rgba(171, 199, 255, .5)',
overflow: 'hidden'
}"
:right-style="{
background: 'rgba(125, 226, 252, .4)',
overflow: 'hidden'
}"
:responsive="false"
style="height: 400px"
>
<div>内容一</div>
<template #content>
<div>内容二</div>
</template>
</ele-split-layout>
</template>
</ele-split-layout>
<div style="margin: 16px 0 8px 0">先上下再左右</div>
<ele-split-layout
space="0px"
width="120px"
:min-size="40"
:max-size="-40"
:vertical="true"
:resizable="true"
:left-style="{
background: 'rgba(185, 182, 229, .4)',
overflow: 'hidden'
}"
:right-style="{ overflow: 'hidden' }"
:responsive="false"
style="height: 400px"
>
<div>顶栏</div>
<template #content>
<ele-split-layout
space="0px"
:min-size="40"
:max-size="-40"
:resizable="true"
:left-style="{
background: 'rgba(171, 199, 255, .5)',
overflow: 'hidden'
}"
:right-style="{
background: 'rgba(125, 226, 252, .4)',
overflow: 'hidden'
}"
:responsive="false"
style="height: 100%"
>
<div>边栏</div>
<template #content>
<div>内容</div>
</template>
</ele-split-layout>
</template>
</ele-split-layout>
</el-card>
</div>
</template>
<script>
export default {
name: 'ExtensionSplit',
data() {
return {
allowCollapse: true,
resizable: false,
vertical: false,
reverse: false
};
}
};
</script>
<style lang="scss" scoped>
.option-item {
display: flex;
align-items: center;
.option-item-body {
flex: 1;
padding-left: 12px;
display: flex;
}
& + .option-item {
margin-top: 6px;
}
}
</style>
-112
View File
@@ -1,112 +0,0 @@
<template>
<div class="ele-body">
<el-card shadow="never" header="水平步骤条" body-style="overflow: auto;">
<div style="min-width: 520px">
<div class="demo-steps-item">
<el-steps :active="stepsActive" class="ele-steps-horizontal">
<el-step title="第一步" />
<el-step title="第二步" />
<el-step title="第三步" />
<el-step title="第四步" />
</el-steps>
</div>
<div class="demo-steps-item">
<el-steps :active="stepsActive" class="ele-steps-horizontal">
<el-step title="第一步" description="这里是该步骤的描述信息" />
<el-step title="第二步" description="这里是该步骤的描述信息" />
<el-step title="第三步" description="这里是该步骤的描述信息" />
<el-step title="第四步" description="这里是该步骤的描述信息" />
</el-steps>
</div>
<div class="demo-steps-item">
<el-button @click="stepsPrev" size="small">上一步</el-button>
<el-button type="primary" @click="stepsNext" size="small">
下一步
</el-button>
</div>
</div>
</el-card>
<el-card shadow="never" header="垂直步骤条">
<div style="white-space: nowrap">
<div class="demo-steps-item-vertical">
<el-steps
direction="vertical"
:active="stepsActive"
style="height: 360px"
>
<el-step title="第一步" />
<el-step title="第二步" />
<el-step title="第三步" />
<el-step title="第四步" />
</el-steps>
</div>
<div class="demo-steps-item-vertical">
<el-steps
direction="vertical"
:active="stepsActive"
style="height: 360px"
>
<el-step title="第一步" description="这里是该步骤的描述信息" />
<el-step title="第二步" description="这里是该步骤的描述信息" />
<el-step title="第三步" description="这里是该步骤的描述信息" />
<el-step title="第四步" description="这里是该步骤的描述信息" />
</el-steps>
</div>
</div>
</el-card>
</div>
</template>
<script>
export default {
name: 'ExtensionSteps',
data() {
return {
stepsActive: 0
};
},
methods: {
/* 下一步 */
stepsNext() {
this.stepsActive++;
if (this.stepsActive > 4) {
this.stepsActive = 0;
}
},
/* 上一步 */
stepsPrev() {
this.stepsActive--;
if (this.stepsActive < 0) {
this.stepsActive = 4;
}
}
}
};
</script>
<style lang="scss" scoped>
.demo-steps-item {
max-width: 900px;
padding: 10px 10px 0 10px;
& + .demo-steps-item {
margin-top: 15px;
}
}
.el-button + .el-button {
margin-left: 20px;
}
.demo-steps-item-vertical {
width: 250px;
display: inline-block;
padding: 10px 0 10px 10px;
}
@media screen and (max-width: 768px) {
.demo-steps-item-vertical {
width: calc(50% - 15px);
}
}
</style>
@@ -1,31 +0,0 @@
<template>
<div style="max-width: 200px">
<el-input
clearable
size="small"
v-model="where.keywords"
placeholder="输入关键字搜索"
prefix-icon="el-icon-search"
@change="search"
/>
</div>
</template>
<script>
export default {
data() {
return {
// 搜索表单
where: {
keywords: ''
}
};
},
methods: {
// 搜索
search() {
this.$emit('search', this.where);
}
}
};
</script>
@@ -1,140 +0,0 @@
<template>
<el-card shadow="never" header="可搜索">
<div style="max-width: 260px">
<ele-table-select
ref="select"
v-model="value"
:multiple="true"
:clearable="true"
placeholder="请选择"
value-key="userId"
label-key="nickname"
:table-config="tableConfig"
:popper-width="580"
:init-value="initValue"
>
<!-- 角色列 -->
<template v-slot:roles="{ row }">
<el-tag
v-for="item in row.roles"
:key="item.roleId"
size="mini"
type="primary"
:disable-transitions="true"
>
{{ item.roleName }}
</el-tag>
</template>
<!-- 表头工具栏 -->
<template v-slot:toolbar>
<demo-advanced-search @search="search" />
</template>
</ele-table-select>
</div>
<div style="margin-top: 12px">
<el-button size="small" type="primary" @click="setInitValue">
回显数据
</el-button>
</div>
</el-card>
</template>
<script>
import { pageUsers } from '@/api/system/user';
import DemoAdvancedSearch from './demo-advanced-search.vue';
export default {
components: { DemoAdvancedSearch },
data() {
return {
value: [],
// 可搜索表格配置
tableConfig: {
datasource({ page, limit, where, order }) {
return pageUsers({ ...where, ...order, page, limit });
},
columns: [
{
columnKey: 'selection',
type: 'selection',
width: 45,
align: 'center',
reserveSelection: true
},
{
columnKey: 'index',
type: 'index',
width: 45,
align: 'center',
showOverflowTooltip: true
},
{
prop: 'username',
label: '用户账号',
sortable: 'custom',
showOverflowTooltip: true,
minWidth: 110
},
{
prop: 'nickname',
label: '用户名',
sortable: 'custom',
showOverflowTooltip: true,
minWidth: 110
},
{
prop: 'sexName',
label: '性别',
sortable: 'custom',
showOverflowTooltip: true,
minWidth: 80
},
{
columnKey: 'roles',
label: '角色',
showOverflowTooltip: true,
minWidth: 110,
slot: 'roles'
}
],
pageSize: 5,
pageSizes: [5, 10, 15, 20],
rowClickChecked: true,
rowClickCheckedIntelligent: false,
toolkit: ['reload', 'columns'],
size: 'small',
toolStyle: { padding: '0 10px' }
},
// 回显值
initValue: undefined
};
},
methods: {
/* 回显数据 */
setInitValue() {
//this.value = [3, 5, 6];
this.initValue = [
{
userId: 3,
nickname: '管理员'
},
{
userId: 5,
nickname: '用户四'
},
{
userId: 6,
nickname: '用户五'
}
];
},
// 搜索
search(where) {
this.$refs.select.reload({
where: where,
page: 1
});
}
}
};
</script>
@@ -1,123 +0,0 @@
<template>
<el-card shadow="never" header="表格后端分页">
<div style="max-width: 260px">
<ele-table-select
v-model="value"
:clearable="true"
placeholder="请选择"
:disabled="disabled"
value-key="userId"
label-key="nickname"
:table-config="tableConfig"
:popper-width="580"
:init-value="initValue"
@select="onSelect"
>
<!-- 角色列 -->
<template v-slot:roles="{ row }">
<el-tag
v-for="item in row.roles"
:key="item.roleId"
size="mini"
type="primary"
:disable-transitions="true"
>
{{ item.roleName }}
</el-tag>
</template>
</ele-table-select>
</div>
<div class="ele-cell" style="margin-top: 15px">
<div style="line-height: 22px">&nbsp;禁用</div>
<div class="ele-cell-content">
<el-radio-group v-model="disabled">
<el-radio :label="false"></el-radio>
<el-radio :label="true"></el-radio>
</el-radio-group>
</div>
</div>
<div style="margin-top: 12px">
<el-button size="small" type="primary" @click="setInitValue">
回显数据
</el-button>
</div>
</el-card>
</template>
<script>
import { pageUsers } from '@/api/system/user';
export default {
data() {
return {
value: undefined,
// 表格配置
tableConfig: {
datasource({ page, limit, where, order }) {
return pageUsers({ ...where, ...order, page, limit });
},
columns: [
{
columnKey: 'index',
type: 'index',
width: 45,
align: 'center',
showOverflowTooltip: true,
fixed: 'left'
},
{
prop: 'username',
label: '用户账号',
sortable: 'custom',
showOverflowTooltip: true,
minWidth: 110
},
{
prop: 'nickname',
label: '用户名',
sortable: 'custom',
showOverflowTooltip: true,
minWidth: 110
},
{
prop: 'sexName',
label: '性别',
sortable: 'custom',
showOverflowTooltip: true,
minWidth: 80
},
{
columnKey: 'roles',
label: '角色',
showOverflowTooltip: true,
minWidth: 110,
slot: 'roles'
}
],
toolbar: false,
pageSize: 5,
pageSizes: [5, 10, 15, 20],
size: 'small'
},
// 禁用
disabled: false,
// 回显值
initValue: undefined
};
},
methods: {
/* 回显数据 */
setInitValue() {
//this.value = 1;
this.initValue = {
userId: 1,
nickname: '管理员'
};
},
/* 选中事件 */
onSelect(item) {
console.log('item:', item);
}
}
};
</script>
@@ -1,102 +0,0 @@
<template>
<el-card shadow="never" header="基础用法">
<div style="max-width: 260px">
<ele-table-select
v-model="value"
:clearable="true"
placeholder="请选择"
value-key="userId"
label-key="nickname"
:table-config="tableConfig"
:popper-width="580"
>
<!-- 角色列 -->
<template v-slot:roles="{ row }">
<el-tag
v-for="item in row.roles"
:key="item.roleId"
size="mini"
type="primary"
:disable-transitions="true"
>
{{ item.roleName }}
</el-tag>
</template>
</ele-table-select>
</div>
<div style="margin-top: 12px">
<el-button size="small" type="primary" @click="setInitValue">
回显数据
</el-button>
</div>
</el-card>
</template>
<script>
import { listUsers } from '@/api/system/user';
export default {
data() {
return {
value: undefined,
// 表格配置
tableConfig: {
datasource: [],
columns: [
{
columnKey: 'index',
type: 'index',
width: 45,
align: 'center',
showOverflowTooltip: true,
fixed: 'left'
},
{
prop: 'username',
label: '用户账号',
sortable: 'custom',
showOverflowTooltip: true,
minWidth: 110
},
{
prop: 'nickname',
label: '用户名',
sortable: 'custom',
showOverflowTooltip: true,
minWidth: 110
},
{
prop: 'sexName',
label: '性别',
sortable: 'custom',
showOverflowTooltip: true,
minWidth: 80
},
{
columnKey: 'roles',
label: '角色',
showOverflowTooltip: true,
minWidth: 110,
slot: 'roles'
}
],
toolbar: false,
pageSize: 5,
pageSizes: [5, 10, 15, 20],
size: 'small'
}
};
},
methods: {
/* 回显数据 */
setInitValue() {
this.value = 1;
}
},
created() {
listUsers().then((data) => {
this.tableConfig.datasource = data;
});
}
};
</script>
@@ -1,123 +0,0 @@
<template>
<el-card shadow="never" header="多选">
<div style="max-width: 260px">
<ele-table-select
v-model="value"
:multiple="true"
:clearable="true"
placeholder="请选择"
:disabled="disabled"
value-key="userId"
label-key="nickname"
:table-config="tableConfig"
:popper-width="580"
>
<!-- 角色列 -->
<template v-slot:roles="{ row }">
<el-tag
v-for="item in row.roles"
:key="item.roleId"
size="mini"
type="primary"
:disable-transitions="true"
>
{{ item.roleName }}
</el-tag>
</template>
</ele-table-select>
</div>
<div class="ele-cell" style="margin-top: 15px">
<div style="line-height: 22px">&nbsp;禁用</div>
<div class="ele-cell-content">
<el-radio-group v-model="disabled">
<el-radio :label="false"></el-radio>
<el-radio :label="true"></el-radio>
</el-radio-group>
</div>
</div>
<div style="margin-top: 12px">
<el-button size="small" type="primary" @click="setInitValue">
回显数据
</el-button>
</div>
</el-card>
</template>
<script>
import { listUsers } from '@/api/system/user';
export default {
data() {
return {
value: undefined,
// 表格配置
tableConfig: {
datasource: [],
columns: [
{
columnKey: 'selection',
type: 'selection',
width: 45,
align: 'center',
reserveSelection: true
},
{
columnKey: 'index',
type: 'index',
width: 45,
align: 'center',
showOverflowTooltip: true
},
{
prop: 'username',
label: '用户账号',
sortable: 'custom',
showOverflowTooltip: true,
minWidth: 110
},
{
prop: 'nickname',
label: '用户名',
sortable: 'custom',
showOverflowTooltip: true,
minWidth: 110
},
{
prop: 'sexName',
label: '性别',
sortable: 'custom',
showOverflowTooltip: true,
minWidth: 80
},
{
columnKey: 'roles',
label: '角色',
showOverflowTooltip: true,
minWidth: 110,
slot: 'roles'
}
],
toolbar: false,
pageSize: 5,
pageSizes: [5, 10, 15, 20],
rowClickChecked: true,
rowClickCheckedIntelligent: false,
size: 'small'
},
// 禁用
disabled: false
};
},
methods: {
/* 回显数据 */
setInitValue() {
this.value = [3, 5, 6];
}
},
created() {
listUsers().then((data) => {
this.tableConfig.datasource = data;
});
}
};
</script>
@@ -1,20 +0,0 @@
<template>
<div class="ele-body">
<demo-basic />
<demo-basic-page />
<demo-multiple />
<demo-advanced />
</div>
</template>
<script>
import DemoBasic from './components/demo-basic.vue';
import DemoBasicPage from './components/demo-basic-page.vue';
import DemoMultiple from './components/demo-multiple.vue';
import DemoAdvanced from './components/demo-advanced.vue';
export default {
name: 'ExtensionTableSelect',
components: { DemoBasic, DemoBasicPage, DemoMultiple, DemoAdvanced }
};
</script>
-203
View File
@@ -1,203 +0,0 @@
<template>
<div class="ele-body">
<el-card shadow="never" header="标签组件" body-style="overflow: auto;">
<div style="min-width: 460px">
<div class="ele-cell">
<div>默认样式:</div>
<div class="ele-cell-content">
<el-tag :size="tagSize" :effect="tagTheme">标签一</el-tag>
<el-tag :size="tagSize" :effect="tagTheme" type="success">
标签二
</el-tag>
<el-tag :size="tagSize" :effect="tagTheme" type="info">
标签三
</el-tag>
<el-tag :size="tagSize" :effect="tagTheme" type="warning">
标签四
</el-tag>
<el-tag :size="tagSize" :effect="tagTheme" type="danger">
标签五
</el-tag>
</div>
</div>
<div class="ele-cell">
<div>圆角样式:</div>
<div class="ele-cell-content">
<el-tag :size="tagSize" :effect="tagTheme" class="ele-tag-radius">
标签一
</el-tag>
<el-tag
:size="tagSize"
:effect="tagTheme"
type="success"
class="ele-tag-radius"
>
标签二
</el-tag>
<el-tag
:size="tagSize"
:effect="tagTheme"
type="info"
class="ele-tag-radius"
>
标签三
</el-tag>
<el-tag
:size="tagSize"
:effect="tagTheme"
type="warning"
class="ele-tag-radius"
>
标签四
</el-tag>
<el-tag
:size="tagSize"
:effect="tagTheme"
type="danger"
class="ele-tag-radius"
>
标签五
</el-tag>
</div>
</div>
<div class="ele-cell">
<div>圆形样式:</div>
<div class="ele-cell-content">
<el-tag :size="tagSize" :effect="tagTheme" class="ele-tag-round">
1
</el-tag>
<el-tag
:size="tagSize"
:effect="tagTheme"
type="success"
class="ele-tag-round"
>
2
</el-tag>
<el-tag
:size="tagSize"
:effect="tagTheme"
type="info"
class="ele-tag-round"
>
3
</el-tag>
<el-tag
:size="tagSize"
:effect="tagTheme"
type="warning"
class="ele-tag-round"
>
4
</el-tag>
<el-tag
:size="tagSize"
:effect="tagTheme"
type="danger"
class="ele-tag-round"
>
5
</el-tag>
</div>
</div>
<div class="ele-cell">
<div>尺寸设置:</div>
<div class="ele-cell-content">
<el-radio-group v-model="tagSize">
<el-radio label="large">默认</el-radio>
<el-radio label="medium">中等</el-radio>
<el-radio label="small">小型</el-radio>
<el-radio label="mini">超小</el-radio>
</el-radio-group>
</div>
</div>
<div class="ele-cell">
<div>主题设置:</div>
<div class="ele-cell-content">
<el-radio-group v-model="tagTheme">
<el-radio label="light">light</el-radio>
<el-radio label="dark">dark</el-radio>
<el-radio label="plain">plain</el-radio>
</el-radio-group>
</div>
</div>
</div>
</el-card>
<el-card shadow="never" header="标签输入">
<ele-tags-input v-model="tags" :size="tagSize" :effect="tagTheme" />
<div style="margin: 8px 0">{{ JSON.stringify(tags) }}</div>
<div style="margin: 8px 0">自定义异步验证:</div>
<ele-tags-input
:validator="validator"
v-model="tags2"
:size="tagSize"
:effect="tagTheme"
/>
</el-card>
<el-card shadow="never" header="状态文字" body-style="overflow: auto;">
<div style="min-width: 360px">
<div class="ele-cell">
<div>默认效果:</div>
<div class="ele-cell-content">
<ele-dot :ripple="ripple" text="运行中" />
<ele-dot type="success" :ripple="ripple" text="已上线" />
<ele-dot type="danger" :ripple="ripple" text="异常" />
<ele-dot type="info" :ripple="ripple" text="关闭" />
</div>
</div>
<div class="ele-cell">
<div>大小设置:</div>
<div class="ele-cell-content">
<ele-dot :ripple="ripple" text="运行中" size="8px" />
<ele-dot type="success" :ripple="ripple" text="已上线" size="8px" />
<ele-dot type="danger" :ripple="ripple" text="异常" size="8px" />
<ele-dot type="info" :ripple="ripple" text="关闭" size="8px" />
</div>
</div>
<div class="ele-cell">
<div>显示动画:</div>
<div class="ele-cell-content">
<el-radio-group v-model="ripple">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
</div>
</div>
</div>
</el-card>
</div>
</template>
<script>
export default {
name: 'ExtensionTag',
data() {
return {
tagSize: 'small',
tagTheme: 'light',
tags: ['标签一', '标签二', '标签三'],
tags2: ['标签一', '标签二', '标签三'],
ripple: true
};
},
methods: {
validator(value) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error(value + '不合法, 请重新输入'));
}, 1000);
});
}
}
};
</script>
<style lang="scss" scoped>
.ele-cell + .ele-cell {
margin-top: 16px;
}
.ele-dot + .ele-dot {
margin-left: 16px;
}
</style>
-150
View File
@@ -1,150 +0,0 @@
<template>
<div class="ele-body">
<el-card shadow="never" header="基本用法">
<div>
<el-button type="primary" @click="onStart1">开始引导</el-button>
</div>
<div style="margin-top: 20px">
<el-button ref="uploadRef1">Upload</el-button>
<el-button ref="saveRef1" type="primary">Save</el-button>
<el-button ref="moreRef1">More</el-button>
</div>
</el-card>
<el-card shadow="never" header="不带遮罩层">
<div>
<el-button type="primary" @click="onStart2">开始引导</el-button>
</div>
<div style="margin-top: 20px">
<el-button ref="uploadRef2">Upload</el-button>
<el-button ref="saveRef2" type="primary">Save</el-button>
<el-button ref="moreRef2">More</el-button>
</div>
</el-card>
<el-card shadow="never" header="混合弹窗等多种形式">
<div>
<el-button type="primary" @click="onStart3">开始引导</el-button>
</div>
<div style="margin-top: 20px">
<el-button ref="uploadRef3">Upload</el-button>
<el-button ref="saveRef3" type="primary">Save</el-button>
<el-button ref="moreRef3">More</el-button>
</div>
</el-card>
<ele-tour v-model="current1" :steps="steps1" />
<ele-tour v-model="current2" :steps="steps2" :mask="false" />
<ele-tour v-model="current3" :steps="steps3">
<template #text="{ step, current }">
<template v-if="current === 0">
<div style="margin-bottom: 10px">
<img
src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*P0S-QIRUbsUAAAAAAAAAAABkARQnAQ"
style="height: 184px; width: 100%; object-fit: cover"
/>
</div>
<div>{{ step.description }}</div>
</template>
</template>
</ele-tour>
</div>
</template>
<script>
export default {
name: 'ExtensionTour',
data() {
return {
// 当前步骤
current1: null,
// 步骤
steps1: [
{
target: () => this.$refs.uploadRef1?.$el,
title: '如何进行文件上传',
description: '点击这个按钮在弹出框中选择想要上传的文件即可.'
},
{
target: () => this.$refs.saveRef1?.$el,
title: '如何提交数据',
description: '数据录入完成后点击这个按钮即可提交数据到后台.'
},
{
target: () => this.$refs.moreRef1?.$el,
title: '如何进行更多的操作',
description: '鼠标移入到此按钮上即可展示出更多的操作功能.'
}
],
// 当前步骤
current2: null,
// 按钮
uploadRef2: null,
saveRef2: null,
moreRef2: null,
// 步骤
steps2: [
{
target: () => this.$refs.uploadRef2?.$el,
title: '如何进行文件上传',
description: '点击这个按钮在弹出框中选择想要上传的文件即可.',
popoverProps: { placement: 'top-start' }
},
{
target: () => this.$refs.saveRef2?.$el,
title: '如何提交数据',
description: '数据录入完成后点击这个按钮即可提交数据到后台.',
popoverProps: { placement: 'bottom' }
},
{
target: () => this.$refs.moreRef2?.$el,
title: '如何进行更多的操作',
description: '鼠标移入到此按钮上即可展示出更多的操作功能.',
popoverProps: { placement: 'top-end' }
}
],
// 当前步骤
current3: null,
// 按钮
uploadRef3: null,
saveRef3: null,
moreRef3: null,
// 步骤
steps3: [
{
title: '欢迎使用 EleAdmin 系统',
description:
'下面将为您介绍一些常用功能的操作说明, 如果之前已经为您介绍过, 您可以直接点击跳过结束指引.'
},
{
target: () => this.$refs.uploadRef3?.$el,
title: '如何进行文件上传',
description: '点击这个按钮在弹出框中选择想要上传的文件即可.'
},
{
target: () => this.$refs.saveRef3?.$el,
title: '如何提交数据',
description: '数据录入完成后点击这个按钮即可提交数据到后台.',
mask: false
},
{
target: () => this.$refs.moreRef3?.$el,
title: '如何进行更多的操作',
description: '鼠标移入到此按钮上即可展示出更多的操作功能.'
}
]
};
},
methods: {
/* 开始引导 */
onStart1() {
this.current1 = 0;
},
/* 开始引导 */
onStart2() {
this.current2 = 0;
},
/* 开始引导 */
onStart3() {
this.current3 = 0;
}
}
};
</script>
@@ -1,30 +0,0 @@
<template>
<el-card shadow="never" header="可搜索">
<div style="max-width: 260px">
<ele-tree-select
:data="data"
v-model="value"
:multiple="true"
:clearable="true"
:filterable="true"
placeholder="请选择"
:default-expand-all="true"
/>
</div>
</el-card>
</template>
<script>
import treeData from './tree-data';
export default {
data() {
return {
// 可搜索
value: [],
// 数据
data: treeData
};
}
};
</script>
@@ -1,59 +0,0 @@
<template>
<el-card shadow="never" header="基础用法">
<div style="max-width: 260px">
<ele-tree-select
:data="data"
v-model="value"
:clearable="true"
placeholder="请选择"
:disabled="disabled"
:default-expand-all="true"
:expand-on-click-node="expandOnClickNode"
/>
</div>
<div class="ele-cell" style="margin-top: 15px">
<div style="line-height: 22px">
&nbsp;<em></em><em></em><em></em>禁用
</div>
<div class="ele-cell-content">
<el-radio-group v-model="disabled">
<el-radio :label="false"></el-radio>
<el-radio :label="true"></el-radio>
</el-radio-group>
</div>
</div>
<div class="ele-cell" style="margin-top: 15px">
<div style="line-height: 22px">&nbsp;只能选子级</div>
<div class="ele-cell-content">
<el-radio-group v-model="expandOnClickNode">
<el-radio :label="false"></el-radio>
<el-radio :label="true"></el-radio>
</el-radio-group>
</div>
</div>
</el-card>
</template>
<script>
import treeData from './tree-data';
export default {
data() {
return {
// 单选
value: undefined,
// 数据
data: treeData,
// 禁用
disabled: false,
// 只能选子级
expandOnClickNode: false
};
},
watch: {
expandOnClickNode() {
this.value = '';
}
}
};
</script>
@@ -1,136 +0,0 @@
<template>
<el-card shadow="never" header="懒加载">
<div style="margin-bottom: 12px">单选</div>
<div style="max-width: 260px">
<ele-tree-select
v-model="value"
:clearable="true"
:lazy="true"
placeholder="请选择"
:load="loadNode"
:init-value="initValue"
/>
</div>
<div style="margin: 12px 0">多选</div>
<div style="max-width: 260px">
<ele-tree-select
v-model="value2"
:multiple="true"
:clearable="true"
:lazy="true"
placeholder="请选择"
:load="loadNode"
:init-value="initValue2"
/>
</div>
<div style="margin-top: 12px">
<el-button size="small" type="primary" @click="setInitValue">
回显数据
</el-button>
</div>
</el-card>
</template>
<script>
export default {
data() {
return {
// 懒加载
value: undefined,
// 回显数据
initValue: undefined,
// 懒加载
value2: [],
// 回显数据
initValue2: undefined
};
},
methods: {
// 懒加载
loadNode(node, resolve) {
setTimeout(() => {
if (!node.data) {
resolve([
{
label: '系统管理',
value: '1'
},
{
label: '日志管理',
value: '8'
}
]);
} else if (node.data.value === '1') {
resolve([
{
label: '用户管理',
value: '2'
},
{
label: '角色管理',
value: '5'
}
]);
} else if (node.data.value === '2') {
resolve([
{
label: '添加用户',
value: '3'
},
{
label: '修改用户',
value: '4'
}
]);
} else if (node.data.value === '5') {
resolve([
{
label: '添加角色',
value: '6'
},
{
label: '修改角色',
value: '7'
}
]);
} else if (node.data.value === '8') {
resolve([
{
label: '登录日志',
value: '9'
},
{
label: '操作日志',
value: '10'
}
]);
return;
} else {
resolve([]);
}
}, 500);
},
// 回显数据
setInitValue() {
this.initValue = {
value: '3',
label: '添加用户'
};
this.initValue2 = [
{
value: '3',
label: '添加用户'
},
{
label: '修改角色',
value: '7'
},
{
label: '登录日志',
value: '9'
}
];
}
}
};
</script>
@@ -1,54 +0,0 @@
<template>
<el-card shadow="never" header="多选">
<div style="max-width: 260px">
<ele-tree-select
:data="data"
v-model="value"
:multiple="true"
:clearable="true"
placeholder="请选择"
:disabled="disabled"
:default-expand-all="true"
:check-strictly="checkStrictly"
expandOnClickNode
/>
</div>
<div class="ele-cell" style="margin-top: 15px">
<div style="line-height: 22px">&nbsp;<em></em><em></em>禁用</div>
<div class="ele-cell-content">
<el-radio-group v-model="disabled">
<el-radio :label="false"></el-radio>
<el-radio :label="true"></el-radio>
</el-radio-group>
</div>
</div>
<div class="ele-cell" style="margin-top: 15px">
<div style="line-height: 22px">&nbsp;父子联动</div>
<div class="ele-cell-content">
<el-radio-group v-model="checkStrictly">
<el-radio :label="false"></el-radio>
<el-radio :label="true"></el-radio>
</el-radio-group>
</div>
</div>
</el-card>
</template>
<script>
import treeData from './tree-data';
export default {
data() {
return {
// 多选
value: [],
// 数据
data: treeData,
// 禁用
disabled: false,
// 关闭父子联动
checkStrictly: false
};
}
};
</script>
@@ -1,80 +0,0 @@
export default [
{
label: '系统管理',
value: '1',
children: [
{
label: '用户管理',
value: '2',
children: [
{
label: '添加用户',
value: '3'
},
{
label: '修改用户',
value: '4'
}
]
},
{
label: '角色管理',
value: '5',
children: [
{
label: '添加角色',
value: '6',
disabled: false
},
{
label: '修改角色',
value: '7'
}
]
}
]
},
{
label: '日志管理',
value: '8',
children: [
{
label: '登录日志',
value: '9'
},
{
label: '操作日志',
value: '10',
disabled: false
}
]
},
{
label: '列表页面',
value: '11',
children: [
{
label: '基础列表',
value: '12'
},
{
label: '卡片列表',
value: '13',
children: [
{
label: '项目',
value: '14'
},
{
label: '应用',
value: '15'
},
{
label: '文章',
value: '16'
}
]
}
]
}
];
@@ -1,20 +0,0 @@
<template>
<div class="ele-body">
<demo-basic />
<demo-multiple />
<demo-lazy />
<demo-advanced />
</div>
</template>
<script>
import DemoBasic from './components/demo-basic.vue';
import DemoMultiple from './components/demo-multiple.vue';
import DemoLazy from './components/demo-lazy.vue';
import DemoAdvanced from './components/demo-advanced.vue';
export default {
name: 'ExtensionTreeSelect',
components: { DemoBasic, DemoMultiple, DemoLazy, DemoAdvanced }
};
</script>
@@ -1,100 +0,0 @@
<template>
<el-card shadow="never" header="手动上传">
<ele-image-upload
v-model="images"
:auto-upload="false"
:before-remove="onBeforeRemove"
/>
<div>
<el-button
type="primary"
size="small"
:loading="loading"
@click="onSubmit"
>
提交
</el-button>
</div>
</el-card>
</template>
<script>
import EleImageUpload from 'ele-admin/es/ele-image-upload';
export default {
components: { EleImageUpload },
data() {
return {
images: [
{
uid: 1,
url: 'https://cdn.eleadmin.com/20200609/c184eef391ae48dba87e3057e70238fb.jpg',
status: 'done'
},
{
uid: 2,
url: 'https://cdn.eleadmin.com/20200610/WLXm7gp1EbLDtvVQgkeQeyq5OtDm00Jd.jpg',
status: 'done'
}
],
loading: false
};
},
methods: {
/* 手动上传 */
onSubmit() {
if (this.checkDone()) {
this.submitForm();
return;
}
this.loading = true;
this.images.forEach((item) => {
if (!item.status) {
this.uploadItem(item);
}
});
},
/* 上传图片 */
uploadItem(item) {
// 模拟上传
item.progress += 20;
item.status = 'uploading';
const timer = setInterval(() => {
item.progress += 20;
if (item.progress === 100) {
item.status = 'done';
clearInterval(timer);
// 每个图片上传完成后都检查是否全部上传完成
if (this.checkDone()) {
this.submitForm();
}
}
}, Math.round(Math.random() * 2500) + 500);
},
/* 检查是否全部上传完毕 */
checkDone() {
return !this.images.some((d) => d.status !== 'done');
},
/* 全部上传完毕后与其它表单数据一起提交 */
submitForm() {
this.$message.success('已全部上传完毕');
console.log('data:', this.images);
this.loading = false;
},
/* 删除增加确认弹窗 */
onBeforeRemove() {
return new Promise((resolve, reject) => {
this.$confirm('确定要删除吗?', '提示', {
type: 'warning'
})
.then(() => {
resolve();
})
.catch(() => {
reject();
});
});
}
}
};
</script>

Some files were not shown because too many files have changed in this diff Show More