Commit 9335d063 by crushh

update: 基础设置

parent 8cc7cec2
......@@ -41,6 +41,6 @@
<script src="//web-1251519181.file.myqcloud.com/components/pagination.1.0.8.js"></script><!-- 分页器 -->
<script src="//web-1251519181.file.myqcloud.com/components/track.1.0.4.js"></script>
<script src="//web-1251519181.file.myqcloud.com/components/upload-file.1.0.10.js"></script><!-- 文件上传 -->
<script src="//web-1251519181.file.myqcloud.com/components/steps.1.0.1.js"></script>
<!-- <script src="//web-1251519181.file.myqcloud.com/components/steps.1.0.1.js"></script> -->
</body>
</html>
......@@ -274,6 +274,9 @@ a:hover {
.w350{
width: 350px!important;
}
.w382{
width: 382px!important;
}
.w400{
width: 400px!important;
}
......
<template>
<div>
<dm-layout :projectName="projectName">
<dm-layout :projectName="projectName" v-if="$store.getters.getShowLayout">
<keep-alive>
<router-view v-if="$route.meta.keepAlive" />
</keep-alive>
<router-view v-if="!this.$route.meta.keepAlive" />
</dm-layout>
<div v-else>
<keep-alive>
<router-view v-if="$route.meta.keepAlive" />
</keep-alive>
<router-view v-if="!this.$route.meta.keepAlive" />
</div>
</div>
</template>
<script>
......@@ -16,6 +22,7 @@ export default {
asideMenu,
description
},
data() {
return {
collapseFlag: false,
......
......@@ -158,19 +158,19 @@ export const getCouponStock = params => requests(PREFIX + 'get-coupon-stock', pa
export const getGameDataUpdatetime = params => requests(PREFIX + 'get-game-data-updatetime', params);
//游戏营销--拆盲盒游戏分页列表
export const cmhPage = params => requests(PREFIX + '/game-pro/page', params);
export const cmhPage = params => requests(PREFIX + '/game-pro/page', params, true, false, 'post');
//游戏营销--拆盲盒游戏统计数据
export const cmhStatistics = params => requests(PREFIX + '/game-pro/page-statistics', params);
//游戏营销--拆盲盒游戏模板信息
export const getGameTemplate = params => requests(PREFIX + '/game-pro/getGameTemplate', params, true, false, 'get');
//游戏营销--拆盲盒游戏新建
export const initActivity = params => requests(PREFIX + '/game-pro/init-activity', params);
//游戏营销--拆盲盒-获取游戏详细信息
export const getGameDetail = params => requests(PREFIX + '/game-pro/getGameDetail', params, true, false, 'get');
//游戏营销--拆盲盒-根据类型获取游戏模板信息
export const getGameTemplateByType = params => requests(PREFIX + '/game-pro/get-game-template-by-type', params, true, false, 'get');
// 生成小程序游戏链接
export const generateMiniProgramLink = params => requests('api-admin/get-page-link-game', params);
......@@ -18,7 +18,8 @@ const state = {
userId: '',
departAuth: 0,
superAdmin: 0,
keepAlive: []
keepAlive: [],
showLayout: true
};
// getters
......@@ -38,7 +39,8 @@ const getters = {
},
getLimitCodeList: state => state.limitCodeList,
// 查询是否被限制使用微信模版消息 true:被限制
getLimitWechatTemplateMessage: state => state.limitCodeList.some(el => el == 'wxTemplateMessage')
getLimitWechatTemplateMessage: state => state.limitCodeList.some(el => el == 'wxTemplateMessage'),
getShowLayout: state => state.showLayout
};
// actions
......@@ -57,6 +59,9 @@ const actions = {
async getIsShowSelfData(state) {
let res = await getIsShowSelf();
this.commit('mutations_auth', res.result);
},
setShowLayout({ commit }, item) {
commit('mutations_Layout', item);
}
};
......@@ -109,6 +114,9 @@ const mutations = {
},
setKeepAlive(state, val) {
state.keepAlive = val;
},
mutations_Layout(state, val) {
state.showLayout = val;
}
};
......
<template>
<el-form size="small" :model="ruleForm" :rules="rules" ref="form" label-width="80px" aria-required>
<dm-sub-title type="line">基本信息</dm-sub-title>
<div class="mt20">
<el-form-item label="游戏名称" prop="gameName" required> <el-input maxlength="10" class="w382" v-model="ruleForm.gameName" show-word-limit :disabled="isDisabled" /> </el-form-item>
<el-form-item label="游戏时间" prop="gameTime" required><el-date-picker class="w382" v-model="ruleForm.gameTime" :picker-options="pickerOptions" value-format="yyyy-MM-dd" @change="refresh" type="daterange" range-separator="~" start-placeholder="开始日期" end-placeholder="结束日期"> </el-date-picker></el-form-item>
<el-form-item label="游戏说明" prop="gameRule" required> <el-input maxlength="500" class="w382" v-model="ruleForm.gameRule" show-word-limit :disabled="isDisabled" :autosize="{ minRows: 4 }" type="textarea" /> </el-form-item>
</div>
<dm-sub-title type="line">展示信息配置</dm-sub-title>
<div class="mt20">
<el-form-item label="游戏模板" prop="gameName">
<el-radio>主题1</el-radio>
<el-radio>主题2</el-radio>
</el-form-item>
<el-form-item label="游戏背景" prop="gameName">
<img src="../../../assets/img/recharge_phone.png" alt="游戏背景" />
<el-button type="text">替换图片</el-button>
<div class="tips">图片建议尺寸 750*1800px,格式 jpg/png/gif,大小 2M 以内。</div>
</el-form-item>
<el-form-item label="抽奖样式" prop="gameName">
<div class="lottery">
<div class="tips">图片建议尺寸 400*400px或等比图片,格式 jpg/png/gif,大小 1M 以内。</div>
</div>
</el-form-item>
<el-form-item label="提示样式" prop="gameName">
<img src="../../../assets/img/recharge_phone.png" alt="游戏背景" />
<el-button type="text">替换图片</el-button>
<div class="tips">图片建议尺寸 348*34px,格式 jpg/png/gif,大小 100KB 以内。</div>
</el-form-item>
<el-form-item label="背景音乐" prop="gameName">
<el-switch />
</el-form-item>
<el-form-item label="氛围弹幕" prop="gameName">
<el-switch />
<div class="tips">开启后,如有三名以上用户获奖后,活动首页将轮播展示用户中奖信息。</div>
</el-form-item>
<el-form-item label="广告位" prop="gameName">
<el-switch />
<div class="tips">图片建议尺寸 750*150px或等比图片,格式 jpg/png/gif,大小 500KB 以内。</div>
</el-form-item>
</div>
</el-form>
</template>
<script>
let _minTime = null;
let _maxTime = null;
import { getGameTemplateByType } from '@/service/api/gameApi.js';
export default {
data() {
return {
rules: {},
ruleForm: {
gameName: '',
gameTime: [],
gameRule: '1、幸运盲盒大抽奖,惊喜好礼抽不停。</br>2、活动最终解释权归品牌方所有。'
},
isDisabled: false,
pickerOptions: {
onPick(time) {
// 查询最大时间跨度为6个月 && 结束时间只能选到当天
if (!time.maxDate) {
const nowTime = new Date().getTime();
const timeRange = 180 * 24 * 60 * 60 * 1000; // 6个月
_minTime = time.minDate.getTime() - timeRange; // 最小时间
_maxTime = nowTime - time.minDate.getTime() > timeRange ? time.minDate.getTime() + timeRange : nowTime; // 最大时间
// 如果选了两个时间,那就清空本次范围判断数据,以备重选
} else {
_minTime = _maxTime = null;
}
},
disabledDate: time => {
if (_minTime && _maxTime) {
return time.getTime() < _minTime || time.getTime() > _maxTime;
} else {
return time.getTime() > new Date().getTime();
}
}
}
};
},
mounted() {
this.getGameTemplateByType();
},
methods: {
getGameTemplateByType() {
getGameTemplateByType({ templateType: 1 }).then(res => {
console.log(res);
});
}
}
};
</script>
<style></style>
<template>
<div>
<div class="navtop">
<div class="gameName">
<img src="../../../assets/img/recharge_phone.png" alt="" />
<span>幸运盲盒</span>
</div>
<div class="rightBtn">
<el-button @click="returnNext">退出</el-button>
<el-button type="primary">发布并预览</el-button>
</div>
</div>
<div class="content">
<div class="left-content">
<el-menu class="dm-aside-menu" ref="asideMenu" :default-active="menuActive" @select="handleMenuSelect">
<el-menu-item class="dm-sub-menu" v-for="(el, index) in menuList" :key="index" :index="index">
{{ el }}
</el-menu-item>
</el-menu>
<div class="iphone" v-if="menuActive == 0">iphone</div>
<div class="iphone" v-else>
<img :src="bcImg[menuActive]" />
</div>
</div>
<div class="rightForm">
<dm-steps :active="active" simple>
<dm-step title="步骤一" @click.native="active = 0"></dm-step>
<dm-step title="步骤二" @click.native="active = 1"></dm-step>
<dm-step title="步骤三" @click.native="active = 2"></dm-step>
</dm-steps>
<div class="formContent">
<baseConfig v-if="active == 0" />
</div>
<dm-form-bottom class="footer">
<el-button type="primary">保存并下一步</el-button>
</dm-form-bottom>
</div>
</div>
</div>
</template>
<script>
import steps from '@/views/game/dm-steps/steps';
import step from '@/views/game/dm-step/step';
import baseConfig from './base-config.vue';
import Img from '../../../components/upload/img.vue';
export default {
data() {
return {
active: 0,
menuActive: 0,
bcImg: {
1: ''
},
menuList: ['首页', '活动规则', '我的奖品', '中奖', '未中奖', '分享效果']
};
},
components: {
'dm-steps': steps,
'dm-step': step,
baseConfig,
Img
},
methods: {
returnNext() {
this.$store.dispatch('setShowLayout', true);
this.$router.go(-1);
},
handleMenuSelect(index, indexPath) {
console.log(index, indexPath);
this.menuActive = index;
}
},
mounted() {
console.log(this);
this.$store.dispatch('setShowLayout', false);
}
};
</script>
<style lang="scss" scoped>
.navtop {
width: 100%;
height: 52px;
background: #ffffff;
box-shadow: 0px 4px 8px 0px rgba(220, 223, 230, 0.4);
border-radius: 4px 0px 0px 0px;
display: flex;
padding: 10px 20px;
justify-content: space-between;
box-sizing: border-box;
position: relative;
.gameName {
align-items: center;
display: flex;
img {
width: 30px;
}
span {
color: #303133;
font-weight: 600;
font-size: 17px;
margin-left: 12px;
}
}
}
.content {
display: flex;
}
.left-content {
width: 520px;
height: calc(100vh - 52px);
background: #f7f8fa;
box-sizing: border-box;
padding: 30px 0 20px 20px;
display: flex;
}
.dm-aside-menu {
width: 90px;
height: 100%;
border-right: none;
background-color: #f7f8fa;
box-sizing: border-box;
overflow-y: auto;
/deep/ .el-menu {
background-color: transparent;
}
/deep/ .el-menu-item {
padding-left: 10px !important;
height: 32px;
width: auto;
font-size: 14px;
font-weight: 400;
color: #303133;
line-height: 34px;
border-radius: 4px;
&:hover {
background: #ebeffe;
}
&.is-active {
font-weight: 500;
color: #2f54eb;
background: #ebeffe;
}
+ .el-menu-item {
margin-top: 8px;
}
}
}
.iphone {
width: 375px;
height: 88px;
background: #ffffff;
border-radius: 8px 8px 0px 0px;
margin: 0 20px 0 13px;
}
.rightForm {
padding: 30px 20px;
box-sizing: border-box;
width: calc(100vw - 520px);
height: 100vh;
background: #ffffff;
.formContent {
margin-top: 20px;
overflow-y: auto;
height: 100%;
}
.footer {
width: calc(100% - 520px) !important;
}
}
</style>
......@@ -32,22 +32,27 @@
<dm-sub-title v-else>
<div class="gameName">
幸运盲盒
<img @click="shrink(1)" style="width: 240px;height: 50px;" src="https://pic01-10001430.cos.ap-shanghai.myqcloud.com/game/template1/banner_web.png" />
<img @click="shrink(1)" style="width: 240px;height: 50px;cursor: pointer;" src="https://pic01-10001430.cos.ap-shanghai.myqcloud.com/game/template1/banner_web.png" />
</div>
</dm-sub-title>
<div class="pt20 pb20 clearfix">
<el-date-picker class="w256" v-model="dateTime" type="daterange" start-placeholder="开始日期" range-separator="~" end-placeholder="结束日期" @change="refresh"></el-date-picker>
<el-date-picker class="w256" v-model="dateTime" value-format="yyyy-MM-dd" @change="refresh" type="daterange" range-separator="~" start-placeholder="开始日期" end-placeholder="结束日期"> </el-date-picker>
<el-input v-model="listParams.gameName" class="w260" placeholder="输入游戏名称" clearable @change="refresh"><i slot="prefix" class="el-input__icon el-icon-search"></i></el-input>
<el-select class="w160" v-model="listParams.status" placeholder="所有游戏状态" @change="refresh">
<el-select class="w160" v-model="listParams.status" placeholder="所有游戏状态" @change="refresh" clearable>
<el-option v-for="(v, i) in gameStatusOptions" :key="i" :label="v.label" :value="v.value"></el-option>
</el-select>
<el-checkbox class="vertical-middle ml0" v-if="$store.state.marketing.isShowSelf" v-model="listParams.createMe" :true-label="1" :false-label="0" label="仅看本人" border @change="refresh" />
<el-button class="fr" type="primary" @click="$router.push('/game/cmh/add')">新建游戏</el-button>
<el-button class="fr" type="primary" @click="addGame">新建游戏</el-button>
</div>
<el-table tooltipEffect="light" :data="tableList" style="width:100%">
<el-table-column label="游戏名称" min-width="183px" prop="gameName" show-overflow-tooltip :formatter="(row, col, val) => val || '--'"></el-table-column>
<el-table-column label="游戏时间" min-width="134px">
<template slot-scope="{ row }"> {{ row.startDate }} - {{ row.endDate }} </template>
<template slot-scope="{ row }">
<p class="cell-time">
{{ formatDateTimeByType(row.startDate, 'yyyy-MM-dd') }}<br />
{{ formatDateTimeByType(row.endDate, 'yyyy-MM-dd') }}
</p>
</template>
</el-table-column>
<el-table-column label="参与门槛" min-width="96px" prop="playConditionFlag ">
<template slot-scope="{ row }">
......@@ -63,14 +68,18 @@
</template>
</el-table-column>
<el-table-column label="创建人" min-width="88px" prop="creatorName"></el-table-column>
<el-table-column label="创建时间" min-width="114px" prop="createTime" :formatter="(row, col, val) => val || '--'"></el-table-column>
<el-table-column label="创建时间" min-width="114px" prop="createTime">
<template slot-scope="{ row }">
{{ formatDateTimeByType(row.createTime) }}
</template>
</el-table-column>
<el-table-column label="操作" align="left" min-width="153px" fixed="right">
<template slot-scope="{ row }">
<dm-dropdown ref="drop" :scope-data="row" :configs="btnArr" @command="onCommand" />
</template>
</el-table-column>
</el-table>
<dm-pagination v-show="tableList.length" background class="dm-pagination" @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listParams.currentPage" :page-sizes="[20, 40, 60, 80]" :page-size="listParams.pageSize" layout="total, sizes, prev, pager, next" :total="total"></dm-pagination>
<dm-pagination v-show="tableList.length" background class="dm-pagination" @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listParams.pageNum" :page-sizes="[20, 40, 60, 80]" :page-size="listParams.pageSize" layout="total, sizes, prev, pager, next" :total="total"></dm-pagination>
<links :show.sync="linkShow" :obj="linksObj" :gameTypeName="gameTypeName"></links>
</section>
</template>
......@@ -78,11 +87,16 @@
import { api as viewerApi } from 'v-viewer';
import { cmhPage } from '@/service/api/gameApi.js';
import linksMixin from '../common/linksMixin.js';
import tableMethods from '@/mixins/tableMethods.js';
import { formatDateTimeByType } from '@/utils/index.js';
import dmDropdown from '@/components/dm-drop-down/dm-drop-down';
export default {
mixins: [linksMixin, tableMethods],
mixins: [linksMixin],
components: {
dmDropdown
},
data() {
return {
formatDateTimeByType,
listParams: {
gameName: '',
status: '',
......@@ -125,7 +139,7 @@ export default {
},
dateTime: [],
loading: false,
notShrink: 1,
notShrink: 0,
btnArr: [
{
text: '查看',
......@@ -133,6 +147,7 @@ export default {
limitCode: this.$buttonCode.marketingCmhInfo
},
visible: row => {
return true;
return this.$getButtonLimit(this.$buttonCode.marketingCmhInfo);
},
handler: row => this.$router.push('/cmh/info/' + row.gameId)
......@@ -143,6 +158,7 @@ export default {
limitCode: this.$buttonCode.marketingCmhEdit
},
visible: row => {
return true;
return (row.status === 1 || row.status === 0) && this.$getButtonLimit(this.$buttonCode.marketingCmhEdit);
},
handler: row => this.$router.push('/cmh/edit/' + row.gameId)
......@@ -153,6 +169,7 @@ export default {
limitCode: this.$buttonCode.marketingCmhCopy
},
visible: row => {
return true;
return this.$getButtonLimit(this.$buttonCode.marketingCmhCopy);
},
handler: row => this.$router.push('/cmh/copy/' + row.gameId)
......@@ -163,6 +180,7 @@ export default {
limitCode: this.$buttonCode.marketingCmhUrl
},
visible: row => {
return true;
return (row.status === 1 || row.status === 0) && this.$getButtonLimit(this.$buttonCode.marketingCmhUrl);
},
handler: row => this.setLinks(row, 6)
......@@ -173,6 +191,7 @@ export default {
limitCode: this.$buttonCode.marketingCmhStop
},
visible: row => {
return true;
return row.status === 1 && this.$getButtonLimit(this.$buttonCode.marketingCmhStop);
},
handler: row => this.stopPlan(row)
......@@ -183,6 +202,7 @@ export default {
limitCode: this.$buttonCode.marketingCmhStatistics
},
visible: row => {
return true;
return (row.status === 1 || row.status === 2 || row.status === 3) && this.$getButtonLimit(this.$buttonCode.marketingCmhStatistics);
},
handler: row => this.$router.push('/cmh/statistics/' + row.gameId)
......@@ -190,13 +210,35 @@ export default {
]
};
},
created() {
this.getTableList();
},
methods: {
refresh() {
this.listParams.pageNum = 1;
this.getTableList();
},
handleSizeChange(val) {
this.listParams.pageSize = val;
this.getTableList();
},
handleCurrentChange(val) {
this.listParams.pageNum = val;
this.getTableList();
},
addGame() {
this.$store.dispatch('setShowLayout', false);
this.$router.push('cmh/add');
},
onView() {
let qrImg = 'https://pic01-10001430.cos.ap-shanghai.myqcloud.com/game/template1/bill_pic.png';
let qrImg = 'https://pic01-10001430.cos.ap-shanghai.myqcloud.com/game/template1/bill_pic.png' + '?imageMogr2/thumbnail/800x800';
viewerApi({
images: [qrImg],
options: {
initialViewIndex: 2
toolbar: false,
navbar: false,
title: false,
zIndex: 9999
}
});
},
......@@ -206,18 +248,22 @@ export default {
getTableList() {
if (this.dateTime && this.dateTime.length) {
this.listParams.startTime = this.dateTime[0];
this.listParams.startTime = this.dateTime[0];
this.listParams.endTime = this.dateTime[1];
} else {
this.listParams.startTime = '';
this.listParams.endTime = '';
}
this.loading = true;
cmhPage(this.listParams)
.then(res => {
if (res.errorCode === 0) {
this.tableList = res.result.page.result || [];
this.total = res.result.page.totalCount || 0;
this.loading = false;
}
console.log(res);
this.tableList = res.result.list || [];
this.total = res.result.total || 0;
this.notShrink = this.tableList.length > 0 ? 0 : 1;
this.loading = false;
})
.catch(err => {
.catch(() => {
console.log('finally');
this.loading = false;
});
}
......
......@@ -8,45 +8,29 @@
<div class="links__body">
<div class="links__body--url">{{ miniprogram.link }}</div>
<div class="links__body--btn">
<el-button v-clipboard:text="miniprogram.link" type="text" icon="iconfont icon-lianjie fz14"> 复制链接</el-button>
<el-button v-clipboard:text="miniprogram.link" v-show="miniprogram.link" type="text" icon="iconfont icon-lianjie fz14"> 复制链接</el-button>
</div>
</div>
<div class="link__divider"></div>
<div class="links__qr">
<!-- <vue-qr id="qrWrap" :text="qcText" :size="102" :margin="0" :logoMargin="10"></vue-qr> -->
<div style="text-align:center">
<el-image style="width:102px;height:102px;border:4px solid #fff;cursor: pointer;" lazy :src="miniprogram.url" @click.native="onView(false)">
<!-- <img slot="placeholder" style="width:102px;height:102px" src="@/assets/img/loaderror.png" /> -->
<div slot="placeholder" style="display:flex;align-items:center;justify-content:center;width:100%;height:100%;">
<i class="el-icon-picture-outline" style="font-size:30px"></i>
</div>
</el-image>
</div>
<el-button class="links__qr--btn" type="text" icon="iconfont icon-icon_yunxiazai fz14 mr4" @click="downloadMiniporgramImg">小程序二维码下载</el-button>
<el-button class="links__qr--btn" v-show="miniprogram.url" type="text" icon="iconfont icon-icon_yunxiazai fz14 mr4" @click="downloadMiniporgramImg">小程序二维码下载</el-button>
</div>
</div>
<!-- <div class="link-title">
<i class="icon iconfont icon-fuwuhao2" style="color:#2CBB64"></i>
H5链接
<div slot="footer" v-if="showFooter">
<slot></slot>
</div>
<div class="links-block" style="margin-bottom:25px">
<div class="links__body">
<div class="links__body--url">{{ obj.gameUrl }}</div>
<div class="links__body--btn">
<el-button v-clipboard:text="obj.gameUrl" type="text" icon="iconfont icon-lianjie fz14"> 复制链接</el-button>
</div>
</div>
<div class="link__divider"></div>
<div class="links__qr">
<vue-qr id="qrWrap" :text="qcText" :size="510" :logoScale="5" :margin="0" :logoMargin="10" @click.native="onView(true)"></vue-qr>
<el-button class="links__qr--btn" type="text" icon="iconfont icon-icon_yunxiazai fz14 mr4" @click="downloadImg">服务号二维码下载</el-button>
</div>
</div> -->
</el-dialog>
</template>
<script>
import VueQr from 'vue-qr';
import { formatDateTimeByType, downloadFile } from '@/utils/index.js';
import { formatDateTimeByType } from '@/utils/index.js';
import { generateMiniProgramLink } from '@/service/api/gameApi.js';
import { api as viewerApi } from 'v-viewer';
import 'viewerjs/dist/viewer.css';
......@@ -69,6 +53,10 @@ export default {
gameTypeName: {
type: String,
default: ''
},
showFooter: {
type: Boolean,
default: false
}
},
data() {
......@@ -123,19 +111,18 @@ export default {
generateMiniProgramLink({
id: this.obj.gameId || this.obj.gameActivityId,
linkId: gameType
}).then(res => {
this.miniprogram = res.result;
this.loading = false;
});
})
.then(res => {
this.miniprogram = res.result;
})
.finally(() => {
this.loading = false;
});
},
close() {
this.$emit('update:show', false);
},
downloadImg() {
const qrWrap = document.getElementById('qrWrap');
const qrImg = qrWrap && qrWrap.childNodes[0].src;
downloadFile(this.gameTypeName + '-' + this.obj.gameName + '-服务号-' + formatDateTimeByType(this.obj.gameStartTime, 'yyyy-MM-dd-HH-mm-ss') || '游戏链接', qrImg);
},
onView(isH5) {
let qrImg = '';
if (isH5) {
......@@ -184,7 +171,7 @@ export default {
overflow-x: hidden;
overflow-y: auto;
word-break: break-all;
padding: 13px 22px 0 16px;
padding: 13px 16px 0 16px;
line-height: 17px;
font-size: 12px;
}
......@@ -208,7 +195,7 @@ export default {
}
.links-block {
display: flex;
background: #f5f7fa;
background: #f7f8fa;
margin: 10px 0 10px;
}
.link-title {
......@@ -224,21 +211,20 @@ export default {
}
}
.link-tip {
width: 544px;
background: #e6f7ff;
border-radius: 4px;
border: 1px solid #91d5ff;
font-size: 13px;
color: #606266;
line-height: 1.2;
padding: 10px 0;
margin-bottom: 10px;
width: 552px;
background: #fcf6f1;
border-radius: 2px;
font-size: 12px;
color: #303133;
line-height: 22px;
padding: 5px 0;
margin-bottom: 16px;
display: flex;
.el-icon-info {
line-height: 18px;
margin-left: 16px;
margin-right: 4px;
color: #2f54eb;
line-height: 22px;
margin-left: 17px;
margin-right: 9px;
color: #fa8c16;
font-size: 12px;
}
}
......
import Step from './step';
/* istanbul ignore next */
const GicStep = {
install(Vue) {
Vue.component(Step.name, Step);
}
};
if (typeof window.Vue !== 'undefined' && window.Vue) {
window.Vue.use(GicStep);
}
export default GicStep;
# 副标题
```
<h2>simple样式</h2>
<dm-steps :active="active" simple>
<dm-step title="步骤一" @click.native="active=0"></dm-step>
<dm-step title="步骤二" @click.native="active=1"></dm-step>
<dm-step title="步骤三" @click.native="active=2"></dm-step>
</dm-steps>
<h2>线性样式</h2>
<dm-steps :active="active">
<dm-step title="步骤一" ></dm-step>
<dm-step title="步骤二" ></dm-step>
<dm-step title="步骤三" ></dm-step>
```
### props
| 参数 | 说明 | 类型 | 可选值 | 默认值 | 是否必传 |
| ------------ | ------------ | ------------ | ------------ | ------------ | ------------ |
| space | 每个 step 的间距,不填写将自适应间距。支持百分比 | [Number, String] | -- | -- | 否 |
| active | 设置当前激活步骤 | Number | -- | 0 | 否 |
| simple | 样式 | Boolean | | false| 否 |
### 更新日志:
1.1.0 重写完成 by黄冷
\ No newline at end of file
<template>
<div class="steps" v-if="$parent.simple">
<div class="step-item" :class="[$parent.active === index ? 'active' : '']">
<slot name="title"> {{ title }} </slot>
</div>
<span class="triangle" :class="[$parent.active === index ? 'triangle-active' : '', $parent.active == index + 1 ? 'triangle-bg' : 'triangle-default']"></span>
</div>
<div v-else class="dm-step" :style="style" :class="[isLast && !space && 'is-flex']">
<div class="dm-step-box" :class="`is-${currentStatus}`">
<!-- 线 -->
<div class="dm-step__line" :style="isLast ? '' : { marginRight: $parent.stepOffset + 'px' }">
<i class="dm-step__line-inner" :style="lineStyle"></i>
</div>
<div class="dm-step__head">
<!-- icon -->
<div class="dm-step__icon">
<slot v-if="currentStatus !== 'success' && currentStatus !== 'error'" name="icon">
<i v-if="icon" class="dm-step__icon-inner" :class="[icon]"></i>
<div class="dm-step__icon-inner" v-if="!icon">{{ index + 1 }}</div>
</slot>
<i v-else :class="['el-icon-' + (currentStatus === 'success' ? 'check' : 'close')]" class="dm-step__icon-inner is-status"> </i>
</div>
<!-- 内容区 -->
<div class="dm-step__content" :class="`is-${currentStatus}`">
<slot name="title">{{ title }}</slot>
</div>
</div>
</div>
<!-- 文字描述 -->
<div class="dm-step__description" :class="`is-${currentStatus}`">
<slot name="description">{{ description }}</slot>
</div>
</div>
</template>
<script>
export default {
name: 'vue-gic-step',
props: {
title: String,
icon: String,
description: String,
status: String
},
data() {
return {
index: -1,
lineStyle: {},
internalStatus: ''
};
},
beforeCreate() {
this.$parent.steps.push(this);
},
beforeDestroy() {
const steps = this.$parent.steps;
const index = steps.indexOf(this);
if (index >= 0) {
steps.splice(index, 1);
}
},
computed: {
currentStatus() {
return this.status || this.internalStatus;
},
prevStatus() {
const prevStep = this.$parent.steps[this.index - 1];
return prevStep ? prevStep.currentStatus : 'wait';
},
isLast() {
const parent = this.$parent;
return parent.steps[parent.steps.length - 1] === this;
},
space() {
const {
$parent: { space }
} = this;
return space;
},
style: function() {
const style = {};
const parent = this.$parent;
const len = parent.steps.length;
const space = typeof this.space === 'number' ? this.space + 'px' : this.space ? this.space : 100 / (len - 1) + '%';
style.flexBasis = space;
return style;
}
},
methods: {
updateStatus(val) {
const prevChild = this.$parent.$children[this.index - 1];
if (val > this.index) {
this.internalStatus = this.$parent.finishStatus;
} else if (val === this.index && this.prevStatus !== 'error') {
this.internalStatus = this.$parent.processStatus;
} else {
this.internalStatus = 'wait';
}
if (prevChild) prevChild.calcProgress(this.internalStatus);
},
calcProgress(status) {
let step = 100;
const style = {};
style.transitionDelay = 150 * this.index + 'ms';
if (status === 'wait') {
step = 0;
style.transitionDelay = -150 * this.index + 'ms';
}
style.borderWidth = step ? '1px' : 0;
style.width = step + '%';
this.lineStyle = style;
}
},
mounted() {
const unwatch = this.$watch('index', val => {
this.$watch('$parent.active', this.updateStatus, { immediate: true });
this.$watch(
'$parent.processStatus',
() => {
const activeIndex = this.$parent.active;
this.updateStatus(activeIndex);
},
{ immediate: true }
);
unwatch();
});
}
};
</script>
<style lang="scss">
.dm-step {
position: relative;
flex-shrink: 1;
&:last-of-type.is-flex {
flex-basis: 80px !important;
flex-shrink: 1;
flex-grow: 0;
.dm-step__content {
flex: 1;
}
}
.dm-step-box {
position: relative;
width: 100%;
&.is-process {
color: #fff;
border-color: #2f54eb;
.dm-step__icon {
background-color: #2f54eb;
}
}
&.is-finish,
&.is-success {
color: #2f54eb;
border-color: #2f54eb;
}
&.is-wait {
color: #c0c4cc;
border-color: #c0c4cc;
}
}
.dm-step__line {
position: absolute;
height: 1px;
top: 11px;
left: 0;
right: 0;
border-color: inherit;
background-color: #dcdfe6;
}
.dm-step__line-inner {
display: block;
border-top: 1px solid;
border-color: inherit;
transition: 0.15s ease-out;
box-sizing: border-box;
width: 0;
height: 0;
}
.dm-step__head {
display: flex;
width: 100%;
border-color: inherit;
}
.dm-step__icon {
position: relative;
z-index: 1;
display: inline-flex;
justify-content: center;
align-items: center;
width: 24px;
height: 24px;
font-size: 14px;
box-sizing: border-box;
background-color: #fff;
transition: 0.15s ease-out;
border-radius: 50%;
border: 1px solid;
border-color: inherit;
&-inner {
display: inline-block;
user-select: none;
text-align: center;
line-height: 1;
color: inherit;
&.is-status {
font-size: 16px;
transform: translateY(1px);
}
}
}
.dm-step__content {
position: relative;
z-index: 2;
line-height: 25px;
padding-left: 8px;
padding-right: 18px;
background-color: #fff;
font-size: 16px;
&.is-process {
color: #303133;
font-weight: 500;
}
&.is-finish,
&.is-success {
color: #303133;
}
&.is-wait {
color: #909399;
}
}
.dm-step__description {
padding-left: 32px;
line-height: 24px;
color: #909399;
&.is-process {
color: #606266;
}
}
}
.steps {
display: flex;
width: 100%;
position: relative;
// margin-right: 10px;
.active {
background: #2f54eb;
color: #fff;
}
}
.step-item {
flex: 1;
background: #eef4ff;
color: #303133;
height: 44px;
text-align: center;
line-height: 44px;
cursor: pointer;
font-size: 14px;
}
.triangle {
width: 0;
height: 0;
display: inline-block;
z-index: 2;
border-style: solid;
border-width: 22px 0 22px 12px;
position: relative;
background: #eef4ff;
border-color: transparent transparent transparent #eef4ff;
}
.steps:last-of-type {
.triangle {
background: #fff;
}
}
.triangle::before {
content: '';
position: absolute;
height: 28px;
width: 4px;
background: #fff;
transform: rotate(-209deg) translateY(-0.7px);
transform-origin: 0 0;
top: 0;
right: -6px;
}
.triangle::after {
content: '';
bottom: 0;
position: absolute;
height: 27px;
width: 4px;
background: #fff;
transform: rotate(209deg) translateY(1.3px);
transform-origin: 100% 100%;
right: 1.8px;
}
.triangle-active {
border-left-color: #2f54eb;
}
.triangle-bg {
background: #2f54eb;
}
.triangle-default {
background: #eef4ff;
}
</style>
import Steps from './steps';
/* istanbul ignore next */
const GicSteps = {
install(Vue) {
Vue.component(Steps.name, Steps);
}
};
if (typeof window !== 'undefined' && window.Vue) {
window.Vue.use(GicSteps);
}
export default GicSteps;
<template>
<div class="dm-steps">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'vue-gic-steps',
props: {
space: [Number, String], // 间距
active: {
// 设置步骤
type: Number,
default: 0
},
finishStatus: {
// 成功状态
type: String,
default: 'success'
},
processStatus: {
// 当前步骤状态
type: String,
default: 'process'
},
simple: {
type: Boolean,
default: false
}
},
data() {
return {
steps: [],
stepOffset: 20
};
},
watch: {
active(newVal, oldVal) {
this.$emit('change', newVal, oldVal);
},
steps(steps) {
steps.forEach((child, index) => {
child.index = index;
});
}
}
};
</script>
<style lang="scss">
.dm-steps {
display: flex;
white-space: nowrap;
background-color: #fff;
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment