我们发布啦

This commit is contained in:
张乐
2020-08-13 16:12:57 +08:00
parent a3e1c38d27
commit c0cec49f41
1885 changed files with 376936 additions and 2 deletions

View File

@@ -0,0 +1,15 @@
<template>
<div>
<router-view />
</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,15 @@
<template>
<div>
<router-view />
</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,13 @@
<template>
</template>
<script>
export default {
name: "routineTemplate"
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,15 @@
<template>
<div>
<router-view />
</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,626 @@
<template>
<div class="divBox">
<el-card class="box-card">
<router-link v-show="$route.path.indexOf('keyword') !== -1" :to="{path: '/appSetting/publicAccount/wxReply/keyword'}">
<el-button size="mini" class="mr20 mb20" icon="el-icon-back">返回</el-button>
</router-link>
<el-row :gutter="30" v-loading="loading">
<el-col v-bind="grid" class="acea-row">
<div class="left mb15 ml40">
<img class="top" src="@/assets/imgs/mobilehead.png">
<img class="bottom" src="@/assets/imgs/mobilefoot.png">
<div class="centent">
<div class="time-wrapper"><span class="time">9:36</span></div>
<div v-if="formValidate.type !== 'news'" class="view-item text-box clearfix">
<div class="avatar fl"><img src="@/assets/imgs/head.gif"></div>
<div class="box-content fl">
<span
v-if="formValidate.type === 'text'"
v-text="formValidate.contents.content"
/>
<div v-if="formValidate.contents.mediaId" class="box-content_pic">
<img v-if="formValidate.type === 'image'" :src="formValidate.contents.srcUrl">
<i class="el-icon-service" v-else></i>
</div>
</div>
</div>
<div v-if="formValidate.type === 'news'">
<div class="newsBox">
<!--<div class="news_pic mb15" style="backgroundImage: url('@/assets/imgs/mobilefoot.png');backgroundSize:'100% 100%'}" />-->
<div class="news_pic mb15" :style="{backgroundImage: 'url(' + (formValidate.contents.articleData.imageInput?formValidate.contents.articleData.imageInput[0]:'') + ')',backgroundSize:'100% 100%'}" />
<span class="news_sp">{{ formValidate.contents.articleData.title }}</span>
</div>
<!--<div v-for="(j, i) in formValidate.contents.list" :key="i">-->
<!--<div v-if="i === 0">-->
<!--<div class="news_pic mb15" :style="{backgroundImage: 'url(' + (j.image_input) + ')',backgroundSize:'100% 100%'}" />-->
<!--<span class="news_sp">{{ j.title }}</span>-->
<!--</div>-->
<!--<div v-else class="news_cent">-->
<!--<span v-if="j.synopsis" class="news_sp1">{{ j.title }}</span>-->
<!--<div v-if="j.image_input.length!==0" class="news_cent_img"><img :src="j.image_input"></div>-->
<!--</div>-->
<!--</div>-->
</div>
</div>
</div>
</el-col>
<el-col :xl="11" :lg="12" :md="14" :sm="22" :xs="22">
<div class="box-card right ml50">
<el-form
ref="formValidate"
:model="formValidate"
:rules="ruleValidate"
label-width="100px"
class="mt20"
@submit.native.prevent
>
<el-form-item v-if="$route.path.indexOf('keyword') !== -1" label="关键字:" prop="val">
<div class="arrbox">
<el-tag
v-for="(item, index) in labelarr"
:key="index"
type="success"
closable
class="mr5"
:disable-transitions="false"
@close="handleClose(item)"
>{{ item }}
</el-tag>
<el-input
v-model="val"
size="mini"
class="arrbox_ip"
placeholder="输入后回车"
style="width: 90%;"
@change="addlabel"
/>
</div>
</el-form-item>
<el-form-item label="规则状态:">
<el-radio-group v-model="formValidate.status">
<el-radio :label="true">启用</el-radio>
<el-radio :label="false">禁用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="消息类型:" prop="type">
<el-select
v-model="formValidate.type"
placeholder="请选择规则状态"
style="width: 90%;"
@change="RuleFactor(formValidate.type)"
>
<el-option label="文字消息" value="text">文字消息</el-option>
<el-option label="图片消息" value="image">图片消息</el-option>
<el-option label="图文消息" value="news">图文消息</el-option>
<el-option label="声音消息" value="voice">声音消息</el-option>
</el-select>
</el-form-item>
<el-form-item v-if="formValidate.type === 'text'" label="规则内容:" prop="content">
<el-input
v-model="formValidate.contents.content"
placeholder="请填写规则内容"
style="width: 90%;"
@input="change($event)"
/>
</el-form-item>
<el-form-item v-if="formValidate.type === 'news'" label="选取图文:">
<el-button size="mini" type="primary" @click="changePic">选择图文消息</el-button>
</el-form-item>
<el-form-item
v-if="formValidate.type === 'image' || formValidate.type === 'voice'"
:label="formValidate.type === 'image'?'图片地址:':'语音地址:'"
prop="mediaId"
>
<div class="acea-row row-middle">
<el-input
v-model="formValidate.contents.mediaId"
readonly="readonly"
placeholder="default size"
style="width: 75%;"
class="mr10"
/>
<el-upload
class="upload-demo mr10 mb15"
action
:http-request="handleUploadForm"
:headers="myHeaders"
:show-file-list="false"
multiple
>
<el-button size="mini" type="primary">点击上传</el-button>
</el-upload>
</div>
<span v-show="formValidate.type === 'image'">文件最大2Mb支持bmp/png/jpeg/jpg/gif格式</span>
<span v-show="formValidate.type === 'voice'">文件最大2Mb支持mp3/wma/wav/amr格式,播放长度不超过60s</span>
</el-form-item>
</el-form>
</div>
<el-col :span="24">
<div class="acea-row row-center">
<el-button
type="primary"
class="ml50"
@click="submenus('formValidate')"
>保存并发布
</el-button>
</div>
</el-col>
</el-col>
</el-row>
</el-card>
</div>
</template>
<script>
import { getToken } from '@/utils/auth'
import { replySaveApi, replyEditApi, replyInfoApi, replyListApi, keywordsInfoApi, replyUpdateApi } from '@/api/wxApi'
import { fileImageApi } from '@/api/systemSetting'
export default {
name: 'Index',
components: { },
data() {
const validateContent = (rule, value, callback) => {
if (this.formValidate.type === 'text') {
if (this.formValidate.contents.content === '') {
callback(new Error('请填写规则内容'))
} else {
callback()
}
}
}
const validateSrc = (rule, value, callback) => {
if (this.formValidate.type === 'image' && this.formValidate.contents.mediaId === '') {
callback(new Error('请上传'))
} else {
callback()
}
}
const validateVal = (rule, value, callback) => {
if (this.labelarr.length === 0) {
callback(new Error('请输入后回车'))
} else {
callback()
}
}
return {
loading: false,
visible: false,
grid: {
xl: 7,
lg: 12,
md: 10,
sm: 24,
xs: 24
},
delfromData: {},
isShow: false,
maxCols: 3,
scrollerHeight: '600',
contentTop: '130',
contentWidth: '98%',
modals: false,
val: '',
formatImg: ['jpg', 'jpeg', 'png', 'bmp', 'gif'],
formatVoice: ['mp3', 'wma', 'wav', 'amr'],
header: {},
formValidate: {
status: true,
type: '',
keywords: '',
contents: {
content: '',
articleData:{},
mediaId: '',
srcUrl: '',
articleId: null
},
id: null
},
ruleValidate: {
val: [
{ required: true, validator: validateVal, trigger: 'blur' }
],
type: [
{ required: true, message: '请选择消息类型', trigger: 'change' }
],
content: [
{ required: true, validator: validateContent, trigger: 'blur' }
],
mediaId: [
{ required: true, validator: validateSrc, trigger: 'change' }
]
},
labelarr: [],
myHeaders: { 'X-Token': getToken() }
}
},
computed: {
fileUrl() {
return https + `/wechat/reply/upload/image`
},
voiceUrl() {
return https + `/wechat/reply/upload/voice`
},
httpsURL() {
return process.env.VUE_APP_BASE_API.replace('api/', '')
}
},
watch: {
$route(to, from) {
if (this.$route.params.id) {
// this.formValidate.keywords = this.$route.params.key
this.details()
} else {
// this.labelarr = []
// this.$refs['formValidate'].resetFields()
}
}
},
mounted() {
if (this.$route.params.id) {
this.details()
}
if (this.$route.path.indexOf('keyword') === -1) {
this.followDetails()
}
},
methods: {
change (e) {
this.$forceUpdate()
},
// 上传
handleUploadForm(param){
const formData = new FormData()
formData.append('media', param.file)
let loading = this.$loading({
lock: true,
text: '上传中,请稍候...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
fileImageApi(formData, {type: this.formValidate.type === 'image'?'image':'voice'}).then(res => {
loading.close()
this.formValidate.contents.mediaId = res.mediaId
this.formValidate.contents.srcUrl = res.url
this.$message.success('上传成功')
}).catch(() => {
loading.close()
})
},
changePic() {
const _this = this
this.$modalArticle(function(row) {
_this.formValidate.contents.articleData ={
title: row.title,
imageInput : row.imageInput
}
_this.formValidate.contents.articleId = row.id
})
},
handleClosePic() {
this.visible = false
},
// 详情
details() {
this.loading = true
replyInfoApi({id:this.$route.params.id}).then(async res => {
const info = res || null
this.formValidate = {
status: info.status,
type: info.type,
keywords: info.keywords,
id: info.id,
contents: {
content: JSON.parse(info.data).content,
mediaId: JSON.parse(info.data).mediaId,
srcUrl: JSON.parse(info.data).srcUrl
}
}
this.labelarr = info.keywords.split(',') || []
this.loading = false
}).catch(() => {
this.loading = false
})
},
// 关注回复,无效关键词详情
followDetails() {
this.loading = true
keywordsInfoApi({ keywords: this.$route.path.indexOf('follow') !== -1 ? 'subscribe' : 'default'}).then(async res => {
const info = res || null
this.formValidate = {
status: info.status,
type: info.type,
keywords: info.keywords,
data: '',
id: info.id,
contents: {
content: JSON.parse(info.data).content || '',
mediaId: JSON.parse(info.data).mediaId || '',
srcUrl: JSON.parse(info.data).srcUrl || '',
articleData: JSON.parse(info.data).articleData || {},
}
}
this.loading = false
}).catch(() => {
this.loading = false
// if (res.message === '数据不存在') return
// this.$message.error(res.message)
})
},
// 下拉选择
RuleFactor(type) {
switch (type) {
case 'text':
this.formValidate.contents.mediaId = ''
this.formValidate.contents.srcUrl = ''
this.formValidate.contents.articleData = {}
break
case 'news':
this.formValidate.contents.mediaId = ''
this.formValidate.contents.content = ''
this.formValidate.contents.srcUrl = ''
this.formValidate.contents.articleData = {}
break
default:
this.formValidate.contents.content = ''
this.formValidate.contents.mediaId = ''
this.formValidate.contents.articleData = {}
}
// this.$refs['formValidate'].resetFields();
},
handleClose(tag) {
const index = this.labelarr.indexOf(tag)
this.labelarr.splice(index, 1)
},
addlabel() {
const count = this.labelarr.indexOf(this.val)
if (count === -1) {
this.labelarr.push(this.val)
}
this.val = ''
},
// 保存
submenus(name) {
this.$refs[name].validate((valid) => {
if (valid) {
this.formValidate.keywords = this.labelarr.join(',')
this.formValidate.data = JSON.stringify(this.formValidate.contents)
if (this.$route.path.indexOf('keyword') !== -1) {
this.$route.params.id ? replyUpdateApi({id:this.$route.params.id}, this.formValidate).then(async res => {
this.operation()
}).catch(res => {
this.$message.error(res.message)
}) : replySaveApi(this.formValidate).then(async res => {
this.operation()
}).catch(res => {
this.$message.error(res.message)
})
} else {
this.$route.path.indexOf('follow') !== -1 ? this.formValidate.keywords = 'subscribe' : this.formValidate.keywords ='default'
replyUpdateApi({id:this.formValidate.id}, this.formValidate).then(async res => {
this.$message.success('操作成功')
})
}
} else {
return false
}
})
},
// 保存成功操作
operation() {
this.$modalSure('继续添加').then(() => {
setTimeout(() => {
this.labelarr = []
this.val = ''
this.$refs['formValidate'].resetFields()
this.formValidate.contents.mediaId = ''
}, 1000)
}).catch(() => {
setTimeout(() => {
this.$router.push({ path: `/publicAccount/wxReply/keyword` })
}, 500)
})
}
}
}
</script>
<style scoped lang="scss">
.newsBox{
background: #fff;
}
.arrbox {
background-color: white;
font-size: 12px;
border: 1px solid #dcdee2;
border-radius: 6px;
margin-bottom: 0px;
padding:0 5px;
text-align: left;
box-sizing: border-box;
width: 90%;
}
.news_sp{
font-size: 12px;
color: #000000;
background: #fff;
width: 100%;
height: 38px;
line-height: 38px;
padding: 0 12px;
box-sizing: border-box;
display: block;
}
.arrbox_ip {
font-size: 12px;
border: none;
box-shadow: none;
outline: none;
background-color: transparent;
padding: 0;
margin: 0;
width: auto !important;
max-width: inherit;
min-width: 80px;
vertical-align: top;
color: #34495e;
margin: 2px;
}
.left {
min-width: 390px;
min-height: 550px;
position: relative;
padding-left: 40px;
}
.top {
position: absolute;
top: 0px;
}
.bottom {
position: absolute;
bottom: 0px;
}
.centent {
background: #F4F5F9;
min-height: 545px;
width: 320px;
padding: 15px;
box-sizing: border-box;
}
.right {
background: #fff;
min-height: 300px;
}
.box-content {
position: relative;
max-width: 60%;
min-height: 40px;
margin-left: 15px;
padding: 10px;
box-sizing: border-box;
border: 1px solid #ccc;
word-break: break-all;
word-wrap: break-word;
line-height: 1.5;
border-radius: 5px;
}
.box-content_pic {
width: 100%;
}
.box-content_pic img {
width: 100%;
height: auto;
}
.box-content:before {
content: '';
position: absolute;
left: -13px;
top: 11px;
display: block;
width: 0;
height: 0;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
border-top: 10px solid #ccc;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
}
.box-content:after {
content: '';
content: '';
position: absolute;
left: -12px;
top: 11px;
display: block;
width: 0;
height: 0;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
border-top: 10px solid #f5f5f5;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
}
.time-wrapper {
margin-bottom: 10px;
text-align: center;
margin-top: 62px;
}
.time {
display: inline-block;
color: #f5f5f5;
background: rgba(0, 0, 0, .3);
padding: 3px 8px;
border-radius: 3px;
font-size: 12px;
}
.text-box {
display: flex;
}
.avatar {
width: 40px;
height: 40px;
}
.avatar img {
width: 100%;
height: 100%;
}
.modelBox{
.ivu-modal-body{
padding: 0 16px 16px 16px !important;
}
}
.news_pic{
width: 100%;
height: 150px;
overflow: hidden;
position: relative;
background-size: 100%;
background-position: center center;
border-radius: 5px 5px 0 0;
padding: 10px;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: flex-end;
}
.news_cent{
width: 100%;
height: auto;
background: #fff;
border-top: 1px dashed #eee;
display: flex;
padding: 10px;
box-sizing: border-box;
justify-content: space-between;
.news_sp1{
font-size: 12px;
color: #000000;
width: 71%;
}
.news_cent_img{
width: 81px;
height: 46px;
border-radius: 6px;
overflow: hidden;
img{
width: 100%;
height: 100%;
}
}
}
</style>

View File

@@ -0,0 +1,3 @@
<template>
<router-view />
</template>

View File

@@ -0,0 +1,156 @@
<template>
<div class="divBox">
<el-card class="box-card">
<div slot="header" class="clearfix">
<div class="container">
<el-form size="small" :inline="true">
<el-form-item label="回复类型:">
<el-select v-model="tableFrom.type" placeholder="请选择类型" @change="seachList" class="selWidth">
<el-option label="文本消息" value="text"></el-option>
<el-option label="图片消息" value="image"></el-option>
<el-option label="图文消息" value="news"></el-option>
<el-option label="音频消息" value="voice"></el-option>
</el-select>
</el-form-item>
<el-form-item label="关键字:">
<el-input v-model="tableFrom.keywords" placeholder="请输入关键字" class="selWidth" size="small">
<el-button slot="append" icon="el-icon-search" size="small" @click="seachList" />
</el-input>
</el-form-item>
</el-form>
<router-link :to="{path: '/appSetting/publicAccount/wxReply/keyword/save'}">
<el-button size="small" type="primary">添加关键字</el-button>
</router-link>
</div>
</div>
<el-table
v-loading="listLoading"
:data="tableData.data"
style="width: 100%"
size="small"
highlight-current-row
>
<el-table-column
prop="id"
label="ID"
width="60"
/>
<el-table-column
prop="keywords"
label="关键字"
min-width="150"
/>
<el-table-column
label="回复类型"
min-width="100"
>
<template slot-scope="scope">
<span>{{ scope.row.type | keywordStatusFilter}}</span>
</template>
</el-table-column>
<el-table-column
prop="status"
label="是否显示"
min-width="100"
>
<template slot-scope="scope">
<el-switch
v-model="scope.row.status"
:active-value="true"
:inactive-value="false"
@change="onchangeIsShow(scope.row)"
/>
</template>
</el-table-column>
<el-table-column label="操作" min-width="100">
<template slot-scope="scope">
<router-link :to="{path: '/appSetting/publicAccount/wxReply/keyword/save/' + scope.row.id}">
<el-button type="text" size="small">编辑</el-button>
</router-link>
<el-button type="text" size="small" @click="handleDelete(scope.row.id, scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="block">
<el-pagination
:page-sizes="[20, 40, 60, 80]"
:page-size="tableFrom.limit"
:current-page="tableFrom.page"
layout="total, sizes, prev, pager, next, jumper"
:total="tableData.total"
@size-change="handleSizeChange"
@current-change="pageChange"
/>
</div>
</el-card>
</div>
</template>
<script>
import { replyListApi, replyDeleteApi, replyUpdateApi } from '@/api/wxApi'
import { getToken } from '@/utils/auth'
export default {
name: 'WechatKeyword',
data() {
return {
tableData: {
data: [],
total: 0
},
tableFrom: {
page: 1,
limit: 20,
keywords: '',
type: ''
},
listLoading: true
}
},
created() {
this.getList()
},
methods: {
seachList() {
this.tableFrom.page = 1
this.getList()
},
onchangeIsShow(row) {
replyUpdateApi(row.id, row).then(() => {
this.$message.success('修改成功')
})
},
// 列表
getList() {
this.listLoading = true
replyListApi(this.tableFrom).then(res => {
this.tableData.data = res.list
this.tableData.total = res.total
this.listLoading = false
}).catch(res => {
this.listLoading = false
})
},
pageChange(page) {
this.tableFrom.page = page
this.getList()
},
handleSizeChange(val) {
this.tableFrom.limit = val
this.getList()
},
// 删除
handleDelete(id, idx) {
this.$modalSure().then(() => {
replyDeleteApi(id).then(() => {
this.$message.success('删除成功')
this.getList()
})
})
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,422 @@
<template>
<div class="divBox">
<el-card class="box-card">
<el-row :gutter="30">
<el-col v-bind="grid" class="left mb15 ml40">
<div>
<img class="top" src="@/assets/imgs/mobilehead.png">
<img class="bottom" src="@/assets/imgs/mobilefoot.png">
<div
style="background: #F4F5F9; min-height: 438px; position: absolute;
top: 63px; width: 320px; "
/>
<div class="textbot">
<div v-for="(item,indx) in list" :key="indx" class="li" :class="{active:item === formValidate}">
<div>
<div class="add" @click="add(item,indx)">
<i class="el-icon-plus" />
<div class="arrow" />
</div>
<div class="tianjia">
<div
v-for="(j,index) in item.sub_button"
:key="index"
class="addadd menuBox"
:class="{active:j === formValidate}"
@click="gettem(j,index,indx)"
>
<el-tooltip class="item" effect="dark" :content="j.name" placement="top-start">
<el-button>{{ j.name || '二级菜单' }}</el-button>
</el-tooltip>
</div>
</div>
</div>
<div class="text menuBox" @click="gettem(item,indx,null)">
<el-tooltip class="item" effect="dark" :content="item.name" placement="top-start">
<el-button>{{ item.name || '一级菜单' }}</el-button>
</el-tooltip>
</div>
</div>
<div v-show="list.length < 3" class="li">
<div class="text" @click="addtext"><i class="el-icon-plus" /></div>
</div>
</div>
</div>
</el-col>
<el-col :xl="11" :lg="12" :md="22" :sm="22" :xs="22">
<div v-if="checkedMenuId !== null">
<div class="dividerTitle acea-row row-between row-bottom">
<span class="title">菜单信息</span>
<el-button slot="extra" size="small" type="danger" @click="deltMenus">删除</el-button>
<el-divider />
</div>
<el-col :span="24" class="userAlert">
<div class="box-card right">
<el-alert
class="mb15"
title="已添加子菜单,仅可设置菜单名称"
type="success"
show-icon
/>
<el-form ref="formValidate" :model="formValidate" :rules="ruleValidate" label-width="100px" class="mt20">
<el-form-item label="菜单名称" prop="name">
<el-input v-model="formValidate.name" placeholder="请填写菜单名称" class="spwidth" />
</el-form-item>
<el-form-item label="规则状态" prop="type">
<el-select v-model="formValidate.type" placeholder="请选择规则状态" class="spwidth">
<el-option value="click" label="关键字">关键字</el-option>
<el-option value="view" label="跳转网页">跳转网页</el-option>
<el-option value="miniprogram" label="小程序">小程序</el-option>
</el-select>
</el-form-item>
<div v-if="formValidate.type === 'click'">
<el-form-item label="关键字" prop="key">
<el-input v-model="formValidate.key" placeholder="请填写关键字" class="spwidth" />
</el-form-item>
</div>
<div v-if="formValidate.type === 'miniprogram'">
<el-form-item label="appid" prop="appid">
<el-input v-model="formValidate.appid" placeholder="请填写appid" class="spwidth" />
</el-form-item>
<el-form-item label="备用网页" prop="pagepath">
<el-input v-model="formValidate.pagepath" placeholder="请填写备用网页" class="spwidth" />
</el-form-item>
<el-form-item label="小程序路径" prop="url">
<el-input v-model="formValidate.url" placeholder="请填写小程序路径" class="spwidth" />
</el-form-item>
</div>
<div v-if="formValidate.type === 'view'">
<el-form-item label="跳转地址" prop="url">
<el-input v-model="formValidate.url" placeholder="请填写跳转地址" class="spwidth" />
</el-form-item>
</div>
</el-form>
</div>
</el-col>
</div>
<el-col v-if="isTrue" :span="24">
<el-button size="mini" type="primary" style="display: block;margin: 10px auto;" @click="submenus('formValidate')">保存并发布</el-button>
</el-col>
</el-col>
</el-row>
</el-card>
</div>
</template>
<script>
import { wechatMenuApi, wechatMenuAddApi } from '@/api/wxApi'
export default {
name: 'WechatMenus',
data() {
return {
grid: {
xl: 8,
lg: 8,
md: 8,
sm: 8,
xs: 24
},
grid2: {
xl: 16,
lg: 16,
md: 16,
sm: 16,
xs: 24
},
modal2: false,
formValidate: {
name: '',
type: 'click',
appid: '',
url: '',
key: '',
pagepath: '',
id: 0
},
ruleValidate: {
name: [
{ required: true, message: '请填写菜单名称', trigger: 'blur' }
],
key: [
{ required: true, message: '请填写关键字', trigger: 'blur' }
],
appid: [
{ required: true, message: '请填写appid', trigger: 'blur' }
],
pagepath: [
{ required: true, message: '请填写备用网页', trigger: 'blur' }
],
url: [
{ required: true, message: '请填写跳转地址', trigger: 'blur' }
],
type: [
{ required: true, message: '请选择规则状态', trigger: 'change' }
]
},
parentMenuId: null,
list: [],
checkedMenuId: null,
isTrue: false,
isAsync: false
}
},
mounted() {
this.getMenus()
if (this.list.length) {
this.formValidate = this.list[this.activeClass]
} else {
return this.formValidate
}
},
methods: {
// 添加一级字段函数
defaultMenusData() {
return {
type: 'click',
name: '',
sub_button: []
}
},
// 添加二级字段函数
defaultChildData() {
return {
type: 'click',
name: ''
}
},
// 获取 菜单
getMenus() {
wechatMenuApi({ isAsync:this.isAsync }).then(async res => {
const data = res.menu
this.list = data.button
})
},
// 点击保存提交
submenus(name) {
if (this.isTrue && !this.checkedMenuId && this.checkedMenuId !== 0) {
this.putData()
} else {
this.$refs[name].validate((valid) => {
if (valid) {
this.putData()
} else {
if (!this.check()) return false
}
})
}
},
// 新增data
putData() {
const data = {
button: this.list
}
wechatMenuAddApi(data).then(async res => {
this.$message.success('提交成功')
this.checkedMenuId = null
this.formValidate = {}
this.isTrue = false
})
},
// 点击元素
gettem(item, index, pid) {
this.checkedMenuId = index
this.formValidate = item
this.parentMenuId = pid
this.isTrue = true
},
// 增加二级
add(item, index) {
if (!this.check()) return false
if (item.sub_button.length < 5) {
const data = this.defaultChildData()
const id = item.sub_button.length
item.sub_button.push(data)
this.formValidate = data
this.checkedMenuId = id
this.parentMenuId = index
this.isTrue = true
}
},
// 增加一级
addtext() {
if (!this.check()) return false
const data = this.defaultMenusData()
const id = this.list.length
this.list.push(data)
this.formValidate = data
this.checkedMenuId = id
this.parentMenuId = null
this.isTrue = true
},
// 判断函数
check: function() {
const reg = /[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\.?/
if (this.checkedMenuId === null) return true
if (!this.isTrue) return true
if (!this.formValidate.name) {
this.$message.warning('请输入按钮名称!')
return false
}
if (this.formValidate.type === 'click' && !this.formValidate.key) {
this.$message.warning('请输入关键字!')
return false
}
if (this.formValidate.type === 'view' && !(reg.test(this.formValidate.url))) {
this.$message.warning('请输入正确的跳转地址!')
return false
}
if (this.formValidate.type === 'miniprogram' &&
(!this.formValidate.appid ||
!this.formValidate.pagepath ||
!this.formValidate.url)) {
this.$message.warning('请填写完整小程序配置!')
return false
}
return true
},
// 删除
deltMenus() {
if (this.isTrue) {
this.$modalSure().then(() => {
this.del()
})
} else {
this.$message.warning('请选择菜单!')
}
},
// 确认删除
del() {
this.parentMenuId === null ? this.list.splice(this.checkedMenuId, 1) : this.list[this.parentMenuId].sub_button.splice(this.checkedMenuId, 1)
this.parentMenuId = null
this.formValidate = {
name: '',
type: 'click',
appid: '',
url: '',
key: '',
pagepath: '',
id: 0
}
this.isTrue = true
this.modal2 = false
this.checkedMenuId = null
this.$refs['formValidate'].resetFields()
}
}
}
</script>
<style scoped lang="scss">
.menuBox{
/deep/.el-button{
border: none;
background: bottom;
padding: 0 !important;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
width: 100%;
}
}
*{
-moz-user-select: none; /*火狐*/
-webkit-user-select: none; /*webkit浏览器*/
-ms-user-select: none; /*IE10*/
-khtml-user-select: none; /*早期浏览器*/
user-select: none;
}
.title{
margin-bottom: -19px !important;
padding-bottom: 17px !important;
}
.left {
min-width: 390px;
min-height: 550px;
position: relative;
padding-left: 40px;
}
.top {
position: absolute;
top: 0px;
}
.bottom {
position: absolute;
bottom: 0px;
}
.textbot {
position: absolute;
bottom: 0px;
left: 59px;
width: 100%;
}
.active {
border: 1px solid #44B549 !important;
color: #44B549 !important;
}
.li {
float: left;
width: 93px;
line-height: 48px;
border: 1px solid #E7E7EB;
background: #FAFAFA;
text-align: center;
cursor: pointer;
color: #999;
position: relative;
}
.text{
height: 50px;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
}
.text:hover {
color: #000;
}
.add {
position: absolute;
bottom: 65px;
width: 100%;
line-height: 48px;
border: 1px solid #E7E7EB;
background: #FAFAFA;
}
.arrow {
position: absolute;
bottom: -16px;
left: 36px;
/* 圆角的位置需要细心调试哦 */
width: 0;
height: 0;
font-size: 0;
border: solid 8px;
border-color:#fff #F4F5F9 #F4F5F9 #F4F5F9;
}
.tianjia {
position: absolute;
bottom: 115px;
width: 100%;
line-height: 48px;
background: #FAFAFA;
}
.addadd {
width: 100%;
line-height: 48px;
border: 1px solid #E7E7EB;
background: #FAFAFA;
height: 48px;
padding: 0 5px;
box-sizing: border-box;
}
.right {
background: #fff;
min-height: 400px;
}
.spwidth{
width: 100%;
}
</style>

View File

@@ -0,0 +1,226 @@
<template>
<div class="divBox">
<el-card class="box-card">
<div slot="header" class="clearfix">
<div class="container">
<el-form size="small" :inline="true" label-width="100px">
<el-form-item label="状态:">
<el-select v-model="tableFrom.status" placeholder="请选择状态" clearable class="selWidth">
<el-option :label="item.label" :value="item.value" v-for="(item, index) in switchData" :key="index"></el-option>
</el-select>
</el-form-item>
<el-form-item label="类型:">
<el-select v-model="tableFrom.type" placeholder="请选择类型" clearable class="selWidth">
<el-option label="订阅消息" value="0"></el-option>
<el-option label="模板消息" value="1"></el-option>
</el-select>
</el-form-item>
<el-form-item label="模板名称:">
<el-input v-model="tableFrom.name" placeholder="请输入模板名称" class="selWidth" size="small"></el-input>
</el-form-item>
<el-form-item label="微信模板ID">
<el-input v-model="tableFrom.tempId" placeholder="请输入微信模板ID" class="selWidth" size="small"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="seachList" size="small">查询</el-button>
</el-form-item>
</el-form>
<el-button type="primary" @click="add" size="small">添加模板消息</el-button>
</div>
</div>
<el-table
v-loading="listLoading"
:data="tableData.data"
style="width: 100%"
size="mini"
class="table"
highlight-current-row
>
<el-table-column
label="ID"
width="80"
prop="id"
/>
<el-table-column
prop="tempId"
label="模板ID"
min-width="340"
/>
<el-table-column
prop="name"
label="模板名"
min-width="150"
/>
<el-table-column
label="回复内容"
min-width="200"
>
<template slot-scope="scope">
<span v-for="(item, index) in scope.row.content.split('\n')" :key="index" style="display: block">{{item}}</span>
</template>
</el-table-column>
<el-table-column
label="状态"
width="100"
>
<template slot-scope="scope">
<el-switch
v-model="scope.row.status"
class="demo"
active-text="开启"
inactive-text="关闭"
:active-value="1"
:inactive-value="0"
@click.native="onchangeIsShow(scope.row)"
/>
</template>
</el-table-column>
<el-table-column
prop="createTime"
label="添加时间"
min-width="150"
/>
<el-table-column label="操作" min-width="150" fixed="right" align="center">
<template slot-scope="scope">
<el-button type="text" size="small" @click="edit(scope.row)">编辑</el-button>
<el-button type="text" size="small" @click="handleDelete(scope.row, scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="block">
<el-pagination
:page-sizes="[20, 40, 60, 80]"
:page-size="tableFrom.limit"
:current-page="tableFrom.page"
layout="total, sizes, prev, pager, next, jumper"
:total="tableData.total"
@size-change="handleSizeChange"
@current-change="pageChange"
/>
</div>
</el-card>
<!--编辑-->
<el-dialog
title="编辑订单"
:visible.sync="dialogVisible"
width="500px"
:before-close="handleClose">
<zb-parser
v-if="dialogVisible"
:form-id="105"
:is-create="isCreate"
:edit-data="editData"
@submit="handlerSubmit"
/>
</el-dialog>
</div>
</template>
<script>
import * as constants from '@/utils/constants.js'
import { wechatTemplateListApi, wechatTemplateStatusApi, wechatTemplateSaveApi, wechatTemplateUpdateApi, wechatTemplateDeleteApi} from '@/api/wxApi'
import zbParser from '@/components/FormGenerator/components/parser/ZBParser'
export default {
name: "Templates",
components: { zbParser },
data() {
return {
labelPosition:'right',
isCreate: 0,
editData: {},
dialogVisible: false,
switchData: constants.switchStatus,
tableFrom: {
page: 1,
limit: 20,
status: '',
name: '',
type: this.$route.path.indexOf('routineTemplate') !== -1? '0' :'1',
tempId: ''
},
tableData: {
data: [],
total: 0
},
listLoading: true,
tempId: null
}
},
mounted() {
this.getList()
},
methods: {
seachList() {
this.tableFrom.page = 1
this.getList()
},
// 订单删除
handleDelete(row, idx) {
this.$modalSure().then(() => {
wechatTemplateDeleteApi( row.id ).then(() => {
this.$message.success('删除成功')
this.tableData.data.splice(idx, 1)
})
})
},
handleClose() {
this.dialogVisible = false
this.editData = {}
},
handlerSubmit(formValue) {
this.isCreate === 0 ? wechatTemplateSaveApi(formValue).then(data => {
this.$message.success('新增成功')
this.dialogVisible = false
this.editData = {}
this.getList()
}) : wechatTemplateUpdateApi(this.tempId, formValue).then(data => {
this.$message.success('编辑成功')
this.dialogVisible = false
this.getList()
})
},
add() {
this.dialogVisible = true
},
edit(row) {
this.tempId = row.id
this.dialogVisible = true
this.isCreate = 1
this.editData = JSON.parse(JSON.stringify(row))
},
// 列表
getList() {
this.listLoading = true
wechatTemplateListApi(this.tableFrom).then(res => {
this.tableData.data = res.list || []
this.tableData.total = res.total
this.listLoading = false
}).catch(() => {
this.listLoading = false
})
},
pageChange(page) {
this.tableFrom.page = page
this.getList()
},
handleSizeChange(val) {
this.tableFrom.limit = val
this.getList()
},
// 修改状态
onchangeIsShow(row) {
wechatTemplateStatusApi(row.id, {status: row.status}).then(() => {
this.$message.success('修改成功')
this.getList()
})
}
}
}
</script>
<style scoped lang="scss">
.selWidth {
width: 350px;
}
</style>

View File

@@ -0,0 +1,205 @@
<template>
<div class="components-container">
<el-form ref="pram" label-width="150px" :model="pram">
<el-form-item label="标题" prop="title" :rules="[{required:true, message:'请填写标题', trigger:['blur','change']}]">
<el-input v-model="pram.title" placeholder="标题" maxlength="100"/>
</el-form-item>
<el-form-item label="作者" prop="author" :rules="[{required:true, message:'请填作者', trigger:['blur','change']}]">
<el-input v-model="pram.author" placeholder="作者" maxlength="20"/>
</el-form-item>
<el-form-item label="文章分类">
<!-- prop="cid" :rules="[{required:true, message:'请选择文章分类', trigger:['blur','change']}]"-->
<el-cascader v-model="pram.cid" :options="categoryTreeData" :props="categoryProps" style="width:100%;" />
</el-form-item>
<el-form-item label="图文封面" prop="imageInput" :rules="[{ required: true, message: '请上传图文封面', trigger: 'change' }]">
<div class="upLoadPicBox" @click="modalPicTap('1')">
<div v-if="pram.imageInput" class="pictrue"><img :src="pram.imageInput"></div>
<div v-else class="upLoad">
<i class="el-icon-camera cameraIconfont" />
</div>
</div>
</el-form-item>
<!--<el-form-item label="微信公众号封面" prop="imageInput" :rules="[{ required: true, message: '请上传图文封面', trigger: 'change' }]">-->
<!--<div class="upLoadPicBox">-->
<!--<div v-if="pram.imageInput" class="pictrue"><img :src="pram.imageInput"></div>-->
<!--<el-upload-->
<!--v-else-->
<!--class="upload-demo mr10 mb15"-->
<!--action-->
<!--:http-request="handleUploadForm"-->
<!--:headers="myHeaders"-->
<!--:show-file-list="false"-->
<!--multiple-->
<!--&gt;-->
<!--<div class="upLoad">-->
<!--<i class="el-icon-camera cameraIconfont" />-->
<!--</div>-->
<!--</el-upload>-->
<!--</div>-->
<!--</el-form-item>-->
<el-form-item label="文章简介" prop="synopsis" :rules="[{required:true, message:'请填写文章简介', trigger:['blur','change']}]">
<el-input v-model="pram.synopsis" maxlength="100" type="textarea" :rows="2" resize="none" placeholder="文章简介" />
</el-form-item>
<el-form-item label="文章内容" prop="content" :rules="[{required:true, message:'请填写文章内容', trigger:['blur','change']}]">
<ueditor-from v-model="pram.content" :content="pram.content" />
</el-form-item>
<el-form-item label="是否Banner">
<el-switch v-model="pram.isBanner" />
</el-form-item>
<el-form-item label="是否热门">
<el-switch v-model="pram.isHot" />
</el-form-item>
<el-form-item label="原文链接">
<p>原文链接选填填写之后在图文左下方会出现此链接</p>
<el-input v-model="pram.url" placeholder="原文链接" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handerSubmit('pram')">保存</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import Tinymce from '@/components/Tinymce/index'
import * as categoryApi from '@/api/categoryApi.js'
import * as constants from '@/utils/constants.js'
import * as articleApi from '@/api/article.js'
import * as selfUtil from '@/utils/ZBKJIutil.js'
import { fileImageApi } from '@/api/systemSetting'
import { getToken } from '@/utils/auth'
export default {
// name: "edit",
components: { Tinymce },
props: {
isEdit: {
type: Number,
required: true
},
editData: {
type: Object
}
},
data() {
return {
constants,
categoryTreeData: [],
categoryProps: {
value: 'id',
label: 'name',
children: 'child',
expandTrigger: 'hover',
checkStrictly: true,
emitPath: false
},
pram: {
author: null,
cid: 0,
content: null,
imageInput: '',
isBanner: false,
isHot: null,
shareSynopsis: null,
shareTitle: null,
sort: 0,
synopsis: null,
title: null,
url: null,
id: null
// mediaId: null
},
myHeaders: { 'X-Token': getToken() }
}
},
mounted() {
this.handlerGetCategoryTreeData()
this.hadlerInitEditData()
},
methods: {
// 上传
handleUploadForm(param){
const formData = new FormData()
formData.append('media', param.file)
let loading = this.$loading({
lock: true,
text: '上传中,请稍候...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
fileImageApi(formData, {type: 'image'}).then(res => {
loading.close()
this.pram.mediaId = res.mediaId
// this.formValidate.contents.mediaId = res.mediaId
// this.formValidate.contents.srcUrl = res.url
this.$message.success('上传成功')
}).catch(() => {
loading.close()
})
},
modalPicTap(tit) {
const _this = this
this.$modalUpload(function(img) {
_this.pram.imageInput = img[0].sattDir
}, tit, 'content')
},
hadlerInitEditData() {
if (this.isEdit !== 1) return
const { author, cid, content, imageInput,
isBanner, isHot, shareSynopsis, shareTitle, sort, synopsis, title, url, id } = this.editData
this.pram.author = author
this.pram.cid = Number.parseInt(cid)
this.pram.content = content
this.pram.imageInput = imageInput
this.pram.isBanner = isBanner
this.pram.isHot = isHot
this.pram.shareSynopsis = shareSynopsis
this.pram.shareTitle = shareTitle
this.pram.sort = sort
this.pram.synopsis = synopsis
this.pram.title = title
this.pram.url = url
this.pram.id = id
// this.pram.mediaId = mediaId
},
handlerGetCategoryTreeData() {
const _pram = { type: constants.categoryType[2].value, status: 1 }
categoryApi.treeCategroy(_pram).then(data => {
this.categoryTreeData = selfUtil.addTreeListLabelForCasCard(data)
})
},
handerSubmit(form) {
this.$refs[form].validate(valid => {
if (!valid) return
if (this.isEdit === 0) {
this.handlerSave()
} else {
this.handlerUpdate()
}
})
},
handlerUpdate() {
this.pram.cid = Array.isArray(this.pram.cid) ? this.pram.cid[0] : this.pram.cid
this.pram.shareTitle = this.pram.title
this.pram.shareSynopsis = this.pram.synopsis
articleApi.UpdateArticle(this.pram).then(data => {
this.$message.success('编辑文章成功')
this.$emit('hideDialog')
})
},
handlerSave() {
this.pram.cid = Array.isArray(this.pram.cid) ? this.pram.cid[0] : this.pram.cid
this.pram.shareTitle = this.pram.title
this.pram.shareSynopsis = this.pram.synopsis
articleApi.AddArticle(this.pram).then(data => {
this.$message.success('新增文章成功')
this.$emit('hideDialog')
})
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,192 @@
<template>
<div class="divBox">
<el-card class="box-card">
<div slot="header" class="clearfix">
<div class="container">
<el-form inline size="small">
<el-form-item>
<el-input class="selWidth" v-model="listPram.keywords" placeholder="请输入关键词" clearable />
</el-form-item>
<el-form-item>
<el-select v-model="listPram.cid" clearable placeholder="请选择文章分类">
<el-option
v-for="item in categoryTreeData"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handerSearch">搜索</el-button>
</el-form-item>
</el-form>
</div>
<el-button size="mini" type="primary" @click="handlerOpenEdit(0)">添加文章</el-button>
</div>
<el-table :data="listData.list" size="mini"
class="table"
highlight-current-row>
<el-table-column
prop="id"
label="ID"
min-width="50"
/>
<el-table-column label="图片" min-width="80">
<template slot-scope="scope">
<div class="demo-image__preview">
<el-image
style="width: 36px; height: 36px"
:src="scope.row.imageInput[0]"
:preview-src-list="[scope.row.imageInput[0]]"
/>
</div>
</template>
</el-table-column>
<el-table-column prop="title" label="标题" min-width="180" />
<el-table-column prop="visit" label="文章分类" min-width="180">
<template slot-scope="scope">
<span>{{ scope.row.cid | articleTypeFilter }}</span>
</template>
</el-table-column>
<el-table-column prop="visit" label="浏览量" min-width="180">
<template slot-scope="scope">
<span>{{ scope.row.visit | filterEmpty }}</span>
</template>
</el-table-column>
<el-table-column prop="author" label="作者" min-width="180" />
<el-table-column prop="synopsis" label="文章简介" show-overflow-tooltip min-width="250"/>
<el-table-column prop="shareTitle" label="分享标题" show-overflow-tooltip min-width="200"/>
<el-table-column prop="updateTime" label="更新时间" min-width="180"/>
<el-table-column label="操作" min-width="180" fixed="right">
<template slot-scope="scope">
<el-button type="text" @click="handlerOpenEdit(1, scope.row)">编辑</el-button>
<el-button type="text" disabled>关联产品</el-button>
<el-button type="text" @click="handlerDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
:current-page="listPram.page"
:page-sizes="constants.page.limit"
:layout="constants.page.layout"
:total="listData.total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</el-card>
<el-dialog
:visible.sync="editDialogConfig.visible"
:title="editDialogConfig.isEdit === 0?'创建文章':'编辑文章'"
top="1vh"
width="80%"
destroy-on-close
:close-on-click-modal="false"
>
<edit
v-if="editDialogConfig.visible"
:is-edit="editDialogConfig.isEdit"
:edit-data="editDialogConfig.editData"
@hideDialog="handlerHideDialog"
/>
</el-dialog>
</div>
</template>
<script>
import * as articleApi from '@/api/article.js'
import * as categoryApi from '@/api/categoryApi.js'
import * as constants from '@/utils/constants.js'
import * as selfUtil from '@/utils/ZBKJIutil.js'
import edit from './edit'
export default {
// name: "list",
components: { edit },
data() {
return {
constants,
listPram: {
keywords: null,
cid: null,
page: 1,
limit: constants.page.limit[0]
},
listData: { list: [], total: 0 },
editDialogConfig: {
visible: false,
data: {},
isEdit: 0 // 0=add 1=edit
},
categoryTreeData: [],
categoryProps: {
value: 'id',
label: 'name',
children: 'child',
expandTrigger: 'hover',
checkStrictly: true,
emitPath: false
}
}
},
mounted() {
this.handlerGetListData(this.listPram)
this.handlerGetTreeList()
},
methods: {
handlerGetTreeList() {
categoryApi.listCategroy({ type: 3, status: '' }).then(data => {
this.categoryTreeData = data.list
localStorage.setItem('articleClass', JSON.stringify(data.list))
})
},
handerSearch() {
this.listPram.page = 1
this.handlerGetListData(this.listPram)
},
handlerGetListData(pram) {
articleApi.ListArticle(pram).then(data => {
this.listData = data
})
},
handlerOpenEdit(isEdit, editData) { // 0=add 1=edit
if (isEdit === 1) {
this.editDialogConfig.isEdit = 1
this.editDialogConfig.editData = editData
}else{
this.editDialogConfig.isEdit = 0
}
this.editDialogConfig.visible = true
},
// handlerGetCategoryTreeData() {
// const _pram = { type: constants.categoryType[2].value, status: 1 }
// categoryApi.treeCategroy(_pram).then(data => {
// this.categoryTreeData = selfUtil.addTreeListLabelForCasCard(data)
// })
// },
handlerHideDialog() {
this.handlerGetListData(this.listPram)
this.editDialogConfig.visible = false
},
handlerDelete(rowData) {
this.$confirm('确定删除当前数据', '提示').then(result => {
articleApi.DelArticle(rowData).then(data => {
this.$message.success('删除数据成功')
this.handlerGetListData(this.listPram)
})
})
},
handleSizeChange(val) {
this.listPram.limit = val
this.handlerGetListData(this.listPram)
},
handleCurrentChange(val) {
this.listPram.page = val
this.handlerGetListData(this.listPram)
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,23 @@
<template>
<div class="components-container">
<category-list :biztype="constants.categoryType[2]" />
</div>
</template>
<script>
import categoryList from '@/components/Category/list'
import * as constants from '@/utils/constants.js'
export default {
// name: "list",
components: { categoryList },
data() {
return {
constants
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,102 @@
<template>
<div :class="className" :style="{height:height,width:width}" />
</template>
<script>
import echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
import resize from './mixins/resize'
const animationDuration = 6000
export default {
mixins: [resize],
props: {
className: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '300px'
}
},
data() {
return {
chart: null
}
},
mounted() {
this.$nextTick(() => {
this.initChart()
})
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(this.$el, 'macarons')
this.chart.setOption({
tooltip: {
trigger: 'axis',
axisPointer: { // 坐标轴指示器,坐标轴触发有效
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
},
grid: {
top: 10,
left: '2%',
right: '2%',
bottom: '3%',
containLabel: true
},
xAxis: [{
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
axisTick: {
alignWithLabel: true
}
}],
yAxis: [{
type: 'value',
axisTick: {
show: false
}
}],
series: [{
name: 'pageA',
type: 'bar',
stack: 'vistors',
barWidth: '60%',
data: [79, 52, 200, 334, 390, 330, 220],
animationDuration
}, {
name: 'pageB',
type: 'bar',
stack: 'vistors',
barWidth: '60%',
data: [80, 52, 200, 334, 390, 330, 220],
animationDuration
}, {
name: 'pageC',
type: 'bar',
stack: 'vistors',
barWidth: '60%',
data: [30, 52, 200, 334, 390, 330, 220],
animationDuration
}]
})
}
}
}
</script>

View File

@@ -0,0 +1,118 @@
<template>
<el-card class="box-card-component" style="margin-left:8px;">
<div slot="header" class="box-card-header">
<img src="https://wpimg.wallstcn.com/e7d23d71-cf19-4b90-a1cc-f56af8c0903d.png">
</div>
<div style="position:relative;">
<pan-thumb :image="avatar" class="panThumb" />
<mallki class-name="mallki-text" text="vue-element-admin" />
<div style="padding-top:35px;" class="progress-item">
<span>Vue</span>
<el-progress :percentage="70" />
</div>
<div class="progress-item">
<span>JavaScript</span>
<el-progress :percentage="18" />
</div>
<div class="progress-item">
<span>Css</span>
<el-progress :percentage="12" />
</div>
<div class="progress-item">
<span>ESLint</span>
<el-progress :percentage="100" status="success" />
</div>
</div>
</el-card>
</template>
<script>
import { mapGetters } from 'vuex'
import PanThumb from '@/components/PanThumb'
import Mallki from '@/components/TextHoverEffect/Mallki'
export default {
components: { PanThumb, Mallki },
filters: {
statusFilter(status) {
const statusMap = {
success: 'success',
pending: 'danger'
}
return statusMap[status]
}
},
data() {
return {
statisticsData: {
article_count: 1024,
pageviews_count: 1024
}
}
},
computed: {
...mapGetters([
'name',
'avatar',
'roles'
])
}
}
</script>
<style lang="scss" scoped>
.box-card-component{
.el-card__header {
padding: 0px!important;
}
}
</style>
<style lang="scss" scoped>
.box-card-component {
.box-card-header {
position: relative;
height: 220px;
img {
width: 100%;
height: 100%;
transition: all 0.2s linear;
&:hover {
transform: scale(1.1, 1.1);
filter: contrast(130%);
}
}
}
.mallki-text {
position: absolute;
top: 0px;
right: 0px;
font-size: 20px;
font-weight: bold;
}
.panThumb {
z-index: 100;
height: 70px!important;
width: 70px!important;
position: absolute!important;
top: -45px;
left: 0px;
border: 5px solid #ffffff;
background-color: #fff;
margin: auto;
box-shadow: none!important;
/deep/ .pan-info {
box-shadow: none!important;
}
}
.progress-item {
margin-bottom: 10px;
font-size: 14px;
}
@media only screen and (max-width: 1510px){
.mallki-text{
display: none;
}
}
}
</style>

View File

@@ -0,0 +1,135 @@
<template>
<div :class="className" :style="{height:height,width:width}" />
</template>
<script>
import echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
import resize from './mixins/resize'
export default {
mixins: [resize],
props: {
className: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '350px'
},
autoResize: {
type: Boolean,
default: true
},
chartData: {
type: Object,
required: true
}
},
data() {
return {
chart: null
}
},
watch: {
chartData: {
deep: true,
handler(val) {
this.setOptions(val)
}
}
},
mounted() {
this.$nextTick(() => {
this.initChart()
})
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(this.$el, 'macarons')
this.setOptions(this.chartData)
},
setOptions({ expectedData, actualData } = {}) {
this.chart.setOption({
xAxis: {
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
boundaryGap: false,
axisTick: {
show: false
}
},
grid: {
left: 10,
right: 10,
bottom: 20,
top: 30,
containLabel: true
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
},
padding: [5, 10]
},
yAxis: {
axisTick: {
show: false
}
},
legend: {
data: ['expected', 'actual']
},
series: [{
name: 'expected', itemStyle: {
normal: {
color: '#FF005A',
lineStyle: {
color: '#FF005A',
width: 2
}
}
},
smooth: true,
type: 'line',
data: expectedData,
animationDuration: 2800,
animationEasing: 'cubicInOut'
},
{
name: 'actual',
smooth: true,
type: 'line',
itemStyle: {
normal: {
color: '#3888fa',
lineStyle: {
color: '#3888fa',
width: 2
},
areaStyle: {
color: '#f3f8ff'
}
}
},
data: actualData,
animationDuration: 2800,
animationEasing: 'quadraticOut'
}]
})
}
}
}
</script>

View File

@@ -0,0 +1,181 @@
<template>
<el-row :gutter="40" class="panel-group">
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('newVisitis')">
<div class="card-panel-icon-wrapper icon-people">
<svg-icon icon-class="peoples" class-name="card-panel-icon" />
</div>
<div class="card-panel-description">
<div class="card-panel-text">
New Visits
</div>
<count-to :start-val="0" :end-val="102400" :duration="2600" class="card-panel-num" />
</div>
</div>
</el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('messages')">
<div class="card-panel-icon-wrapper icon-message">
<svg-icon icon-class="message" class-name="card-panel-icon" />
</div>
<div class="card-panel-description">
<div class="card-panel-text">
Messages
</div>
<count-to :start-val="0" :end-val="81212" :duration="3000" class="card-panel-num" />
</div>
</div>
</el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('purchases')">
<div class="card-panel-icon-wrapper icon-money">
<svg-icon icon-class="money" class-name="card-panel-icon" />
</div>
<div class="card-panel-description">
<div class="card-panel-text">
Purchases
</div>
<count-to :start-val="0" :end-val="9280" :duration="3200" class="card-panel-num" />
</div>
</div>
</el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('shoppings')">
<div class="card-panel-icon-wrapper icon-shopping">
<svg-icon icon-class="shopping" class-name="card-panel-icon" />
</div>
<div class="card-panel-description">
<div class="card-panel-text">
Shoppings
</div>
<count-to :start-val="0" :end-val="13600" :duration="3600" class="card-panel-num" />
</div>
</div>
</el-col>
</el-row>
</template>
<script>
import CountTo from 'vue-count-to'
export default {
components: {
CountTo
},
methods: {
handleSetLineChartData(type) {
this.$emit('handleSetLineChartData', type)
}
}
}
</script>
<style lang="scss" scoped>
.panel-group {
margin-top: 18px;
.card-panel-col {
margin-bottom: 32px;
}
.card-panel {
height: 108px;
cursor: pointer;
font-size: 12px;
position: relative;
overflow: hidden;
color: #666;
background: #fff;
box-shadow: 4px 4px 40px rgba(0, 0, 0, .05);
border-color: rgba(0, 0, 0, .05);
&:hover {
.card-panel-icon-wrapper {
color: #fff;
}
.icon-people {
background: #40c9c6;
}
.icon-message {
background: #36a3f7;
}
.icon-money {
background: #f4516c;
}
.icon-shopping {
background: #34bfa3
}
}
.icon-people {
color: #40c9c6;
}
.icon-message {
color: #36a3f7;
}
.icon-money {
color: #f4516c;
}
.icon-shopping {
color: #34bfa3
}
.card-panel-icon-wrapper {
float: left;
margin: 14px 0 0 14px;
padding: 16px;
transition: all 0.38s ease-out;
border-radius: 6px;
}
.card-panel-icon {
float: left;
font-size: 48px;
}
.card-panel-description {
float: right;
font-weight: bold;
margin: 26px;
margin-left: 0px;
.card-panel-text {
line-height: 18px;
color: rgba(0, 0, 0, 0.45);
font-size: 16px;
margin-bottom: 12px;
}
.card-panel-num {
font-size: 20px;
}
}
}
}
@media (max-width:550px) {
.card-panel-description {
display: none;
}
.card-panel-icon-wrapper {
float: none !important;
width: 100%;
height: 100%;
margin: 0 !important;
.svg-icon {
display: block;
margin: 14px auto !important;
float: none !important;
}
}
}
</style>

View File

@@ -0,0 +1,79 @@
<template>
<div :class="className" :style="{height:height,width:width}" />
</template>
<script>
import echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
import resize from './mixins/resize'
export default {
mixins: [resize],
props: {
className: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '300px'
}
},
data() {
return {
chart: null
}
},
mounted() {
this.$nextTick(() => {
this.initChart()
})
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(this.$el, 'macarons')
this.chart.setOption({
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)'
},
legend: {
left: 'center',
bottom: '10',
data: ['Industries', 'Technology', 'Forex', 'Gold', 'Forecasts']
},
series: [
{
name: 'WEEKLY WRITE ARTICLES',
type: 'pie',
roseType: 'radius',
radius: [15, 95],
center: ['50%', '38%'],
data: [
{ value: 320, name: 'Industries' },
{ value: 240, name: 'Technology' },
{ value: 149, name: 'Forex' },
{ value: 100, name: 'Gold' },
{ value: 59, name: 'Forecasts' }
],
animationEasing: 'cubicInOut',
animationDuration: 2600
}
]
})
}
}
}
</script>

View File

@@ -0,0 +1,116 @@
<template>
<div :class="className" :style="{height:height,width:width}" />
</template>
<script>
import echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
import resize from './mixins/resize'
const animationDuration = 3000
export default {
mixins: [resize],
props: {
className: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '300px'
}
},
data() {
return {
chart: null
}
},
mounted() {
this.$nextTick(() => {
this.initChart()
})
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(this.$el, 'macarons')
this.chart.setOption({
tooltip: {
trigger: 'axis',
axisPointer: { // 坐标轴指示器,坐标轴触发有效
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
},
radar: {
radius: '66%',
center: ['50%', '42%'],
splitNumber: 8,
splitArea: {
areaStyle: {
color: 'rgba(127,95,132,.3)',
opacity: 1,
shadowBlur: 45,
shadowColor: 'rgba(0,0,0,.5)',
shadowOffsetX: 0,
shadowOffsetY: 15
}
},
indicator: [
{ name: 'Sales', max: 10000 },
{ name: 'Administration', max: 20000 },
{ name: 'Information Technology', max: 20000 },
{ name: 'Customer Support', max: 20000 },
{ name: 'Development', max: 20000 },
{ name: 'Marketing', max: 20000 }
]
},
legend: {
left: 'center',
bottom: '10',
data: ['Allocated Budget', 'Expected Spending', 'Actual Spending']
},
series: [{
type: 'radar',
symbolSize: 0,
areaStyle: {
normal: {
shadowBlur: 13,
shadowColor: 'rgba(0,0,0,.2)',
shadowOffsetX: 0,
shadowOffsetY: 10,
opacity: 1
}
},
data: [
{
value: [5000, 7000, 12000, 11000, 15000, 14000],
name: 'Allocated Budget'
},
{
value: [4000, 9000, 15000, 15000, 13000, 11000],
name: 'Expected Spending'
},
{
value: [5500, 11000, 12000, 15000, 12000, 12000],
name: 'Actual Spending'
}
],
animationDuration: animationDuration
}]
})
}
}
}
</script>

View File

@@ -0,0 +1,81 @@
<template>
<li :class="{ completed: todo.done, editing: editing }" class="todo">
<div class="view">
<input
:checked="todo.done"
class="toggle"
type="checkbox"
@change="toggleTodo( todo)"
>
<label @dblclick="editing = true" v-text="todo.text" />
<button class="destroy" @click="deleteTodo( todo )" />
</div>
<input
v-show="editing"
v-focus="editing"
:value="todo.text"
class="edit"
@keyup.enter="doneEdit"
@keyup.esc="cancelEdit"
@blur="doneEdit"
>
</li>
</template>
<script>
export default {
name: 'Todo',
directives: {
focus(el, { value }, { context }) {
if (value) {
context.$nextTick(() => {
el.focus()
})
}
}
},
props: {
todo: {
type: Object,
default: function() {
return {}
}
}
},
data() {
return {
editing: false
}
},
methods: {
deleteTodo(todo) {
this.$emit('deleteTodo', todo)
},
editTodo({ todo, value }) {
this.$emit('editTodo', { todo, value })
},
toggleTodo(todo) {
this.$emit('toggleTodo', todo)
},
doneEdit(e) {
const value = e.target.value.trim()
const { todo } = this
if (!value) {
this.deleteTodo({
todo
})
} else if (this.editing) {
this.editTodo({
todo,
value
})
this.editing = false
}
},
cancelEdit(e) {
e.target.value = this.todo.text
this.editing = false
}
}
}
</script>

View File

@@ -0,0 +1,320 @@
.todoapp {
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
line-height: 1.4em;
color: #4d4d4d;
min-width: 230px;
max-width: 550px;
margin: 0 auto ;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-weight: 300;
background: #fff;
z-index: 1;
position: relative;
button {
margin: 0;
padding: 0;
border: 0;
background: none;
font-size: 100%;
vertical-align: baseline;
font-family: inherit;
font-weight: inherit;
color: inherit;
-webkit-appearance: none;
appearance: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
:focus {
outline: 0;
}
.hidden {
display: none;
}
.todoapp {
background: #fff;
margin: 130px 0 40px 0;
position: relative;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
.todoapp input::-webkit-input-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
.todoapp input::-moz-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
.todoapp input::input-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
.todoapp h1 {
position: absolute;
top: -155px;
width: 100%;
font-size: 100px;
font-weight: 100;
text-align: center;
color: rgba(175, 47, 47, 0.15);
-webkit-text-rendering: optimizeLegibility;
-moz-text-rendering: optimizeLegibility;
text-rendering: optimizeLegibility;
}
.new-todo,
.edit {
position: relative;
margin: 0;
width: 100%;
font-size: 18px;
font-family: inherit;
font-weight: inherit;
line-height: 1.4em;
border: 0;
color: inherit;
padding: 6px;
border: 1px solid #999;
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.new-todo {
padding: 10px 16px 16px 60px;
border: none;
background: rgba(0, 0, 0, 0.003);
box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03);
}
.main {
position: relative;
z-index: 2;
border-top: 1px solid #e6e6e6;
}
.toggle-all {
text-align: center;
border: none;
/* Mobile Safari */
opacity: 0;
position: absolute;
}
.toggle-all+label {
width: 60px;
height: 34px;
font-size: 0;
position: absolute;
top: -52px;
left: -13px;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
}
.toggle-all+label:before {
content: '';
font-size: 22px;
color: #e6e6e6;
padding: 10px 27px 10px 27px;
}
.toggle-all:checked+label:before {
color: #737373;
}
.todo-list {
margin: 0;
padding: 0;
list-style: none;
}
.todo-list li {
position: relative;
font-size: 24px;
border-bottom: 1px solid #ededed;
}
.todo-list li:last-child {
border-bottom: none;
}
.todo-list li.editing {
border-bottom: none;
padding: 0;
}
.todo-list li.editing .edit {
display: block;
width: 506px;
padding: 12px 16px;
margin: 0 0 0 43px;
}
.todo-list li.editing .view {
display: none;
}
.todo-list li .toggle {
text-align: center;
width: 40px;
/* auto, since non-WebKit browsers doesn't support input styling */
height: auto;
position: absolute;
top: 0;
bottom: 0;
margin: auto 0;
border: none;
/* Mobile Safari */
-webkit-appearance: none;
appearance: none;
}
.todo-list li .toggle {
opacity: 0;
}
.todo-list li .toggle+label {
/*
Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433
IE and Edge requires *everything* to be escaped to render, so we do that instead of just the `#` - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7157459/
*/
background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E');
background-repeat: no-repeat;
background-position: center left;
background-size: 36px;
}
.todo-list li .toggle:checked+label {
background-size: 36px;
background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E');
}
.todo-list li label {
word-break: break-all;
padding: 15px 15px 15px 50px;
display: block;
line-height: 1.0;
font-size: 14px;
transition: color 0.4s;
}
.todo-list li.completed label {
color: #d9d9d9;
text-decoration: line-through;
}
.todo-list li .destroy {
display: none;
position: absolute;
top: 0;
right: 10px;
bottom: 0;
width: 40px;
height: 40px;
margin: auto 0;
font-size: 30px;
color: #cc9a9a;
transition: color 0.2s ease-out;
cursor: pointer;
}
.todo-list li .destroy:hover {
color: #af5b5e;
}
.todo-list li .destroy:after {
content: '×';
}
.todo-list li:hover .destroy {
display: block;
}
.todo-list li .edit {
display: none;
}
.todo-list li.editing:last-child {
margin-bottom: -1px;
}
.footer {
color: #777;
position: relative;
padding: 10px 15px;
height: 40px;
text-align: center;
border-top: 1px solid #e6e6e6;
}
.footer:before {
content: '';
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 40px;
overflow: hidden;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 8px 0 -3px #f6f6f6, 0 9px 1px -3px rgba(0, 0, 0, 0.2), 0 16px 0 -6px #f6f6f6, 0 17px 2px -6px rgba(0, 0, 0, 0.2);
}
.todo-count {
float: left;
text-align: left;
}
.todo-count strong {
font-weight: 300;
}
.filters {
margin: 0;
padding: 0;
position: relative;
z-index: 1;
list-style: none;
}
.filters li {
display: inline;
}
.filters li a {
color: inherit;
font-size: 12px;
padding: 3px 7px;
text-decoration: none;
border: 1px solid transparent;
border-radius: 3px;
}
.filters li a:hover {
border-color: rgba(175, 47, 47, 0.1);
}
.filters li a.selected {
border-color: rgba(175, 47, 47, 0.2);
}
.clear-completed,
html .clear-completed:active {
float: right;
position: relative;
line-height: 20px;
text-decoration: none;
cursor: pointer;
}
.clear-completed:hover {
text-decoration: underline;
}
.info {
margin: 65px auto 0;
color: #bfbfbf;
font-size: 10px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
text-align: center;
}
.info p {
line-height: 1;
}
.info a {
color: inherit;
text-decoration: none;
font-weight: 400;
}
.info a:hover {
text-decoration: underline;
}
/*
Hack to remove background from Mobile Safari.
Can't use it globally since it destroys checkboxes in Firefox
*/
@media screen and (-webkit-min-device-pixel-ratio:0) {
.toggle-all,
.todo-list li .toggle {
background: none;
}
.todo-list li .toggle {
height: 40px;
}
}
@media (max-width: 430px) {
.footer {
height: 50px;
}
.filters {
bottom: 10px;
}
}
}

View File

@@ -0,0 +1,127 @@
<template>
<section class="todoapp">
<!-- header -->
<header class="header">
<input class="new-todo" autocomplete="off" placeholder="Todo List" @keyup.enter="addTodo">
</header>
<!-- main section -->
<section v-show="todos.length" class="main">
<input id="toggle-all" :checked="allChecked" class="toggle-all" type="checkbox" @change="toggleAll({ done: !allChecked })">
<label for="toggle-all" />
<ul class="todo-list">
<todo
v-for="(todo, index) in filteredTodos"
:key="index"
:todo="todo"
@toggleTodo="toggleTodo"
@editTodo="editTodo"
@deleteTodo="deleteTodo"
/>
</ul>
</section>
<!-- footer -->
<footer v-show="todos.length" class="footer">
<span class="todo-count">
<strong>{{ remaining }}</strong>
{{ remaining | pluralize('item') }} left
</span>
<ul class="filters">
<li v-for="(val, key) in filters" :key="key">
<a :class="{ selected: visibility === key }" @click.prevent="visibility = key">{{ key | capitalize }}</a>
</li>
</ul>
<!-- <button class="clear-completed" v-show="todos.length > remaining" @click="clearCompleted">
Clear completed
</button> -->
</footer>
</section>
</template>
<script>
import Todo from './Todo.vue'
const STORAGE_KEY = 'todos'
const filters = {
all: todos => todos,
active: todos => todos.filter(todo => !todo.done),
completed: todos => todos.filter(todo => todo.done)
}
const defalutList = [
{ text: 'star this repository', done: false },
{ text: 'fork this repository', done: false },
{ text: 'follow author', done: false },
{ text: 'vue-element-admin', done: true },
{ text: 'vue', done: true },
{ text: 'element-ui', done: true },
{ text: 'axios', done: true },
{ text: 'webpack', done: true }
]
export default {
components: { Todo },
filters: {
pluralize: (n, w) => n === 1 ? w : w + 's',
capitalize: s => s.charAt(0).toUpperCase() + s.slice(1)
},
data() {
return {
visibility: 'all',
filters,
// todos: JSON.parse(window.localStorage.getItem(STORAGE_KEY)) || defalutList
todos: defalutList
}
},
computed: {
allChecked() {
return this.todos.every(todo => todo.done)
},
filteredTodos() {
return filters[this.visibility](this.todos)
},
remaining() {
return this.todos.filter(todo => !todo.done).length
}
},
methods: {
setLocalStorage() {
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(this.todos))
},
addTodo(e) {
const text = e.target.value
if (text.trim()) {
this.todos.push({
text,
done: false
})
this.setLocalStorage()
}
e.target.value = ''
},
toggleTodo(val) {
val.done = !val.done
this.setLocalStorage()
},
deleteTodo(todo) {
this.todos.splice(this.todos.indexOf(todo), 1)
this.setLocalStorage()
},
editTodo({ todo, value }) {
todo.text = value
this.setLocalStorage()
},
clearCompleted() {
this.todos = this.todos.filter(todo => !todo.done)
this.setLocalStorage()
},
toggleAll({ done }) {
this.todos.forEach(todo => {
todo.done = done
this.setLocalStorage()
})
}
}
}
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>

View File

@@ -0,0 +1,55 @@
<template>
<el-table :data="list" style="width: 100%;padding-top: 15px;">
<el-table-column label="Order_No" min-width="200">
<template slot-scope="scope">
{{ scope.row.order_no | orderNoFilter }}
</template>
</el-table-column>
<el-table-column label="Price" width="195" align="center">
<template slot-scope="scope">
¥{{ scope.row.price | toThousandFilter }}
</template>
</el-table-column>
<el-table-column label="Status" width="100" align="center">
<template slot-scope="{row}">
<el-tag :type="row.status | statusFilter">
{{ row.status }}
</el-tag>
</template>
</el-table-column>
</el-table>
</template>
<script>
import { transactionList } from '@/api/remote-search'
export default {
filters: {
statusFilter(status) {
const statusMap = {
success: 'success',
pending: 'danger'
}
return statusMap[status]
},
orderNoFilter(str) {
return str.substring(0, 30)
}
},
data() {
return {
list: null
}
},
created() {
this.fetchData()
},
methods: {
fetchData() {
transactionList().then(response => {
this.list = response.data.items.slice(0, 8)
})
}
}
}
</script>

View File

@@ -0,0 +1,55 @@
import { debounce } from '@/utils'
export default {
data() {
return {
$_sidebarElm: null,
$_resizeHandler: null
}
},
mounted() {
this.$_resizeHandler = debounce(() => {
if (this.chart) {
this.chart.resize()
}
}, 100)
this.$_initResizeEvent()
this.$_initSidebarResizeEvent()
},
beforeDestroy() {
this.$_destroyResizeEvent()
this.$_destroySidebarResizeEvent()
},
// to fixed bug when cached by keep-alive
// https://github.com/PanJiaChen/vue-element-admin/issues/2116
activated() {
this.$_initResizeEvent()
this.$_initSidebarResizeEvent()
},
deactivated() {
this.$_destroyResizeEvent()
this.$_destroySidebarResizeEvent()
},
methods: {
// use $_ for mixins properties
// https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
$_initResizeEvent() {
window.addEventListener('resize', this.$_resizeHandler)
},
$_destroyResizeEvent() {
window.removeEventListener('resize', this.$_resizeHandler)
},
$_sidebarResizeHandler(e) {
if (e.propertyName === 'width') {
this.$_resizeHandler()
}
},
$_initSidebarResizeEvent() {
this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
},
$_destroySidebarResizeEvent() {
this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
}
}
}

View File

@@ -0,0 +1,120 @@
<template>
<div class="dashboard-editor-container">
<panel-group @handleSetLineChartData="handleSetLineChartData" />
<el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
<line-chart :chart-data="lineChartData" />
</el-row>
<el-row :gutter="32">
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper">
<raddar-chart />
</div>
</el-col>
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper">
<pie-chart />
</div>
</el-col>
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper">
<bar-chart />
</div>
</el-col>
</el-row>
<el-row :gutter="8">
<el-col :xs="{span: 24}" :sm="{span: 24}" :md="{span: 24}" :lg="{span: 12}" :xl="{span: 12}" style="padding-right:8px;margin-bottom:30px;">
<transaction-table />
</el-col>
<el-col :xs="{span: 24}" :sm="{span: 12}" :md="{span: 12}" :lg="{span: 6}" :xl="{span: 6}" style="margin-bottom:30px;">
<todo-list />
</el-col>
<el-col :xs="{span: 24}" :sm="{span: 12}" :md="{span: 12}" :lg="{span: 6}" :xl="{span: 6}" style="margin-bottom:30px;">
<box-card />
</el-col>
</el-row>
</div>
</template>
<script>
import PanelGroup from './components/PanelGroup'
import LineChart from './components/LineChart'
import RaddarChart from './components/RaddarChart'
import PieChart from './components/PieChart'
import BarChart from './components/BarChart'
import TransactionTable from './components/TransactionTable'
import TodoList from './components/TodoList'
import BoxCard from './components/BoxCard'
const lineChartData = {
newVisitis: {
expectedData: [100, 120, 161, 134, 105, 160, 165],
actualData: [120, 82, 91, 154, 162, 140, 145]
},
messages: {
expectedData: [200, 192, 120, 144, 160, 130, 140],
actualData: [180, 160, 151, 106, 145, 150, 130]
},
purchases: {
expectedData: [80, 100, 121, 104, 105, 90, 100],
actualData: [120, 90, 100, 138, 142, 130, 130]
},
shoppings: {
expectedData: [130, 140, 141, 142, 145, 150, 160],
actualData: [120, 82, 91, 154, 162, 140, 130]
}
}
export default {
name: 'DashboardAdmin',
components: {
PanelGroup,
LineChart,
RaddarChart,
PieChart,
BarChart,
TransactionTable,
TodoList,
BoxCard
},
data() {
return {
lineChartData: lineChartData.newVisitis
}
},
methods: {
handleSetLineChartData(type) {
this.lineChartData = lineChartData[type]
}
}
}
</script>
<style lang="scss" scoped>
.dashboard-editor-container {
padding: 32px;
background-color: rgb(240, 242, 245);
position: relative;
.github-corner {
position: absolute;
top: 0px;
border: 0;
right: 0;
}
.chart-wrapper {
background: #fff;
padding: 16px 16px 0;
margin-bottom: 32px;
}
}
@media (max-width:1024px) {
.chart-wrapper {
padding: 8px;
}
}
</style>

View File

@@ -0,0 +1,176 @@
<template>
<div class="divBox">
<el-row :gutter="24" class="baseInfo">
<el-col v-bind="grid" class="ivu-mb">
<el-card :bordered="false" dis-hover :padding="12">
<div slot="header" class="acea-row row-between-wrapper">
<span>销售额</span>
<el-tag type="success">昨日</el-tag>
</div>
<div class="content" v-if="sales">
<span class="content-number spBlock mb15">{{ sales.count }}</span>
<div>
<span class="content-time mr20">日同比<i class="content-is" :class="Number(sales.dayRate)>=0?'up':'down'">{{ sales.dayRate }}</i><i :class="Number(sales.dayRate)>=0?'el-icon-caret-top':'el-icon-caret-bottom'" /></span>
<span class="content-time">周同比<i class="content-is" :class="Number(sales.weekRate)>=0?'up':'down'">{{ sales.weekRate }}</i><i :class="Number(sales.weekRate)>=0?'el-icon-caret-top':'el-icon-caret-bottom'" /></span>
</div>
<el-divider></el-divider>
<div class="acea-row row-between-wrapper">
<span class="content-time">总销售额</span>
<span>{{sales.total}} </span>
</div>
</div>
</el-card>
</el-col>
<el-col v-bind="grid" class="ivu-mb">
<el-card :bordered="false" dis-hover :padding="12">
<div slot="header" class="acea-row row-between-wrapper">
<span>用户量访问</span>
<el-tag type="success">昨日</el-tag>
</div>
<div class="content" v-if="views">
<span class="content-number spBlock mb15">{{ views.count }}</span>
<div>
<span class="content-time mr20">日同比<i class="content-is" :class="Number(views.dayRate)>=0?'up':'down'">{{ views.dayRate }}</i><i :class="Number(views.dayRate)>=0?'el-icon-caret-top':'el-icon-caret-bottom'" /></span>
<span class="content-time">周同比<i class="content-is" :class="Number(views.weekRate)>=0?'up':'down'">{{ views.weekRate }}</i><i :class="Number(views.weekRate)>=0?'el-icon-caret-top':'el-icon-caret-bottom'" /></span>
</div>
<el-divider></el-divider>
<div class="acea-row row-between-wrapper">
<span class="content-time">总访问量</span>
<span>{{ views.total }} Pv</span>
</div>
</div>
</el-card>
</el-col>
<el-col v-bind="grid" class="ivu-mb">
<el-card :bordered="false" dis-hover :padding="12">
<div slot="header" class="acea-row row-between-wrapper">
<span>订单量</span>
<el-tag type="success">昨日</el-tag>
</div>
<div class="content" v-if="order">
<span class="content-number spBlock mb15">{{ order.count }}</span>
<div>
<span class="content-time mr20">日同比<i class="content-is" :class="Number(order.dayRate)>=0?'up':'down'">{{ order.dayRate }}</i><i :class="Number(order.dayRate)>=0?'el-icon-caret-top':'el-icon-caret-bottom'" /></span>
<span class="content-time">周同比<i class="content-is" :class="Number(order.weekRate)>=0?'up':'down'">{{ order.weekRate }}</i><i :class="Number(order.weekRate)>=0?'el-icon-caret-top':'el-icon-caret-bottom'" /></span>
</div>
<el-divider></el-divider>
<div class="acea-row row-between-wrapper">
<span class="content-time">总订单量</span>
<span>{{ order.total }} </span>
</div>
</div>
</el-card>
</el-col>
<el-col v-bind="grid" class="ivu-mb">
<el-card :bordered="false" dis-hover :padding="12">
<div slot="header" class="acea-row row-between-wrapper">
<span>新增用户</span>
<el-tag type="success">昨日</el-tag>
</div>
<div class="content" v-if="user">
<span class="content-number spBlock mb15">{{ user.count }}</span>
<div>
<span class="content-time mr20">日同比<i class="content-is" :class="Number(user.dayRate)>=0?'up':'down'">{{ user.dayRate }}</i><i :class="Number(user.dayRate)>=0?'el-icon-caret-top':'el-icon-caret-bottom'" /></span>
<span class="content-time">周同比<i class="content-is" :class="Number(user.weekRate)>=0?'up':'down'">{{ user.weekRate }}</i><i :class="Number(user.weekRate)>=0?'el-icon-caret-top':'el-icon-caret-bottom'" /></span>
</div>
<el-divider></el-divider>
<div class="acea-row row-between-wrapper">
<span class="content-time">总用户</span>
<span>{{ user.total }} </span>
</div>
</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
import {statisticsOrderApi, statisticsSalesApi, statisticsUserApi, statisticsViewsApi} from '@/api/dashboard'
export default {
data() {
return {
infoList: [],
grid: {
xl: 6,
lg: 6,
md: 12,
sm: 12,
xs: 24
},
excessStyle: {
color: '#f56a00',
backgroundColor: '#fde3cf'
},
avatarList: [],
sales: null,
order: null,
user: null,
views: null
}
},
methods: {
// 订单量
statisticsOrder() {
statisticsOrderApi().then(async res => {
this.order = res
})
},
// 销售额
statisticsSales() {
statisticsSalesApi().then(async res => {
this.sales = res
})
},
// 新增用户
statisticsUser() {
statisticsUserApi().then(async res => {
this.user = res
})
},
// 用户访问量
statisticsViews() {
statisticsViewsApi().then(async res => {
this.views = res
})
}
},
mounted() {
this.statisticsOrder();
this.statisticsSales();
this.statisticsUser();
this.statisticsViews();
}
}
</script>
<style scoped lang="scss">
.ivu-mb{
margin-bottom: 10px;
}
.up, .el-icon-caret-top {
color: #F5222D;
font-size: 12px;
opacity: 1 !important;
}
.down, .el-icon-caret-bottom {
color: #39C15B;
font-size: 12px;
opacity: 100% !important;
}
.baseInfo {
/deep/ .el-card__header {
padding: 15px 20px !important;
}
}
.content {
&-number {
font-size: 30px;
}
&-time{
font-size:14px;
/*color: #8C8C8C;*/
}
}
</style>

View File

@@ -0,0 +1,110 @@
<template>
<div class="divBox">
<el-row :gutter="24" class="dashboard-console-grid">
<el-col v-bind="grid" class="ivu-mb">
<el-card :bordered="false">
<router-link :to="{path:'/user/index'}">
<i class="el-icon-user" style="color:#69c0ff" />
<p>会员管理</p>
</router-link>
</el-card>
</el-col>
<el-col v-bind="grid" class="ivu-mb">
<el-card :bordered="false">
<router-link :to="{path:'/operation/setting'}">
<i class="el-icon-setting" style="color:#95de64" />
<p>系统设置</p>
</router-link>
</el-card>
</el-col>
<el-col v-bind="grid" class="ivu-mb">
<el-card :bordered="false">
<router-link :to="{path:'/store/index'}">
<i class="el-icon-goods" style="color:#ff9c6e" />
<p>商品</p>
</router-link>
</el-card>
</el-col>
<el-col v-bind="grid" class="ivu-mb">
<el-card :bordered="false">
<router-link :to="{path:'/order/index'}">
<i class="el-icon-s-order" style="color:#b37feb" />
<p>订单管理</p>
</router-link>
</el-card>
</el-col>
<el-col v-bind="grid" class="ivu-mb">
<el-card :bordered="false">
<router-link :to="{path:'/operation/systemSms/config'}">
<i class="el-icon-message" style="color:#ffd666" />
<p>短信配置</p>
</router-link>
</el-card>
</el-col>
<el-col v-bind="grid" class="ivu-mb">
<el-card :bordered="false">
<router-link :to="{path:'/content/articleManager'}">
<i class="el-icon-notebook-1" style="color:#5cdbd3" />
<p>文章管理</p>
</router-link>
</el-card>
</el-col>
<el-col v-bind="grid" class="ivu-mb">
<el-card :bordered="false">
<router-link :to="{path:'/distribution/index'}">
<i class="el-icon-s-finance" style="color:#ff85c0" />
<p>分销管理</p>
</router-link>
</el-card>
</el-col>
<el-col v-bind="grid" class="ivu-mb">
<el-card :bordered="false">
<router-link :to="{path:'/marketing/coupon/list'}">
<i class="el-icon-s-ticket" style="color:#ffc069" />
<p>优惠券</p>
</router-link>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
export default {
data () {
return {
grid: {
xl: 3,
lg: 6,
md: 6,
sm: 8,
xs: 8
}
}
}
}
</script>
<style lang="scss" scoped>
.ivu-mb{
margin-bottom: 10px;
}
.divBox {
padding: 0 20px !important;
}
.dashboard-console-grid {
text-align: center;
.ivu-card-body {
padding: 0;
}
i {
font-size: 32px;
}
a {
display: block;
color: inherit;
}
p {
margin-top: 8px;
}
}
</style>

View File

@@ -0,0 +1,187 @@
<template>
<div class="divBox">
<el-row :gutter="24">
<el-col :xl="16" :lg="12" :md="24" :sm="24" :xs="24" class="ivu-mb mb10 dashboard-console-visit">
<el-card :bordered="false" dis-hover>
<div slot="header">
<div class="acea-row row-middle">
<el-avatar icon="el-icon-s-operation" size="small" style="color:#1890ff;background:#e6f7ff;font-size: 13px"/>
<span class="ivu-pl-8">用户</span>
</div>
</div>
<echarts-from ref="userChart" :echartsTitle="line" :xAxis="xAxis" :series="series" v-if="infoList"></echarts-from>
</el-card>
</el-col>
<el-col :xl="8" :lg="12" :md="24" :sm="24" :xs="24">
<el-card :bordered="false" dis-hover class="dashboard-console-visit">
<div slot="header">
<div class="acea-row row-middle">
<el-avatar icon="el-icon-picture-outline-round" size="small" style="color:#1890ff;background:#e6f7ff;font-size: 13px" />
<span class="ivu-pl-8">购买用户统计</span>
</div>
</div>
<echarts-from ref="visitChart" :echartsTitle="circle" :legendData="legendData"
:series="seriesUser" v-if="chartBuy"></echarts-from>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
import {chartUserApi, chartBuyApi} from '@/api/dashboard';
import echartsFrom from '@/components/echarts/index';
export default {
name: 'user-chart',
components: {echartsFrom},
data() {
return {
line: 'line',
circle: 'circle',
xAxis: [],
infoList: {},
series: [],
xData: [],
y1Data: [],
y2Data: [],
lists: [],
bing_data: [],
bing_xdata: [],
legendData: [],
seriesUser: [],
chartBuy: {}
}
},
methods: {
// 统计
getStatistics() {
chartUserApi().then(async res => {
this.infoList = res
let data = []
for (let key in res) {
data.push(res[key])
this.xAxis.push(key)
}
this.series = [
{
data: data,
name: '人数(人)',
type: 'line',
tooltip: true,
smooth: true,
symbol: 'none',
areaStyle: {
normal: {
opacity: 0.2
}
}
}
];
// this.bing_data = res.bing_data;
// this.bing_xdata = res.bing_xdata;
})
},
// 用户购买统计
getRank() {
chartBuyApi().then(async res => {
this.chartBuy = res
this.legendData = ["未消费用户", "消费一次用户", "留存客户", "回流客户"]
this.seriesUser = [{
"name": "未消费用户",
"value": res.zero,
"itemStyle": {
"color": "#5cadff"
}
},
{
"name": "消费一次用户",
"value": res.one,
"itemStyle": {
"color": "#b37feb"
}
},
{
"name": "留存客户",
"value": res.history,
"itemStyle": {
"color": "#19be6b"
}
},
{
"name": "回流客户",
"value": res.back,
"itemStyle": {
"color": "#ff9900"
}
}]
})
},
// 监听页面宽度变化,刷新表格
handleResize() {
if (this.infoList && this.series.length !== 0) this.$refs.userChart.handleResize();
if (this.infoList) this.$refs.visitChart.handleResize();
}
},
mounted() {
this.getStatistics();
this.getRank();
},
beforeDestroy() {
if (this.visitChart) {
this.visitChart.dispose();
this.visitChart = null;
}
}
}
</script>
<style scoped lang="scss">
.acea-row{
/deep/.el-avatar--small {
width: 22px;
height: 22px;
line-height: 22px;
}
}
.ivu-pl-8{
margin-left: 8px;
font-size: 14px;
}
.dashboard-console-visit {
/deep/.el-card__header{
padding: 14px 20px !important;
}
ul {
li {
list-style-type: none;
margin-top: 12px;
}
}
}
.trees-coadd {
width: 100%;
height: 100%;
.scollhide {
width: 100%;
height: 100%;
overflow-x: hidden;
overflow-y: scroll;
}
}
.scollhide::-webkit-scrollbar {
display: none;
}
.names {
display: inline-block;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
width: 84%;
margin-bottom: -7px;
}
</style>

View File

@@ -0,0 +1,594 @@
<template>
<div class="divBox">
<el-row :gutter="24">
<el-col san="24" class="ivu-mb">
<el-card :bordered="false" class="dashboard-console-visit">
<div slot="header">
<div class="acea-row row-between-wrapper">
<div class="acea-row row-middle">
<el-avatar icon="el-icon-s-data" size="small" style="color:#1890ff;background:#e6f7ff;font-size: 13px" />
<span class="ivu-pl-8">订单</span>
</div>
<div class="checkTime">
<el-radio-group v-model="visitDate" class="ivu-mr-8">
<el-radio label="last30" @change="handleChangeVisitType">30天</el-radio>
<el-radio label="week" @change="handleChangeWeek"></el-radio>
<el-radio label="month" @change="handleChangeMonth"></el-radio>
<el-radio label="year" @change="handleChangeYear"></el-radio>
</el-radio-group>
</div>
</div>
</div>
<h4>订单量趋势</h4>
<echarts-from ref="visitChart" :series="series" :xAxis="xAxis" v-if="info"></echarts-from>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
import { chartOrder30Api, chartOrderWeekApi, chartOrderMonthApi, chartOrderYearApi } from '@/api/dashboard';
import echartsFrom from '@/components/echarts/index';
export default {
components: {echartsFrom},
data() {
return {
infoList: null,
visitDate: 'last30',
series: [],
xAxis: [],
info: {},
legendData: []
}
},
methods: {
// 时间改变
handleChangeVisitType() {
this.xAxis = []
this.legendData = []
chartOrder30Api().then(async res => {
this.info = res
let pices = []
let qualitys = []
for (let key in res.price) {
pices.push(Number(res.price[key]))
this.xAxis.push(key)
}
for (let key in res.quality) {
qualitys.push(Number(res.quality[key]))
}
this.series = [{
"name":"订单金额",
"type":"bar",
"itemStyle":{
"normal":{
"color":{
"x":0,
"y":0,
"x2":0,
"y2":1,
"colorStops":[
{
"offset":0,
"color":"#69cdff"
},
{
"offset":0.5,
"color":"#3eb3f7"
},
{
"offset":1,
"color":"#1495eb"
}
]
}
}
},
"data": pices
},
{
"name":"订单数",
"type":"bar",
"itemStyle":{
"normal":{
"color":{
"x":0,
"y":0,
"x2":0,
"y2":1,
"colorStops":[
{
"offset":0,
"color":"#6fdeab"
},
{
"offset":0.5,
"color":"#44d693"
},
{
"offset":1,
"color":"#2cc981"
}
]
}
}
},
"data": qualitys
}]
})
},
handleChangeWeek() {
this.xAxis = []
this.legendData = []
chartOrderWeekApi().then(async res => {
this.info = res
this.legendData = ["上周金额", "本周金额", "上周订单数", "本周订单数"]
let prePrice = []
let price = []
let qualitys = []
let preQuality = []
for (let key in res.prePrice) {
prePrice.push(Number(res.prePrice[key]))
this.xAxis.push(key)
}
for (let key in res.price) {
price.push(Number(res.price[key]))
}
for (let key in res.preQuality) {
preQuality.push(Number(res.preQuality[key]))
}
for (let key in res.quality) {
qualitys.push(Number(res.quality[key]))
}
this.series = [
{
"name":"上周金额",
"type":"bar",
"itemStyle":{
"normal":{
"color":{
"x":0,
"y":0,
"x2":0,
"y2":1,
"colorStops":[
{
"offset":0,
"color":"#69cdff"
},
{
"offset":0.5,
"color":"#3eb3f7"
},
{
"offset":1,
"color":"#1495eb"
}
]
}
}
},
"data": prePrice
},
{
"name":"本周金额",
"type":"bar",
"itemStyle":{
"normal":{
"color":{
"x":0,
"y":0,
"x2":0,
"y2":1,
"colorStops":[
{
"offset":0,
"color":"#69cdff"
},
{
"offset":0.5,
"color":"#3eb3f7"
},
{
"offset":1,
"color":"#1495eb"
}
]
}
}
},
"data": price
},
{
"name":"上周订单数",
"type":"line",
"itemStyle":{
"normal":{
"color":{
"x":0,
"y":0,
"x2":0,
"y2":1,
"colorStops":[
{
"offset":0,
"color":"#6fdeab"
},
{
"offset":0.5,
"color":"#44d693"
},
{
"offset":1,
"color":"#2cc981"
}
]
}
}
},
"data": preQuality
},
{
"name":"本周订单数",
"type":"line",
"itemStyle":{
"normal":{
"color":{
"x":0,
"y":0,
"x2":0,
"y2":1,
"colorStops":[
{
"offset":0,
"color":"#6fdeab"
},
{
"offset":0.5,
"color":"#44d693"
},
{
"offset":1,
"color":"#2cc981"
}
]
}
}
},
"data": qualitys
}
]
})
},
handleChangeMonth() {
this.xAxis = []
this.legendData = []
chartOrderMonthApi().then(async res => {
this.info = res
this.legendData = ["上月金额", "本月金额", "上月订单数", "本月订单数"]
let prePrice = []
let price = []
let qualitys = []
let preQuality = []
for (let key in res.prePrice) {
prePrice.push(Number(res.prePrice[key]))
this.xAxis.push(key)
}
for (let key in res.price) {
price.push(Number(res.price[key]))
}
for (let key in res.preQuality) {
preQuality.push(Number(res.preQuality[key]))
}
for (let key in res.quality) {
qualitys.push(Number(res.quality[key]))
}
this.series = [
{
"name":"上月金额",
"type":"bar",
"itemStyle":{
"normal":{
"color":{
"x":0,
"y":0,
"x2":0,
"y2":1,
"colorStops":[
{
"offset":0,
"color":"#69cdff"
},
{
"offset":0.5,
"color":"#3eb3f7"
},
{
"offset":1,
"color":"#1495eb"
}
]
}
}
},
"data": prePrice
},
{
"name":"本月金额",
"type":"bar",
"itemStyle":{
"normal":{
"color":{
"x":0,
"y":0,
"x2":0,
"y2":1,
"colorStops":[
{
"offset":0,
"color":"#69cdff"
},
{
"offset":0.5,
"color":"#3eb3f7"
},
{
"offset":1,
"color":"#1495eb"
}
]
}
}
},
"data": price
},
{
"name":"上月订单数",
"type":"line",
"itemStyle":{
"normal":{
"color":{
"x":0,
"y":0,
"x2":0,
"y2":1,
"colorStops":[
{
"offset":0,
"color":"#6fdeab"
},
{
"offset":0.5,
"color":"#44d693"
},
{
"offset":1,
"color":"#2cc981"
}
]
}
}
},
"data": preQuality
},
{
"name":"本月订单数",
"type":"line",
"itemStyle":{
"normal":{
"color":{
"x":0,
"y":0,
"x2":0,
"y2":1,
"colorStops":[
{
"offset":0,
"color":"#6fdeab"
},
{
"offset":0.5,
"color":"#44d693"
},
{
"offset":1,
"color":"#2cc981"
}
]
}
}
},
"data": qualitys
}
]
})
},
handleChangeYear() {
this.xAxis = []
this.legendData = []
chartOrderYearApi().then(async res => {
this.info = res
this.legendData = ["去年金额", "今年金额", "去年订单数", "今年订单数"]
let prePrice = []
let price = []
let qualitys = []
let preQuality = []
for (let key in res.prePrice) {
prePrice.push(Number(res.prePrice[key]))
this.xAxis.push(key)
}
for (let key in res.price) {
price.push(Number(res.price[key]))
}
for (let key in res.preQuality) {
preQuality.push(Number(res.preQuality[key]))
}
for (let key in res.quality) {
qualitys.push(Number(res.quality[key]))
}
this.series = [
{
"name":"去年金额",
"type":"bar",
"itemStyle":{
"normal":{
"color":{
"x":0,
"y":0,
"x2":0,
"y2":1,
"colorStops":[
{
"offset":0,
"color":"#69cdff"
},
{
"offset":0.5,
"color":"#3eb3f7"
},
{
"offset":1,
"color":"#1495eb"
}
]
}
}
},
"data": prePrice
},
{
"name":"今年金额",
"type":"bar",
"itemStyle":{
"normal":{
"color":{
"x":0,
"y":0,
"x2":0,
"y2":1,
"colorStops":[
{
"offset":0,
"color":"#69cdff"
},
{
"offset":0.5,
"color":"#3eb3f7"
},
{
"offset":1,
"color":"#1495eb"
}
]
}
}
},
"data": price
},
{
"name":"去年订单数",
"type":"line",
"itemStyle":{
"normal":{
"color":{
"x":0,
"y":0,
"x2":0,
"y2":1,
"colorStops":[
{
"offset":0,
"color":"#6fdeab"
},
{
"offset":0.5,
"color":"#44d693"
},
{
"offset":1,
"color":"#2cc981"
}
]
}
}
},
"data": preQuality
},
{
"name":"今年订单数",
"type":"line",
"itemStyle":{
"normal":{
"color":{
"x":0,
"y":0,
"x2":0,
"y2":1,
"colorStops":[
{
"offset":0,
"color":"#6fdeab"
},
{
"offset":0.5,
"color":"#44d693"
},
{
"offset":1,
"color":"#2cc981"
}
]
}
}
},
"data": qualitys
}
]
})
},
// 监听页面宽度变化,刷新表格
handleResize() {
if (this.infoList) this.$refs.visitChart.handleResize();
}
},
created() {
this.handleChangeVisitType();
}
}
</script>
<style lang="scss" scoped>
.acea-row{
/deep/.el-avatar--small {
width: 22px;
height: 22px;
line-height: 22px;
}
}
.checkTime{
/deep/.el-radio__input{
display: none;
}
}
.ivu-pl-8{
margin-left: 8px;
font-size: 14px;
}
.divBox {
padding: 0 20px !important;
}
.dashboard-console-visit {
/deep/.el-card__header{
padding: 14px 20px !important;
}
ul {
li {
list-style-type: none;
margin-top: 12px;
}
}
}
.ivu-mb{
margin-bottom: 10px;
}
</style>

View File

@@ -0,0 +1,72 @@
<template>
<div class="dashboard-editor-container">
<div class=" clearfix">
<pan-thumb :image="avatar" style="float: left">
Your roles:
<span v-for="item in roles" :key="item" class="pan-info-roles">{{ item }}</span>
</pan-thumb>
<div class="info-container">
<span class="display_name">{{ name }}</span>
<span style="font-size:20px;padding-top:20px;display:inline-block;">Editor's Dashboard</span>
</div>
</div>
<div>
<img :src="emptyGif" class="emptyGif">
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import PanThumb from '@/components/PanThumb'
export default {
name: 'DashboardEditor',
components: { PanThumb },
data() {
return {
emptyGif: 'https://wpimg.wallstcn.com/0e03b7da-db9e-4819-ba10-9016ddfdaed3'
}
},
computed: {
...mapGetters([
'name',
'avatar',
'roles'
])
}
}
</script>
<style lang="scss" scoped>
.emptyGif {
display: block;
width: 45%;
margin: 0 auto;
}
.dashboard-editor-container {
background-color: #e3e3e3;
min-height: 100vh;
padding: 50px 60px 0px;
.pan-info-roles {
font-size: 12px;
font-weight: 700;
color: #333;
display: block;
}
.info-container {
position: relative;
margin-left: 190px;
height: 150px;
line-height: 200px;
.display_name {
font-size: 48px;
line-height: 48px;
color: #212121;
position: absolute;
top: 25px;
}
}
}
</style>

View File

@@ -0,0 +1,43 @@
<template>
<div>
<!--头部-->
<base-info ref="baseInfo"/>
<!--小方块-->
<grid-menu class="mb20"/>
<!--订单统计-->
<visit-chart ref="visitChart"/>
<!--用户-->
<user-chart ref="userChart" class="mb20"/>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import adminDashboard from './admin'
import editorDashboard from './editor'
import baseInfo from './components/baseInfo';
import gridMenu from './components/gridMenu';
import visitChart from './components/visitChart';
import userChart from './components/userChart';
export default {
name: 'Dashboard',
components: { baseInfo, gridMenu, visitChart, userChart, adminDashboard, editorDashboard },
data() {
return {
currentRole: 'adminDashboard'
}
},
computed: {
...mapGetters([
'roles'
])
},
created() {
if (!this.roles.includes('admin')) {
this.currentRole = 'editorDashboard'
}
}
}
</script>

View File

View File

@@ -0,0 +1,15 @@
<template>
<div>
<router-view />
</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,13 @@
<template>
<div>商品数据</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,15 @@
<template>
<div>
<router-view />
</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,13 @@
<template>
<div>订单数据</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,173 @@
<template>
<div class="divBox">
<el-card class="box-card">
<el-form ref="promoterForm" :model="promoterForm" :rules="rules" label-width="200px" class="demo-promoterForm">
<el-form-item prop="brokerageFuncStatus">
<span slot="label">
<span>分销启用</span>
<el-tooltip class="item" effect="dark" content="商城分销功能开启关闭" placement="top-start">
<i class="el-icon-warning-outline" />
</el-tooltip>
</span>
<el-radio-group v-model="promoterForm.brokerageFuncStatus">
<el-radio label="1">开启</el-radio>
<el-radio label="0">关闭</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="storeBrokerageStatus">
<span slot="label">
<span>分销模式</span>
<el-tooltip class="item" effect="dark" content="人人分销”默认每个人都可以分销,“指定分销”仅可后台手动设置推广员,“满额分销”指用户购买商品满足消费金额后自动开启分销" placement="top-start">
<i class="el-icon-warning-outline" />
</el-tooltip>
</span>
<el-radio-group v-model="promoterForm.storeBrokerageStatus">
<el-radio label="1">指定分销</el-radio>
<el-radio label="2">人人分销</el-radio>
<el-radio label="3">满额分销</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="brokerageBindind">
<span slot="label">
<span>分销关系绑定</span>
<el-tooltip class="item" effect="dark" content="所有用户”指所有没有上级推广人的用户,“新用户”指新注册的用户" placement="top-start">
<i class="el-icon-warning-outline" />
</el-tooltip>
</span>
<el-radio-group v-model="promoterForm.brokerageBindind">
<el-radio label="0">所有用户</el-radio>
<el-radio label="1">新用户</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="storeBrokerageRatio">
<span slot="label">
<span>一级返佣比例</span>
<el-tooltip class="item" effect="dark" content="订单交易成功后给上级返佣的比例0 - 100,例:5 = 反订单金额的5%" placement="top-start">
<i class="el-icon-warning-outline" />
</el-tooltip>
</span>
<el-input-number v-model="promoterForm.storeBrokerageRatio" :precision="2" :step="0.1" class="selWidth" placeholder="订单交易成功后给上级返佣的比例0 - 100,例:5 = 反订单金额的5%"></el-input-number>
<span>%</span>
</el-form-item>
<el-form-item prop="storeBrokerageTwo">
<span slot="label">
<span>二级返佣比例</span>
<el-tooltip class="item" effect="dark" content="订单交易成功后给上级返佣的比例0 ~ 100,例:5 = 反订单金额的5%" placement="top-start">
<i class="el-icon-warning-outline" />
</el-tooltip>
</span>
<el-input-number v-model="promoterForm.storeBrokerageTwo" :precision="2" :step="0.1" class="selWidth" placeholder="订单交易成功后给上级返佣的比例0 ~ 100,例:5 = 反订单金额的5%"></el-input-number>
<span>%</span>
</el-form-item>
<el-form-item prop="userExtractMinPrice">
<span slot="label">
<span>提现最低金额</span>
<el-tooltip class="item" effect="dark" content="用户提现最低金额" placement="top-start">
<i class="el-icon-warning-outline" />
</el-tooltip>
</span>
<el-input-number v-model="promoterForm.userExtractMinPrice" :precision="2" :step="0.1" class="selWidth" placeholder="用户提现最低金额"></el-input-number>
</el-form-item>
<el-form-item prop="userExtractBank">
<span slot="label">
<span>提现银行卡</span>
<el-tooltip class="item" effect="dark" content="提现银行卡,每个银行换行" placement="top-start">
<i class="el-icon-warning-outline" />
</el-tooltip>
</span>
<el-input
type="textarea"
:rows="4"
placeholder="提现银行卡,每个银行换行"
v-model="promoterForm.userExtractBank">
</el-input>
</el-form-item>
<el-form-item prop="extractTime">
<span slot="label">
<span>冻结时间</span>
<el-tooltip class="item" effect="dark" content="佣金冻结时间(天)" placement="top-start">
<i class="el-icon-warning-outline" />
</el-tooltip>
</span>
<el-input-number v-model="promoterForm.extractTime" :precision="2" :step="0.1" class="selWidth" placeholder="佣金冻结时间(天)"></el-input-number>
</el-form-item>
<el-form-item prop="extension_two_rate">
<span slot="label">
<span>满额分销最低金额</span>
<el-tooltip class="item" effect="dark" content="满额分销满足金额开通分销权限" placement="top-start">
<i class="el-icon-warning-outline" />
</el-tooltip>
</span>
<el-input-number v-model="promoterForm.extension_two_rate" placeholder="满额分销满足金额开通分销权限" :precision="2" :step="0.1" class="selWidth"></el-input-number>
</el-form-item>
<el-form-item>
<el-button size="mini" type="primary" :loading="loading" @click="submitForm('promoterForm')">立即创建</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script>
import { configApi, configUpdateApi, productCheckApi } from '@/api/distribution'
export default {
name: 'Index',
data() {
return {
promoterForm: {},
loading: false,
rules: {
brokerageFuncStatus: [
{ required: true, message: '请选择是否启用分销', trigger: 'change' }
],
storeBrokerageRatio: [
{ required: true, message: '请输入一级返佣比例', trigger: 'blur' }
],
storeBrokerageTwo: [
{ required: true, message: '请输入二级返佣比例', trigger: 'blur' }
]
}
}
},
mounted() {
this.getDetal()
},
methods: {
getDetal() {
configApi().then(res => {
this.promoterForm = res
}).catch((res) => {
this.$message.error(res.message)
})
},
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
this.loading = true
configUpdateApi(this.promoterForm).then(res => {
this.loading = false
this.$modalSure('提交成功,是否自动下架商户低于此佣金比例的商品').then(() => {
productCheckApi().then(({ message }) => {
this.$message.success(message)
}).catch(({ message }) => {
this.$message.error(message)
})
})
}).catch((res) => {
this.$message.error(res.message)
this.loading = false
})
} else {
return false
}
})
}
}
}
</script>
<style scoped lang="scss">
.selWidth{
width: 300px;
}
</style>

View File

@@ -0,0 +1,458 @@
<template>
<div class="divBox">
<el-card class="box-card">
<div slot="header" class="clearfix">
<div class="container">
<el-form size="small" label-width="100px">
<el-form-item label="时间选择:" class="width100">
<el-radio-group v-model="tableFrom.dateLimit" type="button" class="mr20" size="small" @change="selectChange(tableFrom.dateLimit)">
<el-radio-button v-for="(item,i) in fromList.fromTxt" :key="i" :label="item.val">{{ item.text }}</el-radio-button>
</el-radio-group>
<el-date-picker v-model="timeVal" value-format="yyyy/MM/dd" format="yyyy/MM/dd" size="small" type="daterange" placement="bottom-end" placeholder="自定义时间" style="width: 250px;" @change="onchangeTime" />
</el-form-item>
<el-form-item label="关键字:">
<el-input v-model="tableFrom.keyword" placeholder="请输入请输入姓名、电话、UID" class="selWidth" size="small">
<el-button slot="append" icon="el-icon-search" size="small" @click="seachList" />
</el-input>
</el-form-item>
</el-form>
</div>
<cards-data :cardLists="cardLists"></cards-data>
</div>
<el-table
v-loading="listLoading"
:data="tableData.data"
style="width: 100%"
size="mini"
class="table"
highlight-current-row
>
<el-table-column
prop="uid"
label="ID"
width="60"
/>
<el-table-column
label="头像"
min-width="80"
>
<template slot-scope="scope">
<div class="demo-image__preview">
<el-image
:src="scope.row.avatar"
:preview-src-list="[scope.row.avatar]"
/>
</div>
</template>
</el-table-column>
<el-table-column
prop="nickname"
label="用户信息"
min-width="130"
/>
<el-table-column
sortable
prop="spreadCount"
label="推广用户数量"
min-width="120"
/>
<el-table-column
sortable
label="订单数量"
min-width="120"
prop="payCount"
/>
<el-table-column
sortable
label="推广订单金额"
min-width="120"
prop="payCount"
/>
<el-table-column
sortable
label="佣金金额"
min-width="120"
prop="brokeragePrice"
/>
<el-table-column
sortable
label="已提现金额"
min-width="120"
prop="brokeragePrice"
/>
<el-table-column
sortable
label="提现金额"
min-width="120"
prop="brokeragePrice"
/>
<el-table-column
sortable
label="未提现金额"
min-width="120"
prop="brokeragePrice"
/>
<el-table-column
prop="spread.nickname"
label="上级推广人"
min-width="150"
/>
<el-table-column label="操作" min-width="150" fixed="right" align="center">
<template slot-scope="scope">
<el-button type="text" size="small" class="mr10" @click="onSpread(scope.row.uid, 'man')">推广人</el-button>
<el-dropdown>
<span class="el-dropdown-link">
更多<i class="el-icon-arrow-down el-icon--right" />
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="onSpreadOrder(scope.row.uid, 'order')">推广订单</el-dropdown-item>
<!--<el-dropdown-item @click.native="onSpreadType(scope.row.uid)">推广方式</el-dropdown-item>-->
<el-dropdown-item @click.native="clearSpread(scope.row)">清除上级推广人</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-table-column>
</el-table>
<div class="block">
<el-pagination
:page-sizes="[20, 40, 60, 80]"
:page-size="tableFrom.limit"
:current-page="tableFrom.page"
layout="total, sizes, prev, pager, next, jumper"
:total="tableData.total"
@size-change="handleSizeChange"
@current-change="pageChange"
/>
</div>
</el-card>
<!--推广人-->
<el-dialog
title="提示"
:visible.sync="dialogVisible"
width="900px"
:before-close="handleClose"
>
<div class="container">
<el-form size="small" label-width="100px">
<el-form-item label="时间选择:" class="width100">
<el-radio-group v-model="spreadFrom.dateLimit" type="button" class="mr20" size="small" @change="selectChangeSpread(spreadFrom.dateLimit)">
<el-radio-button v-for="(item,i) in fromList.fromTxt" :key="i" :label="item.val">{{ item.text }}</el-radio-button>
</el-radio-group>
<el-date-picker v-model="timeValSpread" value-format="yyyy/MM/dd" format="yyyy/MM/dd" size="small" type="daterange" placement="bottom-end" placeholder="自定义时间" style="width: 250px;" @change="onchangeTimeSpread" />
</el-form-item>
<el-form-item label="用户类型:">
<el-radio-group v-model="spreadFrom.type" size="small" @change="onChanges">
<el-radio-button label="null">全部</el-radio-button>
<el-radio-button label="1">一级推广人</el-radio-button>
<el-radio-button label="2">二级推广人</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="关键字:" class="width100">
<el-input v-model="spreadFrom.nickName" placeholder="请输入请输入姓名、电话、UID" class="selWidth" size="small">
<el-button slot="append" icon="el-icon-search" size="small" @click="onChanges" />
</el-input>
</el-form-item>
</el-form>
</div>
<el-table
v-if="onName === 'man'"
key="men"
v-loading="spreadLoading"
:data="spreadData.data"
style="width: 100%"
size="mini"
class="table"
highlight-current-row
>
<el-table-column
prop="uid"
label="ID"
width="60"
/>
<el-table-column
label="头像"
min-width="80"
>
<template slot-scope="scope">
<div class="demo-image__preview">
<el-image
:src="scope.row.avatar"
:preview-src-list="[scope.row.avatar]"
/>
</div>
</template>
</el-table-column>
<el-table-column
prop="nickname"
label="用户信息"
min-width="130"
/>
<el-table-column
prop="is_promoter"
label="是否推广员"
min-width="120"
>
<template slot-scope="scope">
<span>{{ scope.row.is_promoter | filterYesOrNo }}</span>
</template>
</el-table-column>
<el-table-column
sortable
label="推广人数"
min-width="120"
prop="spread_count"
/>
<el-table-column
sortable
label="订单数"
min-width="120"
prop="pay_count"
/>
<el-table-column
prop="create_time"
label="关注时间"
min-width="150"
/>
</el-table>
<el-table
v-if="onName === 'order'"
key="order"
v-loading="spreadLoading"
:data="spreadData.data"
style="width: 100%"
size="mini"
class="table"
highlight-current-row
>
<el-table-column
prop="order_sn"
label="订单ID"
min-width="120"
/>
<el-table-column
label="用户信息"
min-width="100"
>
<template slot-scope="scope">
<span>{{ scope.row.user.nickname }}</span>
</template>
</el-table-column>
<el-table-column
prop="create_time"
label="时间"
min-width="150"
/>
<el-table-column
sortable
label="返佣金额"
min-width="120"
prop="brokerage"
/>
</el-table>
<div class="block">
<el-pagination
:page-sizes="[10, 20, 30, 40]"
:page-size="spreadFrom.limit"
:current-page="spreadFrom.page"
layout="total, sizes, prev, pager, next, jumper"
:total="spreadData.total"
@size-change="handleSizeChangeSpread"
@current-change="pageChangeSpread"
/>
</div>
</el-dialog>
</div>
</template>
<script>
import { promoterListApi, spreadStatisticsApi, spreadListApi, spreadOrderListApi, spreadClearApi } from '@/api/distribution'
import { fromList } from '@/utils/constants.js'
import cardsData from '@/components/cards/index'
export default {
name: 'AccountsUser',
components: { cardsData },
data() {
return {
cardLists: [],
timeVal: [],
tableData: {
data: [],
total: 0
},
listLoading: true,
tableFrom: {
dateLimit: '',
keyword: '',
page: 1,
limit: 20
},
fromList: fromList,
dialogVisible: false,
spreadData: {
data: [],
total: 0
},
spreadFrom: {
page: 1,
limit: 10,
dateLimit: '',
type: null,
nickName: '',
uid: ''
},
timeValSpread: [],
spreadLoading: false,
uid: '',
onName: ''
}
},
mounted() {
this.spreadStatistics()
this.getList()
},
methods: {
seachList() {
this.tableFrom.page = 1
this.getList()
},
// 统计
spreadStatistics() {
spreadStatisticsApi({ dateLimit: this.tableFrom.dateLimit, nickName: this.tableFrom.nickName}).then((res) => {
this.cardLists = res
})
},
// 清除
clearSpread(row) {
this.$modalSure('解除【' + row.nickname + '】的上级推广人吗').then(() => {
spreadClearApi(row.uid).then((res) => {
this.$message.success('清除成功')
this.getList()
})
})
},
onSpread(uid, n) {
this.onName = n
this.uid = uid
this.dialogVisible = true
this.spreadFrom = {
page: 1,
limit: 10,
dateLimit: '',
type: null,
nickName: '',
uid: uid
}
this.getListSpread()
},
handleClose() {
this.dialogVisible = false
},
// 选择时间
selectChangeSpread(tab) {
this.timeValSpread = []
this.spreadFrom.dateLimit = tab
this.onName === 'man' ? this.getListSpread() : this.getSpreadOrderList()
},
// 具体日期
onchangeTimeSpread(e) {
this.timeValSpread = e
this.tableFrom.dateLimit = e ? this.timeValSpread.join('-') : ''
this.onName === 'man' ? this.getListSpread() : this.getSpreadOrderList()
},
onChanges() {
this.onName === 'man' ? this.getListSpread() : this.getSpreadOrderList()
},
// 推广人列表
getListSpread() {
this.spreadLoading = true
spreadListApi({ page: this.spreadFrom.page, limit: this.spreadFrom.limit}, this.spreadFrom).then(res => {
this.spreadData.data = res.list
this.spreadData.total = res.total
this.spreadLoading = false
}).catch(() => {
this.spreadLoading = false
})
},
pageChangeSpread(page) {
this.spreadFrom.page = page
this.onName === 'man' ? this.getListSpread(this.uid) : this.getSpreadOrderList(this.uid)
},
handleSizeChangeSpread(val) {
this.spreadFrom.limit = val
this.onName === 'man' ? this.getListSpread(this.uid) : this.getSpreadOrderList(this.uid)
},
// 推广订单
onSpreadOrder(uid, n) {
this.uid = uid
this.onName = n
this.dialogVisible = true
this.spreadFrom = {
page: 1,
limit: 10,
dateLimit: '',
type: '',
nickName: '',
uid: uid
}
this.getSpreadOrderList()
},
getSpreadOrderList() {
this.spreadLoading = true
spreadOrderListApi({ page: this.spreadFrom.page, limit: this.spreadFrom.limit}, this.spreadFrom).then(res => {
this.spreadData.data = res.list
this.spreadData.total = res.total
this.spreadLoading = false
}).catch(() => {
this.spreadLoading = false
})
},
selectChange(tab) {
this.tableFrom.dateLimit = tab
this.tableFrom.page = 1
this.timeVal = []
this.getList()
},
// 具体日期
onchangeTime(e) {
this.timeVal = e
this.tableFrom.dateLimit = e ? this.timeVal.join('-') : ''
this.tableFrom.page = 1
this.getList()
},
// 列表
getList() {
this.listLoading = true
promoterListApi(this.tableFrom).then(res => {
this.tableData.data = res.list
this.tableData.total = res.total
this.listLoading = false
}).catch(() => {
this.listLoading = false
})
},
pageChange(page) {
this.tableFrom.page = page
this.getList()
},
handleSizeChange(val) {
this.tableFrom.limit = val
this.getList()
}
}
}
</script>
<style scoped>
.selWidth{
width: 350px;
}
.el-dropdown-link {
cursor: pointer;
color: #409EFF;
font-size: 12px;
}
.el-icon-arrow-down {
font-size: 12px;
}
</style>

View File

@@ -0,0 +1,13 @@
<template>
<div>
<!--error code-->
{{ a.a }}
<!--error code-->
</div>
</template>
<script>
export default {
name: 'ErrorTestA'
}
</script>

View File

@@ -0,0 +1,11 @@
<template>
<div />
</template>
<script>
export default {
created() {
this.b = b // eslint-disable-line
}
}
</script>

View File

@@ -0,0 +1,32 @@
<template>
<div class="errPage-container">
<ErrorA />
<ErrorB />
<h3>Please click the bug icon in the upper right corner</h3>
<aside>
Now the management system are basically the form of the spa, it enhances the user experience, but it also increases the possibility of page problems, a small negligence may lead to the entire page deadlock. Fortunately Vue provides a way to catch handling exceptions, where you can handle errors or report exceptions.
<a target="_blank" class="link-type" href="https://panjiachen.github.io/vue-element-admin-site/guide/advanced/error.html">
Document introduction
</a>
</aside>
<a href="#">
<img src="https://wpimg.wallstcn.com/360e4842-4db5-42d0-b078-f9a84a825546.gif">
</a>
</div>
</template>
<script>
import ErrorA from './components/ErrorTestA'
import ErrorB from './components/ErrorTestB'
export default {
name: 'ErrorLog',
components: { ErrorA, ErrorB }
}
</script>
<style scoped>
.errPage-container {
padding: 30px;
}
</style>

View File

@@ -0,0 +1,99 @@
<template>
<div class="errPage-container">
<el-button size="mini" icon="el-icon-arrow-left" class="pan-back-btn" @click="back">
返回
</el-button>
<el-row>
<el-col :span="12">
<h1 class="text-jumbo text-ginormous">
Oops!
</h1>
gif来源<a href="https://zh.airbnb.com/" target="_blank">airbnb</a> 页面
<h2>你没有权限去该页面</h2>
<h6>如有不满请联系你领导</h6>
<ul class="list-unstyled">
<li>或者你可以去:</li>
<li class="link-type">
<router-link to="/dashboard">
回首页
</router-link>
</li>
<li class="link-type">
<a href="https://www.taobao.com/">随便看看</a>
</li>
<li><a href="#" @click.prevent="dialogVisible=true">点我看图</a></li>
</ul>
</el-col>
<el-col :span="12">
<img :src="errGif" width="313" height="428" alt="Girl has dropped her ice cream.">
</el-col>
</el-row>
<el-dialog :visible.sync="dialogVisible" title="随便看">
<img :src="ewizardClap" class="pan-img">
</el-dialog>
</div>
</template>
<script>
import errGif from '@/assets/401_images/401.gif'
export default {
name: 'Page401',
data() {
return {
errGif: errGif + '?' + +new Date(),
ewizardClap: 'https://wpimg.wallstcn.com/007ef517-bafd-4066-aae4-6883632d9646',
dialogVisible: false
}
},
methods: {
back() {
if (this.$route.query.noGoBack) {
this.$router.push({ path: '/dashboard' })
} else {
this.$router.go(-1)
}
}
}
}
</script>
<style lang="scss" scoped>
.errPage-container {
width: 800px;
max-width: 100%;
margin: 100px auto;
.pan-back-btn {
background: #008489;
color: #fff;
border: none!important;
}
.pan-gif {
margin: 0 auto;
display: block;
}
.pan-img {
display: block;
margin: 0 auto;
width: 100%;
}
.text-jumbo {
font-size: 60px;
font-weight: 700;
color: #484848;
}
.list-unstyled {
font-size: 14px;
li {
padding-bottom: 5px;
}
a {
color: #008489;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
}
</style>

View File

@@ -0,0 +1,237 @@
<template>
<div class="wscn-http404-container">
<div class="wscn-http404">
<div class="pic-404">
<img class="pic-404__parent" src="@/assets/404_images/404.png" alt="404">
<img class="pic-404__child left" src="@/assets/404_images/404_cloud.png" alt="404">
<img class="pic-404__child mid" src="@/assets/404_images/404_cloud.png" alt="404">
<img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404">
</div>
<div class="bullshit">
<div class="bullshit__oops">OOPS!</div>
<!--<div class="bullshit__info">All rights reserved-->
<!--<a style="color:#20a0ff" href="https://wallstreetcn.com" target="_blank">wallstreetcn</a>-->
<!--</div>-->
<div class="bullshit__headline">{{ message }}</div>
<div class="bullshit__info">请检查您输入的URL是否正确或单击下面的按钮返回主页.</div>
<router-link :to="{path: '/dashboard'}">
<span class="bullshit__return-home">返回控制台</span>
</router-link>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Page404',
data() {
return {
}
},
computed: {
message() {
return '你不能进入这个页面...'
}
},
methods: {
}
}
</script>
<style lang="scss" scoped>
.wscn-http404-container{
transform: translate(-50%,-50%);
position: absolute;
top: 40%;
left: 50%;
}
.wscn-http404 {
position: relative;
width: 1200px;
padding: 0 50px;
overflow: hidden;
.pic-404 {
position: relative;
float: left;
width: 600px;
overflow: hidden;
&__parent {
width: 100%;
}
&__child {
position: absolute;
&.left {
width: 80px;
top: 17px;
left: 220px;
opacity: 0;
animation-name: cloudLeft;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1s;
}
&.mid {
width: 46px;
top: 10px;
left: 420px;
opacity: 0;
animation-name: cloudMid;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1.2s;
}
&.right {
width: 62px;
top: 100px;
left: 500px;
opacity: 0;
animation-name: cloudRight;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1s;
}
@keyframes cloudLeft {
0% {
top: 17px;
left: 220px;
opacity: 0;
}
20% {
top: 33px;
left: 188px;
opacity: 1;
}
80% {
top: 81px;
left: 92px;
opacity: 1;
}
100% {
top: 97px;
left: 60px;
opacity: 0;
}
}
@keyframes cloudMid {
0% {
top: 10px;
left: 420px;
opacity: 0;
}
20% {
top: 40px;
left: 360px;
opacity: 1;
}
70% {
top: 130px;
left: 180px;
opacity: 1;
}
100% {
top: 160px;
left: 120px;
opacity: 0;
}
}
@keyframes cloudRight {
0% {
top: 100px;
left: 500px;
opacity: 0;
}
20% {
top: 120px;
left: 460px;
opacity: 1;
}
80% {
top: 180px;
left: 340px;
opacity: 1;
}
100% {
top: 200px;
left: 300px;
opacity: 0;
}
}
}
}
.bullshit {
position: relative;
float: left;
width: 300px;
padding: 30px 0;
overflow: hidden;
&__oops {
font-size: 32px;
font-weight: bold;
line-height: 40px;
color: #1482f0;
opacity: 0;
margin-bottom: 20px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-fill-mode: forwards;
}
&__headline {
font-size: 20px;
line-height: 24px;
color: #222;
font-weight: bold;
opacity: 0;
margin-bottom: 10px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.1s;
animation-fill-mode: forwards;
}
&__info {
font-size: 13px;
line-height: 21px;
color: grey;
opacity: 0;
margin-bottom: 30px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.2s;
animation-fill-mode: forwards;
}
&__return-home {
display: block;
float: left;
width: 110px;
height: 36px;
background: #1482f0;
border-radius: 100px;
text-align: center;
color: #ffffff;
opacity: 0;
font-size: 14px;
line-height: 36px;
cursor: pointer;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.3s;
animation-fill-mode: forwards;
}
@keyframes slideUp {
0% {
transform: translateY(60px);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
}
}
</style>

View File

@@ -0,0 +1,13 @@
<template>
<div>佣金记录</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,15 @@
<template>
<div>
<router-view />
</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,13 @@
<template>
<div>提现申请</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,15 @@
<template>
<div>
<router-view />
</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

View File

@@ -0,0 +1,13 @@
<template>
<div>充值记录</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,15 @@
<template>
<div>
<router-view />
</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,13 @@
<template>
<div>资金监控</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,15 @@
<script>
export default {
name: 'AuthRedirect',
created() {
const hash = window.location.search.slice(1)
if (window.localStorage) {
window.localStorage.setItem('x-admin-oauth-code', hash)
window.close()
}
},
render: function(h) {
return h() // avoid warning message
}
}
</script>

View File

@@ -0,0 +1,508 @@
<template>
<div class="page-account">
<div class="container" :class="[ fullWidth > 768 ? 'containerSamll':'containerBig']">
<template v-if="fullWidth>768">
<swiper :options="swiperOption" class="swiperPross">
<swiper-slide v-for="(item,index) in swiperList" :key="index" class="swiperPic">
<img :src="item.pic">
</swiper-slide>
<div slot="pagination" class="swiper-pagination" />
</swiper>
</template>
<div class="index_from page-account-container">
<div class="page-account-top ">
<div class="page-account-top-logo">
<img :src="loginLogo" alt="logo">
</div>
</div>
<el-form
ref="loginForm"
:model="loginForm"
:rules="loginRules"
class="login-form"
autocomplete="on"
label-position="left"
@keyup.enter="handleLogin"
>
<el-form-item prop="account">
<el-input
ref="account"
v-model="loginForm.account"
prefix-icon="el-icon-user"
placeholder="用户名"
name="username"
type="text"
tabindex="1"
autocomplete="on"
/>
</el-form-item>
<el-form-item prop="pwd">
<el-input
:key="passwordType"
ref="pwd"
v-model="loginForm.pwd"
prefix-icon="el-icon-lock"
:type="passwordType"
placeholder="密码"
name="pwd"
tabindex="2"
auto-complete="on"
/>
<span class="show-pwd" @click="showPwd">
<svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
</span>
</el-form-item>
<el-form-item prop="code" class="captcha">
<div class="captcha">
<el-input
ref="username"
v-model="loginForm.code"
style="width: 218px;"
prefix-icon="el-icon-message"
placeholder="验证码"
name="username"
type="text"
tabindex="3"
autocomplete="on"
/>
<div class="imgs" @click="getCaptcha()"><img :src="captchatImg"></div>
</div>
</el-form-item>
<el-button
:loading="loading"
type="primary"
style="width:100%;margin-bottom:30px;"
@click.native.prevent="handleLogin"
>登录
</el-button>
</el-form>
</div>
</div>
</div>
</template>
<script>
import { validUsername } from '@/utils/validate'
import { getLoginPicApi, captchaApi, codeCheckApi } from '@/api/user'
export default {
name: 'Login',
data() {
const validateUsername = (rule, value, callback) => {
if (!validUsername(value)) {
callback(new Error('Please enter the correct user name'))
} else {
callback()
}
}
const validatePassword = (rule, value, callback) => {
if (value.length < 6) {
callback(new Error('The password can not be less than 6 digits'))
} else {
callback()
}
}
return {
captchatImg: '',
swiperList: [],
loginLogo: '',
backgroundImage: '',
fullWidth: document.body.clientWidth,
swiperOption: {
pagination: {
el: '.pagination'
},
autoplay: {
enabled: true,
disableOnInteraction: false,
delay: 3000
}
},
loginForm: {
account: 'demo', // admin
pwd: '123456',
key: '',
code: ''
},
loginRules: {
account: [{ required: true, trigger: 'blur' }], // validator: validateUsername
pwd: [{ required: true, trigger: 'blur', validator: validatePassword }],
code: [{ required: true, message: '请输入正确的验证码', trigger: 'blur' }]
},
passwordType: 'password',
capsTooltip: false,
loading: false,
showDialog: false,
redirect: undefined,
otherQuery: {}
}
},
watch: {
fullWidth(val) {
// 为了避免频繁触发resize函数导致页面卡顿使用定时器
if (!this.timer) {
// 一旦监听到的screenWidth值改变就将其重新赋给data里的screenWidth
this.screenWidth = val
this.timer = true
const that = this
setTimeout(function() {
// 打印screenWidth变化的值
that.timer = false
}, 400)
}
},
$route: {
handler: function(route) {
const query = route.query
if (query) {
this.redirect = query.redirect
this.otherQuery = this.getOtherQuery(query)
}
},
immediate: true
}
},
created() {
const _this = this
document.onkeydown = function(e) {
if (_this.$route.path.indexOf('login') !== -1) {
const key = window.event.keyCode
if (key === 13) {
_this.handleLogin()
}
}
}
window.addEventListener('resize', this.handleResize)
},
mounted() {
this.getInfo()
if (this.loginForm.account === '') {
this.$refs.account.focus()
} else if (this.loginForm.pwd === '') {
this.$refs.pwd.focus()
}
this.getCaptcha()
},
destroyed() {
// window.removeEventListener('storage', this.afterQRScan)
},
beforeDestroy: function() {
window.removeEventListener('resize', this.handleResize)
},
methods: {
handleResize(event) {
this.fullWidth = document.body.clientWidth
},
getInfo() {
getLoginPicApi().then(res => {
this.swiperList = res.banner
this.loginLogo = res.logo
this.backgroundImage = res.backgroundImage
// Cookies.set('MerInfo', JSON.stringify(data))
})
},
checkCapslock(e) {
const { key } = e
this.capsTooltip = key && key.length === 1 && (key >= 'A' && key <= 'Z')
},
showPwd() {
if (this.passwordType === 'password') {
this.passwordType = ''
} else {
this.passwordType = 'password'
}
this.$nextTick(() => {
this.$refs.pwd.focus()
})
},
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
this.$store.dispatch('user/login', this.loginForm)
.then(() => {
this.$router.push({ path: this.redirect || '/', query: this.otherQuery })
this.loading = false
}).catch(() => {
this.loading = false
this.getCaptcha()
})
} else {
console.log('error submit!!')
return false
}
})
},
getCaptcha() {
captchaApi().then(( data ) => {
this.captchatImg = data.code
this.loginForm.key = data.key
}).catch(({ message }) => {
this.$message.error(message)
})
},
getOtherQuery(query) {
return Object.keys(query).reduce((acc, cur) => {
if (cur !== 'redirect') {
acc[cur] = query[cur]
}
return acc
}, {})
}
}
}
</script>
<style lang="scss" scoped>
$screen-md: 768px;
$font-size-base: 14px;
$animation-time : .3s;
$animation-time-quick : .15s;
$transition-time : .2s;
$ease-in-out : ease-in-out;
$subsidiary-color : #808695;
.page-account{
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
overflow: auto;
&-container{
flex: 1;
padding: 32px 0;
text-align: center;
width: 384px;
margin: 0 auto;
&-result{
width: 100%;
}
}
&-tabs{
.ivu-tabs-bar{
border-bottom: none;
}
.ivu-tabs-nav-scroll{
text-align: center;
}
.ivu-tabs-nav{
display: inline-block;
float: none;
}
}
&-top{
padding: 32px 0;
&-logo{
img{
max-height: 75px;
}
}
&-desc{
font-size: $font-size-base;
color: $subsidiary-color;
}
}
&-auto-login{
margin-bottom: 24px;
text-align: left;
a{
float: right;
}
}
&-other{
margin: 24px 0;
text-align: left;
span{
font-size: $font-size-base;
}
img{
width: 24px;
margin-left: 16px;
cursor: pointer;
vertical-align: middle;
opacity: 0.7;
transition: all $transition-time $ease-in-out;
&:hover{
opacity: 1;
}
}
}
.ivu-poptip, .ivu-poptip-rel{
display: block;
}
&-register{
float: right;
&-tip{
text-align: left;
&-title{
font-size: $font-size-base;
}
&-desc{
white-space: initial;
font-size: $font-size-base;
margin-top: 6px;
}
}
}
&-to-login{
text-align: center;
margin-top: 16px;
}
&-header{
text-align: right;
position: fixed;
top: 16px;
right: 24px;
}
}
.labelPic{
position: absolute;
right: 0;
}
@media (min-width: $screen-md) {
.page-account {
background-image: url('../../assets/imgs/bg.jpg');
background-repeat: no-repeat;
background-position: center;
background-size: cover;
}
.page-account-container {
padding: 32px 0 24px 0;
position: relative;
}
}
.page-account {
display: flex;
}
.page-account .code {
display: flex;
align-items: center;
justify-content: center;
}
.page-account .code .pictrue {
height: 40px;
}
.swiperPross {
border-radius: 6px 0px 0px 6px;
overflow: hidden;
}
.swiperPross, .swiperPic, .swiperPic img {
width: 286px;
height: 100%;
}
.swiperPic img {
width: 100%;
height: 100%;
}
.container {
height: 400px !important;
padding: 0 !important;
/*overflow: hidden;*/
border-radius: 6px;
z-index: 1;
display: flex;
}
.containerSamll {
/*width: 56% !important;*/
background: #fff !important;
}
.containerBig {
width: auto !important;
background: #f7f7f7 !important;
}
.index_from {
padding: 0 40px 32px 40px;
height: 400px;
box-sizing: border-box;
}
.page-account-top {
padding: 20px 0 !important;
box-sizing: border-box !important;
display: flex;
justify-content: center;
}
.page-account-container {
border-radius: 0px 6px 6px 0px;
}
.btn {
background: linear-gradient(90deg, rgba(25, 180, 241, 1) 0%, rgba(14, 115, 232, 1) 100%) !important;
}
</style>
<style lang="scss" scoped>
.captcha{
display: flex;
align-items: flex-start;
}
$bg: #2d3a4b;
$dark_gray: #889aa4;
$light_gray: #eee;
.imgs{
img{
height: 36px;
}
}
.login-form {
position: relative;
max-width: 100%;
margin: 0 auto;
overflow: hidden;
}
.tips {
font-size: 14px;
color: #fff;
margin-bottom: 10px;
span {
&:first-of-type {
margin-right: 16px;
}
}
}
.svg-container {
padding: 6px 5px 6px 15px;
color: $dark_gray;
vertical-align: middle;
width: 30px;
display: inline-block;
}
.show-pwd {
position: absolute;
right: 10px;
top: 7px;
font-size: 16px;
color: $dark_gray;
cursor: pointer;
user-select: none;
/deep/.svg-icon {
vertical-align: 0.3em;
}
}
.thirdparty-button {
position: absolute;
right: 0;
bottom: 6px;
}
</style>

View File

@@ -0,0 +1,182 @@
<template>
<div class="components-container">
<div class="container">
<el-form inline>
<el-form-item label="状态">
<el-select v-model="listPram.status" placeholder="状态" clearable @change="handlerSearch" class="selWidth">
<el-option
v-for="item in constants.roleListStatus"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<!-- <el-form-item label="关键词">-->
<!-- <el-input v-model="listPram.keywords" placeholder="请输入关键词" clearable></el-input>-->
<!-- </el-form-item>-->
<!-- <el-form-item>-->
<!-- <el-button type="primary" @click="handlerSearch">查询</el-button>-->
<!-- </el-form-item>-->
</el-form>
</div>
<el-button type="primary" size="mini" @click="handlerOpenEditData({},0)">添加数据</el-button>
<el-dialog
:title="editDataConfig.isCreate === 0?'添加数据':'编辑数据'"
:visible.sync="editDataConfig.visible"
append-to-body
destroy-on-close
>
<edit
v-if="editDataConfig.visible"
:form-data="formData"
:edit-data="editDataConfig.editData"
:is-create="editDataConfig.isCreate"
@hideDialog="handlerHideDia"
/>
</el-dialog>
<el-table
:data="dataList.list"
style="width: 100%;margin-bottom: 20px;"
>
<el-table-column label="编号" prop="id" />
<el-table-column
v-for="item,index in formConf.fields"
:key="index"
:label="item.__config__.label"
:prop="item.__vModel__"
>
<template slot-scope="scope">
<div v-if="['img','image','pic'].indexOf(item.__vModel__) > -1" class="demo-image__preview">
<el-image
style="width: 36px; height: 36px"
:src="scope.row[item.__vModel__]"
:preview-src-list="[scope.row[item.__vModel__]]"
/>
</div>
<span v-else>{{ scope.row[item.__vModel__] }}</span>
</template>
</el-table-column>
<el-table-column label="状态" prop="status">
<template slot-scope="scope">
<span>{{ scope.row.status | filterShowOrHide }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="200">
<template slot-scope="scope">
<el-button type="text" size="small" @click="handlerOpenEditData(scope.row,1)">编辑</el-button>
<el-button type="text" size="small" @click="handlerDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
:current-page="listPram.page"
:page-sizes="constants.page.limit"
:layout="constants.page.layout"
:total="dataList.total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</template>
<script>
import edit from './combineEdit'
import * as constants from '@/utils/constants.js'
import * as systemGroupDataApi from '@/api/systemGroupData.js'
import * as systemFormConfigApi from '@/api/systemFormConfig.js'
export default {
// name: "combineDataList"
components: { edit },
props: {
formData: {
type: Object,
required: true
}
},
data() {
return {
constants,
listPram: {
gid: null,
keywords: null,
status: null, // 1=开启 2=关闭
page: 1,
pageSize: constants.page.limit[0]
},
editDataConfig: {
visible: false,
isCreate: 0, // 0=create 1=edit
editData: {}
},
formConf: { fields: [] },
dataList: { list: [], total: 0 }
}
},
mounted() {
this.handlerGetFormConfig()
this.listPram.gid = this.formData.id
this.handlerGetListData(this.listPram)
},
methods: {
handlerSearch() {
this.listPram.page = 1
this.handlerGetListData(this.listPram)
},
handlerGetListData(pram) { // 获取列表数据
systemGroupDataApi.groupDataList(pram).then(data => {
const _selfList = []
data.list.forEach(_lItem => {
_lItem.value = JSON.parse(_lItem.value)
const _fields = _lItem.value.fields
const _rowData = {}
_fields.map((item) => {
_rowData[item.name] = item.value
})
_rowData.id = _lItem.id
_rowData.sort = _lItem.sort
_rowData.status = _lItem.status
_selfList.push(_rowData)
})
this.dataList.list = _selfList
this.dataList.total = data.total
})
},
handlerGetFormConfig() { // 获取表单配置后生成table列
const _pram = { id: this.formData.formId }
systemFormConfigApi.getFormConfigInfo(_pram).then(data => {
this.formConf = JSON.parse(data.content)
})
},
handlerOpenEditData(rowData, isCreate) {
this.editDataConfig.editData = rowData
this.editDataConfig.isCreate = isCreate
this.editDataConfig.visible = true
},
handlerHideDia() {
this.handlerGetListData(this.listPram)
this.editDataConfig.visible = false
},
handlerDelete(rowData) {
this.$confirm('确实删除当前数据', '提示').then(() => {
systemGroupDataApi.groupDataDelete(rowData).then(data => {
this.$message.success('删除数据成功')
this.handlerHideDia()
})
})
},
handleSizeChange(val) {
this.listPram.limit = val
this.handlerGetListData(this.listPram)
},
handleCurrentChange(val) {
this.listPram.page = val
this.handlerGetListData(this.listPram)
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,118 @@
<template>
<div>
<el-form ref="selfForm" :model="selfForm" label-width="100px">
<el-form-item label="排序" prop="sort" :rules="[{ required: true, message:'排序不能为空', trigger:['blur','change'] }]">
<el-input-number v-model="selfForm.sort" />
</el-form-item>
<el-form-item
label="状态"
prop="status"
:rules="[{ required: true, message:'正确操作状态', trigger:['change'] }]"
>
<el-switch
v-model="selfForm.status"
active-color="#13ce66"
inactive-color="#ff4949"
/>
</el-form-item>
</el-form>
<parser
v-if="formConf.fields.length > 0"
:is-edit="isCreate === 1"
:form-conf="formConf"
:form-edit-data="editData"
@submit="handlerSubmit"
/>
<!-- {{ editData }}-->
</div>
</template>
<script>
import parser from '@/components/FormGenerator/components/parser/Parser'
import * as systemGroupDataApi from '@/api/systemGroupData.js'
import * as systemFormConfigApi from '@/api/systemFormConfig.js'
export default {
// name: "combineEdit"
components: { parser },
props: {
formData: {
type: Object,
required: true
},
isCreate: {
type: Number,
default: 0 // 0=create 1=edit
},
editData: {
type: Object
}
},
data() {
return {
formConf: { fields: [] },
selfForm: {
sort: 0,
status: 0
}
}
},
mounted() {
this.handlerGetFormConfig()
this.handlerInitEditData()
},
methods: {
handlerInitEditData() {
const { sort, status } = this.editData
this.selfForm.sort = sort
this.selfForm.status = status
},
handlerGetFormConfig() { // 获取表单配置后生成table列
const _pram = { id: this.formData.formId }
systemFormConfigApi.getFormConfigInfo(_pram).then(data => {
this.formConf = JSON.parse(data.content)
})
},
handlerSubmit(formValue) {
this.isCreate === 0 ? this.handlerSave(formValue) : this.handlerEdit(formValue)
},
handlerSave(formValue) {
const _pram = this.buildFormPram(formValue)
systemGroupDataApi.groupDataSave(_pram).then(data => {
this.$message.success('添加数据成功')
this.$emit('hideDialog')
})
},
handlerEdit(formValue) {
const _pram = this.buildFormPram(formValue)
systemGroupDataApi.groupDataEdit(_pram, this.editData.id).then(data => {
this.$message.success('编辑数据成功')
this.$emit('hideDialog')
})
},
buildFormPram(formValue) {
const _pram = {
gid: this.formData.id,
form: {
fields: [],
id: this.formData.formId,
sort: this.selfForm.sort,
status: this.selfForm.status
}}
const _fields = []
Object.keys(formValue).forEach((key) => {
_fields.push({
name: key,
title: key,
value: formValue[key]
})
})
_pram.form.fields = _fields
return _pram
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,143 @@
<template>
<div class="divBox">
<el-card class="box-card">
<div slot="header" class="clearfix">
<div class="container">
<el-form inline>
<el-form-item label="数据搜索">
<el-input v-model="listPram.keywords" placeholder="请输入IDKEY组合数据名称简介" class="selWidth" size="small">
<el-button slot="append" icon="el-icon-search" size="small" @click="handlerSearch" />
</el-input>
</el-form-item>
</el-form>
</div>
<el-button size="mini" type="primary" @click="handlerOpenEdit({},0)">添加数据组</el-button>
</div>
<el-table
:data="dataList.list"
style="width: 100%;margin-bottom: 20px;"
size="mini"
highlight-current-row
>
<el-table-column label="数据组名称" prop="name" min-width="150"/>
<el-table-column label="简介" prop="info" min-width="150"/>
<el-table-column label="操作" fixed="right" min-width="180">
<template slot-scope="scope">
<el-button size="small" type="text" @click="handleDataList(scope.row)">数据列表</el-button>
<el-button size="small" type="text" @click="handlerOpenEdit(scope.row, 1)">编辑</el-button>
<el-button size="small" type="text" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
:current-page="listPram.page"
:page-sizes="constants.page.limit"
:layout="constants.page.layout"
:total="dataList.total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</el-card>
<el-dialog
:title="editDialogConfig.isCreate === 0?'创建数据组':'编辑数据组'"
:visible.sync="editDialogConfig.visible"
>
<edit
v-if="editDialogConfig.visible"
:is-create="editDialogConfig.isCreate"
:edit-data="editDialogConfig.editData"
@hideDialog="handlerHideDialog"
/>
</el-dialog>
<el-dialog title="组合数据列表" :visible.sync="comDataListConfig.visible" fullscreen>
<cm-data-list v-if="comDataListConfig.visible" :form-data="comDataListConfig.formData" />
</el-dialog>
</div>
</template>
<script>
import * as constants from '@/utils/constants.js'
import edit from '@/views/maintain/devconfig/combinedDataEdit'
import * as systemGroupApi from '@/api/systemGroup'
import cmDataList from './combineDataList'
export default {
// name: "combinedData"
components: { edit, cmDataList },
data() {
return {
constants,
dataList: {
list: [],
total: 0
},
listPram: {
keywords: null,
page: 1,
pageSize: constants.page.limit[0]
},
editDialogConfig: {
visible: false,
isCreate: 0, // 0=创建 1=编辑
editData: {}
},
comDataListConfig: {
visible: false,
formData: {}
}
}
},
mounted() {
this.handlerGetList(this.listPram)
},
methods: {
handlerSearch() {
this.listPram.page = 1
this.handlerGetList(this.listPram)
},
handlerOpenEdit(editData, isCreate) {
isCreate === 0 ? this.editDialogConfig.editData = {} : this.editDialogConfig.editData = editData
this.editDialogConfig.isCreate = isCreate
this.editDialogConfig.visible = true
},
handlerGetList(pram) {
systemGroupApi.groupList(pram).then(data => {
this.dataList = data
})
},
handleDataList(rowData) {
if (rowData.formId <= 0) return this.$message.error('请先关联表单')
this.comDataListConfig.formData = rowData
this.comDataListConfig.visible = true
},
handleDelete(rowData) {
this.$confirm('确定删除当前数据', '提示').then(() => {
systemGroupApi.groupDelete(rowData).then(data => {
this.$message.success('删除数据成功')
setTimeout(() => {
this.handlerGetList(this.listPram)
}, 800)
})
})
},
handleSizeChange(val) {
this.listPram.limit = val
this.handlerGetList(this.listPram)
},
handleCurrentChange(val) {
this.listPram.page = val
this.handlerGetList(this.listPram)
},
handlerHideDialog() {
setTimeout(() => {
this.editDialogConfig.visible = false
this.handlerGetList(this.listPram)
}, 800)
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,108 @@
<template>
<div class="components-container">
<el-form ref="editPram" :model="editPram" label-width="100px">
<el-form-item
label="数据组名称"
prop="name"
:rules="[{ required:true, message:'填写数据组名称', trigger:['blur','change'] }]"
>
<el-input v-model="editPram.name" placeholder="数据组名称" clearable />
</el-form-item>
<el-form-item
label="数据简介"
prop="info"
:rules="[{ required:true, message:'填写数据简介', trigger:['blur','change'] }]"
>
<el-input v-model="editPram.info" placeholder="数据简介" clearable />
</el-form-item>
<el-form-item
label="表单数据ID"
prop="formId"
:rules="[{ required:true, message:'请选择表单数据', trigger:['change'] }]"
>
<span>{{ editPram.formId }}</span>
<el-button type="primary" @click="selectFormDialogConfig.visible = true">选择模板数据</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" class="btn-width100" @click="handlerSubmit('editPram')">确定</el-button>
</el-form-item>
</el-form>
<el-dialog title="选择表单模板" :visible.sync="selectFormDialogConfig.visible" append-to-body>
<form-config-list select-model @selectedRowData="handlerSelectedRowData" />
</el-dialog>
</div>
</template>
<script>
import formConfigList from '@/views/maintain/formConfig'
import * as systemGroupApi from '@/api/systemGroup'
export default {
// name: "combinedDataEdit"
components: { formConfigList },
props: {
isCreate: {
type: Number,
default: 0
},
editData: {
type: Object,
default: {}
}
},
data() {
return {
editPram: {
formId: null,
info: null,
name: null,
id: null
},
selectedFormConfigData: {},
selectFormDialogConfig: {
visible: false
}
}
},
mounted() {
this.handlerInitEditData()
},
methods: {
handlerInitEditData() {
if (this.isCreate !== 1) return
const { id, name, info, formId, createTime, updateTime } = this.editData
this.editPram.id = id
this.editPram.name = name
this.editPram.info = info
this.editPram.formId = formId
},
handlerSelectedRowData(rowData) {
this.selectedFormConfigData = rowData
this.editPram.formId = this.selectedFormConfigData.id
this.selectFormDialogConfig.visible = false
},
handlerSubmit(form) {
this.$refs[form].validate(result => {
if (!result) return
this.isCreate === 0 ? this.handlerSave(this.editPram) : this.handlerEdit(this.editPram)
})
},
handlerSave(pram) {
systemGroupApi.groupSave(pram).then(data => {
this.$message.success('添加组合数据成功')
this.$emit('hideDialog')
})
},
handlerEdit(pram) {
systemGroupApi.groupEdit(pram).then(data => {
this.$message.success('编辑组合数据成功')
this.$emit('hideDialog')
})
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,151 @@
<template>
<div class="components-container">
<el-form ref="editPram" :model="editPram" label-width="100px">
<el-form-item label="父级">
<!-- <span>{{ prent.name}}</span>-->
<el-cascader
v-model="editPram.pid"
:options="allTreeList"
:props="categoryProps"
disabled
style="width:100%"
/>
</el-form-item>
<el-form-item
label="分类名称"
prop="name"
:rules="[{ required:true,message:'请输入分类名称',trigger:['blur','change'] }]"
>
<el-input v-model="editPram.name" placeholder="分类名称" />
</el-form-item>
<el-form-item label="英文名称" prop="url" :rules="[{required:true,message:'英文名称不能为空',trigger:['blur','change']}]">
<el-input v-model="editPram.url" placeholder="URL" />
</el-form-item>
<el-form-item label="排序">
<el-input-number v-model="editPram.sort" :min="1" :max="10" />
</el-form-item>
<el-form-item label="状态">
<el-switch v-model="editPram.status" :active-value="true" :inactive-value="false" />
</el-form-item>
<!-- 这里的类型是无限极分类的类型不能当做配置分类的类型使用下面的扩展字段实现原有业务中的类型-->
<!-- <el-form-item label="类型" prop="type" :rules="[{required:true,message:'请选择类型',trigger:['blur']}]">-->
<!-- <el-select v-model="editPram.type" disabled>-->
<!-- <el-option v-for="item in constants.categoryType" :key="item.value"-->
<!-- :label="item.name" :value="item.value"></el-option>-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="类型">-->
<!-- <el-radio-group v-model="editPram.extra">-->
<!-- <el-radio v-for="item,index in constants.configCategory" :label="item.value">-->
<!-- {{ item.label }}-->
<!-- </el-radio>-->
<!-- </el-radio-group>-->
<!-- &lt;!&ndash; <el-input type="textarea" v-model="editPram.extra" placeholder="扩展字段"/>&ndash;&gt;-->
<!-- </el-form-item>-->
<el-form-item>
<el-button size="mini" type="primary" @click="handlerSubmit('editPram')">确定</el-button>
<el-button size="mini" @click="close">取消</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import * as constants from '@/utils/constants.js'
import * as categoryApi from '@/api/categoryApi.js'
import * as selfUtil from '@/utils/ZBKJIutil.js'
export default {
// name: "configCategotyEdit"
props: {
prent: {
type: Object,
default: 0
},
isCreate: {
type: Number,
default: 0
},
editData: {
type: Object
},
allTreeList: {
type: Array
}
},
data() {
return {
constants,
editPram: {
extra: null, // 关联表单id
name: null,
pid: null,
sort: 0,
status: true,
type: constants.categoryType[5].value,
url: null,
id: 0
},
categoryProps: {
value: 'id',
label: 'name',
children: 'child',
expandTrigger: 'hover',
checkStrictly: true,
emitPath: false
},
parentOptions: []
}
},
mounted() {
this.initEditData()
},
methods: {
close() {
this.$emit('hideEditDialog')
},
initEditData() {
this.parentOptions = selfUtil.addTreeListLabelForCasCard(this.allTreeList)
if (this.isCreate !== 1) {
const { id } = this.prent
this.editPram.pid = id
} else {
const { extra, name, pid, sort, status, type, url, id } = this.editData
// this.editPram.extra = extra
this.editPram.name = name
this.editPram.pid = pid
this.editPram.sort = sort
this.editPram.status = status
this.editPram.type = type
this.editPram.url = url
this.editPram.id = id
this.editPram.extra = extra
}
},
handlerSubmit(formName) {
this.$refs[formName].validate((valid) => {
if (!valid) return
this.handlerSaveOrUpdate(this.isCreate === 0)
})
},
handlerSaveOrUpdate(isSave) {
if (isSave) {
this.editPram.pid = this.prent.id
categoryApi.addCategroy(this.editPram).then(data => {
this.$emit('hideEditDialog')
this.$message.success('创建分类成功')
})
} else {
this.editPram.pid = Array.isArray(this.editPram.pid) ? this.editPram.pid[0] : this.editPram.pid
categoryApi.updateCategroy(this.editPram).then(data => {
this.$emit('hideEditDialog')
this.$message.success('更新分类成功')
})
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,203 @@
<template>
<div class="divBox">
<el-card class="box-card">
<div slot="header">
<el-form inline>
<el-form-item>
<el-button size="mini" type="primary" @click="handlerOpenAdd({id:0,name:'顶层目录'})">添加分类</el-button>
</el-form-item>
</el-form>
</div>
<el-table
ref="treeList"
:data="treeList"
style="width: 100%;"
row-key="id"
size="mini"
class="table"
highlight-current-row
:tree-props="{children: 'child', hasChildren: 'hasChildren'}"
>
<el-table-column prop="name" label="分类昵称" min-width="300">
<template slot-scope="scope">
{{ scope.row.name }}
</template>
</el-table-column>
<el-table-column label="英文名称" show-overflow-tooltip min-width="180">
<template slot-scope="scope">
<span>{{ scope.row.url }}</span>
</template>
</el-table-column>
<el-table-column label="已关联的表单" show-overflow-tooltip min-width="130">
<template slot-scope="scope">
<span>{{ scope.row.extra }}</span>
</template>
</el-table-column>
<!-- <el-table-column label="排序" prop="sort" width="150"></el-table-column>-->
<el-table-column label="启用状态" min-width="100">
<template slot-scope="scope">
<span>{{ scope.row.status | filterYesOrNo }}</span>
</template>
</el-table-column>
<el-table-column label="操作" min-width="250" fixed="right">
<template slot-scope="scope">
<el-button
type="text"
size="small"
:disabled="scope.row.pid > 0"
@click="handlerOpenAdd(scope.row)"
>添加子目录</el-button>
<el-button type="text" size="small" @click="handleEditMenu(scope.row)">编辑</el-button>
<el-button type="text" size="small" @click="handlerOpenFormConfig(scope.row)">配置列表</el-button>
<el-button type="text" size="small" @click="handleDelMenu(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<el-dialog
:title="editDialogConfig.isCreate === 0?'添加分类':'编辑分类'"
:visible.sync="editDialogConfig.visible"
destroy-on-close
:close-on-click-modal="false"
>
<edit
v-if="editDialogConfig.visible"
:prent="editDialogConfig.prent"
:is-create="editDialogConfig.isCreate"
:edit-data="editDialogConfig.data"
:biztype="editDialogConfig.biztype"
:all-tree-list="treeList"
@hideEditDialog="hideEditDialog"
/>
</el-dialog>
<el-dialog title="选择已配置的表单" :visible.sync="configFormSelectedDialog.visible">
<span class="color-red">注意表单不能重复关联</span>
<form-config-list
v-if="configFormSelectedDialog.visible"
select-model
@selectedRowData="handlerSelectedRowData"
/>
<el-form>
<el-form-item>
<el-button type="primary" style="width:100%;" @click="handlerAddFormExtra">关联</el-button>
</el-form-item>
</el-form>
</el-dialog>
</div>
</template>
<script>
import * as constants from '@/utils/constants.js'
import * as categoryApi from '@/api/categoryApi.js'
import edit from '@/views/maintain/devconfig/configCategotyEdit.vue'
import * as selfUtil from '@/utils/ZBKJIutil.js'
import configList from './configList'
import formConfigList from '@/views/maintain/formConfig'
export default {
// name: "configCategroy"
components: { edit, configList, formConfigList },
props: {
},
data() {
return {
constants,
searchPram: {
status: null,
type: null
},
editDialogConfig: {
visible: false,
isCreate: 0, // 0=创建1=编辑
prent: {}, // 父级对象
data: {}
},
treeList: [],
listPram: {
pid: 0,
type: constants.categoryType[5].value,
status: null,
name: null,
page: constants.page.page,
limit: constants.page.limit[1]
},
configFormSelectedDialog: {
visible: false,
currentData: {}
}
}
},
mounted() {
this.handlerGetTreeList()
},
methods: {
handlerOpenFormConfig(rowData) {
this.configFormSelectedDialog.currentData = rowData
this.configFormSelectedDialog.visible = true
},
handlerGetList() {
categoryApi.listCategroy(this.listPram).then(data => {
// this.dataList = data
this.treeList = data.list
})
},
handlerOpenAdd(rowData) {
this.editDialogConfig.isCreate = 0
this.editDialogConfig.prent = rowData
this.editDialogConfig.data = {}
this.editDialogConfig.biztype = this.biztype
this.editDialogConfig.visible = true
},
handleEditMenu(rowData) {
this.editDialogConfig.isCreate = 1
this.editDialogConfig.data = rowData
this.editDialogConfig.prent = rowData
this.editDialogConfig.visible = true
},
handleDelMenu(rowData) {
this.$confirm('确定删除当前数据?').then(() => {
categoryApi.deleteCategroy(rowData).then(data => {
this.handlerGetTreeList()
this.$message.success('删除成功')
})
})
},
hideEditDialog() {
setTimeout(() => {
this.editDialogConfig.prent = {}
this.editDialogConfig.type = 0
this.editDialogConfig.visible = false
this.handlerGetTreeList()
}, 200)
},
handlerGetTreeList() {
// status: this.selectModel?1:-1
const _pram = { type: constants.categoryType[5].value, status: -1 }
categoryApi.treeCategroy(_pram).then(data => {
this.treeList = this.handleAddArrt(data)
})
},
handleAddArrt(treeData) {
// let _result = this.addTreeListLabel(treeData)
const _result = selfUtil.addTreeListLabel(treeData)
return _result
},
handlerSelectedRowData(rowData) {
this.configFormSelectedDialog.currentData.extra = rowData.id
},
handlerAddFormExtra() {
categoryApi.updateCategroy(this.configFormSelectedDialog.currentData).then(data => {
this.$message.success('关联表单成功')
setTimeout(() => {
this.configFormSelectedDialog.visible = false
this.handlerGetTreeList()
}, 800)
})
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,23 @@
<template>
<div class="components-container">
<config-list :prent-data="prentData" />
</div>
</template>
<script>
import configList from '@/components/FormGenerator/index/Home.vue'
export default {
components: { configList },
// name: "configList",
props: {
prentData: {
type: Object,
default: {}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,56 @@
<template>
<div>
<config-list
:edit-data="editData"
:is-create="isCreate"
@getFormConfigDataResult="handlerGetFormConfigData"
/>
</div>
</template>
<script>
import configList from '@/components/FormGenerator/index/Home.vue'
import * as systemFormConfigApi from '@/api/systemFormConfig.js'
export default {
// name: "edit"
components: { configList },
props: {
editData: {
type: Object,
default: {}
},
isCreate: {
type: Number,
default: 0 // 0=创建1=编辑
}
},
data() {
return {}
},
methods: {
handlerGetFormConfigData(formConfigData) {
formConfigData.id ? this.handlerEdit(formConfigData) : this.handlerSave(formConfigData)
},
handlerSave(pram) {
systemFormConfigApi.getFormConfigSave(pram).then(data => {
this.$message.success('创建表单配置成功')
setTimeout(() => {
this.$emit('hideDialog')
}, 800)
})
},
handlerEdit(pram) {
systemFormConfigApi.getFormConfigEdit(pram).then(data => {
this.$message.success('编辑表单配置成功')
setTimeout(() => {
this.$emit('hideDialog')
}, 800)
})
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,142 @@
<template>
<div class="divBox">
<el-card class="box-card">
<div slot="header" class="clearfix">
<div class="container">
<el-form inline size="small">
<el-form-item label="关键字">
<el-input v-model="listPram.keywords" placeholder="请输入id名称描述" clearable class="selWidth" size="small">
<el-button slot="append" icon="el-icon-search" size="small" @click="handlerSearch" />
</el-input>
</el-form-item>
<el-form-item v-if="selectModel">
<el-button type="primary" :disabled="!selectedConfigData.id" @click="handlerConfimSelect">确定选择</el-button>
</el-form-item>
</el-form>
</div>
<el-button size="mini" type="primary" @click="handlerEditData({},0)" v-if="!selectModel">创建表单</el-button>
</div>
<el-table
:data="dataList.list"
:highlight-current-row="selectModel"
size="mini"
class="table"
highlight-current-row
@current-change="handleCurrentRowChange"
>
<el-table-column label="ID" prop="id" width="80"/>
<el-table-column label="名称" prop="name" min-width="180"/>
<el-table-column label="描述" prop="info" min-width="220"/>
<el-table-column label="更新时间" prop="updateTime" min-width="200" />
<el-table-column v-if="!selectModel" label="操作" min-width="80" fixed="right">
<template slot-scope="scope">
<el-button type="text" size="small" @click="handlerEditData(scope.row,1)">编辑</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
:current-page="listPram.page"
:page-sizes="constants.page.limit"
:layout="constants.page.layout"
:total="dataList.total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</el-card>
<el-dialog
:visible.sync="editDialogConfig.visible"
title="title"
fullscreen
:title="editDialogConfig.isCreate === 0? '创建表单':'编辑表单'"
destroy-on-close
:close-on-click-modal="false"
>
<edit
v-if="editDialogConfig.visible"
:is-create="editDialogConfig.isCreate"
:edit-data="editDialogConfig.editData"
@hideDialog="handlerHide"
/>
</el-dialog>
</div>
</template>
<script>
import * as systemFormConfigApi from '@/api/systemFormConfig.js'
import * as constants from '@/utils/constants.js'
import edit from './edit'
export default {
// name: "index"
components: { edit },
props: {
selectModel: {
type: Boolean,
default: false
}
},
data() {
return {
constants,
listPram: {
keywords: null,
page: 1,
limit: constants.page.limit[0]
},
editDialogConfig: {
visible: false,
editData: {},
isCreate: 0
},
dataList: { list: [], total: 0 },
selectedConfigData: {}
}
},
mounted() {
this.handlerGetList(this.listPram)
},
methods: {
handlerSearch() {
this.listPram.page = 1
this.handlerGetList(this.listPram)
},
handlerGetList(pram) {
systemFormConfigApi.getFormConfigList(pram).then(data => {
this.dataList = data
})
},
handlerEditData(rowData, isCreate) {
if (isCreate === 0) {
this.editDialogConfig.editData = {}
} else {
this.editDialogConfig.editData = rowData
}
this.editDialogConfig.isCreate = isCreate
this.editDialogConfig.visible = true
},
handlerHide() {
this.editDialogConfig.editData = {}
this.editDialogConfig.isCreate = 0
this.editDialogConfig.visible = false
this.handlerGetList(this.listPram)
},
handleSizeChange(val) {
this.listPram.limit = val
this.handlerGetList(this.listPram)
},
handleCurrentChange(val) {
this.listPram.page = val
this.handlerGetList(this.listPram)
},
handleCurrentRowChange(rowData) {
this.selectedConfigData = rowData
},
handlerConfimSelect() {
this.$emit('selectedRowData', this.selectedConfigData)
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,15 @@
<template>
<div>
<router-view />
</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,110 @@
<template>
<div class="divBox">
<el-card class="box-card">
<el-form ref="pram" :model="pram" :rules="rules" label-width="100px">
<el-form-item label="管理员账号" prop="account">
<el-input v-model="pram.account" placeholder="管理员账号" :disabled="true"/>
</el-form-item>
<el-form-item label="管理员姓名" prop="realName">
<el-input v-model="pram.realName" placeholder="管理员姓名" />
</el-form-item>
<el-form-item label="原始密码">
<el-input v-model="password" placeholder="原始密码" />
</el-form-item>
<el-form-item label="新密码" prop="pwd">
<el-input
v-model="pram.pwd"
placeholder="管理员密码,不更改可以不填写"
clearable
@input="handlerPwdInput"
@clear="handlerPwdInput"
/>
</el-form-item>
<el-form-item v-if="pram.pwd" label="确认新密码" prop="repwd">
<el-input v-model="pram.repwd" placeholder="确认新密码" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handlerSubmit('pram')">提交</el-button>
<el-button @click="close('pram')">取消</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script>
import * as systemAdminApi from '@/api/systemadmin.js'
import Cookies from 'js-cookie'
export default {
name: "index",
data() {
const validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次输入密码'))
} else if (value !== this.pram.pwd) {
callback(new Error('两次输入密码不一致!'))
} else {
callback()
}
}
return {
password: '',
JavaInfo: JSON.parse(Cookies.get('JavaInfo')),
pram: {
account: JSON.parse(Cookies.get('JavaInfo')).account,
pwd: null,
repwd: null,
realName: null,
id: JSON.parse(Cookies.get('JavaInfo')).id
},
roleList: [],
rules: {
account: [{ required: true, message: '请填管理员账号', trigger: ['blur', 'change'] }],
pwd: [{ required: true, message: '请填管理员密码', trigger: ['blur', 'change'] }],
repwd: [{ required: true, message: '确认密码密码', validator: validatePass, trigger: ['blur', 'change'] }],
realName: [{ required: true, message: '管理员姓名', trigger: ['blur', 'change'] }],
roles: [{ required: true, message: '管理员身份', trigger: ['blur', 'change'] }]
}
}
},
methods: {
close(formName) {
this.$refs[formName].resetFields();
},
handlerSubmit(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
systemAdminApi.adminUpdate(this.pram).then(data => {
this.$message.success('提交成功')
})
} else {
return false;
}
});
},
handlerPwdInput(val) {
if (!val) {
this.rules.pwd = []
this.rules.repwd = []
return
}
this.rules.pwd = [
{ required: true, message: '请填管理员密码', trigger: ['blur', 'change'] },
{ min: 6, max: 20, message: '长度6-20个字符', trigger: ['blur', 'change'] }]
this.rules.repwd = [{ required: true, message: '两次输入密码不一致', validator: (rule, value, callback) => {
if (value === '') {
callback(new Error('两次输入密码不一致!'))
} else if (value !== this.pram.pwd) {
callback(new Error('两次输入密码不一致!'))
} else {
callback()
}
}, trigger: ['blur', 'change'] }]
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,13 @@
<template>
<div>砍价</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,15 @@
<template>
<div>
营销
</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,15 @@
<template>
<div>
优惠券模板
</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,15 @@
<template>
<div>
<router-view />
</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,271 @@
<template>
<div class="divBox">
<el-card class="box-card">
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="150px" class="demo-ruleForm">
<el-form-item label="优惠劵名称" prop="name">
<el-input v-model="ruleForm.name" style="width: 350px" placeholder="请输入优惠券名称"></el-input>
</el-form-item>
<el-form-item label="优惠劵类型">
<el-radio-group v-model="ruleForm.useType">
<el-radio :label="1">通用卷</el-radio>
<el-radio :label="2">商品券</el-radio>
<el-radio :label="3">品类券</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="选择品类:" prop="primaryKey" v-if="ruleForm.useType === 3">
<el-cascader v-model="ruleForm.primaryKey" :options="merCateList" :props="props2" clearable class="selWidth" :show-all-levels="false" />
</el-form-item>
<el-form-item label="商品:" v-if="ruleForm.useType === 2">
<div class="acea-row">
<template v-if="checked.length">
<div class="pictrue" v-for="(item, index) in checked" :key="index">
<img :src="item.image">
<i class="el-icon-error btndel" @click="handleRemove(index)" />
</div>
</template>
<div class="upLoadPicBox" @click="changeGood">
<div class="upLoad">
<i class="el-icon-camera cameraIconfont" />
</div>
</div>
</div>
</el-form-item>
<el-form-item label="优惠券面值" prop="money">
<el-input-number v-model="ruleForm.money" :min="1" :max="10" label="描述文字"></el-input-number>
</el-form-item>
<el-form-item label="使用门槛">
<el-radio-group v-model="threshold">
<el-radio :label="false">无门槛</el-radio>
<el-radio :label="true">有门槛</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="优惠券最低消费" prop="minPrice" v-if="threshold">
<el-input-number v-model="ruleForm.minPrice" :min="1" label="描述文字"></el-input-number>
</el-form-item>
<el-form-item label="使用有效期">
<el-radio-group v-model="ruleForm.isFixedTime">
<el-radio :label="false">天数</el-radio>
<el-radio :label="true">时间段</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="使用有效期限(天)" prop="resource" v-if="!ruleForm.isFixedTime">
<el-input-number v-model="ruleForm.day" :min="0" label="描述文字"></el-input-number>
</el-form-item>
<el-form-item label="使用有效期限" prop="resource" v-if="ruleForm.isFixedTime">
<el-date-picker
style="width: 550px"
v-model="termTime"
type="datetimerange"
range-separator=""
format="yyyy - MM - dd - HH : mm : ss"
value-format="yyyy-MM-dd HH:mm:ss"
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
</el-form-item>
<el-form-item label="领取是否限时" prop="isForever">
<el-radio-group v-model="ruleForm.isForever">
<el-radio :label="true">限时</el-radio>
<el-radio :label="false">不限时</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="领取时间" v-if="ruleForm.isForever">
<el-date-picker
style="width: 550px"
v-model="isForeverTime"
type="datetimerange"
range-separator=""
format="yyyy - MM - dd - HH : mm : ss"
value-format="yyyy-MM-dd HH:mm:ss"
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
</el-form-item>
<el-form-item label="领取方式" prop="resource">
<el-radio-group v-model="ruleForm.type">
<el-radio :label="1">手动领取</el-radio>
<el-radio :label="2">新人卷</el-radio>
<el-radio :label="3">赠送卷</el-radio>
<!--<el-radio :label="4">付费会员卷</el-radio>-->
</el-radio-group>
</el-form-item>
<el-form-item label="是否限量" prop="isLimited">
<el-radio-group v-model="ruleForm.isLimited">
<el-radio :label="true">限量</el-radio>
<el-radio :label="false">不限量</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="发布数量" prop="total" v-if="ruleForm.isLimited">
<el-input-number v-model="ruleForm.total" :min="1" label="排序"></el-input-number>
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input-number v-model="ruleForm.sort" :min="0" label="排序"></el-input-number>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="ruleForm.status">
<el-radio :label="true">开启</el-radio>
<el-radio :label="false">关闭</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item>
<el-button size="mini" type="primary" @click="submitForm('ruleForm')" :loading="loading">立即创建</el-button>
<!--<el-button @click="resetForm('ruleForm')">重置</el-button>-->
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script>
import { couponSaveApi, couponInfoApi } from '@/api/marketing'
import { categoryApi } from '@/api/store'
export default {
name: "creatCoupon",
data() {
return {
loading: false,
threshold: false,
termTime: [],
isForeverTime: [],
props2: {
children: 'child',
label: 'name',
value: 'id',
checkStrictly: true,
emitPath: false
},
couponType: 0,
term: 'termday',
merCateList: [], // 商户分类筛选
ruleForm: {
useType: 1,
isFixedTime: false,
name: '',
money: 1,
minPrice: 1,
day: null,
isForever: false,
primaryKey: '',
type: 2,
isLimited: false,
useStartTime: '', // 使用
useEndTime: '', // 结束
receiveStartTime: '', //领取
receiveEndTime: '',
sort: 0,
total: 1,
status: false
},
rules: {
name: [
{ required: true, message: '请输入优惠券名称', trigger: 'blur' },
],
},
checked: []
}
},
mounted() {
this.getCategorySelect()
if( this.$route.params.id ) this.getInfo()
},
methods: {
// 商品分类;
getCategorySelect() {
categoryApi({ status: -1, type: 1 }).then(res => {
this.merCateList = res
this.merCateList.map(item => {
this.$set(item , 'disabled', true)
})
})
},
getInfo(){
this.loading = true
couponInfoApi({id: this.$route.params.id}).then(res => {
const info = res.coupon
this.ruleForm = {
useType: info.useType,
isFixedTime: info.isFixedTime,
isForever: info.isForever,
name: info.name,
money: info.money,
minPrice: info.minPrice,
day: info.day,
type: info.type,
isLimited: info.isLimited,
sort: info.sort,
total: info.total,
status: info.status,
primaryKey: Number(info.primaryKey)
}
this.checked = res.product
info.minPrice === 0 ? this.threshold = false : this.threshold = true
info.isForever ? this.isForeverTime = [info.receiveStartTime, info.receiveEndTime] : this.isForeverTime = []
info.isFixedTime ? this.termTime = [info.useStartTime, info.useEndTime] : this.termTime = []
this.loading = false
}).catch(res => {
this.loading = false
this.$message.error(res.message)
})
},
handleRemove (i) {
this.checked.splice(i, 1)
},
changeGood(){
const _this = this
this.$modalGoodList(function(row) {
_this.checked = row
},'many',_this.checked)
},
submitForm(formName) {
if( this.ruleForm.useType === 2 ) this.ruleForm.primaryKey = this.checked.map(item => {return item.id}).join(',')
if( this.ruleForm.useType === 1 ) this.ruleForm.primaryKey = ''
if( !this.threshold ) this.ruleForm.minPrice = 0
if( !this.ruleForm.isLimited ) this.ruleForm.total = 0
this.ruleForm.isFixedTime && this.termTime.length ? (this.ruleForm.useStartTime = this.termTime[0], this.ruleForm.day = null) : this.ruleForm.useStartTime = ''
this.ruleForm.isFixedTime && this.termTime.length ? (this.ruleForm.useEndTime = this.termTime[1], this.ruleForm.day = null) : this.ruleForm.useEndTime = ''
this.ruleForm.isForever && this.isForeverTime.length ? this.ruleForm.receiveStartTime = this.isForeverTime[0] : this.ruleForm.receiveStartTime = ''
this.ruleForm.isForever && this.isForeverTime.length ? this.ruleForm.receiveEndTime = this.isForeverTime[1] : this.ruleForm.receiveEndTime = ''
this.$refs[formName].validate((valid) => {
if (valid) {
this.loading = true
couponSaveApi(this.ruleForm).then(() => {
this.$message.success("新增成功")
this.loading = false
setTimeout(() => {
this.$router.push({ path: `/marketing/coupon/list` })
}, 200);
}).catch(() => {
this.loading = false
})
} else {
this.loading = false
return false;
}
});
},
}
}
</script>
<style scoped lang="scss">
.pictrue{
width: 60px;
height: 60px;
border: 1px dotted rgba(0,0,0,0.1);
margin-right: 10px;
position: relative;
cursor: pointer;
img{
width: 100%;
height: 100%;
}
}
.btndel{
position: absolute;
z-index: 1;
width :20px !important;
height: 20px !important;
left: 46px;
top: -4px;
}
</style>

View File

@@ -0,0 +1,295 @@
<template>
<div class="divBox">
<el-card class="box-card">
<div slot="header" class="clearfix">
<div class="filter-container">
<div class="demo-input-suffix acea-row">
<span class="seachTiele">状态</span>
<el-select v-model="tableFrom.status" placeholder="请选择" class="filter-item selWidth mr20" @change="seachList" clearable>
<el-option label="未开启" :value="0" />
<el-option label="开启" :value="1" />
</el-select>
<span class="seachTiele">优惠券名称</span>
<el-input v-model="tableFrom.name" placeholder="请输入优惠券名称" class="selWidth">
<el-button slot="append" icon="el-icon-search" @click="seachList" />
</el-input>
</div>
</div>
<router-link :to=" { path: '/marketing/coupon/list/save' } ">
<el-button size="small" type="primary">添加优惠劵</el-button>
</router-link>
</div>
<el-table
v-loading="listLoading"
:data="tableData.data"
style="width: 100%"
size="mini"
>
<el-table-column
prop="id"
label="ID"
min-width="50"
/>
<el-table-column
prop="name"
label="名称"
min-width="120"
/>
<el-table-column
label="类型"
min-width="80"
>
<template slot-scope="{ row }">
<span>{{row.useType | couponUserTypeFilter}}</span>
</template>
</el-table-column>
<el-table-column
prop="money"
label="面值"
min-width="100"
/>
<el-table-column
prop="name"
label="领取方式"
min-width="100"
>
<template slot-scope="{ row }">
<span>{{row.useType | couponTypeFilter}}</span>
</template>
</el-table-column>
<el-table-column
min-width="260"
label="领取日期"
>
<template slot-scope="{ row }">
<div v-if="row.receiveEndTime">
{{ row.receiveStartTime }} - {{ row.receiveEndTime }}
</div>
<span v-else>不限时</span>
</template>
</el-table-column>
<el-table-column
min-width="260"
label="使用时间"
>
<template slot-scope="{ row }">
<div v-if="row.day">
{{ row.day }}
</div>
<span v-else>
{{ row.useStartTime }} - {{ row.useEndTime }}
</span>
</template>
</el-table-column>
<el-table-column
min-width="100"
label="发布数量"
>
<template slot-scope="{ row }">
<span v-if=" !row.isLimited ">不限量</span>
<div v-else>
<span class="fa">发布{{ row.total }}</span>
<span class="sheng">剩余{{ row.lastTotal }}</span>
</div>
</template>
</el-table-column>
<el-table-column
label="是否开启"
min-width="100"
>
<template slot-scope="scope">
<el-switch
v-model="scope.row.status"
:active-value="true"
:inactive-value="false"
active-text="开启"
inactive-text="关闭"
@click.native="onchangeIsShow(scope.row)"
/>
</template>
</el-table-column>
<el-table-column label="操作" min-width="130" fixed="right">
<template slot-scope="scope">
<el-button type="text" class="mr10" size="small" @click="receive(scope.row)">领取记录</el-button>
<router-link :to=" { path: '/marketing/coupon/list/save/' + scope.row.id } ">
<el-button type="text" size="small">复制</el-button>
</router-link>
</template>
</el-table-column>
</el-table>
<div class="block">
<el-pagination
:page-sizes="[20, 40, 60, 80]"
:page-size="tableFrom.limit"
:current-page="tableFrom.page"
layout="total, sizes, prev, pager, next, jumper"
:total="tableData.total"
@size-change="handleSizeChange"
@current-change="pageChange"
/>
</div>
</el-card>
<!--领取记录-->
<el-dialog
title="领取记录"
:visible.sync="dialogVisible"
width="500px"
:before-close="handleClose"
>
<el-table
v-loading="Loading"
:data="issueData.data"
style="width: 100%"
>
<el-table-column
prop="user.nickname"
label="用户名"
min-width="120"
/>
<el-table-column label="用户头像" min-width="80">
<template slot-scope="scope">
<div class="demo-image__preview">
<el-image
style="width: 36px; height: 36px"
:src="scope.row.avatar"
:preview-src-list="[scope.row.avatar]"
/>
</div>
</template>
</el-table-column>
<el-table-column
prop="createTime"
label="领取时间"
min-width="180"
/>
</el-table>
<div class="block">
<el-pagination
:page-sizes="[10, 20, 30, 40]"
:page-size="tableFromIssue.limit"
:current-page="tableFromIssue.page"
layout="total, sizes, prev, pager, next, jumper"
:total="issueData.total"
@size-change="handleSizeChangeIssue"
@current-change="pageChangeIssue"
/>
</div>
</el-dialog>
</div>
</template>
<script>
import { marketingListApi, couponIssueStatusApi, couponUserListApi } from '@/api/marketing'
import { roterPre } from '@/settings'
export default {
name: 'CouponList',
data() {
return {
Loading: false,
dialogVisible: false,
roterPre: roterPre,
listLoading: true,
tableData: {
data: [],
total: 0
},
tableFrom: {
page: 1,
limit: 20,
status: '',
name: ''
},
tableFromIssue: {
page: 1,
limit: 10,
couponId: ''
},
issueData: {
data: [],
total: 0
}
}
},
mounted() {
this.getList()
},
methods: {
seachList() {
this.tableFrom.page = 1
this.getList()
},
handleClose() {
this.dialogVisible = false
},
// 领取记录
receive(row) {
this.dialogVisible = true
this.getIssueList(row)
},
// 列表
getIssueList(row) {
this.Loading = true
this.tableFromIssue.couponId = row.id
couponUserListApi(this.tableFromIssue).then(res => {
this.issueData.data = res.list
this.issueData.total = res.total
this.Loading = false
}).catch(res => {
this.Loading = false
this.$message.error(res.message)
})
},
pageChangeIssue(page) {
this.tableFromIssue.page = page
this.getIssueList()
},
handleSizeChangeIssue(val) {
this.tableFromIssue.limit = val
this.getIssueList()
},
// 列表
getList() {
this.listLoading = true
marketingListApi(this.tableFrom).then(res => {
this.tableData.data = res.list
this.tableData.total = res.total
this.listLoading = false
}).catch(res => {
this.listLoading = false
})
},
pageChange(page) {
this.tableFrom.page = page
this.getList()
},
handleSizeChange(val) {
this.tableFrom.limit = val
this.getList()
},
// 修改状态
onchangeIsShow(row) {
couponIssueStatusApi({id:row.id, status:row.status}).then(() => {
this.$message.success('修改成功')
this.getList()
})
}
}
}
</script>
<style scoped lang="scss">
.selWidth{
width: 350px !important;
}
.seachTiele{
line-height: 35px;
}
.fa{
color: #0a6aa1;
display: block;
}
.sheng{
color: #ff0000;
display: block;
}
</style>

View File

@@ -0,0 +1,201 @@
<template>
<div class="divBox">
<el-card class="box-card">
<div slot="header" class="clearfix">
<div class="filter-container">
<el-form :inline="true">
<el-form-item label="使用状态:" class="mr10">
<el-select v-model="tableFromIssue.status" placeholder="请选择评价状态" clearable class="selWidth" @change="seachList">
<el-option label="已使用" value="1" />
<el-option label="未使用" value="0" />
<el-option label="已过期" value="2" />
</el-select>
</el-form-item>
<el-form-item label="领取人:" class="mr10">
<el-input v-model="tableFromIssue.coupon_id" placeholder="请输入领取人" class="selWidth">
<el-button size="mini" slot="append" icon="el-icon-search" @click="seachList"/>
</el-input>
</el-form-item>
<el-form-item label="优惠劵:" class="mr10">
<el-input v-model="tableFromIssue.name" placeholder="请输入优惠劵" class="selWidth">
<el-button slot="append" icon="el-icon-search" @click="seachList"/>
</el-input>
</el-form-item>
</el-form>
</div>
</div>
<el-table
v-loading="Loading"
:data="issueData.data"
style="width: 100%"
>
<el-table-column
prop="couponId"
label="优惠券ID"
min-width="80"
/>
<el-table-column
prop="name"
label="优惠券名称"
min-width="150"
/>
<el-table-column
prop="nickname"
label="领取人"
min-width="130"
/>
<el-table-column
prop="money"
label="面值"
min-width="100"
/>
<el-table-column
prop="minPrice"
label="最低消费额"
min-width="120"
/>
<el-table-column
prop="startTime"
label="开始使用时间"
min-width="150"
/>
<el-table-column
prop="endTime"
label="结束使用时间"
min-width="150"
/>
<el-table-column
label="获取方式"
min-width="150"
>
<template slot-scope="scope">
<span>{{scope.row.type | failFilter}}</span>
</template>
</el-table-column>
<el-table-column
prop="is_fail"
label="是否可用"
min-width="100"
>
<template slot-scope="scope">
<i v-if="scope.row.status === 0" class="el-icon-check" style="font-size: 14px;color: #0092DC;" />
<i v-else class="el-icon-download" style="font-size: 14px;color: #ed5565;" />
</template>
</el-table-column>
<el-table-column
label="使用状态"
min-width="100"
>
<template slot-scope="scope">
<span>{{scope.row.status | statusFilter}}</span>
</template>
</el-table-column>
</el-table>
<div class="block">
<el-pagination
:page-sizes="[20, 40, 60, 80]"
:page-size="tableFromIssue.limit"
:current-page="tableFromIssue.page"
layout="total, sizes, prev, pager, next, jumper"
:total="issueData.total"
@size-change="handleSizeChangeIssue"
@current-change="pageChangeIssue"
/>
</div>
</el-card>
</div>
</template>
<script>
import { couponUserListApi } from '@/api/marketing'
import { roterPre } from '@/settings'
export default {
name: 'CouponUser',
filters: {
failFilter(status) {
const statusMap = {
'receive': '自己领取',
'send': '后台发送',
'give': '满赠',
'new': '新人',
'buy': '买赠送'
}
return statusMap[status]
},
statusFilter(status) {
const statusMap = {
0: '未使用',
1: '已使用',
2: '已过期'
}
return statusMap[status]
}
},
data() {
return {
Loading: false,
roterPre: roterPre,
imgList: [],
tableFromIssue: {
page: 1,
limit: 20,
name: '',
status: ''
},
issueData: {
data: [],
total: 0
}
}
},
mounted() {
this.getIssueList()
},
methods: {
seachList() {
this.tableFromIssue.page = 1
this.getIssueList()
},
// 列表
getIssueList() {
this.Loading = true
couponUserListApi(this.tableFromIssue).then(res => {
this.issueData.data = res.list
this.issueData.total = res.total
// this.issueData.data.map((item) => {
// this.imgList.push(item.user.avatar)
// })
this.Loading = false
}).catch(res => {
this.Loading = false
this.$message.error(res.message)
})
},
pageChangeIssue(page) {
this.tableFromIssue.page = page
this.getIssueList()
},
handleSizeChangeIssue(val) {
this.tableFromIssue.limit = val
this.getIssueList()
}
}
}
</script>
<style scoped lang="scss">
.selWidth{
width: 350px !important;
}
.seachTiele{
line-height: 35px;
}
.fa{
color: #0a6aa1;
display: block;
}
.sheng{
color: #ff0000;
display: block;
}
</style>

View File

@@ -0,0 +1,13 @@
<template>
<div>拼团</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,15 @@
<template>
<div>
<router-view />
</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,13 @@
<template>
<div>list222</div>
</template>
<script>
export default {
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,39 @@
<template>
<div class="divBox">
<el-card class="box-card">
<zb-parser
:form-id="109"
:is-create="isCreate"
:edit-data="editData"
@submit="handlerSubmit"
/>
</el-card>
</div>
</template>
<script>
import zbParser from '@/components/FormGenerator/components/parser/ZBParser'
import { smsSaveApi } from '@/api/sms'
export default {
name: "integralconfig",
components: { zbParser },
data() {
return {
isCreate: 0,
editData: {}
}
},
methods: {
handlerSubmit(formValue) {
smsSaveApi(formValue).then(data => {
this.$message.success('新增成功')
this.editData = {}
})
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,15 @@
<template>
<div>
<router-view />
</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,104 @@
<template>
<div>
<zb-parser
v-if="formConf.fields.length > 0"
:form-id="formid"
:is-create="isCreate"
:edit-data="editData"
@submit="handlerSubmit"
/>
<!-- {{ editData }}-->
</div>
</template>
<script>
import * as constants from '@/utils/constants.js'
import zbParser from '@/components/FormGenerator/components/parser/ZBParser'
import * as systemGroupDataApi from '@/api/systemGroupData.js'
import * as systemFormConfigApi from '@/api/systemFormConfig.js'
export default {
// name: "combineEdit"
components: { zbParser },
props: {
formid: {
type: Number,
required: true
},
isCreate: {
type: Number,
default: 0 // 0=create 1=edit
},
editData: {
type: Object
}
},
data() {
return {
constants,
formConf: { fields: [] },
selfForm: {
sort: 0,
status: 0
}
}
},
mounted() {
this.handlerGetFormConfig()
this.handlerInitEditData()
},
methods: {
handlerInitEditData() {
const { sort, status } = this.editData
this.selfForm.sort = sort
this.selfForm.status = status
},
handlerGetFormConfig() { // 获取表单配置后生成table列
const _pram = { id: this.formid }
systemFormConfigApi.getFormConfigInfo(_pram).then(data => {
this.formConf = JSON.parse(data.content)
})
},
handlerSubmit(formValue) {
this.isCreate === 0 ? this.handlerSave(formValue) : this.handlerEdit(formValue)
},
handlerSave(formValue) {
const _pram = this.buildFormPram(formValue)
systemGroupDataApi.groupDataSave(_pram).then(data => {
this.$message.success('添加数据成功')
this.$emit('hideDialog')
})
},
handlerEdit(formValue) {
const _pram = this.buildFormPram(formValue)
systemGroupDataApi.groupDataEdit(_pram, this.editData.id).then(data => {
this.$message.success('编辑数据成功')
this.$emit('hideDialog')
})
},
buildFormPram(formValue) {
const _pram = {
gid: this.formid,
form: {
fields: [],
id: this.formid
// sort: this.selfForm.sort,
// status: this.selfForm.status
}}
const _fields = []
Object.keys(formValue).forEach((key) => {
_fields.push({
name: key,
title: key,
value: formValue[key]
})
})
_pram.form.fields = _fields
return _pram
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,167 @@
<template>
<div class="components-container">
<el-form inline>
<el-form-item>
<el-button type="primary" @click="handlerOpenEditData({},0)">添加数据</el-button>
</el-form-item>
<el-form-item>
<el-select v-model="listPram.status" placeholder="状态" clearable @change="handlerSearch">
<el-option
v-for="item in constants.showHiddenStatus"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<!-- <el-form-item label="关键词">-->
<!-- <el-input v-model="listPram.keywords" placeholder="请输入关键词" clearable></el-input>-->
<!-- </el-form-item>-->
<!-- <el-form-item>-->
<!-- <el-button type="primary" @click="handlerSearch">查询</el-button>-->
<!-- </el-form-item>-->
</el-form>
<el-dialog
:title="editDataConfig.isCreate === 0?'添加数据':'编辑数据'"
:visible.sync="editDataConfig.visible"
append-to-body
destroy-on-close
>
<edit
v-if="editDataConfig.visible"
:formid="formId"
:edit-data="editDataConfig.editData"
:is-create="editDataConfig.isCreate"
@hideDialog="handlerHideDia"
/>
</el-dialog>
<el-table
:data="dataList.list"
style="width: 100%;margin-bottom: 20px;"
>
<el-table-column label="编号" prop="id" />
<el-table-column
v-for="item,index in formConf.fields"
:key="index"
:label="item.__config__.label"
:prop="item.__vModel__"
>
<template slot-scope="scope"><!-- 自定义维护特殊列展示 -->
<span v-if="item.__config__.label === '状态'">
{{ scope.row[item.__vModel__] | filterShowOrHideForFormConfig }}</span>
<span v-else>{{ scope.row[item.__vModel__] }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="200">
<template slot-scope="scope">
<el-button type="primary" @click="handlerOpenEditData(scope.row,1)">编辑</el-button>
<el-button type="danger" @click="handlerDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
:current-page="listPram.page"
:page-sizes="constants.page.limit"
:layout="constants.page.layout"
:total="dataList.total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</template>
<script>
import edit from './edit'
import * as constants from '@/utils/constants.js'
import * as systemGroupDataApi from '@/api/systemGroupData.js'
import * as systemFormConfigApi from '@/api/systemFormConfig.js'
export default {
// name: "combineDataList"
components: { edit },
data() {
return {
constants,
listPram: {
gid: null,
keywords: null,
status: null, // 1=开启 2=关闭
page: 1,
limit: constants.page.limit[0]
},
editDataConfig: {
visible: false,
isCreate: 0, // 0=create 1=edit
editData: {}
},
formConf: { fields: [] },
dataList: { list: [], total: 0 },
formId: constants.formConfigIds[1].id
}
},
mounted() {
this.handlerGetFormConfig()
this.listPram.gid = this.formId
this.handlerGetListData(this.listPram)
},
methods: {
handlerSearch() {
this.listPram.page = 1
this.handlerGetListData(this.listPram)
},
handlerGetListData(pram) { // 获取列表数据
systemGroupDataApi.groupDataList(pram).then(data => {
const _selfList = []
data.list.forEach(_lItem => {
_lItem.value = JSON.parse(_lItem.value)
const _fields = _lItem.value.fields
const _rowData = {}
_fields.map((item) => {
_rowData[item.name] = item.value
})
_rowData.id = _lItem.id
_rowData.sort = _lItem.sort
_rowData.status = _lItem.status
_selfList.push(_rowData)
})
this.dataList.list = _selfList
this.dataList.total = data.total
})
},
handlerGetFormConfig() { // 获取表单配置后生成table列
const _pram = { id: this.formId }
systemFormConfigApi.getFormConfigInfo(_pram).then(data => {
this.formConf = JSON.parse(data.content)
})
},
handlerOpenEditData(rowData, isCreate) {
this.editDataConfig.editData = rowData
this.editDataConfig.isCreate = isCreate
this.editDataConfig.visible = true
},
handlerHideDia() {
this.handlerGetListData(this.listPram)
this.editDataConfig.visible = false
},
handlerDelete(rowData) {
this.$confirm('确实删除当前数据', '提示').then(() => {
systemGroupDataApi.groupDataDelete(rowData).then(data => {
this.$message.success('删除数据成功')
this.handlerHideDia()
})
})
},
handleSizeChange(val) {
this.listPram.limit = val
this.handlerGetListData(this.listPram)
},
handleCurrentChange(val) {
this.listPram.page = val
this.handlerGetListData(this.listPram)
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,13 @@
<template>
<div>秒杀商品</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,15 @@
<template>
<div>
<router-view />
</div>
</template>
<script>
export default {
}
</script>
<style lang="sass" scoped>
</style>

View File

@@ -0,0 +1,565 @@
<template>
<div class="divBox">
<el-card class="box-card">
<div slot="header" class="clearfix">
<!--<el-tabs v-model="tableFrom.type" @tab-click="getList">-->
<!--<el-tab-pane label="全部订单" name="" />-->
<!--<el-tab-pane label="普通订单" name="1" />-->
<!--<el-tab-pane label="拼团订单" name="2" />-->
<!--<el-tab-pane label="秒杀订单" name="3" />-->
<!--<el-tab-pane label="砍价订单" name="4" />-->
<!--</el-tabs>-->
<div class="container">
<el-form size="small" label-width="100px">
<el-form-item label="订单状态:">
<el-radio-group v-model="tableFrom.status" type="button" @change="seachList">
<el-radio-button label="all">全部 {{ '(' +orderChartType.all?orderChartType.all:0 + ')' }}</el-radio-button>
<el-radio-button label="unPaid">未支付 {{ '(' +orderChartType.unPaid?orderChartType.unPaid:0+ ')' }}</el-radio-button>
<el-radio-button label="notShipped">未发货 {{ '(' +orderChartType.notShipped?orderChartType.notShipped:0+ ')' }}</el-radio-button>
<el-radio-button label="spike">待收货 {{ '(' +orderChartType.spike?orderChartType.spike:0+ ')' }}</el-radio-button>
<el-radio-button label="bargain">待评价 {{ '(' +orderChartType.bargain?orderChartType.bargain:0+ ')' }}</el-radio-button>
<el-radio-button label="complete">交易完成 {{ '(' +orderChartType.complete?orderChartType.complete:0+ ')' }}</el-radio-button>
<el-radio-button label="toBeWrittenOff">待核销 {{ '(' +orderChartType.toBeWrittenOff?orderChartType.toBeWrittenOff:0+ ')' }}</el-radio-button>
<el-radio-button label="refunding">退款中 {{ '(' +orderChartType.refunding?orderChartType.refunding:0+ ')' }}</el-radio-button>
<el-radio-button label="refunded">已退款 {{ '(' +orderChartType.refunded?orderChartType.refunded:0+ ')' }}</el-radio-button>
<el-radio-button label="deleted">已删除 {{ '(' +orderChartType.deleted?orderChartType.deleted:0+ ')' }}</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="时间选择:" class="width100">
<el-radio-group v-model="tableFrom.dateLimit" type="button" class="mr20" size="small" @change="selectChange(tableFrom.dateLimit)">
<el-radio-button v-for="(item,i) in fromList.fromTxt" :key="i" :label="item.val">{{ item.text }}</el-radio-button>
</el-radio-group>
<el-date-picker v-model="timeVal" value-format="yyyy-MM-dd" format="yyyy-MM-dd" size="small" type="daterange" placement="bottom-end" placeholder="自定义时间" style="width: 220px;" @change="onchangeTime" />
</el-form-item>
<el-form-item label="订单号:" class="width100">
<el-input v-model="tableFrom.orderId" placeholder="请输入订单号" class="selWidth" size="small">
<el-button slot="append" icon="el-icon-search" size="small" @click="seachList" />
</el-input>
</el-form-item>
</el-form>
</div>
<cards-data :cardLists="cardLists"></cards-data>
</div>
<el-table
v-loading="listLoading"
:data="tableData.data"
style="width: 100%"
size="mini"
class="table"
highlight-current-row
@selection-change="handleSelectionChange"
>
<el-table-column type="expand">
<template slot-scope="props">
<el-form label-position="left" inline class="demo-table-expand">
<el-form-item label="商品总价:">
<span>{{ props.row.totalPrice }}</span>
</el-form-item>
<el-form-item label="推广人:">
<span>{{ props.row.spreadInfo.id + ' / ' + props.row.spreadInfo.name }}</span>
</el-form-item>
<el-form-item label="用户备注:">
<span>{{ props.row.mark }}</span>
</el-form-item>
<el-form-item label="商家备注:">
<span>{{ props.row.remark }}</span>
</el-form-item>
</el-form>
</template>
</el-table-column>
<el-table-column
type="selection"
width="55"
/>
<el-table-column
label="订单号"
min-width="170"
>
<template slot-scope="scope">
<span style="display: block;" v-text="scope.row.orderId" />
<span v-show="scope.row.isDel" style="color: #ED4014;display: block;">用户已删除</span>
</template>
</el-table-column>
<!--<el-table-column-->
<!--prop="id"-->
<!--label="订单类型"-->
<!--min-width="150"-->
<!--/>-->
<el-table-column
prop="realName"
label="用户信息"
min-width="130"
/>
<el-table-column
label="商品信息"
min-width="330"
>
<!--<template slot-scope="scope">-->
<!--<div v-if="scope.row.productList.length">-->
<!--<div v-for="(val, i ) in scope.row.productList" :key="i" class="tabBox acea-row row-middle">-->
<!--<div class="demo-image__preview">-->
<!--<el-image-->
<!--:src="val.info.productInfo.image"-->
<!--:preview-src-list="imgList"-->
<!--/>-->
<!--</div>-->
<!--&lt;!&ndash;<span class="tabBox_tit">{{ val.info.productInfo.store_name + ' | ' }}{{ val.info.productInfo.attrInfo.suk ? val.info.productInfo.attrInfo.suk:'-' }}</span>&ndash;&gt;-->
<!--&lt;!&ndash;<span class="tabBox_pice">{{ '¥'+ val.info.productInfo.attrInfo.price ? val.info.productInfo.attrInfo.price:'-' + ' x '+ val.info.cart_num }}</span>&ndash;&gt;-->
<!--</div>-->
<!--</div>-->
<!--</template>-->
</el-table-column>
<el-table-column
prop="payPrice"
label="实际支付"
min-width="80"
/>
<el-table-column
label="支付方式"
min-width="80"
>
<template slot-scope="scope">
<span>{{ scope.row.payTypeStr }}</span>
</template>
</el-table-column>
<el-table-column
label="订单状态"
min-width="150"
>
<template slot-scope="scope">
<div v-if="scope.row.statusStr.key === 'refunding'" class="refunding">
<b style="color: #f124c7;">申请退款</b>
<span>退款原因{{scope.row.refundReasonWap}}</span>
<span>备注说明{{scope.row.refundReasonWapExplain}}</span>
<span>退款时间{{scope.row.refundReasonTime}}</span>
<span>
退款凭证
<img :src="scope.row.refundReasonWapImg" v-if="scope.row.refundReasonWapImg">
<span v-else style="display: inline-block"></span>
</span>
</div>
<span v-else>{{ scope.row.statusStr.value }}</span>
</template>
</el-table-column>
<el-table-column
prop="createTime"
label="下单时间"
min-width="150"
/>
<el-table-column label="操作" min-width="150" fixed="right" align="center">
<template slot-scope="scope">
<el-button v-if="scope.row.paid === false" type="text" size="small" @click="edit(scope.row)" class="mr10">编辑</el-button>
<el-button v-if="scope.row.statusStr.key === 'notShipped'" type="text" size="small" class="mr10" @click="sendOrder(scope.row)">发送货</el-button>
<el-dropdown trigger="click">
<span class="el-dropdown-link">
更多<i class="el-icon-arrow-down el-icon--right" />
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="onOrderDetails(scope.row.id)">订单详情</el-dropdown-item>
<el-dropdown-item @click.native="onOrderLog(scope.row.id)">订单记录</el-dropdown-item>
<el-dropdown-item @click.native="onOrderMark(scope.row)">订单备注</el-dropdown-item>
<el-dropdown-item v-show="scope.row.statusStr.key === 'refunding'" @click.native="onOrderRefuse(scope.row)">拒绝退款</el-dropdown-item>
<el-dropdown-item v-show="scope.row.statusStr.key === 'refunding'" @click.native="onOrderRefund(scope.row)">立即退款</el-dropdown-item>
<el-dropdown-item @click.native="handleDelete(scope.row, scope.$index)">删除订单</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-table-column>
</el-table>
<div class="block">
<el-pagination
:page-sizes="[20, 40, 60, 80]"
:page-size="tableFrom.limit"
:current-page="tableFrom.page"
layout="total, sizes, prev, pager, next, jumper"
:total="tableData.total"
@size-change="handleSizeChange"
@current-change="pageChange"
/>
</div>
</el-card>
<!--编辑-->
<el-dialog
title="编辑订单"
:visible.sync="dialogVisible"
width="500px"
:before-close="handleClose">
<zb-parser
:form-id="104"
:is-create="isCreate"
:edit-data="editData"
@submit="handlerSubmit"
/>
</el-dialog>
<!--记录-->
<el-dialog
title="操作记录"
:visible.sync="dialogVisibleJI"
width="700px"
>
<el-table
v-loading="LogLoading"
border
:data="tableDataLog.data"
style="width: 100%"
>
<el-table-column
prop="oid"
align="center"
label="ID"
min-width="80"
/>
<el-table-column
prop="changeMessage"
label="操作记录"
align="center"
min-width="280"
/>
<el-table-column
prop="createTime"
label="操作时间"
align="center"
min-width="280"
/>
</el-table>
<div class="block">
<el-pagination
:page-sizes="[10, 20, 30, 40]"
:page-size="tableFromLog.limit"
:current-page="tableFromLog.page"
layout="total, sizes, prev, pager, next, jumper"
:total="tableDataLog.total"
@size-change="handleSizeChangeLog"
@current-change="pageChangeLog"
/>
</div>
</el-dialog>
<!--详情-->
<details-from ref="orderDetail" :orderId="orderId"/>
<!-- 发送货 -->
<order-send ref="send" :orderId="orderId" @submitFail="getList"></order-send>
<!--拒绝退款-->
<el-dialog
title="拒绝退款原因"
:visible.sync="RefuseVisible"
width="500px"
:before-close="RefusehandleClose">
<zb-parser
:form-id="106"
:is-create="1"
:edit-data="RefuseData"
@submit="RefusehandlerSubmit"
/>
</el-dialog>
<!--立即拒绝-->
<el-dialog
title="退款处理"
:visible.sync="refundVisible"
width="500px"
:before-close="refundhandleClose">
<zb-parser
:form-id="107"
:is-create="1"
:edit-data="refundData"
@submit="refundhandlerSubmit"
/>
</el-dialog>
</div>
</template>
<script>
import { orderListApi, orderUpdateApi, orderLogApi, orderMarkApi, orderDeleteApi, orderRefuseApi, orderRefundApi } from '@/api/order'
import cardsData from '@/components/cards/index'
import zbParser from '@/components/FormGenerator/components/parser/ZBParser'
import detailsFrom from './orderDetail'
import orderSend from './orderSend'
export default {
name: 'orderlistDetails',
components: {
cardsData,
zbParser,
detailsFrom,
orderSend
},
data() {
return {
RefuseVisible: false,
RefuseData:{},
orderId: 0,
refundVisible: false,
refundData: {},
dialogVisibleJI: false,
tableDataLog: {
data: [],
total: 0
},
tableFromLog: {
page: 1,
limit: 10,
oid: null
},
LogLoading: false,
isCreate: 1,
editData: null,
dialogVisible: false,
imgList: [],
tableData: {
data: [],
total: 0
},
listLoading: true,
tableFrom: {
status: 'all',
dateLimit: '',
orderId: '',
page: 1,
limit: 20
},
orderChartType: {},
timeVal: [],
fromList: {
title: '选择时间',
custom: true,
fromTxt: [
{ text: '全部', val: '' },
{ text: '今天', val: 'today' },
{ text: '昨天', val: 'yesterday' },
{ text: '最近7天', val: 'lately7' },
{ text: '最近30天', val: 'lately30' },
{ text: '本月', val: 'month' },
{ text: '本年', val: 'year' }
]
},
selectionList: [],
ids: '',
orderids: '',
cardLists: []
}
},
mounted() {
this.getList()
},
methods: {
seachList() {
this.tableFrom.page = 1
this.getList()
},
// 拒绝退款
RefusehandleClose() {
this.RefuseVisible = false
},
onOrderRefuse(row) {
this.orderids = row.id
this.RefuseData = {
orderId: row.orderId,
reason: ''
}
this.RefuseVisible = true
},
RefusehandlerSubmit(formValue) {
orderRefuseApi({ id: this.orderids, reason: formValue.reason}).then(data => {
this.$message.success('操作成功')
this.RefuseVisible = false
this.getList()
})
},
// 立即退款
refundhandleClose() {
this.refundVisible = false
},
onOrderRefund(row) {
this.refundData = {
orderId: row.orderId,
amount: row.payPrice,
type: ''
}
this.orderids = row.id
this.refundVisible = true
},
refundhandlerSubmit(formValue) {
orderRefundApi({ amount: formValue.amount, orderId: this.orderids, type: formValue.type}).then(data => {
this.$message.success('操作成功')
this.refundVisible = false
this.getList()
})
},
// 发送
sendOrder(row) {
this.$refs.send.modals = true;
this.$refs.send.getList();
this.orderId = row.id;
},
// 订单删除
handleDelete(row, idx) {
if (row.isDel) {
this.$modalSure().then(() => {
orderDeleteApi({ id: row.id }).then(() => {
this.$message.success('删除成功')
this.tableData.data.splice(idx, 1)
})
})
} else {
this.$confirm('您选择的的订单存在用户未删除的订单,无法删除用户未删除的订单!', '提示', {
confirmButtonText: '确定',
type: 'error'
})
}
},
// 详情
onOrderDetails(id) {
this.orderId = id
this.$refs.orderDetail.getDetail(id)
this.$refs.orderDetail.dialogVisible = true
},
// 订单记录
onOrderLog(id) {
this.dialogVisibleJI = true
this.LogLoading = true
this.tableFromLog.oid = id
orderLogApi( this.tableFromLog ).then(res => {
this.tableDataLog.data = res.list
this.tableDataLog.total = res.total
this.LogLoading = false
}).catch(() => {
this.LogLoading = false
})
},
pageChangeLog(page) {
this.tableFromLog.page = page
this.getList()
},
handleSizeChangeLog(val) {
this.tableFromLog.limit = val
this.getList()
},
handleClose() {
this.dialogVisible = false
},
// 备注
onOrderMark(row) {
this.$prompt('订单备注', {
confirmButtonText: '确定',
cancelButtonText: '取消',
inputErrorMessage: '请输入订单备注',
inputType: 'textarea',
inputValue: row.mark,
inputPlaceholder: '请输入订单备注',
inputValidator: (value) => { if(!value) return '输入不能为空'}
}).then(({value}) => {
orderMarkApi({ mark : value, id: row.id}).then(() => {
this.$message.success('操作成功')
this.getList();
})
}).catch(() => {
this.$message.info('取消输入')
})
},
handleSelectionChange(val) {
this.selectionList = val
const data = []
this.selectionList.map((item) => {
data.push(item.id)
})
this.ids = data.join(',')
},
// 选择时间
selectChange (tab) {
this.timeVal = [];
this.tableFrom.page = 1
this.getList();
},
// 具体日期
onchangeTime (e) {
this.timeVal = e;
this.tableFrom.dateLimit = e ? this.timeVal.join(',') : ''
this.tableFrom.page = 1
this.getList();
},
// 编辑
edit(row) {
this.dialogVisible = true
this.orderId = row.id
this.editData = {
orderId: row.orderId,
totalPrice: row.totalPrice,
totalPostage: row.totalPostage,
payPrice: row.payPrice,
payPostage: row.payPostage,
gainIntegral: row.gainIntegral,
}
},
handlerSubmit(formValue) {
orderUpdateApi(formValue, {id: this.orderId}).then(data => {
this.$message.success('编辑数据成功')
this.dialogVisible = false
this.getList()
})
},
// 列表
getList() {
this.listLoading = true
orderListApi(this.tableFrom).then(res => {
this.tableData.data = res.list.list || []
this.tableData.total = res.list.total
this.orderChartType = res.status
this.tableData.data.map((item) => {
item.productList.map((i) => {
this.imgList.push(i.info.productInfo.image)
})
})
const stat = res.top
this.cardLists = [
{ name: '订单数量', count: stat.count },
{ name: '订单金额', count: stat.amount },
{ name: '微信支付金额', count: stat.weChatAmount },
{ name: '余额支付金额', count: stat.yueAmount }
]
this.listLoading = false
}).catch(() => {
this.listLoading = false
})
},
pageChange(page) {
this.tableFrom.page = page
this.getList()
},
handleSizeChange(val) {
this.tableFrom.limit = val
this.getList()
},
}
}
</script>
<style lang="scss" scoped>
.refunding{
span{
display: block;
}
}
.selWidth{
width: 300px;
}
.el-dropdown-link {
cursor: pointer;
color: #409EFF;
font-size: 12px;
}
.el-icon-arrow-down {
font-size: 12px;
}
.tabBox_tit {
width: 60%;
font-size: 12px !important;
margin: 0 2px 0 10px;
letter-spacing: 1px;
padding: 5px 0;
box-sizing: border-box;
}
</style>

View File

@@ -0,0 +1,113 @@
<template>
<el-dialog
title="订单信息"
:visible.sync="dialogVisible"
width="700px"
v-if="orderDatalist"
>
<div class="description" v-loading="loading">
<div class="title">用户信息</div>
<div class="acea-row">
<div class="description-term">用户昵称{{orderDatalist.realName}}</div>
<div class="description-term">收货人{{orderDatalist.realName}}</div>
<div class="description-term">联系电话{{orderDatalist.userPhone}}</div>
<div class="description-term">收货地址{{orderDatalist.userAddress}}</div>
</div>
<el-divider></el-divider>
<div class="title">收货信息</div>
<div class="acea-row">
<div class="description-term">订单编号{{orderDatalist.orderId}}</div>
<div class="description-term">订单状态{{orderDatalist.status | orderStatusFilter}}</div>
<div class="description-term">商品总数{{orderDatalist.totalNum}}</div>
<div class="description-term">商品总价{{orderDatalist.totalPrice}}</div>
<div class="description-term">交付邮费{{orderDatalist.payPostage}}</div>
<div class="description-term">优惠券金额{{orderDatalist.couponPrice}}</div>
<div class="description-term">实际支付{{orderDatalist.payPrice}}</div>
<div class="description-term" v-if="orderDatalist.refundPrice">退款金额{{orderDatalist.refundPrice}}</div>
<div class="description-term" v-if="orderDatalist.useIntegral">使用积分{{orderDatalist.useIntegral}}</div>
<div class="description-term" v-if="orderDatalist.backIntegral">退回积分{{orderDatalist.backIntegral}}</div>
<div class="description-term">创建时间{{orderDatalist.createTime}}</div>
<div class="description-term">支付方式{{orderDatalist.payTypeStr}}</div>
<div class="description-term">推广人{{orderDatalist.spreadInfo.id + ' / ' +orderDatalist.spreadInfo.name}}</div>
<div class="description-term" v-if="orderDatalist.shippingType === 2 && orderDatalist.statusStr.key === 'notShipped'">门店名称{{orderDatalist.storeName}}</div>
<div class="description-term" v-if="orderDatalist.shippingType === 2 && orderDatalist.statusStr.key === 'notShipped'">核销码{{orderDatalist.user_phone}}</div>
<div class="description-term">商家备注{{orderDatalist.remark}}</div>
</div>
<template v-if="orderDatalist.deliveryType === 'express'">
<el-divider></el-divider>
<div class="title">物流信息</div>
<div class="acea-row">
<div class="description-term">快递公司{{orderDatalist.deliveryName}}</div>
<div class="description-term">快递单号{{orderDatalist.deliveryId}}</div>
</div>
</template>
<template v-if="orderDatalist.deliveryType === 'send'">
<el-divider></el-divider>
<div class="title">配送信息</div>
<div class="acea-row">
<div class="description-term">送货人姓名{{orderDatalist.deliveryName}}</div>
<div class="description-term">送货人电话{{orderDatalist.deliveryId}}</div>
</div>
</template>
<template v-if="orderDatalist.mark">
<el-divider></el-divider>
<div class="title">用户备注</div>
<div class="acea-row">
<div class="description-term">{{orderDatalist.mark}}</div>
</div>
</template>
</div>
</el-dialog>
</template>
<script>
import { orderDetailApi } from '@/api/order'
export default {
name: 'OrderDetail',
props: {
orderId: {
type: Number,
default: 0
}
},
data() {
return {
dialogVisible: false,
orderDatalist: null,
loading: false
}
},
mounted() {
},
methods: {
getDetail(id) {
this.loading = true
orderDetailApi({id: id}).then(res => {
this.orderDatalist = res
this.loading = false
}).catch(() => {
this.loading = false
})
}
}
}
</script>
<style scoped lang="scss">
.title{
margin-bottom: 16px;
color: #17233d;
font-weight: 500;
font-size: 14px;
}
.description{
&-term {
display: table-cell;
padding-bottom: 10px;
line-height: 20px;
width: 50%;
font-size: 12px;
}
}
</style>

View File

@@ -0,0 +1,103 @@
<template>
<el-dialog :visible.sync="modals" title="订单记录" class="order_box">
<el-form ref="formItem" :model="formItem" label-width="110px" @submit.native.prevent>
<el-form-item label="选择类型:">
<el-radio-group v-model="formItem.type" @change="changeRadio(formItem.type)">
<el-radio label="1">发货</el-radio>
<el-radio label="2">送货</el-radio>
<el-radio label="3">虚拟</el-radio>
</el-radio-group>
</el-form-item>
<div v-if="formItem.type==='1'">
<el-form-item label="快递公司:" prop="expressId"
:rules="[{ required: true, message: '请选择快递公司', trigger: 'change' }]">
<el-select v-model="formItem.expressId" style="width:80%;">
<el-option v-for="(item,i) in express" :value="item.id" :key="i">{{ item.name }}</el-option>
</el-select>
</el-form-item>
<el-form-item label="快递单号:" prop="expressCode"
:rules="[{ required: true, message: '请输入快递单号', trigger: 'blur' }]">
<el-input v-model="formItem.expressCode" placeholder="请输入快递单号" style="width:80%;"></el-input>
</el-form-item>
</div>
<div v-if="formItem.type==='2'">
<el-form-item label="送货人姓名:" prop="expressId"
:rules="[{ required: true, message: '请输入送货人姓名', trigger: 'blur' }]">
<el-input v-model="formItem.expressId" placeholder="请输入送货人姓名" style="width:80%;"></el-input>
</el-form-item>
<el-form-item label="送货人电话:" prop="expressCode"
:rules="[{ required: true, message: '请输入送货人电话', trigger: 'blur' }]">
<el-input v-model="formItem.expressCode" placeholder="请输入送货人电话" style="width:80%;"></el-input>
</el-form-item>
</div>
</el-form>
<div slot="footer">
<el-button size="mini" type="primary" @click="putSend('formItem')">提交</el-button>
<el-button size="mini" @click="cancel('formItem')">取消</el-button>
</div>
</el-dialog>
</template>
<script>
import { orderSendApi } from '@/api/order'
import { expressList } from '@/api/logistics';
export default {
name: 'orderSend',
props: {
orderId: Number
},
data () {
return {
formItem: {
type: '1',
expressId: '',
expressCode: '',
id: ''
},
modals: false,
express: []
}
},
mounted () {
},
methods: {
changeRadio (o) {
if( o === '3'){
this.formItem.expressId = ''
this.formItem.expressCode = ''
}
},
// 物流公司列表
getList () {
expressList({ page: 1, limit: 999}).then(async res => {
this.express = res.list
})
},
// 提交
putSend(name) {
this.formItem.id = this.orderId
this.$refs[name].validate((valid) => {
if (valid) {
orderSendApi(this.formItem).then(async => {
this.$message.success('发送货成功');
this.modals = false;
this.$refs[name].resetFields();
this.$emit('submitFail')
})
} else {
this.$message.error('请填写信息');
}
})
},
cancel (name) {
this.modals = false;
this.$refs[name].resetFields();
this.formItem.type = '1';
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,12 @@
<script>
export default {
created() {
const { params, query } = this.$route
const { path } = params
this.$router.replace({ path: '/' + path, query })
},
render: function(h) {
return h() // avoid warning message
}
}
</script>

View File

@@ -0,0 +1,13 @@
<template>
<div>
<router-view />
</div>
</template>
<script>
export default {}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,174 @@
<template>
<div class="login-container">
<el-row type="flex">
<el-col :span="24">
<el-form ref="formInline" size="small" :model="formInline" :rules="ruleInline" class="login-form"
autocomplete="on" label-position="left">
<div class="title-container">
<h3 class="title">短信账户登录</h3>
</div>
<el-form-item prop="account">
<el-input
ref="account"
v-model="formInline.account"
placeholder="用户名"
prefix-icon="el-icon-user"
name="username"
type="text"
tabindex="1"
autocomplete="off"
/>
</el-form-item>
<el-form-item prop="token">
<el-input
:key="passwordType"
ref="token"
v-model="formInline.token"
:type="passwordType"
placeholder="密码"
name="token"
tabindex="2"
auto-complete="off"
prefix-icon="el-icon-lock"
/>
<span class="show-pwd" @click="showPwd">
<svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'"/>
</span>
</el-form-item>
<el-button size="mini" :loading="loading" type="primary" style="width:100%;margin-bottom:20px;"
@click="handleSubmit('formInline')">登录
</el-button>
<el-button size="mini" type="text" style="width: 100%;" @click="changeReg">注册账户</el-button>
</el-form>
</el-col>
</el-row>
</div>
</template>
<script>
import { configApi } from '@/api/sms'
export default {
name: 'Login',
data() {
return {
formInline: {
account: '',
token: ''
},
ruleInline: {
account: [
{ required: true, message: '请输入用户名', trigger: 'blur' }
],
token: [
{ required: true, message: '请输入密码', trigger: 'blur' }
]
},
passwordType: 'password',
loading: false
}
},
created() {
var _this = this
document.onkeydown = function(e) {
const key = window.event.keyCode
if (key === 13) {
_this.handleSubmit('formInline')
}
}
},
methods: {
showPwd() {
if (this.passwordType === 'password') {
this.passwordType = ''
} else {
this.passwordType = 'password'
}
this.$nextTick(() => {
this.$refs.token.focus()
})
},
handleSubmit(name) {
this.$refs[name].validate((valid) => {
if (valid) {
configApi(this.formInline).then(async res => {
this.$message.success('登录成功!')
this.$store.dispatch('user/isLogin')
this.$emit('on-Login')
}).catch(res => {
this.$message.error(res.message)
})
} else {
return false
}
})
},
// 休息密码
changePassword() {
this.$emit('on-change')
},
changeReg() {
this.$emit('on-changes')
}
}
}
</script>
<style lang="scss" scoped>
.title{
text-align: center;
}
.captcha{
display: flex;
align-items: flex-start;
}
$bg: #2d3a4b;
$dark_gray: #889aa4;
$light_gray: #eee;
.imgs{
img{
height: 36px;
}
}
.login-form {
flex: 1;
padding: 32px 0;
text-align: center;
width: 384px;
margin: 0 auto;
overflow: hidden;
}
.tips {
font-size: 14px;
color: #fff;
margin-bottom: 10px;
span {
&:first-of-type {
margin-right: 16px;
}
}
}
.svg-container {
padding: 6px 5px 6px 15px;
color: $dark_gray;
vertical-align: middle;
width: 30px;
display: inline-block;
}
.show-pwd {
position: absolute;
right: 10px;
top: 7px;
font-size: 16px;
color: $dark_gray;
cursor: pointer;
user-select: none;
/deep/.svg-icon {
vertical-align: 0.3em;
}
}
.thirdparty-button {
position: absolute;
right: 0;
bottom: 6px;
}
</style>

View File

@@ -0,0 +1,254 @@
<template>
<div class="login-container">
<el-form ref="formInline" size="small" :model="formInline" :rules="ruleInline" class="login-form" autocomplete="on" label-position="left">
<div class="title-container">
<h3 class="title">短信账户注册</h3>
</div>
<el-form-item prop="account">
<el-input
ref="account"
v-model="formInline.account"
placeholder="请输入短信平台账号"
prefix-icon="el-icon-user"
name="username"
type="text"
tabindex="1"
auto-complete="off"
/>
</el-form-item>
<el-form-item prop="password">
<el-input
:key="passwordType"
ref="password"
v-model="formInline.password"
:type="passwordType"
placeholder="请输入短信平台密码/token"
name="password"
tabindex="2"
auto-complete="off"
prefix-icon="el-icon-lock"
/>
<span class="show-pwd" @click="showPwd">
<svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
</span>
</el-form-item>
<el-form-item prop="domain">
<el-input
ref="password"
v-model="formInline.domain"
placeholder="请输入网址域名"
name="password"
prefix-icon="el-icon-position"
/>
</el-form-item>
<el-form-item prop="phone">
<el-input
ref="password"
v-model="formInline.phone"
placeholder="请输入您的手机号"
prefix-icon="el-icon-phone-outline"
name="password"
/>
</el-form-item>
<el-form-item prop="sign">
<el-input
ref="password"
v-model="formInline.sign"
placeholder="请输入短信签名例如CRMEB"
name="password"
prefix-icon="el-icon-price-tag"
/>
</el-form-item>
<el-form-item prop="code" class="captcha">
<div class="acea-row" style="flex-wrap: nowrap;">
<el-input
ref="username"
v-model="formInline.code"
placeholder="验证码"
name="username"
type="text"
tabindex="1"
autocomplete="off"
prefix-icon="el-icon-message"
style="width: 90%"
/>
<el-button size="mini" :disabled=!this.canClick @click="cutDown">{{cutNUm}}</el-button>
</div>
</el-form-item>
<el-button size="mini" :loading="loading" type="primary" style="width:100%;margin-bottom:20px;" @click="handleSubmit('formInline')">注册</el-button>
<el-button size="mini" type="primary" style="width:100%;margin-bottom:20px;" @click="changelogo">立即登录</el-button>
</el-form>
</div>
</template>
<script>
import { captchaApi, registerApi } from '@/api/sms'
export default {
name: 'Register',
data() {
const validatePhone = (rule, value, callback) => {
if (!value) {
return callback(new Error('请填写手机号'))
} else if (!/^1[3456789]\d{9}$/.test(value)) {
callback(new Error('手机号格式不正确!'))
} else {
callback()
}
}
return {
loading: false,
passwordType: 'password',
captchatImg: '',
cutNUm: '获取验证码',
canClick: true,
formInline: {
account: '',
code: '',
domain: '',
phone: '',
sign: '',
password: ''
},
ruleInline: {
account: [
{ required: true, message: '请输入短信平台账号', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入短信平台密码/token', trigger: 'blur' }
],
domain: [
{ required: true, message: '请输入网址域名', trigger: 'blur' }
],
phone: [
{ required: true, validator: validatePhone, trigger: 'blur' }
],
sign: [
{ required: true, message: '请输入短信签名', trigger: 'blur' }
],
code: [
{ required: true, message: '请输入验证码', trigger: 'blur' }
]
}
}
},
methods: {
showPwd() {
if (this.passwordType === 'password') {
this.passwordType = ''
} else {
this.passwordType = 'password'
}
this.$nextTick(() => {
this.$refs.password.focus()
})
},
// 短信验证码
cutDown() {
if (this.formInline.phone) {
if (!this.canClick) return
this.canClick = false
this.cutNUm = 60
captchaApi(this.formInline.phone).then(async res => {
this.$message.success(res.data.message)
})
const time = setInterval(() => {
this.cutNUm--
if (this.cutNUm === 0) {
this.cutNUm = '获取验证码'
this.canClick = true
clearInterval(time)
}
}, 1000)
} else {
this.$message.warning('请填写手机号!')
}
},
// 注册
handleSubmit(name) {
this.$refs[name].validate((valid) => {
if (valid) {
registerApi(this.formInline).then(async res => {
console.log(res)
this.$message.success('注册成功')
setTimeout(() => {
this.changelogo()
}, 1000)
})
} else {
return false
}
})
},
// 立即登录
changelogo() {
this.$emit('on-change')
}
}
}
</script>
<style lang="scss" scoped>
.el-button+.el-button{
margin-left: 0px !important;
}
.title{
text-align: center;
}
.captcha{
display: flex;
align-items: flex-start;
/deep/.el-form-item__content{
width: 100%;
}
}
$bg: #2d3a4b;
$dark_gray: #889aa4;
$light_gray: #eee;
.imgs{
img{
height: 36px;
}
}
.login-form {
flex: 1;
padding: 32px 0;
text-align: center;
width: 384px;
margin: 0 auto;
overflow: hidden;
}
.tips {
font-size: 14px;
color: #fff;
margin-bottom: 10px;
span {
&:first-of-type {
margin-right: 16px;
}
}
}
.svg-container {
padding: 6px 5px 6px 15px;
color: $dark_gray;
vertical-align: middle;
width: 30px;
display: inline-block;
}
.show-pwd {
position: absolute;
right: 10px;
top: 7px;
font-size: 16px;
color: $dark_gray;
cursor: pointer;
user-select: none;
/deep/.svg-icon {
vertical-align: 0.3em;
}
}
.thirdparty-button {
position: absolute;
right: 0;
bottom: 6px;
}
</style>

View File

@@ -0,0 +1,129 @@
<template>
<div class="divBox">
<el-card class="box-card">
<div class="filter-container mb20">
<div class="demo-input-suffix">
<span class="seachTiele">短信状态</span>
<el-radio-group v-model="tableFrom.resultCode" size="small" @change="getList">
<el-radio-button label="">全部</el-radio-button>
<el-radio-button label="100">成功</el-radio-button>
<el-radio-button label="130">失败</el-radio-button>
<el-radio-button label="131">空号</el-radio-button>
<el-radio-button label="132">停机</el-radio-button>
<el-radio-button label="133">关机</el-radio-button>
<el-radio-button label="134">无状态</el-radio-button>
<el-radio-button label="400">黑名单</el-radio-button>
</el-radio-group>
</div>
</div>
<el-table
v-loading="listLoading"
:data="tableData.data"
style="width: 100%"
size="mini"
highlight-current-row
>
<el-table-column
prop="id"
label="ID"
min-width="50"
/>
<el-table-column
prop="phone"
label="手机号"
min-width="120"
/>
<el-table-column
prop="content"
label="模板内容"
min-width="450"
/>
<el-table-column
prop="template"
label="模板ID"
min-width="100"
/>
<el-table-column
prop="memo"
label="备注"
min-width="200"
/>
<el-table-column
label="发送时间"
min-width="150"
>
<template slot-scope="scope">
<span>{{scope.row.creatTime}}</span>
</template>
</el-table-column>
<el-table-column
prop="resultcode"
label="状态码"
min-width="100"
/>
</el-table>
<div class="block">
<el-pagination
:page-sizes="[20, 40, 60, 80]"
:page-size="tableFrom.limit"
:current-page="tableFrom.page"
layout="total, sizes, prev, pager, next, jumper"
:total="tableData.total"
@size-change="handleSizeChange"
@current-change="pageChange"
/>
</div>
</el-card>
</div>
</template>
<script>
import { smsLstApi } from '@/api/sms'
import Template from "../../../appSetting/wxAccount/wxTemplate/index";
export default {
name: 'TableList',
components: {Template},
data() {
return {
listLoading: false,
tableData: {
data: [],
total: 0
},
tableFrom: {
page: 1,
limit: 20,
resultCode: ''
}
}
},
mounted() {
this.getList()
},
methods: {
// 列表
getList() {
this.listLoading = true
smsLstApi(this.tableFrom).then(res => {
this.tableData.data = res.list
this.tableData.total = res.total
this.listLoading = false
}).catch(res => {
this.listLoading = false
})
},
pageChange(page) {
this.tableFrom.page = page
this.getList()
},
handleSizeChange(val) {
this.tableFrom.limit = val
this.getList()
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,190 @@
<template>
<div class="divBox">
<el-card v-if="isShowList" v-loading="fullscreenLoading" class="box-card">
<div slot="header" class="clearfix">
<div class="content acea-row row-middle">
<div class="demo-basic--circle acea-row row-middle">
<el-avatar :size="50" :src="circleUrl" class="mr20" />
<div class="dashboard-workplace-header-tip">
<div class="dashboard-workplace-header-tip-title">{{ smsAccount }}祝您每一天开心</div>
<div class="dashboard-workplace-header-tip-desc">
<span class="mr10">修改密码</span>
<span @click="signOut">退出登录</span>
</div>
</div>
</div>
<div class="dashboard-workplace-header-extra">
<el-row type="flex" justify="center" align="middle" :gutter="12">
<el-col :span="8">
<span class="pfont acea-row row-middle">
<el-avatar icon="el-icon-user-solid" size="small" class="mr10" />
<span>剩余条数</span>
</span>
<span class="rR" v-text="numbers" />
</el-col>
<el-col :span="8">
<span class="pfont acea-row row-middle">
<el-avatar icon="el-icon-user-solid" size="small" class="mr10" />
<span>已发送</span>
</span>
<span class="rR" v-text="sendTotal" />
</el-col>
<el-col :span="8">
<span class="pfont acea-row row-middle">
<el-avatar icon="el-icon-user-solid" size="small" class="mr10" />
<span>总条数</span>
</span>
<span class="rR" v-text="amount" />
</el-col>
</el-row>
</div>
</div>
</div>
</el-card>
<table-list v-if="isShowList" />
<login-from v-if="isShowLogn" @on-changes="onChangeReg" @on-Login="onLogin" />
<register-from v-if="isShowReg" @on-change="logoup" />
</div>
</template>
<script>
import tableList from './components/tableList'
import loginFrom from './components/loginFrom'
import registerFrom from './components/register'
import { logoutApi, smsNumberApi, smsInfoApi } from '@/api/sms'
import { mapGetters } from 'vuex'
export default {
name: 'SmsConfig',
components: { tableList, loginFrom, registerFrom },
data() {
return {
fullscreenLoading: false,
smsAccount: '',
circleUrl: 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png',
spinShow: false,
isShowLogn: false,
isShow: false,
isShowReg: false,
isShowList: false,
amount: 0,
numbers: 0,
sendTotal: 0
}
},
computed: {
...mapGetters([
'isLogin'
])
},
mounted() {
this.onIsLogin()
// if (!this.isLogin) {
// this.onIsLogin()
// } else {
// this.isShowList = true
// }
},
methods: {
// 剩余条数
getNumber() {
smsInfoApi().then(async res => {
const data = res
this.numbers = data.number
this.sendTotal = data.send_total
this.amount = data.number + data.send_total
this.smsAccount = data.account
})
},
// 登录跳转
onLogin() {
const url = this.$route.query.url
if (url) {
this.$router.replace(url)
} else {
this.isShowLogn = false
this.isShow = false
this.isShowReg = false
this.isShowList = true
}
},
// 查看是否登录
onIsLogin() {
this.fullscreenLoading = true
this.$store.dispatch('user/isLogin').then(async res => {
const data = res
this.isShowLogn = !data.status
this.isShowList = data.status
if (data.status) {
this.smsAccount = data.info
}
this.getNumber()
this.fullscreenLoading = false
}).catch(res => {
this.fullscreenLoading = false
this.isShowLogn = true
})
},
// 退出登录
signOut() {
logoutApi().then(async res => {
this.isShowLogn = true
this.isShowList = false
this.$store.dispatch('user/isLogin')
}).catch(res => {
this.$message.error(res.message)
})
},
// 立即注册
onChangeReg() {
this.isShowLogn = false
this.isShow = false
this.isShowReg = true
},
// 立即登录
logoup() {
this.isShowLogn = true
this.isShow = false
this.isShowReg = false
}
}
}
</script>
<style scoped lang="scss">
$cursor: #1890ff;
.content{
justify-content: space-between;
}
.rR{
text-align: center;
font-size: 22px;
display: block;
}
.dashboard-workplace-header-tip {
display: inline-block;
vertical-align: middle;
}
.dashboard-workplace-header-tip-title {
font-size: 20px;
font-weight: 700;
margin-bottom: 12px;
}
.dashboard-workplace-header-tip-desc{
/*line-height: 0 !important;*/
display: block;
span{
font-size: 12px;
color: $cursor;
cursor: pointer;
display: inline-block;
}
}
.dashboard-workplace-header-extra{
width: auto!important;
min-width: 400px;
}
.pfont{
font-size: 12px;
color: #808695;
}
</style>

View File

@@ -0,0 +1,39 @@
<template>
<div class="divBox">
<el-card class="box-card">
<zb-parser
:form-id="111"
:is-create="isCreate"
:edit-data="editData"
@submit="handlerSubmit"
/>
</el-card>
</div>
</template>
<script>
import zbParser from '@/components/FormGenerator/components/parser/ZBParser'
import { smsSaveApi } from '@/api/sms'
export default {
name: "SmsMessage",
components: { zbParser },
data() {
return {
isCreate: 0,
editData: {}
}
},
methods: {
handlerSubmit(formValue) {
smsSaveApi(formValue).then(data => {
this.$message.success('新增成功')
this.editData = {}
})
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,256 @@
<template>
<div class="divBox">
<el-card class="box-card">
<el-row v-loading="fullscreenLoading" :gutter="16">
<el-col :span="24" class="ivu-text-left mb20">
<el-col :xs="12" :sm="6" :md="4" :lg="3" class="mr20">
<span class="ivu-text-right ivu-block">短信账户名称</span>
</el-col>
<el-col :xs="11" :sm="13" :md="19" :lg="20">
<span>{{ account }}</span>
</el-col>
</el-col>
<el-col :span="24" class="ivu-text-left mb20">
<el-col :xs="12" :sm="6" :md="4" :lg="3" class="mr20">
<span class="ivu-text-right ivu-block">当前剩余条数</span>
</el-col>
<el-col :xs="11" :sm="13" :md="19" :lg="20">
<span>{{ numbers }}</span>
</el-col>
</el-col>
<el-col :span="24" class="ivu-text-left mb20">
<el-col :xs="12" :sm="6" :md="4" :lg="3" class="mr20">
<span class="ivu-text-right ivu-block">选择套餐</span>
</el-col>
<el-col :xs="11" :sm="13" :md="19" :lg="20">
<el-row :gutter="20">
<el-col
v-for="(item, index) in list"
:key="index"
:xxl="4"
:xl="8"
:lg="8"
:md="12"
:sm="24"
:xs="24"
>
<div
class="list-goods-list-item mb15"
:class="{active:index === current}"
@click="check(item,index)"
>
<div class="list-goods-list-item-title" :class="{active:index === current}">¥ <i>{{ item.price }}</i></div>
<div class="list-goods-list-item-price" :class="{active:index === current}">
<span>短信条数: {{ item.num }}</span>
</div>
</div>
</el-col>
</el-row>
</el-col>
</el-col>
<el-col v-if="checkList" :span="24" class="ivu-text-left mb20">
<el-col :xs="12" :sm="6" :md="4" :lg="3" class="mr20">
<span class="ivu-text-right ivu-block">充值条数</span>
</el-col>
<el-col :xs="11" :sm="13" :md="19" :lg="20">
<span>{{ checkList.num }}</span>
</el-col>
</el-col>
<el-col v-if="checkList" :span="24" class="ivu-text-left mb20">
<el-col :xs="12" :sm="6" :md="4" :lg="3" class="mr20">
<span class="ivu-text-right ivu-block">支付金额</span>
</el-col>
<el-col :xs="11" :sm="13" :md="19" :lg="20">
<span class="list-goods-list-item-number">{{ checkList.price }}</span>
</el-col>
</el-col>
<el-col :span="24" class="ivu-text-left mb20">
<el-col :xs="12" :sm="6" :md="4" :lg="3" class="mr20">
<span class="ivu-text-right ivu-block">付款方式</span>
</el-col>
<el-col :xs="11" :sm="13" :md="19" :lg="20">
<span class="list-goods-list-item-pay">微信支付<i v-if="code.invalid">{{ ' 支付码过期时间' + code.invalid + ' ' }}</i></span>
</el-col>
</el-col>
<el-col :span="24">
<el-col :xs="12" :sm="6" :md="4" :lg="3" class="mr20">&nbsp;</el-col>
<el-col :xs="11" :sm="13" :md="19" :lg="20">
<div class="list-goods-list-item-code mr20"><img :src="code.code_url"></div>
</el-col>
</el-col>
</el-row>
</el-card>
</div>
</template>
<script>
import { smsNumberApi, smsPriceApi, payCodeApi, smsInfoApi } from '@/api/sms'
import { isLogin } from '@/libs/public'
import { mapGetters } from 'vuex'
export default {
name: 'SmsPay',
data() {
return {
numbers: '',
account: '',
list: [],
current: 0,
checkList: {},
fullscreenLoading: false,
code: {}
}
},
computed: {
...mapGetters([
'isLogin'
])
},
mounted() {
this.getNumber()
this.getPrice()
return
if (!this.isLogin) {
this.$router.push('/operation/systemSms/config?url=' + this.$route.path)
} else {
this.getNumber()
this.getPrice()
}
},
methods: {
// 查看是否登录
onIsLogin() {
this.fullscreenLoading = true
this.$store.dispatch('user/isLogin').then(async res => {
const data = res
if (!data.status) {
this.$message.warning('请先登录')
this.$router.push('/operation/systemSms/config?url=' + this.$route.path)
} else {
this.getNumber()
this.getPrice()
}
this.fullscreenLoading = false
}).catch(res => {
this.$router.push('/operation/systemSms/config?url=' + this.$route.path)
this.fullscreenLoading = false
})
},
// 剩余条数
getNumber() {
smsInfoApi().then(async res => {
const data = res
this.numbers = data.number
this.account = data.account
})
},
// 支付套餐
getPrice() {
this.fullscreenLoading = true
smsPriceApi({ page: 1, limit: 9999}).then(async res => {
setTimeout(() => {
this.fullscreenLoading = false
}, 800)
const data = res
this.list = data.data
this.checkList = this.list[0]
this.getCode(this.checkList)
}).catch(() => {
this.fullscreenLoading = false
})
},
// 选中
check(item, index) {
this.fullscreenLoading = true
this.current = index
setTimeout(() => {
this.getCode(item)
this.checkList = item
this.fullscreenLoading = false
}, 800)
},
// 支付码
getCode(item) {
const data = {
payType: 'weixin',
mealId: item.id,
price: item.price
}
payCodeApi(data).then(async res => {
this.code = res
})
}
}
}
</script>
<style lang="scss" scoped>
.active{
background: #0091FF;
box-shadow:0px 6px 20px 0px rgba(0, 145, 255, 0.3);
color: #fff !important;
}
.list-goods-list-item{
border: 1px solid #DADFE6;
padding: 20px 10px;
box-sizing: border-box;
border-radius:3px;
}
.list-goods-list{
&-item{
text-align: center;
position: relative;
cursor: pointer;
img{
width: 60%;
}
.ivu-tag{
position: absolute;
top: 10px;
right: 10px;
}
&-title{
font-size: 16px;
font-weight: bold;
color: #0091FF;
margin-bottom: 3px;
i{
font-size: 30px;
font-style: normal;
}
}
&-desc{
font-size: 14px;
color: #808695;
}
&-price{
font-size: 14px;
color: #000000;
s{
color: #c5c8ce;
}
}
&-number{
font-size: 14px;
color: #ED4014;
}
&-pay{
font-size: 14px;
color: #00C050;
i{
font-size: 12px;
font-style: normal;
color: #6D7278;
}
}
&-code{
width: 130px;
height: 130px;
img{
width: 100%;
height: 100%;
}
}
}
}
</style>

View File

@@ -0,0 +1,218 @@
<template>
<!--v-if="isLogin"-->
<div class="divBox" v-if="isLogin">
<el-card v-loading="fullscreenLoading" class="box-card">
<div slot="header" class="clearfix">
<div class="filter-container">
<div class="demo-input-suffix acea-row">
<span class="seachTiele">模板状态</span>
<el-select v-model="tableFrom.status" placeholder="请选择" clearable class="filter-item selWidth mr20" @change="userSearchs">
<el-option value="1">可用</el-option>
<el-option value="0">不可用</el-option>
</el-select>
<span class="seachTiele">模板名称</span>
<el-input v-model="tableFrom.title" placeholder="请输入商品名称,关键字,产品编号" class="selWidth">
<el-button slot="append" icon="el-icon-search" @change="userSearchs" />
</el-input>
</div>
</div>
<el-button size="mini" type="primary" @click="add">添加短信模板</el-button>
</div>
<el-table
v-loading="listLoading"
:data="tableData.data"
style="width: 100%"
size="mini"
highlight-current-row
>
<el-table-column
prop="id"
label="ID"
min-width="50"
/>
<el-table-column
prop="templateid"
label="模板ID"
min-width="80"
/>
<el-table-column
prop="title"
label="模板名称"
min-width="120"
/>
<el-table-column
prop="content"
label="模板内容"
min-width="500"
/>
<el-table-column
label="模板类型"
min-width="100"
>
<template slot-scope="{row}">
<span>{{ row.type | typesFilter }}</span>
</template>
</el-table-column>
<el-table-column label="模板状态">
<template slot-scope="{row}">
<span>{{ row.status | statusFilter }}</span>
</template>
</el-table-column>
<el-table-column
prop="add_time"
label="添加时间"
min-width="150"
/>
</el-table>
<div class="block">
<el-pagination
:page-sizes="[20, 40, 60, 80]"
:page-size="tableFrom.limit"
:current-page="tableFrom.page"
layout="total, sizes, prev, pager, next, jumper"
:total="tableData.total"
@size-change="handleSizeChange"
@current-change="pageChange"
/>
</div>
</el-card>
<!--编辑-->
<el-dialog
title="添加模板"
:visible.sync="dialogVisible"
width="500px"
:before-close="handleClose">
<zb-parser
v-if="dialogVisible"
:form-id="110"
:is-create="isCreate"
:edit-data="editData"
@submit="handlerSubmit"
/>
</el-dialog>
</div>
</template>
<script>
import { smsTempLstApi, tempCreateApi } from '@/api/sms'
import { roterPre } from '@/settings'
import { mapGetters } from 'vuex'
import zbParser from '@/components/FormGenerator/components/parser/ZBParser'
export default {
name: 'SmsTemplate',
components: { zbParser },
filters: {
statusFilter(status) {
const statusMap = {
0: '没有',
1: '有'
}
return statusMap[status]
},
typesFilter(status) {
const statusMap = {
1: '验证码',
2: '通知',
3: '推广'
}
return statusMap[status]
}
},
data() {
return {
isCreate: 0,
editData: {},
dialogVisible: false,
fullscreenLoading: false,
listLoading: false,
tableData: {
data: [],
total: 0
},
tableFrom: {
page: 1,
limit: 20,
status: '',
title: ''
}
}
},
computed: {
...mapGetters([
'isLogin'
])
},
mounted() {
if (!this.isLogin) {
this.$router.push('/operation/systemSms/config?url=' + this.$route.path)
} else {
this.getList()
}
},
methods: {
handleClose() {
this.dialogVisible = false
this.editData = {}
},
handlerSubmit(formValue) {
tempCreateApi(formValue).then(data => {
this.$message.success('新增成功')
this.dialogVisible = false
this.editData = {}
this.getList()
})
},
add() {
this.dialogVisible = true
},
// 查看是否登录
onIsLogin() {
this.fullscreenLoading = true
this.$store.dispatch('user/isLogin').then(async res => {
const data = res
if (!data.status) {
this.$message.warning('请先登录')
this.$router.push( '/operation/systemSms/config?url=' + this.$route.path)
} else {
this.getList()
}
this.fullscreenLoading = false
}).catch(res => {
this.$router.push( '/operation/systemSms/config?url=' + this.$route.path)
this.fullscreenLoading = false
})
},
// 列表
getList() {
this.listLoading = true
smsTempLstApi(this.tableFrom).then(res => {
this.tableData.data = res.data
this.tableData.total = res.count
this.listLoading = false
}).catch(res => {
this.listLoading = false
})
},
pageChange(page) {
this.tableFrom.page = page
this.getList()
},
handleSizeChange(val) {
this.tableFrom.limit = val
this.getList()
},
// 表格搜索
userSearchs() {
this.tableFrom.page = 1
this.getList()
}
}
}
</script>
<style scoped lang="scss">
.selWidth{
width: 350px !important;
}
</style>

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,274 @@
<template>
<div class="divBox">
<el-card class="box-card">
<div slot="header" class="clearfix">
<el-tabs v-model="tableFrom.type" @tab-click="seachList">
<el-tab-pane :label="item.name +'('+item.count +')' " :name="item.type.toString()" v-for="(item,index) in headeNum" :key="index"/>
</el-tabs>
<div class="container">
<el-form inline size="small">
<el-form-item label="商品分类:">
<el-cascader v-model="tableFrom.cateId" :options="merCateList" :props="props" clearable class="selWidth mr20" @change="seachList" size="small"/>
</el-form-item>
<el-form-item label="商品搜索:">
<el-input v-model="tableFrom.keywords" placeholder="请输入商品名称关键字商品ID" class="selWidth" size="small">
<el-button slot="append" icon="el-icon-search" @click="seachList" size="small"/>
</el-input>
</el-form-item>
</el-form>
</div>
<router-link :to=" { path:'/store/list/creatProduct' } ">
<el-button size="small" type="primary" class="mr10">添加商品</el-button>
</router-link>
<el-button size="small" type="success" class="mr10" @click="onCopy">复制淘宝天猫拼多多京东苏宁</el-button>
<el-button size="small" @click="exports">导出</el-button>
</div>
<el-table
v-loading="listLoading"
:data="tableData.data"
style="width: 100%"
size="mini"
highlight-current-row
>
<el-table-column type="expand">
<template slot-scope="props">
<el-form label-position="left" inline class="demo-table-expand">
<el-form-item label="商品分类:">
<span v-for="(item, index) in props.row.cateValues.split(',')" :key="index" class="mr10">{{ item }}</span>
</el-form-item>
<el-form-item label="市场价:">
<span>{{ props.row.otPrice }}</span>
</el-form-item>
<el-form-item label="成本价:">
<span>{{ props.row.cost }}</span>
</el-form-item>
<el-form-item label="收藏:">
<span>{{ props.row.collectCount }}</span>
</el-form-item>
<el-form-item label="虚拟销量:">
<span>{{ props.row.ficti }}</span>
</el-form-item>
</el-form>
</template>
</el-table-column>
<el-table-column
prop="id"
label="ID"
min-width="50"
/>
<el-table-column label="商品图" min-width="80">
<template slot-scope="scope">
<div class="demo-image__preview">
<el-image
style="width: 36px; height: 36px"
:src="scope.row.image"
:preview-src-list="[scope.row.image]"
/>
</div>
</template>
</el-table-column>
<el-table-column
prop="storeName"
label="商品名称"
min-width="200"
/>
<el-table-column
prop="price"
label="商品售价"
min-width="90"
/>
<el-table-column
prop="sales"
label="销量"
min-width="90"
/>
<el-table-column
prop="stock"
label="库存"
min-width="90"
/>
<el-table-column
prop="sort"
label="排序"
min-width="70"
/>
<el-table-column
label="状态"
min-width="150"
>
<template slot-scope="scope">
<el-switch
v-model="scope.row.isShow"
:active-value="true"
:inactive-value="false"
active-text="上架"
inactive-text="下架"
@change="onchangeIsShow(scope.row)"
/>
</template>
</el-table-column>
<el-table-column
label="操作时间"
min-width="120"
>
<template slot-scope="scope">
<span>{{scope.row.addTime | formatDate}}</span>
</template>
</el-table-column>
<el-table-column label="操作" min-width="120" fixed="right" align="center">
<template slot-scope="scope">
<router-link :to="{path: '/store/list/creatProduct/' + scope.row.id}">
<el-button type="text" size="small" class="mr10">编辑</el-button>
</router-link>
<el-button type="text" size="small" @click="handleDelete(scope.row.id, scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="block">
<el-pagination
:page-sizes="[20, 40, 60, 80]"
:page-size="tableFrom.limit"
:current-page="tableFrom.page"
layout="total, sizes, prev, pager, next, jumper"
:total="tableData.total"
@size-change="handleSizeChange"
@current-change="pageChange"
/>
</div>
</el-card>
<el-dialog
title="复制淘宝、天猫、拼多多、京东、苏宁"
:visible.sync="dialogVisible"
width="1200px"
:before-close="handleClose">
<tao-bao v-if="dialogVisible"></tao-bao>
</el-dialog>
</div>
</template>
<script>
import { productLstApi, productDeleteApi, categoryApi, putOnShellApi, offShellApi, productHeadersApi, productExportApi } from '@/api/store'
import { getToken } from '@/utils/auth'
import taoBao from './taoBao'
export default {
name: 'ProductList',
components: { taoBao },
data() {
return {
props: {
children: 'child',
label: 'name',
value: 'id',
emitPath: false
},
// roterPre: roterPre,
headeNum: [],
listLoading: true,
tableData: {
data: [],
total: 0
},
tableFrom: {
page: 1,
limit: 20,
cateId: '',
keywords: '',
type: '1'
},
categoryList: [],
merCateList: [],
objectUrl: process.env.VUE_APP_BASE_API,
dialogVisible: false
}
},
mounted() {
this.goodHeade()
this.getList()
this.getCategorySelect()
},
methods: {
seachList() {
this.tableFrom.page = 1
this.getList()
},
handleClose() {
this.dialogVisible = false
},
// 复制
onCopy(){
this.dialogVisible = true
},
// 导出
exports () {
window.open(this.objectUrl + 'admin/export/excel/product?type=1&Authori-zation=' + getToken())
},
// 获取商品表单头数量
goodHeade () {
productHeadersApi().then(res => {
console.log(res)
this.headeNum = res
}).catch(res => {
this.$message.error(res.message);
})
},
// 商户分类;
getCategorySelect() {
categoryApi({ status: -1, type: 1 }).then(res => {
console.log(res)
this.merCateList = res
}).catch(res => {
this.$message.error(res.message)
})
},
// 列表
getList() {
this.listLoading = true
productLstApi(this.tableFrom).then(res => {
this.tableData.data = res.list
this.tableData.total = res.total
this.listLoading = false
}).catch(res => {
this.listLoading = false
this.$message.error(res.message)
})
},
pageChange(page) {
this.tableFrom.page = page
this.getList()
},
handleSizeChange(val) {
this.tableFrom.limit = val
this.getList()
},
// 删除
handleDelete(id, idx) {
this.$modalSure().then(() => {
productDeleteApi(id).then(() => {
this.$message.success('删除成功')
this.getList()
})
})
},
onchangeIsShow(row) {
row.isShow
? putOnShellApi( row.id ).then(() => {
this.$message.success('上架成功')
this.getList()
}) : offShellApi(row.id).then(() => {
this.$message.success('下架成功')
this.getList()
})
}
}
}
</script>
<style scoped lang="scss">
.selWidth{
width: 350px !important;
}
.seachTiele{
line-height: 30px;
}
</style>

View File

@@ -0,0 +1,23 @@
<template>
<div class="components-container">
<category-list :biztype="constants.categoryType[0]" />
</div>
</template>
<script>
import categoryList from '@/components/Category/list'
import * as constants from '@/utils/constants.js'
export default {
// name: "list",
components: { categoryList },
data() {
return {
constants
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,188 @@
<template>
<div class="divBox">
<el-card class="box-card">
<div slot="header" class="clearfix">
<div class="container">
<el-form inline size="small">
<el-form-item label="规格搜索:">
<el-input v-model="tableFrom.keywords" placeholder="请输入商品规格" class="selWidth">
<el-button slot="append" icon="el-icon-search" @click="seachList" />
</el-input>
</el-form-item>
</el-form>
</div>
<div class="acea-row">
<el-button size="small" type="primary" @click="add">添加商品规格</el-button>
<el-button size="small" @click="handleDeleteAll">批量删除</el-button>
</div>
</div>
<el-table
v-loading="listLoading"
:data="tableData.data"
style="width: 100%"
size="mini"
highlight-current-row
@selection-change="handleSelectionChange"
>
<el-table-column
type="selection"
width="55"
/>
<el-table-column
prop="id"
label="ID"
min-width="60"
/>
<el-table-column
prop="ruleName"
label="规格名称"
min-width="150"
/>
<el-table-column
label="商品规格"
min-width="150"
>
<template slot-scope="scope">
<span v-for="(item, index) in scope.row.ruleValue" :key="index" class="mr10" v-text="item.value" />
</template>
</el-table-column>
<el-table-column
label="商品属性"
min-width="300"
>
<template slot-scope="scope">
<div v-for="(item, index) in scope.row.ruleValue" :key="index" v-text="item.detail.join(',')" />
</template>
</el-table-column>
<el-table-column label="操作" min-width="120" align="center">
<template slot-scope="scope">
<el-button type="text" size="small" @click="onEdit(scope.row)" class="mr10">编辑</el-button>
<el-button type="text" size="small" @click="handleDelete(scope.row.id, scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="block">
<el-pagination
:page-sizes="[20, 40, 60, 80]"
:page-size="tableFrom.limit"
:current-page="tableFrom.page"
layout="total, sizes, prev, pager, next, jumper"
:total="tableData.total"
@size-change="handleSizeChange"
@current-change="pageChange"
/>
</div>
</el-card>
</div>
</template>
<script>
import { templateListApi, attrDeleteApi } from '@/api/store'
export default {
name: 'StoreAttr',
data() {
return {
formDynamic: {
ruleName: '',
ruleValue: []
},
tableFrom: {
page: 1,
limit: 20,
keywords: ''
},
tableData: {
data: [],
loading: false,
total: 0
},
listLoading: true,
selectionList: []
}
},
mounted() {
this.getList()
},
methods: {
seachList() {
this.tableFrom.page = 1
this.getList()
},
handleSelectionChange(val) {
this.selectionList = val
const data = []
this.selectionList.map((item) => {
data.push(item.id)
})
this.ids = data.join(',')
},
add() {
const _this = this
this.$modalAttr(Object.assign({}, this.formDynamic), function() {
_this.getList()
})
},
// 列表
getList() {
this.listLoading = true
templateListApi(this.tableFrom).then(res => {
const list = res.list
this.tableData.data = list
this.tableData.total = res.total
for (var i = 0; i < list.length; i++) {
list[i].ruleValue = JSON.parse(list[i].ruleValue)
}
this.listLoading = false
}).catch(() => {
this.listLoading = false
})
},
pageChange(page) {
this.tableFrom.page = page
this.getList()
},
handleSizeChange(val) {
this.tableFrom.limit = val
this.getList()
},
// 删除
handleDelete(id, idx) {
this.$modalSure().then(() => {
attrDeleteApi( id ).then(() => {
this.$message.success('删除成功')
this.tableData.data.splice(idx, 1)
})
}).catch(() => {
})
},
handleDeleteAll(){
if(!this.selectionList.length) return this.$message.warning('请选择商品规格')
this.$modalSure().then(() => {
attrDeleteApi( this.ids ).then(() => {
this.$message.success('删除成功')
this.getList()
})
}).catch(() => {
})
},
onEdit(val) {
const _this = this
this.$modalAttr(JSON.parse(JSON.stringify(val)), function() {
_this.getList()
})
}
}
}
</script>
<style scoped lang="scss">
.selWidth{
width: 350px !important;
}
.seachTiele{
line-height: 35px;
}
.fr{
float: right;
}
</style>

View File

@@ -0,0 +1,240 @@
<template>
<el-form :model="formValidate" :rules="rules" ref="formValidate" label-width="100px" class="demo-formValidate" v-loading="loading">
<el-form-item label="商品:" prop="productId">
<div class="upLoadPicBox" @click="changeGood">
<div v-if="formValidate.productId" class="pictrue"><img :src="image"></div>
<div v-else class="upLoad">
<i class="el-icon-camera cameraIconfont"/>
</div>
</div>
</el-form-item>
<el-form-item label="用户名称:" prop="nickname">
<el-input type="text" v-model="formValidate.nickname "></el-input>
</el-form-item>
<el-form-item label="评价文字:" prop="comment">
<el-input type="textarea" v-model="formValidate.comment "></el-input>
</el-form-item>
<el-form-item label="商品分数:" prop="productScore" class="productScore">
<el-rate v-model="formValidate.productScore"></el-rate>
<!--<el-input-number type="textarea" v-model="formValidate.productScore "></el-input-number>-->
</el-form-item>
<el-form-item label="服务分数:" prop="serviceScore" class="productScore">
<el-rate v-model="formValidate.serviceScore"></el-rate>
<!--<el-input-number type="textarea" v-model="formValidate.serviceScore "></el-input-number>-->
</el-form-item>
<el-form-item label="用户头像:" prop="avatar">
<div class="upLoadPicBox" @click="modalPicTap('1')">
<div v-if="formValidate.avatar" class="pictrue"><img :src="formValidate.avatar"></div>
<div v-else class="upLoad">
<i class="el-icon-camera cameraIconfont"/>
</div>
</div>
</el-form-item>
<el-form-item label="评价图片:">
<div class="acea-row">
<div
v-for="(item,index) in pics"
:key="index"
class="pictrue"
draggable="false"
@dragstart="handleDragStart($event, item)"
@dragover.prevent="handleDragOver($event, item)"
@dragenter="handleDragEnter($event, item)"
@dragend="handleDragEnd($event, item)"
>
<img :src="item">
<i class="el-icon-error btndel" @click="handleRemove(index)" />
<!--<Button shape="circle" icon="md-close" class="btndel" @click.native="handleRemove(index)" />-->
</div>
<div class="upLoadPicBox" @click="modalPicTap('2')">
<div class="upLoad">
<i class="el-icon-camera cameraIconfont" />
</div>
</div>
</div>
</el-form-item>
<el-form-item>
<el-button size="mini" type="primary" @click="submitForm('formValidate')">立即创建</el-button>
<el-button size="mini" @click="resetForm('formValidate')">取消</el-button>
</el-form-item>
</el-form>
</template>
<script>
import { replyCreatApi, replyEditApi, replyInfoApi } from '@/api/store'
const defaultObj= {
avatar: '',
comment: '',
nickname: '',
pics: '',
productId: '',
productScore: null,
serviceScore: null
}
export default {
name: "creatComment",
props:{
num: {
type: Number,
required: 0
},
},
data() {
var checkProductScore = (rule, value, callback) => {
if (!value) {
return callback(new Error('商品分数不能为空'));
}else{
callback();
}
};
var checkServiceScore = (rule, value, callback) => {
if (!value) {
return callback(new Error('服务分数不能为空'));
}else{
callback();
}
};
return {
loading: false,
pics: [],
image: '',
formValidate: Object.assign({}, defaultObj),
rules: {
avatar: [
{required: true, message: '请选择用户头像', trigger: 'change'},
],
productId: [
{required: true, message: '请选择商品', trigger: 'change'},
],
comment: [
{required: true, message: '请填写评价内容', trigger: 'blur'},
],
nickname: [
{required: true, message: '请填写用户名称', trigger: 'blur'},
],
pics: [
{required: true, message: '请选择评价图片', trigger: 'change'},
],
productScore: [
{required: true, validator: checkProductScore, trigger: 'blur'},
],
serviceScore: [
{required: true, validator: checkServiceScore, trigger: 'change'},
],
}
}
},
watch: {
num: {
handler: function(val) {
this.resetForm('formValidate')
},
deep: true
}
},
methods: {
changeGood(){
const _this = this
this.$modalGoodList(function(row) {
_this.image = row.image
_this.formValidate.productId = row.id
})
},
// 点击商品图
modalPicTap (tit) {
const _this = this
_this.$modalUpload(function(img) {
console.log(img)
tit==='1' ? _this.formValidate.avatar = img[0].sattDir : img.map((item) => {
_this.pics.push( item.sattDir)
})
},tit, 'store')
},
handleRemove (i) {
this.pics.splice(i, 1)
},
submitForm(formName) {
this.formValidate.pics = JSON.stringify(this.pics)
this.$refs[formName].validate((valid) => {
if (valid) {
replyCreatApi(this.formValidate).then(() => {
this.$message.success("新增成功")
this.$msgbox.close()
setTimeout(() => {
// this.clear();
this.$emit('getList');
}, 600);
})
} else {
console.log('error submit!!');
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields()
this.$msgbox.close()
this.pics=[]
this.formValidate.pics=''
},
info(){
this.loading = true
replyInfoApi(this.formValidate).then(() => {
this.formValidate = res
this.loading = false
}).catch(() => {
this.loading = false
})
},
// 移动
handleDragStart (e, item) {
this.dragging = item;
},
handleDragEnd (e, item) {
this.dragging = null
},
handleDragOver (e) {
e.dataTransfer.dropEffect = 'move'
},
handleDragEnter (e, item) {
e.dataTransfer.effectAllowed = 'move'
if (item === this.dragging) {
return
}
const newItems = [...this.pics]
const src = newItems.indexOf(this.dragging)
const dst = newItems.indexOf(item)
newItems.splice(dst, 0, ...newItems.splice(src, 1))
this.pics = newItems;
}
}
}
</script>
<style scoped lang="scss">
.productScore{
/deep/.el-rate{
line-height: 2.4;
}
}
.pictrue{
width: 60px;
height: 60px;
border: 1px dotted rgba(0,0,0,0.1);
margin-right: 10px;
position: relative;
cursor: pointer;
img{
width: 100%;
height: 100%;
}
}
.btndel{
position: absolute;
z-index: 1;
width :20px !important;
height: 20px !important;
left: 46px;
top: -4px;
}
</style>

View File

@@ -0,0 +1,318 @@
<template>
<div class="divBox">
<el-card class="box-card">
<div slot="header" class="clearfix">
<div class="container">
<el-form :inline="true">
<el-form-item label="时间选择:" class="width100">
<el-radio-group v-model="tableFrom.dateLimit" type="button" @change="selectChange(tableFrom.dateLimit)" class="mr20" size="small">
<el-radio-button :label=item.val v-for="(item,i) in fromList.fromTxt" :key="i">{{item.text}}</el-radio-button>
</el-radio-group>
<el-date-picker @change="onchangeTime" v-model="timeVal" value-format="yyyy-MM-dd" format="yyyy-MM-dd" size="small" type="daterange" placement="bottom-end" placeholder="自定义时间" style="width: 220px;"></el-date-picker>
</el-form-item>
<el-form-item label="评价状态:" class="mr10">
<el-select v-model="tableFrom.isReply" placeholder="请选择评价状态" @change="seachList" size="small" class="selWidth" clearable>
<el-option label="已回复" value="1"></el-option>
<el-option label="未回复" value="0"></el-option>
</el-select>
</el-form-item>
<el-form-item label="商品搜索:" class="mr10">
<el-input v-model="tableFrom.productId" placeholder="请输入商品名称,关键字,产品编号" class="selWidth" size="small">
<el-button slot="append" icon="el-icon-search" @click="seachList" size="small"/>
</el-input>
</el-form-item>
<el-form-item label="用户名称:">
<el-input v-model="tableFrom.nickname" placeholder="请输入用户名称" class="selWidth" size="small">
<el-button slot="append" icon="el-icon-search" @click="seachList" size="small"/>
</el-input>
</el-form-item>
</el-form>
</div>
<el-button size="small" type="primary" @click="add">添加虚拟评论</el-button>
</div>
<el-table
v-loading="listLoading"
:data="tableData.data"
style="width: 100%"
size="mini"
class="table"
>
<el-table-column
prop="id"
label="ID"
width="50"
/>
<el-table-column label="商品信息" min-width="300">
<template slot-scope="scope">
<div class="demo-image__preview acea-row row-middle" v-if="scope.row.storeProduct">
<el-image
style="width:30px;height: 30px;"
:src="scope.row.storeProduct.image"
:preview-src-list="[scope.row.storeProduct.image]"
class="mr10"
/>
<div class="info">{{scope.row.storeProduct.storeName}}</div>
</div>
</template>
</el-table-column>
<el-table-column
prop="nickname"
label="用户名称"
min-width="200"
/>
<el-table-column
prop="serviceScore"
label="评分"
min-width="90"
/>
<el-table-column
label="评价内容"
min-width="210"
>
<template slot-scope="scope">
<div class="mb5 content_font">{{scope.row.comment}}</div>
<div class="demo-image__preview">
<el-image
:src="item"
class='mr5'
:preview-src-list="[item]"
v-for="(item,index) in scope.row.pics" :key="index"
/>
</div>
</template>
</el-table-column>
<el-table-column
prop="merchantReplyContent"
label="回复内容"
min-width="250"
/>
<el-table-column
label="评价时间"
min-width="120"
>
<template slot-scope="scope">
<span> {{scope.row.createTime}}</span>
</template>
</el-table-column>
<el-table-column label="操作" min-width="120" fixed="right" align="center">
<template slot-scope="scope">
<el-button type="text" size="small" @click="reply(scope.row.id)" class="mr10">回复</el-button>
<el-button type="text" size="small" @click="handleDelete(scope.row.id, scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="block">
<el-pagination
:page-sizes="[20, 40, 60, 80]"
:page-size="tableFrom.limit"
:current-page="tableFrom.page"
layout="total, sizes, prev, pager, next, jumper"
:total="tableData.total"
@size-change="handleSizeChange"
@current-change="pageChange"
/>
</div>
</el-card>
</div>
</template>
<script>
import creatComment from './creatComment.vue'
import { categoryApi, replyListApi, replyDeleteApi, replyCommentApi } from '@/api/store'
import { formatDates } from '@/utils/index';
export default {
name: 'StoreComment',
filters: {
formatDate (time) {
if (time !== 0) {
const date = new Date(time * 1000);
return formatDates(date, 'yyyy-MM-dd hh:mm');
}
}
},
components: { creatComment },
data() {
return {
merCateList: [],
props: {
children: 'child',
label: 'name',
value: 'id',
emitPath: false
},
fromList: {
title: '选择时间',
custom: true,
fromTxt: [
{ text: '全部', val: '' },
{ text: '今天', val: 'today' },
{ text: '昨天', val: 'yesterday' },
{ text: '最近7天', val: 'lately7' },
{ text: '最近30天', val: 'lately30' },
{ text: '本月', val: 'month' },
{ text: '本年', val: 'year' }
]
},
tableData: {
data: [],
total: 0
},
listLoading: true,
tableFrom: {
page: 1,
limit: 20,
isReply: '',
dateLimit: '',
nickname: '',
productId:'',
isDel: false
},
timeVal: []
}
},
mounted() {
// this.getLstFilterApi()
this.getList()
this.getCategorySelect()
},
methods:{
seachList() {
this.tableFrom.page = 1
this.getList()
},
// 回复
reply(id) {
this.$prompt('回复内容', {
confirmButtonText: '确定',
cancelButtonText: '取消',
inputErrorMessage: '请输入回复内容',
inputType: 'textarea',
inputPlaceholder: '请输入回复内容',
inputValidator: (value) => {
if (!value) {
return '输入不能为空';
}
}
}).then(({value}) => {
replyCommentApi({
ids: id,
merchantReplyContent: value
}).then(res => {
this.$message({
type: 'success',
message: '回复成功'
});
this.getList();
})
}).catch(() => {
this.$message({
type: 'info',
message: '取消输入'
})
})
},
// 选择时间
selectChange (tab) {
this.timeVal = [];
this.tableFrom.page = 1
this.getList();
},
// 商户分类;
getCategorySelect() {
categoryApi({ status: -1, type: 1 }).then(res => {
this.merCateList = res
}).catch(res => {
this.$message.error(res.message)
})
},
add() {
const timer = new Date().getTime()
const _this = this
this.modalFrom(timer,null,function() {
_this.getList()
})
},
modalFrom(timer, callback){
const h = this.$createElement
this.$msgbox({
title: '虚拟评论',
customClass: 'creatformModel',
message: h('div', { class: 'common-form-upload' }, [
h('creatComment', {
props: {
num: timer
},
on: {
getList() {
callback()
}
}
})
]),
showCancelButton: false,
showConfirmButton: false
}).then(() => {
}).catch(() => {
this.$message({
type: 'info',
message: '已取消'
})
})
},
// 具体日期
onchangeTime (e) {
this.timeVal = e;
this.tableFrom.dateLimit = e ? this.timeVal.join(',') : ''
this.tableFrom.page = 1
this.getList();
},
// 删除
handleDelete(id, idx) {
this.$modalSure().then(() => {
replyDeleteApi(id).then(() => {
this.$message.success('删除成功')
this.tableData.data.splice(idx, 1)
})
})
},
// 列表
getList() {
this.listLoading = true
replyListApi(this.tableFrom).then(res => {
this.tableData.data = res.list
this.tableData.total = res.total
this.listLoading = false
}).catch(() => {
this.listLoading = false
})
},
pageChange(page) {
this.tableFrom.page = page
this.getList()
},
handleSizeChange(val) {
this.tableFrom.limit = val
this.getList()
},
}
}
</script>
<style scoped lang="scss">
.selWidth{
width: 350px !important;
}
.table{
.el-image{
width: auto !important;
height: 30px !important;
}
/deep/.el-image__inner, .el-image__placeholder, .el-image__error {
width: auto !important;
}
}
.info{
width:63%;
}
</style>

View File

@@ -0,0 +1,593 @@
<template>
<div class="Box">
<el-card>
<div>生成的商品默认是没有上架的请手动上架商品</div>
</el-card>
<el-form class="formValidate mt20" ref="formValidate" :model="formValidate" :rules="ruleInline" label-width="120px"
@submit.native.prevent v-loading="loading">
<el-form-item>
<el-radio-group v-model="form">
<el-radio :label="1">淘宝</el-radio>
<el-radio :label="2">京东</el-radio>
<el-radio :label="3">苏宁</el-radio>
<el-radio :label="4">拼多多</el-radio>
<el-radio :label="5">天猫</el-radio>
</el-radio-group>
</el-form-item>
<el-row :gutter="24">
<el-col :span="24">
<el-form-item label="链接地址:">
<el-input v-model="url" placeholder="请输入链接地址" class="selWidth" size="small">
<el-button slot="append" icon="el-icon-search" @click="add" size="small"/>
</el-input>
</el-form-item>
</el-col>
<el-col v-if="formValidate">
<el-col :span="24">
<el-form-item label="商品名称:" prop="storeName">
<el-input v-model="formValidate.storeName" placeholder="请输入商品名称"></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="商品简介:">
<el-input v-model="formValidate.storeInfo" type="textarea" :rows="3" placeholder="请输入商品简介"></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="商品分类:" prop="cateIds">
<el-cascader v-model="formValidate.cateIds" :options="merCateList" :props="props2" clearable
class="selWidth" :show-all-levels="false"/>
</el-form-item>
</el-col>
<el-col v-bind="grid">
<el-form-item label="商品关键字:" prop="keyword">
<el-input v-model="formValidate.keyword" placeholder="请输入商品关键字"></el-input>
</el-form-item>
</el-col>
<el-col v-bind="grid">
<el-form-item label="单位:" prop="unitName">
<el-input v-model="formValidate.unitName" placeholder="请输入单位"></el-input>
</el-form-item>
</el-col>
<el-col v-bind="grid">
<el-form-item label="积分:">
<el-input-number v-model="formValidate.giveIntegral" placeholder="请输入排序" />
</el-form-item>
</el-col>
<el-col v-bind="grid">
<el-form-item label="虚拟销量:">
<el-input-number v-model="formValidate.ficti" placeholder="请输入排序" />
</el-form-item>
</el-col>
<el-col v-bind="grid">
<el-form-item label="运费模板:" prop="tempId">
<el-select v-model="formValidate.tempId" placeholder="请选择" class="selWidthd mr20">
<el-option
v-for="item in shippingList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="商品封面图:" prop="image">
<div class="upLoadPicBox" @click="modalPicTap('1')">
<div v-if="formValidate.image" class="pictrue"><img :src="formValidate.image"></div>
<div v-else class="upLoad">
<i class="el-icon-camera cameraIconfont"/>
</div>
</div>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="商品轮播图:">
<div class="acea-row">
<div
v-for="(item,index) in formValidate.sliderImages"
:key="index"
class="lunBox mr5"
draggable="false"
@dragstart="handleDragStart($event, item)"
@dragover.prevent="handleDragOver($event, item)"
@dragenter="handleDragEnter($event, item)"
@dragend="handleDragEnd($event, item)"
>
<div class="pictrue"><img :src="item"></div>
<el-button-group>
<el-button size="mini" @click.native="checked(item,index)">主图</el-button>
<el-button size="mini" @click.native="handleRemove(index)">移除</el-button>
</el-button-group>
</div>
</div>
</el-form-item>
</el-col>
<el-col v-if="formValidate.specType" :span="24" class="noForm">
<el-form-item label="批量设置:" class="labeltop">
<el-table :data="oneFormBatch" border class="tabNumWidth" size="mini">
<el-table-column align="center" label="图片" min-width="80">
<template slot-scope="scope">
<div class="upLoadPicBox" @click="modalPicTap('1','pi')">
<div v-if="scope.row.image" class="pictrue pictrueTab"><img :src="scope.row.image"></div>
<div v-else class="upLoad pictrueTab">
<i class="el-icon-camera cameraIconfont"/>
</div>
</div>
</template>
</el-table-column>
<el-table-column v-for="(item,iii) in attrValue" :key="iii" :label="formThead[iii].title"
align="center" min-width="120">
<template slot-scope="scope">
<el-input v-model="scope.row[iii]" :type="formThead[iii].title==='商品编号'?'text':'number'" :min="0"
class="priceBox"/>
</template>
</el-table-column>
<el-table-column align="center" label="操作" min-width="80">
<template>
<el-button type="text" class="submission" @click="batchAdd">批量添加</el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-col>
<el-col :span="24" v-if="formValidate.specType">
<el-form-item label="商品规格:" props="spec_type" label-for="spec_type">
<el-table :data="ManyAttrValue" border class="tabNumWidth" size="mini">
<template v-if="manyTabDate">
<el-table-column v-for="(item,iii) in manyTabDate" :key="iii" align="center"
:label="manyTabTit[iii].title" min-width="80">
<template slot-scope="scope">
<span class="priceBox" v-text="scope.row[iii]"/>
</template>
</el-table-column>
</template>
<el-table-column align="center" label="图片" min-width="80">
<template slot-scope="scope">
<div class="upLoadPicBox" @click="modalPicTap('1','duo',scope.$index)">
<div v-if="scope.row.image" class="pictrue pictrueTab"><img :src="scope.row.image"></div>
<div v-else class="upLoad pictrueTab">
<i class="el-icon-camera cameraIconfont"/>
</div>
</div>
</template>
</el-table-column>
<el-table-column v-for="(item,iii) in attrValue" :key="iii" :label="formThead[iii].title"
align="center" min-width="120">
<template slot-scope="scope">
<el-input v-model="scope.row[iii]" :type="formThead[iii].title==='商品编号'?'text':'number'"
class="priceBox"/>
</template>
</el-table-column>
<el-table-column align="center" label="操作" min-width="80">
<template slot-scope="scope">
<el-button type="text" class="submission" @click="delAttrTable(scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="商品详情:">
<ueditor-from v-model="formValidate.content" :content="formValidate.content"/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item>
<el-button type="primary" :loading="modal_loading" class="submission"
@click="handleSubmit('formValidate')">提交
</el-button>
</el-form-item>
</el-col>
</el-col>
</el-row>
</el-form>
</div>
</template>
<script>
import {crawlFromApi, treeListApi, crawlSaveApi, categoryApi, importProductApi, productCreateApi} from '@/api/store';
import { shippingTemplatesList } from '@/api/logistics'
const defaultObj = [{
image: '',
price: null,
cost: null,
ot_price: null,
stock: null,
barCode: '',
weight: null,
volume: null
}]
const objTitle = {
price: {
title: '售价'
},
cost: {
title: '成本价'
},
ot_price: {
title: '原价'
},
stock: {
title: '库存'
},
barCode: {
title: '商品编号'
},
weight: {
title: '重量KG'
},
volume: {
title: '体积(m³)'
}
}
export default {
name: 'taoBao',
data() {
return {
loading: false,
formThead: Object.assign({}, objTitle),
manyTabTit: {},
manyTabDate: {},
formValidate: null,
form: 1,
props2: {
children: 'child',
label: 'name',
value: 'id',
multiple: true,
emitPath: false
},
modal_loading: false,
ManyAttrValue: [Object.assign({}, defaultObj[0])], // 多规格
imgList: [],
tempData: {
page: 1,
limit: 9999
},
shippingList:[],
merCateList:[],
images: '',
url: '',
modalPic: false,
isChoice: '',
ruleInline: {
storeName: [
{ required: true, message: '请输入商品名称', trigger: 'blur' }
],
cateIds: [
{ required: true, message: '请选择商品分类', trigger: 'change', type: 'array', min: '1' }
],
unitName: [
{ required: true, message: '请输入单位', trigger: 'blur' }
],
tempId: [
{required: true, message: '请选择运费模板', trigger: 'change', type: 'number'}
],
keyword: [
{ required: true, message: '请输入商品关键字', trigger: 'blur' }
]
},
grid: {
xl: 8,
lg: 8,
md: 12,
sm: 24,
xs: 24
}
}
},
created() {
this.goodsCategory();
},
computed: {
attrValue() {
const obj = Object.assign({}, defaultObj[0])
delete obj.image
return obj
},
oneFormBatch() {
const obj = [Object.assign({}, defaultObj[0])]
delete obj[0].barCode
return obj
}
},
watch: {
'formValidate.attr': {
handler: function(val) {
this.watCh(val)
},
immediate: false,
deep: true
}
},
mounted() {
this.productGetTemplate();
},
methods: {
// 批量添加
batchAdd() {
// if (!this.oneFormBatch[0].pic || !this.oneFormBatch[0].price || !this.oneFormBatch[0].cost || !this.oneFormBatch[0].ot_price ||
// !this.oneFormBatch[0].stock || !this.oneFormBatch[0].bar_code) return this.$Message.warning('请填写完整的批量设置内容!');
for (const val of this.ManyAttrValue) {
this.$set(val, 'image', this.oneFormBatch[0].image)
this.$set(val, 'price', this.oneFormBatch[0].price)
this.$set(val, 'cost', this.oneFormBatch[0].cost)
this.$set(val, 'ot_price', this.oneFormBatch[0].ot_price)
this.$set(val, 'stock', this.oneFormBatch[0].stock)
this.$set(val, 'barCode', this.oneFormBatch[0].barCode)
this.$set(val, 'weight', this.oneFormBatch[0].weight)
this.$set(val, 'volume', this.oneFormBatch[0].volume)
}
},
watCh(val) {
const tmp = {}
const tmpTab = {}
this.formValidate.attr.forEach((o, i) => {
tmp['value' + i] = { title: o.attrName }
tmpTab['value' + i] = ''
})
this.ManyAttrValue = this.attrFormat(val)
this.manyTabTit = tmp
this.manyTabDate = tmpTab
this.formThead = Object.assign({}, this.formThead, tmp)
},
attrFormat(arr) {
let data = []
const res = []
return format(arr)
function format(arr) {
if (arr.length > 1) {
arr.forEach((v, i) => {
if (i === 0) data = arr[i]['attrValue']
const tmp = []
data.forEach(function(vv) {
arr[i + 1] && arr[i + 1]['attrValue'] && arr[i + 1]['attrValue'].forEach(g => {
const rep2 = (i !== 0 ? '' : arr[i]['attrName'] + '_') + vv + '$&' + arr[i + 1]['attrName'] + '_' + g
tmp.push(rep2)
if (i === (arr.length - 2)) {
const rep4 = {
image: '',
price: 0,
cost: 0,
ot_price: 0,
stock: 0,
barCode: '',
weight: 0,
volume: 0,
brokerage: 0,
brokerage_two: 0
}
rep2.split('$&').forEach((h, k) => {
const rep3 = h.split('_')
if (!rep4['attrValue']) rep4['attrValue'] = {}
rep4['attrValue'][rep3[0]] = rep3.length > 1 ? rep3[1] : ''
})
Object.values(rep4.attrValue).forEach((v, i) => {
rep4['value' + i] = v
})
res.push(rep4)
}
})
})
data = tmp.length ? tmp : []
})
} else {
const dataArr = []
arr.forEach((v, k) => {
v['attrValue'].forEach((vv, kk) => {
dataArr[kk] = v['attrName'] + '_' + vv
res[kk] = {
image: '',
price: 0,
cost: 0,
ot_price: 0,
stock: 0,
barCode: '',
weight: 0,
volume: 0,
brokerage: 0,
brokerage_two: 0,
attrValue: { [v['attrName']]: vv }
}
Object.values(res[kk].attrValue).forEach((v, i) => {
res[kk]['value' + i] = v
})
})
})
data.push(dataArr.join('$&'))
}
return res
}
},
// 获取运费模板;
productGetTemplate() {
shippingTemplatesList(this.tempData).then(res => {
this.shippingList = res.list
})
},
// 删除图片
handleRemove(i) {
this.formValidate.sliderImages.splice(i, 1);
},
// 选择主图
checked(item, index) {
this.formValidate.image = item;
},
// 商品分类;
goodsCategory() {
categoryApi({ status: -1, type: 1 }).then(res => {
this.merCateList = res
})
},
// 生成表单
add() {
if (this.url) {
// var reg = /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/;
// if (!reg.test(this.soure_link)) {
// return this.$message.warning('请输入以http开头的地址');
// }
this.loading = true;
importProductApi({ url: this.url, form: this.form}).then(res => {
let info = res
this.formValidate = {
image: info.image,
sliderImages: JSON.parse(info.sliderImage),
sliderImage: info.sliderImage,
storeName: info.storeName,
storeInfo: info.storeInfo,
keyword: info.keyword,
cateIds: info.cateId ? info.cateId.split(',') : [], // 商品分类id
cateId: info.cateId,// 商品分类id传值
unitName: info.unitName,
sort: 0,
isShow: 0,
isBenefit: 0,
isNew: 0,
isGood: 0,
isHot: 0,
isBest: 0,
tempId: info.tempId,
attrValue: info.attrValue,
attr: info.attr,
selectRule: info.selectRule,
isSub: false,
content: info.content,
specType: info.specType,
id: info.id,
giveIntegral: info.giveIntegral,
ficti: info.ficti
}
for (var i = 0; i < this.formValidate.attr.length; i++) {
this.formValidate.attr[i].attrValue = JSON.parse(info.attr[i].attrValues)
}
this.loading = false;
}).catch(() => {
this.loading = false;
})
} else {
this.$message.warning('请输入链接地址!');
}
},
// 提交
handleSubmit (name) {
this.formValidate.attr.length ? this.formValidate.attrValue=JSON.stringify(this.ManyAttrValue):this.formValidate.attrValue=[]
this.formValidate.cateId = this.formValidate.cateIds.join(',')
this.formValidate.sliderImage = JSON.stringify(this.formValidate.sliderImages)
if(!this.formValidate.specType){
this.formValidate.attr = []
this.formValidate.attrValue = ''
}
for (var i = 0; i < this.formValidate.attr.length; i++) {
this.formValidate.attr[i].attrValues = JSON.stringify(this.formValidate.attr[i].attrValue)
}
this.$refs[name].validate((valid) => {
if (valid) {
this.modal_loading = true
productCreateApi(this.formValidate).then(async res => {
this.$message.success('新增成功');
this.$parent.dialogVisible = false
this.modal_loading = false
}).catch(() => {
this.modal_loading = false
})
} else {
if(!this.formValidate.storeName || !this.formValidate.cateId || !this.formValidate.keyword
|| !this.formValidate.unitName || !this.formValidate.image){
this.$message.warning("请填写完整商品信息!");
}
}
})
},
// 点击商品图
modalPicTap (tit, num, i) {
const _this = this
this.$modalUpload(function(img) {
if(tit==='1'&& !num){
_this.formValidate.image = img[0].sattDir
_this.OneattrValue[0].image = img[0].sattDir
}
if(tit==='2'&& !num){
img.map((item) => {
_this.formValidate.sliderImages.push(item.sattDir)
});
}
if(tit==='1'&& num === 'dan' ){
_this.OneattrValue[0].image = img[0].sattDir
}
if(tit==='1'&& num === 'duo' ){
_this.ManyAttrValue[i].image = img[0].sattDir
}
if(tit==='1'&& num === 'pi' ){
_this.oneFormBatch[0].image = img[0].sattDir
}
},tit, 'store')
},
handleDragStart(e, item) {
this.dragging = item;
},
handleDragEnd(e, item) {
this.dragging = null
},
// 首先把div变成可以放置的元素即重写dragenter/dragover
handleDragOver(e) {
// e.dataTransfer.dropEffect="move";//在dragenter中针对放置目标来设置!
e.dataTransfer.dropEffect = 'move'
},
handleDragEnter(e, item) {
// 为需要移动的元素设置dragstart事件
e.dataTransfer.effectAllowed = 'move'
if (item === this.dragging) {
return
}
const newItems = [...this.formValidate.slider_image]
const src = newItems.indexOf(this.dragging)
const dst = newItems.indexOf(item)
newItems.splice(dst, 0, ...newItems.splice(src, 1))
this.formValidate.slider_image = newItems
}
}
}
</script>
<style scoped lang="scss">
.selWidth{
width: 100%;
}
.lunBox{
display: flex;
flex-direction: column;
border: 1px solid #0bb20c;
}
.pictrueBox{
display: inline-block;
}
.pictrue{
width:111px;
height:111px;
border:1px dotted rgba(0,0,0,0.1);
display: inline-block;
position: relative;
cursor: pointer;
img{
width: 100%;
height: 100%;
}
}
.pictrueTab{
width:40px !important;
height:40px !important;
}
.upLoad {
width: 86px;
height: 86px;
border: 1px dotted rgba(0, 0, 0, 0.1);
border-radius: 4px;
background: rgba(0, 0, 0, 0.02);
cursor: pointer;
}
.ft{
color: red;
}
</style>

View File

@@ -0,0 +1,180 @@
<template>
<div>
<el-form ref="pram" :model="pram" :rules="rules" label-width="100px">
<el-form-item label="管理员账号" prop="account">
<el-input v-model="pram.account" placeholder="管理员账号" />
</el-form-item>
<el-form-item label="管理员密码" prop="pwd">
<el-input
v-model="pram.pwd"
placeholder="管理员密码,不更改可以不填写"
clearable
@input="handlerPwdInput"
@clear="handlerPwdInput"
/>
</el-form-item>
<el-form-item v-if="pram.pwd" label="确认密码" prop="repwd">
<el-input v-model="pram.repwd" placeholder="确认密码" clearable />
</el-form-item>
<el-form-item label="管理员姓名" prop="realName">
<el-input v-model="pram.realName" placeholder="管理员姓名" />
</el-form-item>
<el-form-item label="管理员身份" prop="roles">
<el-select v-model="pram.roles" placeholder="身份" clearable multiple>
<el-option
v-for="item,index in roleList.list"
:key="index"
:label="item.roleName"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="状态">
<el-switch v-model="pram.status" :active-value="true" :inactive-value="false" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handlerSubmit('pram')">{{ isCreate===0?'確定':'更新' }}</el-button>
<el-button @click="close">取消</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import * as constants from '@/utils/constants.js'
import * as roleApi from '@/api/role.js'
import * as systemAdminApi from '@/api/systemadmin.js'
export default {
// name: "edit"
components: { },
props: {
isCreate: {
type: Number,
required: true
},
editData: {
type: Object,
default: () => {
return { rules: [] }
}
}
},
data() {
const validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次输入密码'))
} else if (value !== this.pram.pwd) {
callback(new Error('两次输入密码不一致!'))
} else {
callback()
}
}
return {
constants,
pram: {
account: null,
level: null,
pwd: null,
repwd: null,
realName: null,
roles: null,
status: null,
id: null
},
roleList: [],
rules: {
account: [{ required: true, message: '请填管理员账号', trigger: ['blur', 'change'] }],
// level: null,
pwd: [{ required: true, message: '请填管理员密码', trigger: ['blur', 'change'] }],
repwd: [{ required: true, message: '确认密码密码', validator: validatePass, trigger: ['blur', 'change'] }],
realName: [{ required: true, message: '管理员姓名', trigger: ['blur', 'change'] }],
roles: [{ required: true, message: '管理员身份', trigger: ['blur', 'change'] }]
}
}
},
mounted() {
this.initEditData()
this.handleGetRoleList()
},
methods: {
close() {
this.$emit('hideEditDialog')
},
handleGetRoleList() {
const _pram = {
page: 1,
limit: constants.page.limit[4]
}
roleApi.getRoleList(_pram).then(data => {
this.roleList = data
})
},
initEditData() {
if (this.isCreate !== 1) return
const { account, realName, roles, level, status, id } = this.editData
this.pram.account = account
this.pram.realName = realName
const _roles = []
if (roles.length > 0 && !roles.includes(',')) {
_roles.push(Number.parseInt(roles))
} else {
_roles.push(...roles.split(',').map(item => Number.parseInt(item)))
}
this.pram.roles = _roles
this.pram.status = status
this.pram.id = id
this.rules.pwd = []
this.rules.repwd = []
},
handlerSubmit(form) {
this.$refs[form].validate(valid => {
if (!valid) return
if (this.isCreate === 0) {
this.handlerSave()
} else {
this.handlerEdit()
}
})
},
handlerSave() {
systemAdminApi.adminAdd(this.pram).then(data => {
this.$message.success('创建管理员成功')
this.$emit('hideEditDialog')
})
},
handlerEdit() {
this.pram.roles = this.pram.roles.join(',')
systemAdminApi.adminUpdate(this.pram).then(data => {
this.$message.success('更新管理员成功')
this.$emit('hideEditDialog')
})
},
rulesSelect(selectKeys) {
this.pram.rules = selectKeys
},
handlerPwdInput(val) {
if (!val) {
this.rules.pwd = []
this.rules.repwd = []
return
}
this.rules.pwd = [
{ required: true, message: '请填管理员密码', trigger: ['blur', 'change'] },
{ min: 6, max: 20, message: '长度6-20个字符', trigger: ['blur', 'change'] }]
this.rules.repwd = [{ required: true, message: '两次输入密码不一致', validator: (rule, value, callback) => {
if (value === '') {
callback(new Error('两次输入密码不一致!'))
} else if (value !== this.pram.pwd) {
callback(new Error('两次输入密码不一致!'))
} else {
callback()
}
}, trigger: ['blur', 'change'] }]
}
}
}
</script>
<style scoped>
</style>

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