Compare commits

...

41 Commits
main ... client

Author SHA1 Message Date
p97balmkq 534415dd52 ADD file via upload
2 years ago
p97balmkq 19e6c3970f ADD file via upload
2 years ago
p97balmkq 2bd17a3362 ADD file via upload
2 years ago
p97balmkq d754ad85ec ADD file via upload
2 years ago
p97balmkq ed70a48893 ADD file via upload
2 years ago
p97balmkq a3ed62bc21 ADD file via upload
2 years ago
p97balmkq def3153557 ADD file via upload
2 years ago
p97balmkq 16c4c448a4 ADD file via upload
2 years ago
p97balmkq b32155778f ADD file via upload
2 years ago
p97balmkq 33db26e675 ADD file via upload
2 years ago
p97balmkq e2b5c2b142 ADD file via upload
2 years ago
p97balmkq de5a83b9d3 ADD file via upload
2 years ago
p97balmkq 7c3ad3da81 ADD file via upload
2 years ago
p97balmkq e304c3c925 ADD file via upload
2 years ago
p97balmkq 349f2b8cde ADD file via upload
2 years ago
p97balmkq 60f24ad140 ADD file via upload
2 years ago
p97balmkq c16bd68968 ADD file via upload
2 years ago
p97balmkq 45e99eec0f ADD file via upload
2 years ago
p97balmkq 6b9e65e8b4 ADD file via upload
2 years ago
p97balmkq 5987f9fe96 ADD file via upload
2 years ago
p97balmkq 80c8b4836b ADD file via upload
2 years ago
p97balmkq eb311264be ADD file via upload
2 years ago
p97balmkq 2e506c52f7 ADD file via upload
2 years ago
p97balmkq 61cbe3bd6c ADD file via upload
2 years ago
p97balmkq 95dfdcbb63 ADD file via upload
2 years ago
p97balmkq 90670bcfb1 ADD file via upload
2 years ago
p97balmkq 99b84ab6e6 ADD file via upload
2 years ago
p97balmkq 1258e6d0d2 ADD file via upload
2 years ago
p97balmkq c952acd701 ADD file via upload
2 years ago
p97balmkq e7c3ed7572 ADD file via upload
2 years ago
p97balmkq a59f20ad4a ADD file via upload
2 years ago
p97balmkq dbb47b0383 ADD file via upload
2 years ago
p97balmkq 44fc8a2846 ADD file via upload
2 years ago
p97balmkq 6a869a7fd7 ADD file via upload
2 years ago
p97balmkq 29bb7bb312 ADD file via upload
2 years ago
p97balmkq 05f6bb09a0 ADD file via upload
2 years ago
p97balmkq b2c718c74e ADD file via upload
2 years ago
p97balmkq 939b7a44c9 ADD file via upload
2 years ago
p97balmkq 0b85933889 ADD file via upload
2 years ago
p97balmkq 20835c7e81 ADD file via upload
2 years ago
p97balmkq 5cb6a4b8c3 ADD file via upload
2 years ago

@ -0,0 +1,12 @@
<template>
<div id="app">
<router-view/>
</div>
</template>
<style>
html,body,#app{
width: 100%;
height: 100%;
}
</style>

@ -0,0 +1,108 @@
<template>
<div class="MKPlayer" id="MKPlayer" @click.stop.prevent>
<div class="notification" v-show="message!=''" v-text="message">
</div>
<div class="MKPlayer-play-message" :class="{active:openMusicList}">
<!-- 播放列表 -->
<div class="MKPlayer-play-disc">
<div class="mkdisc">
<a class="mkloop" style="display: inline-block">
<i class="mkicon mkicon-disc"></i>
</a>
</div>
<div class="mklyric" :style="{transform:scrollTopText}">
<ul>
<li v-for="(v,k,index) in lyricList" :data-on="index" class="lrc-item" :class="{mkactive:k==lastLyric}" v-text="v"></li>
</ul>
</div>
</div>
<div class="MKPlayer-play-list" :class="{mkempty:musicList.length==0}">
<div class="MKPlayer-play-header">
<div class="mkheader">播放列表 <span v-html="musicList.length"></span></div>
</div>
<div class="mkempty-text">
暂无音乐
</div>
<div class="MKPlayer-play-music">
<div class="mkmusic-row clearfix" v-for="(v,k) in musicList" :class="{active:v.id == music.id}">
<div class="mkmusic-icon">
<i class="mkicon mkicon-play-o"></i>
</div>
<div class="mkmusic-title" @click="playIndex(k)">
<div class="mkmusic-hover-icon">
<i class="mkicon mkicon-collect" title="收藏" @click.prevent.stop="collect(v)"></i>
<i class="mkicon mkicon-download" title="下载" @click.prevent.stop="download(v)"></i>
<i class="mkicon mkicon-like" title="喜欢" @click.prevent.stop="like(v)"></i>
</div>
<div class="mkgeming" v-html="v.name"></div>
</div>
<div class="mkmusic-name" v-text="v.artist"></div>
<div class="mkmusic-album" v-text="v.album"></div>
</div>
</div>
</div>
</div>
<div class="MKPlayer-bottom">
<div class="MKPlayer-bottom-btn">
<a href="javascript:;">
<i class="mkicon mkicon-prev" @click.stop.prevent="prevMusic"></i>
</a>
<a href="javascript:;" class="MKPlayer-play" :class="{active:playState}">
<i class="mkicon mkicon-play text-active" @click.stop.prevent="playMusic"></i>
<i class="mkicon mkicon-pause" @click.stop.prevent="pauseMusic"></i>
</a>
<a href="javascript:;">
<i class="mkicon mkicon-next" data-func="next" @click.stop.prevent="nextMusic"></i>
</a>
</div>
<div class="MKPlayer-info">
<a href="javascript:;" :class="'MKPlayer-play-type '+ orderby[playOrderby]" @click="updateOrderby">
<i class="mkicon mkicon-list-cycle" data-type="mklist"></i>
<i class="mkicon mkicon-random" data-type="mkrandom"></i>
<i class="mkicon mkicon-single-cycle" data-type="mksingle"></i>
</a>
<a href="javascript:;">
<i class="mkicon mkicon-gedan" @click="gedanClick"></i><span style="font-size: 14px">{{musicList.length}}</span>
</a>
</div>
<div class="MKPlayer-volume">
<div class="MKPlayer-volume-left">
<i class="mkicon" :class="{'mkicon-volume':!mkmute ,'mkicon-mute':mkmute }" @click="setMute"></i>
</div>
<mk-progress v-model="volume" @changed="onVolumeChange" :lock="false"></mk-progress>
</div>
<!--进度条 -->
<div class="MKPlayer-progress">
<div class="MKPlayer-music-info clearfix">
<span v-text="progressTime" style="float: right"></span>
<span v-text="music.name"></span>
<span v-text="music.artist"></span>
</div>
<mk-progress v-model="musicProsess" @changed="onMusicProsess" :lock="!playState"></mk-progress>
</div>
</div>
</div>
</template>
<style type="text/scss" lang="scss">
@import "./asset/icon/MKPlayer";
</style>
<script>
export default {
name: "MKPlayer",
data() {
return {}
},
watch: {},
computed: {},
methods: {},
created() {
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,123 @@
<template>
<div class="admins-add" v-loading="loading">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span class="title"> 添加管理员</span>
</div>
<div class="form-database-form">
<el-form :model="form" ref="formModel" label-width="130px" status-icon validate-on-rule-change>
<el-form-item label="帐号" prop="username" required :rules="[{required:true, message:'请填写帐号'}, {validator:rule.checkRemote, message:'内容重复了', checktype:'insert', module:'admins', col:'username', trigger:'blur'}]">
<el-input placeholder="输入帐号" style="width:250px;" v-model="form.username" /> </el-form-item>
<el-form-item label="密码" prop="pwd" required :rules="[{required:true, message:'请填写密码'}]">
<el-input placeholder="输入密码" style="width:250px;" v-model="form.pwd" /> </el-form-item>
<el-form-item v-if="btnText">
<el-button type="primary" @click="submit">{{ btnText }}</el-button>
</el-form-item>
</el-form>
</div>
</el-card>
</div>
</template>
<style type="text/scss" scoped lang="scss">
.admins-add{
}
</style>
<script>
import api from '@/api'
import rule from '@/utils/rule'
import { extend } from '@/utils/extend'
export default {
name:'admins-add',
data() {
return {
rule,
loading:false,
form:{
username:'',
pwd:'',
},
}
},
watch: {
},
props: {
isRead:{
type:Boolean,
default:true
},
btnText:{
type:String,
default:'提交'
},
},
computed: {},
methods: {
submit(){
this.$refs.formModel.validate().then(res=>{
if(this.loading)return;
this.loading = true;
var form = this.form;
this.$post(api.admins.insert , form).then(res=>{
this.loading = false;
if(res.code == api.code.OK){
this.$message.success('添加成功');
this.$emit('success' , res.data);
this.$refs.formModel.resetFields();
this.loadInfo();
}else{
this.$message.error(res.msg);
}
}).catch(err=>{
this.loading = false;
this.$message.error(err.message);
})
}).catch(err=>{
console.log(err.message);
})
},
loadInfo(){
var form = this.form;
//
this.loading = true;
this.$post(api.admins.create , {
id:this.$route.query.id
}).then(res=>{
this.loading = false;
if(res.code == api.code.OK){
extend(this , res.data);
}else{
this.$message.error(res.msg);
this.$router.go(-1);
}
}).catch(err=>{
this.$message.error(err.message);
this.$router.go(-1);
});
},
},
created() {
this.loadInfo();
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,42 @@
<template>
<span>
{{ weizhi.address }}
</span>
</template>
<script>
import {empty, isObject} from "@/utils/extend";
export default {
name: "e-address-name",
props:{
address:[String,Object],
},
computed:{
weizhi(){
if(empty(this.address))
{
return {
address:''
};
}
if(isObject(this.address))
{
return this.address;
}
try{
var result = eval("("+this.address+")");
return result
}catch (e) {
return {
address:''
};
}
}
}
}
</script>
<style scoped>
</style>

@ -0,0 +1,100 @@
<template>
<div class="">
<baidu-map :center="{lng:data.lng,lat:data.lat}" @ready="readyBaidu" :zoom="data.zoom" class="baidumap" style="height: 250px" ref="baiduMap">
<bm-view class="map" style=";height: 250px"></bm-view>
<bm-control :offset="{width: '10px', height: '10px'}" v-if="initMap">
<el-input v-model="address" style="width: 250px" placeholder="请输入地名" />
</bm-control>
<bm-local-search v-if="initMap" class="localSearch" style="width: 350px;height: 250px;overflow: hidden auto" :auto-viewport="true" :keyword.sync="address"
@infohtmlset="searchComplete"></bm-local-search>
</baidu-map>
{{value}}
</div>
</template>
<style type="text/scss" lang="scss">
.baidumap{
display: flex;
.localSearch{
padding: 0 10px;
}
}
.map{
flex-grow: 1;
img{
max-width: none;
max-height: none;
}
}
</style>
<script>
import jdk from '@/utils/extend'
export default {
name: "e-baidu-address",
data() {
return {
initMap:false,
address:''
}
},
props:{
value:[String,Object],
},
watch: {},
computed: {
data(){
var result = this.value;
try{
if( !jdk.isObject(result) )
{
result = JSON.parse(result);
}
}catch (e) {
result = {
address:'',
lng:114.053703,
lat:22.673854,
zoom:15
};
}
return result;
}
},
methods: {
readyBaidu({BMap, map}){
this.initMap = true;
this.$BMap = BMap;
this.address = this.data.address;
},
searchComplete(e){
this.showPointValue(e)
},
showPointValue(p)
{
var $this = this;
var bmap = $this.$refs.baiduMap.map;
var point = p.point;
var obj = {
lng:point.lng,
lat:point.lat,
zoom:bmap.getZoom(),
title:p.title,
address:p.address || this.address
};
this.$emit('input' , JSON.stringify(obj));
}
},
created() {
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,97 @@
<template>
<span class="e-audio">
<a :href="formatImageSrc(src)" download target="_blank">下载</a>
<span class="mkicon" @click="playAudio" :class="{'mkicon-play':!playState,'mkicon-pause':playState}"></span>
<span>{{currTime}}</span>
/
<span>{{endTime}}</span>
<audio :src="formatImageSrc(src)" @canplay="canplay" @timeupdate="updateTime" preload="auto" ref="audio" @play="play" @pause="pause" @ended="pause" @error="pause"></audio>
</span>
</template>
<style type="text/scss" lang="scss">
.e-audio{
.mkicon{
font-size: 16px;
color: #888888;
}
}
</style>
<script>
import './asset/icon/MKPlayer.scss'
import {formatImageSrc} from "@/utils/utils";
function formatTime(time) {
var hour, minute, second;
hour = (parseInt(time / 3600, 10));
if (hour <10) hour = '0' + hour;
minute = (parseInt((time % 3600) / 60, 10));
if (minute < 10) minute = '0' + minute;
second = (parseInt(time % 60, 10));
if (second < 10) second = '0' + second;
if (hour > 0) {
return hour + ":" + minute + ":" + second;
} else {
return minute + ":" + second;
}
}
export default {
name: "e-audio",
data() {
return {
playState:false,
currentTime:0,
duration:0,
}
},
props:{
src:String
},
watch: {},
computed: {
currTime(){
return formatTime(this.currentTime)
},
endTime(){
return formatTime(this.duration)
}
},
methods: {
formatImageSrc,
canplay(){
this.updateTime()
},
updateTime(){
this.duration = this.$refs.audio.duration
this.currentTime = this.$refs.audio.currentTime
},
playAudio(){
if(this.playState){
this.$refs.audio.pause();
this.playState = false;
}else{
this.$refs.audio.play();
this.playState = true;
}
},
play(){
this.playState = true;
},
pause(){
this.playState = false;
}
},
created() {
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,211 @@
<template>
<article class="single_blog">
<figure>
<div class="blog_thumb" v-if="image" @click="$gotoUrl">
<a href="javascript:;" class="img-box" :class="['pb'+imageHeight , (isScale?'img-scale':'')]">
<div class="img" :style="{'background-image':'url('+$getImage(image)+')'}"></div>
</a>
</div>
<figcaption class="blog_content">
<h4 class="post_title">
<a href="javascript:;" @click="$gotoUrl"> {{ title }} </a>
</h4>
<div class="articles_date">
<span><i class="fa fa-calendar" aria-hidden="true"></i> {{ formatTime }}</span>
<span v-if="sendUser"><i class="fa fa-user" aria-hidden="true"></i> {{ sendUser }}</span>
</div>
<p class="post_desc">
{{ contents }}
</p>
<a href="javascript:;" class="btn-see" @click="$gotoUrl"> {{btnText}} </a>
<span class="article-price" v-if="price"> {{ price }}</span>
</figcaption>
</figure>
</article>
</template>
<script>
import gotoUrl from "../mixins/gotoUrl";
export default {
name: "e-module-blog",
data() {
return {}
},
props:{
to:[String,Object],
replace:{
type:Boolean,
default:false
},
title:String,
price:[String,Number],
content:[String,Number],
sendUser:String,
time:String,
image:String,
imageHeight:{
type:[String,Number],
default:80
},
btnText:{
type:String,
default:'+ 查看详情'
},
isScale:{
type:Boolean,
default:false
},
len:{
type:Number,
default:30
}
},
mixins:[gotoUrl],
watch: {},
computed: {
contents() {
if (this.content) {
return this.content.replace(/<[^>]+>/g, "")
.replace(/\&nbsp\;/ig,'')
.replace(/\s+/ig , '')
.replace(/(\n|\r)/ig , '')
.substr(0, this.len);
}
return '';
},
formatTime () {
if ( this.time ) {
return this.time.substr(0,10);
}
return "";
},
imageSrc(){
return this.image ? this.image.split(',')[0] : '';
}
},
methods: {
},
created() {
},
mounted() {
},
destroyed() {
}
}
</script>
<style type="text/scss" scoped lang="scss">
.single_blog{
padding: 10px;
background: #ffffff;
figure{
margin: 0px;
padding: 0px;
.blog_content {
padding-top: 20px;
position: relative;
.post_title {
margin: 0px;
padding: 0px;
font-size: 16px;
text-transform: capitalize;
line-height: 30px;
margin-bottom: 10px;
font-weight: 500;
}
.articles_date {
margin-bottom: 10px;
display: flex;
}
.articles_date span {
font-size: 13px;
line-height: 15px;
margin-right: 5px;
}
p.post_desc {
font-size: 14px;
line-height: 24px;
height: 48px;
overflow: hidden;
color: #9a9a9a;
margin-bottom: 0;
}
> a.btn-see {
font-size: 14px;
text-transform: uppercase;
font-weight: 600;
display: inline-block;
border: 1px solid #454545;
line-height: 20px;
padding: 10px;
border-radius: 15px;
margin-top: 24px;
text-decoration: none;
color: rgba(91,40,158,0.8);
width: 100px;
}
> a:hover {
color: #fff;
background: #F53737;
border-color: #F53737;
}
.article-price{
position: absolute;
right: 10px;
bottom: 10px;
color: #F53737;
font-size: 18px;
}
}
.blog_carousel:hover .owl-nav div {
opacity: 1;
visibility: visible;
left: 0;
}
.blog_carousel:hover .owl-nav div.owl-next {
right: 0;
}
.blog_carousel .owl-nav.disabled {
display: block;
}
.blog_carousel .owl-nav div {
position: absolute;
top: 50%;
transform: translatey(-50%);
font-size: 18px;
-webkit-transition: 0.3s;
transition: 0.3s;
opacity: 0;
visibility: hidden;
width: 62px;
height: 62px;
line-height: 60px;
text-align: center;
background: rgba(255, 255, 255, 0.75);
border-radius: 50%;
left: 25px;
border: 1px solid #e5e5e5;
}
.blog_carousel .owl-nav div:hover {
color: #fff;
background: #F53737;
border-color: #F53737;
}
.blog_carousel .owl-nav div.owl-next {
right: 15px;
left: auto;
}
@media only screen and (max-width: 767px) {
.blog_carousel .owl-nav div {
display: none;
}
}
}
}
</style>

@ -0,0 +1,53 @@
<template>
<el-checkbox-group v-model="select" @change="changeSelect">
<el-checkbox v-for="v in list" :label="v"> {{ v.zimu }} {{ v.title }} </el-checkbox>
</el-checkbox-group>
</template>
<script>
import {findObject} from "@/utils/utils";
import {each} from "@/utils/extend";
export default {
name: "t-checkbox",
data () {
return {
select:[],
}
},
props:{
obj:Object,
paper:String,
daan:String
},
computed:{
list(){
if(!this.paper){
return [];
}
return eval("("+this.paper+")")
}
},
methods:{
changeSelect(val){
var daan = [];
var zimu = [];
var defen = 0;
each(this.select , (i,o)=>{
daan.push(o.title);
zimu.push(o.zimu);
defen +=Math.floor( o.point === undefined ? o.defen : o.point);
});
this.obj.zimu = zimu.join(","),
this.obj[this.daan] = daan.join(","),
this.obj.defen = defen;
}
}
}
</script>
<style scoped>
</style>

@ -0,0 +1,44 @@
<template>
<el-tooltip class="item" effect="dark" :content="isCollect ? '已收藏':'收藏'" placement="top-start">
<el-button v-if="isCollect" icon="el-icon-star-on" type="danger" circle></el-button>
<el-button @click="collect" v-else icon="el-icon-star-off" type="warning" circle></el-button>
</el-tooltip>
</template>
<style type="text/scss" lang="scss">
</style>
<script>
export default {
name: "e-collect",
data() {
return {
}
},
props:{
value:[Boolean,Number],
module:String,
id:[String,Number],
ziduan:[String,Number],
},
watch: {},
computed: {
isCollect(){
return this.value;
}
},
methods: {
collect(){
this.$collect(this.module , this.ziduan , this.id).then(res=>{
this.$emit('input' , true);
});
}
},
created() {
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,84 @@
<template>
<div class="e-container">
<slot></slot>
</div>
</template>
<style type="text/scss" lang="scss">
@media screen and (min-width: 1100px){
.e-container{
width: 980px;
margin:0 auto;
}
}
@media screen and (min-width: 1200px){
.e-container{
width: 1100px;
margin:0 auto;
}
}
@media screen and (min-width: 1300px){
.e-container{
width: 1200px;
margin:0 auto;
}
}
@media screen and (max-width: 768px) {
.e-container{
padding: 0px 8px;
}
#app{
overflow-x: hidden;
}
#project-box .info{
float: none!important;
}
#project-box .entry-content{
float: none!important;
width: 100% !important;
padding: 10px;
}
.el-form{
.el-form-item__label{
width: 100% !important;
text-align: left;
}
.el-form-item__content{
width: 100%!important;
margin-left: 0px!important;
}
}
p{
white-space:pre-wrap;
}
.Home >div>div>.el-carousel{
display: none;
}
.goods-info {
.gallery-list{
float: none!important;
width: 100% !important;
height: 350px;
}
.goods-right-content{
margin-left: 0px!important;
}
}
.hjlgf{
.row1{
float: none!important;
width: auto;
}
.row2{
margin-left: 0px!important;
}
}
}
</style>
<script>
export default {
name: "e-container",
}
</script>

@ -0,0 +1,83 @@
<template>
<div class="detail" v-if="address.lng">
<baidu-map class="map" :center="{lng: address.lng, lat: address.lat}" :zoom="15">
<bm-info-window :position="{lng: address.lng, lat: address.lat}"
title="位置信息"
:show="infoWindow"
@close="infoWindowClose" @open="infoWindowOpen">
<p v-text="address.address"></p>
<el-button type="primary" @click="open"></el-button>
</bm-info-window>
<bm-marker :position="{lng:address.lng,lat:address.lat}" :dragging="false" animation="BMAP_ANIMATION_BOUNCE"></bm-marker>
</baidu-map>
<a :href="daohangUrl" ref="daohang" target="_blank"></a>
</div>
</template>
<style type="text/scss" scoped lang="scss">
.detail {
width: 100%;
height: 350px;
.map {
width: 100%;
height: 100%;
img{
max-width: none;
max-height: none;
}
}
}
</style>
<script>
import {isObject} from "@/utils/extend";
export default {
name: "e-baidu-address-detail",
data() {
return {
daohangUrl:'',
infoWindow: true
}
},
props:{
map:[Object,String]
},
watch: {},
computed: {
address(){
var map = this.map;
console.log(map)
if(!map){
return {};
}
if(!isObject(map)){
map = JSON.parse(map);
}
return map;
}
},
methods: {
infoWindowClose () {
this.infoWindow = false
},
infoWindowOpen () {
this.infoWindow = true
},
open(){
var obj = this.address;
var url = "http://api.map.baidu.com/marker?location="+obj.lat+","+obj.lng+"&title=目的地&content="+obj.address+"&output=html&src=webapp.baidu.openAPIdemo&output=html";
var a = document.createElement('a');
a.href = url;
a.target = '_blank';
a.click();
}
},
created() {
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,37 @@
<template>
<jt-tinymce @input="$emit('input' , $event)" :upload-image="uploadFile" :value="value"></jt-tinymce>
</template>
<style type="text/scss" lang="scss">
</style>
<script>
import JtTinymce from "@/components/Tinymce/index";
import api from "@/api";
import {formatImageSrc} from "@/utils/utils";
export default {
name: "e-editor",
components: {JtTinymce},
data() {
return {}
},
props:{
value:String
},
watch: {},
computed: {},
methods: {
uploadFile(file , success , error)
{
api.attachment.upload(file).then(file=>{
success(formatImageSrc(file))
}).catch(error);
}
},
created() {
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,45 @@
<template>
<span>
<template v-if="value">
<a :href="setting.proxyUrl + '/'+(value)" :download="filename ? filename : basename(value)">
下载
</a>
</template>
<template v-else>
-
</template>
</span>
</template>
<style type="text/scss" lang="scss">
</style>
<script>
import setting from '@/setting'
const path = require('path');
export default {
name: "e-file-list",
data() {
return {
setting,
path
}
},
props:{
value:String,
filename:String
},
watch: {},
computed: {},
methods: {
basename:path.basename
},
created() {
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,50 @@
<template>
<div class="footer mt10">
<div class="copyrightnr link">
友情链接&nbsp;
<a v-for="v in likeList" :href="v.wangzhi" target="_blank">{{ v.wangzhanmingcheng }}</a> &nbsp;
</div>
</div>
</template>
<style type="text/scss" scoped lang="scss">
.footer{
padding: 15px;
color: #767676;
text-align: center;
.link{
a:after{
content: ' | ';
}
a:last-child:after{
content: '';
}
}
}
</style>
<script>
import api from '@/api';
import {extend} from '@/utils/extend';
const setting = require('@/setting');
export default {
data(){
return {
likeList:[]
};
},
methods:{
loadListMenu(module, target) {
this.$post(api.search.all, {table: module, order: 'id desc'}).then(res => {
this[target] = res.data;
});
},
},
created(){
this.loadListMenu("youqinglianjie",'likeList');
}
}
</script>

@ -0,0 +1,328 @@
<template>
<div class="header-box" :class="{ open: status }">
<e-container>
<div class="header-top clearfix">
<div class="left">欢迎光临</div>
<div class="right">
<template v-if="$session.username">
<el-dropdown>
<span class="el-dropdown-link">
{{ $session.username }} <i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item icon="el-icon-user" @click.native="$router.push('/admin')">个人中心</el-dropdown-item>
<el-dropdown-item icon="el-icon-arrow-left" @click.native="logout">退出登录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<template v-else>
<el-button type="primary" @click="$router.push('/login')" size="mini">
登录
</el-button>
</template>
</div>
</div>
</e-container>
<div class="marks-bg" @click="status = false"></div>
<div class="header-nav">
<e-container class="clearfix">
<div class="logo nav-left">
<div class="brand" @click="status = true">
<span class="fa fa-bars"></span>
</div>
{{ setting.title }}
</div>
<div class="header-nav-ul nav-left clearfix">
<ul class="header-nav-left clearfix">
<li>
<router-link to="/">首页
</router-link>
</li>
<li>
<router-link to="/xinwenxinxi">旅游新闻
<i class="el-icon-arrow-down"></i>
</router-link>
<ul class="submenu">
<li v-for="m in listMenuxinwenfenlei">
<router-link :to="'/xinwenxinxi?fenlei=' + m.id" v-text="m.fenleimingcheng"></router-link>
</li>
</ul>
</li>
<li>
<router-link to="/jingdianxinxi">景区信息
<i class="el-icon-arrow-down"></i>
</router-link>
<ul class="submenu">
<li v-for="m in listMenudiqu">
<router-link :to="'/jingdianxinxi?suoshudiqu=' + m.id" v-text="m.diqumingcheng"></router-link>
</li>
</ul>
</li>
<li>
<router-link to="/difangmeishi">美食信息
</router-link>
</li>
<li>
<router-link to="/lvyouxianlu">旅游线路
</router-link>
</li>
<li>
<router-link to="/liuyanbanadd">在线留言
</router-link>
</li>
<li>
<router-link to="/yonghuadd">注册
</router-link>
</li>
</ul>
</div>
</e-container>
</div>
</div>
</template>
<style type="text/scss" scope lang="scss">
.el-button--primary{
background: rgba(15, 80, 37, 0.8) !important;
}
.header-box {
.header-top {
padding: 5px;
}
.marks-bg,
.brand {
display: none;
}
.marks-bg {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 100;
background: rgba(0, 0, 0, .5);
}
.left {
float: left;
}
.right {
float: right;
}
.header-nav {
background: rgba(11, 85, 14, 0.8);
height: 55px;
line-height: 55px;
a {
color: #ffffff;
}
.logo {
font-size: 18px;
color: #ffffff;
margin-right: 10px;
}
.nav-left {
float: left;
}
.nav-right {
float: right;
}
}
.header-nav-ul {
>ul>li {
float: left;
position: relative;
>a {
display: block;
padding: 0px 10px;
>i {
transition: .2s linear;
}
}
>.submenu {
visibility: hidden;
opacity: .5;
position: absolute;
top: 100%;
left: 0px;
max-height: 0px;
width: 200px;
z-index: 5;
background: rgba(75, 154, 200, 1);
transition: .5s cubic-bezier(0, 1, 0.5, 1);
border-radius: 0 0 8px 8px;
>li>a {
line-height: 20px;
display: block;
padding: 10px 15px;
border-bottom: 1px #2B6C99 solid;
}
>li:last-child>a {
border-bottom: none;
}
}
}
>ul>li.active,
>ul>li:hover {
>a {
background: #4B9AC8;
}
}
>ul>li:hover {
>a>i {
transform: rotate(180deg);
}
>.submenu {
visibility: initial;
opacity: 1;
max-height: 900px;
}
}
}
}
@media screen and (max-width: 768px) {
.header-box {
.brand {
display: inline;
float: right;
}
.nav-right {
display: none;
}
.logo {
float: none;
width: 100%;
}
.header-nav-ul {
position: fixed;
left: 0;
top: 0;
bottom: 0;
z-index: 120;
transform: translateX(-100%);
width: 50%;
visibility: hidden;
background: rgba(0, 0, 0, .5);
transition: transform 100ms ease-in-out;
.header-nav-left {
>li {
width: 100%;
float: none;
>.submenu {
visibility: visible;
max-height: none;
position: static;
background: transparent;
padding-left: 20px;
>li {
>a {
border-bottom: none;
}
}
}
}
}
}
}
.header-box.open {
.marks-bg {
display: block;
}
.header-nav-ul {
visibility: visible;
transform: translateX(0);
}
}
}
</style>
<script>
import api from '@/api';
import { extend } from '@/utils/extend';
const setting = require('@/setting');
export default {
name: "bootstrap-header",
data() {
return {
status: false,
keyword: '',
setting,
listMenuxinwenfenlei: [],
listMenudiqu: [],
}
},
watch: {
$route() {
this.status = false;
}
},
computed: {
},
methods: {
searchKeyword() {
var filter = {};
filter[""] = this.keyword;
this.$router.push({
path: '/',
query: filter
});
},
logout() {
this.$confirm('确定退出登录?', '确认信息').then(() => {
// 退
this.$store.dispatch('user/logout');
});
},
loadListMenu(module, target) {
this.$post(api.search.all, { table: module, order: 'id desc' }).then(res => {
this[target] = res.data;
});
},
},
created() {
this.loadListMenu('xinwenfenlei', 'listMenuxinwenfenlei');
this.loadListMenu('diqu', 'listMenudiqu');
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,55 @@
<template>
<div class="Home">
<v-header></v-header>
<transition name="slide-slip">
<router-view/>
</transition>
<v-footer></v-footer>
</div>
</template>
<style type="text/scss" lang="scss">
.slide-slip-enter-active,
.slide-slip-leave-active {
transition: all .3s;
}
.slide-slip-enter {
transform: translateX(100%);
/* opacity: 0; */
}
.slide-slip-leave-to {
transform: translateX(-100%);
}
.dye-bottom-leave-active,
.dye-bottom-enter-active {
transition: all .3s;
}
.dye-bottom-enter,
.dye-bottom-leave-to {
opacity: 0.5;
}
</style>
<script>
import VHeader from "@/views/header";
import VFooter from "@/views/footer";
export default {
name: "home",
components: { VFooter, VHeader},
data() {
return {
}
},
watch: {},
computed: {},
methods: {},
created() {
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,99 @@
<template>
<div class="product-preview">
<div class="big-image">
<a href="javascript:;" data-toggle="lightbox">
<img :src="lists[active]" alt="" />
</a>
</div>
<ul class="thumbs unstyled clearfix">
<li v-for="(r,k) in lists" :class="{active:active == k}" :key="r" @click="active=k">
<a href="javascript:;">
<img :src="r" alt="" />
</a>
</li>
</ul>
</div>
</template>
<style type="type/scss" lang="scss">
.product-preview {
position: relative;
overflow: hidden;
zoom: 1;
.big-image {
margin-right: 124px;
overflow: hidden;
zoom: 1;
}
.thumbs {
position: absolute;
top: 25px;
right: 0;
width: 68px;
> li {
margin-top: 5px;
border: 3px solid #919191;
border-radius: 50%;
overflow: hidden;
transition: all 200ms ease-in-out;
> a {
display: block;
width: 100%;
height: 84px;
}
> a:hover {
}
}
>li.active{
border-color: #fa6f57;
}
> li:first-child {
margin-top: 0;
}
}
}
</style>
<script>
import { isArray } from "@/utils/extend";
export default {
name: "e-image-toggle",
data() {
return {
active:0
}
},
props:{
images:{
type:[String,Array]
}
},
watch: {},
computed: {
lists(){
var images = this.images;
if(!images){
return [];
}
var arr;
if(isArray(images)){
arr = images;
}else{
arr = images.split(',');
}
arr = arr.filter(s=>s);
return arr;
}
},
methods: {},
created() {
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,66 @@
<template>
<fieldset class="images_box">
<div class="imagesList" v-viewer>
<div class="uploadImage" v-for="(img,k) in images" :key="k">
<el-image :src="$formatImageSrc(img)" fit="cover" style="width: 100px;height: 100px">
</el-image>
</div>
</div>
</fieldset>
</template>
<style type="text/scss" lang="scss">
.images_box{
border: 1px solid #DEDEDE;
}
.imagesList{
.uploadImage{
display: inline-block;
width: 120px;
height: 120px;
padding: 10px;
border: 1px solid #DEDEDE;
text-align: center;
margin-right: 10px;
margin-bottom: 10px;
}
}
</style>
<script>
import {isString} from "@/utils/extend";
export default {
name: "e-images",
data() {
return {}
},
props:{
src:{
type:[String,Array]
},
type:String
},
watch: {},
computed: {
images(){
var src = this.src;
if(isString(src)){
src = src.split(",").filter(s=>s!='');
}
if(!src)return[];
src = src.map(s=>this.$formatImageSrc(s));
return src;
}
},
methods: {
},
created() {
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,48 @@
<template>
<div class="img-box" :class="['pb'+pb,isScale?'img-scale':'']">
<div class="img" :style="{'background-image':'url('+image+')'}"></div>
</div>
</template>
<style type="text/scss" lang="scss">
</style>
<script>
import {formatImageSrc} from "@/utils/utils";
export default {
name: "e-img-box",
data() {
return {}
},
props:{
pb:{
type:[String,Number],
default:100
},
src:[String],
isScale:{
type:Boolean,
default:false
}
},
watch: {},
computed: {
image(){
var src = this.src;
if(src == ''){
return '';
}
var a = src.split(',');
return formatImageSrc(a[0]);
}
},
methods: {},
created() {
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,256 @@
<template>
<div :class="{fullscreen:fullscreen}" class="tinymce-container" :style="{width:containerWidth}">
<textarea :id="tinymceId" class="tinymce-textarea"/>
<div class="editor-custom-btn-container">
<editorImage color="#1890ff" class="editor-upload-btn" @successCBK="imageSuccessCBK"/>
</div>
</div>
</template>
<script>
/**
* docs:
* https://panjiachen.github.io/vue-element-admin-site/feature/component/rich-editor.html#tinymce
*/
import editorImage from './components/EditorImage'
import plugins from './plugins'
import toolbar from './toolbar'
import load from './dynamicLoadScript'
// why use this cdn, detail see https://github.com/PanJiaChen/tinymce-all-in-one
const tinymceCDN = '/static/tinymce/tinymce.min.js'
export default {
name: 'jt-tinymce',
components: {editorImage},
props: {
id: {
type: String,
default: function () {
return 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
}
},
value: {
type: String,
default: ''
},
toolbar: {
type: Array,
required: false,
default() {
return []
}
},
menubar: {
type: String,
default: 'file edit insert view format table'
},
height: {
type: [Number, String],
required: false,
default: 360
},
width: {
type: [Number, String],
required: false,
default: 'auto'
},
uploadImage:{
type: Function,
required: true
},
pickerUploadImage:{
type: Function,
default:function () {
return function (file,success,failure) {
}
}
}
},
data() {
return {
hasChange: false,
hasInit: false,
tinymceId: this.id,
fullscreen: false,
languageTypeList: {
'en': 'en',
'zh': 'zh_CN',
'es': 'es_MX',
'ja': 'ja'
}
}
},
computed: {
containerWidth() {
const width = this.width
if (/^[\d]+(\.[\d]+)?$/.test(width)) { // matches `100`, `'100'`
return `${width}px`
}
return width
}
},
watch: {
value(val) {
if (!this.hasChange && this.hasInit) {
this.$nextTick(() =>
window.tinymce.get(this.tinymceId).setContent(val || ''))
}
}
},
mounted() {
this.init()
},
activated() {
if (window.tinymce) {
this.initTinymce()
}
},
deactivated() {
this.destroyTinymce()
},
destroyed() {
this.destroyTinymce()
},
methods: {
init() {
// dynamic load tinymce from cdn
load(tinymceCDN, (err) => {
if (err) {
this.$message.error(err.message)
return
}
this.initTinymce()
})
},
initTinymce() {
const _this = this
window.tinymce.init({
selector: `#${this.tinymceId}`,
language: this.languageTypeList['zh'],
height: this.height,
body_class: 'panel-body ',
object_resizing: false,
paste_data_images:true,
toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
menubar: this.menubar,
plugins: plugins,
end_container_on_empty_block: true,
powerpaste_word_import: 'clean',
code_dialog_height: 450,
code_dialog_width: 1000,
branding:false,
automatic_uploads: true,
advlist_bullet_styles: 'square',
advlist_number_styles: 'default',
imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'],
default_link_target: '_blank',
link_title: false,
nonbreaking_force_tab: true, // inserting nonbreaking space &nbsp; need Nonbreaking Space Plugin
init_instance_callback: editor => {
if (_this.value) {
editor.setContent(_this.value)
}
_this.hasInit = true
editor.on('NodeChange Change KeyUp SetContent', () => {
this.hasChange = true
this.$emit('input', editor.getContent())
})
},
setup(editor) {
editor.on('FullscreenStateChanged', (e) => {
_this.fullscreen = e.state
})
},
// it will try to keep these URLs intact
// https://www.tiny.cloud/docs-3x/reference/configuration/Configuration3x@convert_urls/
// https://stackoverflow.com/questions/5196205/disable-tinymce-absolute-to-relative-url-conversions
convert_urls: false,
images_upload_handler(blobInfo, success, failure){
_this.uploadImage(blobInfo.blob() , success , failure)
},
//
file_picker_callback: function (callback, value, meta) {
var input = document.createElement('input');
input.setAttribute('type', 'file');
input.onchange = function () {
var file = this.files[0];
if(file){
_this.uploadImage(file , callback , function () {
})
}
/*_this.pickerUploadImage(file, callback , function () {
})*/
};
input.click();
},
paste_upload_image:function (editor , file , success , error) {
_this.uploadImage(file , success , error)
}
})
},
destroyTinymce() {
const tinymce = window.tinymce.get(this.tinymceId)
if (this.fullscreen) {
tinymce.execCommand('mceFullScreen')
}
if (tinymce) {
tinymce.destroy()
}
},
setContent(value) {
window.tinymce.get(this.tinymceId).setContent(value)
},
getContent() {
window.tinymce.get(this.tinymceId).getContent()
},
imageSuccessCBK(arr) {
arr.forEach(v => window.tinymce.get(this.tinymceId).insertContent(`<img class="wscnph" src="${v.url}" >`))
}
}
}
</script>
<style lang="scss" scoped>
.tinymce-container {
position: relative;
line-height: normal;
}
.tinymce-container {
::v-deep {
.mce-fullscreen {
z-index: 10000;
}
}
}
.tinymce-textarea {
visibility: hidden;
z-index: -1;
}
.editor-custom-btn-container {
position: absolute;
right: 4px;
top: 4px;
/*z-index: 2005;*/
}
.fullscreen .editor-custom-btn-container {
z-index: 10000;
position: fixed;
}
.editor-upload-btn {
display: inline-block;
}
</style>

@ -0,0 +1,200 @@
<template>
<div class="v-list" v-loading="loading" element-loading-text="加载中">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span class="title">
管理员列表
</span>
</div>
<!-- 搜索 -->
<div class="form-search">
<el-form @submit.prevent.stop :inline="true" size="mini">
<el-form-item label="帐号">
<el-input v-model="search.username"></el-input>
</el-form-item> <el-form-item>
<el-button type="primary" @click="searchSubmit" icon="el-icon-search">查询</el-button>
</el-form-item>
</el-form>
</div>
<el-table border :data="list" style="width: 100%" highlight-current-row
>
<el-table-column type="index" label="#"></el-table-column> <!-- -->
<el-table-column label="帐号"width="130">
<template slot-scope="{row}">
{{ row.username }} </template>
</el-table-column>
<el-table-column label="密码">
<template slot-scope="{row}">
{{ row.pwd }} </template>
</el-table-column>
<el-table-column label="操作">
<template slot-scope="{row}">
<el-button-group>
<el-tooltip content="编辑" placement="top">
<el-button icon="el-icon-edit" @click="$goto({path:'/admin/adminsupdt',query:{id:row.id } })"
type="warning" size="mini"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button icon="el-icon-delete" type="danger" size="mini" @click="deleteItem(row)">
</el-button>
</el-tooltip>
</el-button-group>
</template>
</el-table-column>
</el-table>
<div class="e-pages" style="margin-top: 10px;text-align: center">
<el-pagination
@current-change="loadList"
:current-page="page"
:page-size="pagesize"
@size-change="sizeChange"
layout="total, sizes, prev, pager, next, jumper"
:total="totalCount">
</el-pagination>
</div>
</el-card>
</div>
</template>
<style type="text/scss" scoped lang="scss">
</style>
<script>
import api from '@/api';
import { remove , checkIssh } from '@/utils/utils';
import { extend } from '@/utils/extend';
import objectDiff from 'objectdiff';
/**
* 后台列表页面
*/
export default {
data() {
return {
loading:false,
list:[],
search:{
username:'',
},
total:{},
page:1, //
pagesize:10, //
totalCount:0, //
}
},
watch: {},
computed: {},
methods: {
searchSubmit(){
this.loadList(1);
},
sizeChange(e){
this.pagesize = e;
this.loadList(1);
},
checkIssh,
loadList( page ){
//
if(this.loading)return;
this.loading = true;
this.page = page;
//
var filter = extend(true, {}, this.search, {page:page+"", pagesize: this.pagesize+""});
var diff = objectDiff.diff(filter, this.$route.query);
if (diff.changed != 'equal') { //
this.$router.push({ // query
path: this.$route.path,
query: filter
});
}
this.$post(api.admins.list , filter).then(res=>{
this.loading = false;
if(res.code == api.code.OK)
{
extend(this , res.data);
}else{
this.$message.error(res.msg);
}
}).catch(err=>{
this.loading = false;
this.$message.error(err.message);
});
},
//
deleteItem( row ){
this.$confirm('确定删除数据?' , '提示',{ //
type: 'warning'
}).then(()=>{//
this.loading = true; //
this.$post(api.admins.delete , {//
id:row.id
}).then(res=>{
this.loading = false;
if(res.code != api.code.OK){
this.$message.error(res.msg);
}else{
remove(this.list , row);
}
}).catch(err=>{ // 访
this.loading = false;
this.$message.error(err.message)
})
}).catch(()=>{
//
})
},
},
beforeRouteUpdate(to,form,next){
extend(this.search , to.query)
this.loadList(1);
next();
},
created() {
var search = extend(this.search , this.$route.query)
if(search.page)
{
this.page = Math.floor(this.$route.query.page)
delete search.page
}
if(search.pagesize)
{
this.pagesize = Math.floor(this.$route.query.pagesize)
delete search.pagesize
}
this.loadList(1);
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,94 @@
<template>
<div class="v-mod" v-loading="loading">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span> 修改密码</span>
</div>
<div class="">
<el-form ref="modForm" :model="form" inline-message label-width="120px">
<el-form-item label="原密码" prop="oldPassword" required :rules="[{required:true,message:'请填写原密码'}]">
<el-input style="width:200px" type="password" v-model="form.oldPassword"></el-input>
</el-form-item>
<el-form-item label="新密码" prop="newPwd" required :rules="[{required:true,message:'请填写新密码'}]">
<el-input style="width:200px" type="password" v-model="form.newPwd"></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="newPwd2" required
:rules="[{required:true,message:'请填写确认密码'},
{validator:checkPassword,message:'两次密码不一致', trigger: 'blur' }]">
<el-input style="width:200px" type="password" v-model="form.newPwd2"></el-input>
</el-form-item>
<el-form-item>
<el-button @click="savePassword"></el-button>
</el-form-item>
</el-form>
</div>
</el-card>
</div>
</template>
<style type="text/scss" lang="scss">
</style>
<script>
import api from '@/api'
export default {
name: "v-mod",
data() {
return {
loading:false,
form:{
oldPassword:'',
newPwd:'',
newPwd2:''
}
}
},
watch: {},
computed: {},
methods: {
savePassword(){
this.$refs.modForm.validate().then(()=>{
if( this.loading )
{
return;
}
this.loading = true;
var form = this.form;
this.$post(api.editorPassword,form).then(res=>{
this.loading = false;
if(res.code == api.code.OK)
{
this.$message.success('密码修改成功');
this.$refs.modForm.resetFields();
}else{
this.$message.error(res.msg);
}
}).catch(err=>{
this.loading = false;
this.$message.error(err.message);
});
}).catch(()=>{
})
},
checkPassword(rule, value, callback){
if(value == this.form.newPwd)
{
callback();
return;
}
callback(new Error('两次密码不一致'));
}
},
created() {
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,57 @@
<template>
<div class="subtitle-modelbox-widget">
<h3 class="section-title">
{{title}}
</h3>
<div class="sidebar-widget-body">
<slot></slot>
</div>
<!-- /.sidebar-widget-body -->
</div>
</template>
<style type="text/scss" scoped lang="scss">
.subtitle-modelbox-widget {
background-color: #fff;
box-shadow: 0 2px 4px 0 rgba(0,0,0,.08);
.section-title {
font-size: 20px;
font-family: 'Open Sans', sans-serif;
border-bottom: 1px solid #e3e3e3;
padding-bottom: 10px;
color: rgba(91,40,158,0.8);
text-transform: uppercase;
font-weight: bold;
margin-top: 0px;
padding-left: 20px;
padding-top: 20px;
}
.sidebar-widget-body{
padding: 20px;
}
}
</style>
<script>
export default {
name: "e-module-model-box",
data() {
return {
}
},
props:{
title:String
},
watch: {},
computed: {
},
methods: {},
created() {
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,72 @@
<template>
<div class="e-module-info">
<slot :data="data"></slot>
</div>
</template>
<style type="type/scss" lang="scss">
</style>
<script>
import api from '@/api'
export default {
name: "e-module-info",
data() {
return {
data:{}
}
},
props:{
module:String,
order:String,
where:Object,
field:String
},
watch: {
module(){
this.loadData();
},
order(){
this.loadData();
},
where(){
this.loadData();
},
field(){
this.loadData();
}
},
computed: {},
methods: {
loadData(){
var param = {};
if(this.where){
param.where = JSON.stringify(this.where);
}
if(this.order){
param.order = this.order;
}
if(this.field){
param.field = this.field;
}
param.limit = 1;
param.table = this.module;
this.$post(api.search.all , param).then(res=>{
if(res.code == 0 && res.data && res.data[0]){
this.data = res.data[0]
}
});
}
},
created() {
if(this.module){
this.loadData();
}
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,109 @@
<template>
<div class="e-news-info clearfix">
<div class="thumb" v-if="image" @click="$gotoUrl">
<div class="img-box pb100">
<div class="img" :style="{'background-image': 'url('+$getImage(image)+')'}"></div>
</div>
</div>
<div class="news-content-text" :class="{'not-thumb':!image}">
<h3 @click="$gotoUrl">{{title}}</h3>
<div class="description" v-html="$substr(description,len)">
</div>
<div class="other-content">
<slot></slot>
</div>
</div>
</div>
</template>
<style type="text/scss" lang="scss">
.e-news-info{
margin-bottom: 10px;
background: #ffffff;
position: relative;
.thumb{
float: left;
width: 120px;
}
.news-content-text{
margin-left: 130px;
h3{
cursor: pointer;
font-size: 14px;
margin: 0px;
margin-bottom: 10px;
font-weight: 700;
}
.description{
color: #7b7b7b;
}
.other-content{
position: absolute;
left: 130px;
bottom: 5px;
span{
display: inline-block;
margin-right: 8px;
}
}
}
.news-content-text.not-thumb{
margin-left: 0px;
}
}
@media screen and (max-width: 768px){
.e-news-info{
.thumb {
width: 100px;
}
.news-content-text {
margin-left: 110px;
.other-content {
left: 110px;
}
.description{
word-break:break-all;
display:-webkit-box;/**对象作为伸缩盒子模型展示**/
-webkit-box-orient:vertical;/**设置或检索伸缩盒子对象的子元素的排列方式**/
-webkit-line-clamp:2;/**显示的行数**/
overflow:hidden;/**隐藏超出的内容**/
}
}
}
}
</style>
<script>
import gotoUrl from "../mixins/gotoUrl";
export default {
name: "e-news-list",
data() {
return {}
},
mixins:[gotoUrl],
props:{
image:String,
title:String,
description:[String,Number],
len:{
type:Number,
default:30
}
},
watch: {},
computed: {
},
methods: {
},
created() {
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,200 @@
<template>
<div class="e-paper">
<div id="TypeFieldabc" v-if="isSelect">
<div style="border: 1px solid #ededed; border-radius: 5px; padding: 10px; background: #F2F2F2;">
<table class="table table-hover">
<thead>
<tr>
<th width="60">&nbsp;</th>
<th style="text-align: left">答案</th>
<!--<th width="80">跳转序号</th>-->
<th style="text-align: left" width="100">得分</th>
<th width="60">
<el-button size="mini" type="primary" @click="addItem"></el-button>
</th>
</tr>
</thead>
<tbody>
<tr v-for="(v,k) in paperList" :key="v.zimu">
<td style="text-align: right" v-text="v.zimu"></td>
<td>
<el-input size="mini" :value="v.title" @input="updatePaper($event,v,k,'title')"></el-input>
</td>
<td>
<el-input size="mini" :value="v.point" @input="updatePaper($event,v,k,'point')" type="number"></el-input>
</td>
<td>
<el-popconfirm icon="el-icon-info" iconColor="red" title="确定删除?" @confirm="deleteItem(k,v)" @onConfirm="deleteItem(k,v)">
<el-button size="mini" type="danger" slot="reference" icon="el-icon-delete-solid"></el-button>
</el-popconfirm>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<style type="text/scss" lang="scss">
</style>
<script>
import {extend, isArray} from "@/utils/extend";
export default {
name: "e-paper",
data() {
return {
isSelect:true
}
},
props:{
value:[String],
vo:Object,
type:String,
danxuanti:{
type:String,
default:''
},
duoxuanti:{
type:String,
default:''
},
panduanti:{
type:String,
default:''
},
correctText:{
type:String,
default:'正确'
},
errorText:{
type:String,
default:'错误'
},
},
watch:{
type( val ){
if(this.value.length == 0){
if(this.panduanti.indexOf(val) != -1)
{
//
//
if(this.paperList.length != 2 || this.paperList[0].title != this.correctText)
{
var obj = [
{
zimu:'A',
title:this.correctText,
point:0
},
{
zimu:'B',
title:this.errorText,
point:0
}
];
this.emitInput(obj);
}
this.isSelect = true;
}else if(this.danxuanti.indexOf(val) == -1 && this.duoxuanti.indexOf(val) == -1)
{
this.isSelect = false;
}else{
if(this.paperList.length == 0)
{
var obj = [
{
zimu:'A',
title:'',
point:0
},
{
zimu:'B',
title:'',
point:0
},
{
zimu:'C',
title:'',
point:0
},
{
zimu:'D',
title:'',
point:0
}
];
this.emitInput(obj);
}
this.isSelect = true;
}
}
}
},
computed: {
paperList(){
var value = this.value;
try{
value = JSON.parse(value);
}catch (e) {
value = [];
}
if(!isArray(value)){
value = [];
}
return value;
}
},
methods: {
updateZimu( paperList )
{
var zimu = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
var result = paperList ? paperList : extend(true,[],this.paperList);
for (var i=0;i<result.length;i++)
{
result[i].zimu = zimu.substr(i,1)
}
this.emitInput(result);
},
updatePaper($event , v , k , key ){
var result = extend(true,[],this.paperList);
var obj = {};
obj[key] = $event;
var nowObj = extend(true,{} , v , obj);
result[k] = nowObj;
this.emitInput(result);
},
emitInput(val){
this.$emit('input' , JSON.stringify(val))
},
addItem(){
var zimu = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
var result = extend(true,[],this.paperList);
var index = result.length;
var obj = {
zimu:zimu.substr(index,1),
title:'',
point:0
}
result.push(obj);
this.emitInput(result);
},
deleteItem(k){
var result = extend(true,[],this.paperList);
result.splice(k,1);
this.updateZimu(result);
}
},
created() {
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,24 @@
<template>
</template>
<style type="text/scss" lang="scss">
@import "./asset/icon/MKPlayer.scss";
</style>
<script>
export default {
name: "e-play-list",
data() {
return {}
},
watch: {},
computed: {},
methods: {},
created() {
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,363 @@
<template>
<div class="v-module-products">
<article>
<div class="pro-btn pro-btn-add" @click="$gotoUrl">
查看
</div>
<div :class="showType">
<div class="image" @click="$gotoUrl">
<e-img-box :src="image" :pb="imageHeight" :is-scale="isScale"></e-img-box>
</div>
<div class="text">
<h2 class="title h4">
<a href="javascript:;" @click="$gotoUrl">{{title}}</a>
</h2>
<sup v-if="price!=''" class="price"> {{price}}</sup>
<span class="description clearfix" v-text="$substr(description , 30)">
</span>
</div>
</div>
</article>
</div>
</template>
<style type="text/scss" scoped lang="scss">
.v-module-products{
article {
position: relative;
transition: all 0.3s;
overflow: hidden;
border: 1px solid #F5F4EF;
margin-left: -1px;
margin-top: -2px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.05);
border-radius: 8px;
.badge {
position: absolute;
top: 10px;
left: 10px;
line-height: initial;
color: white;
}
sub, sup {
font-size: 100%;
}
.text {
width: 100%;
padding: 10px;
}
.text a:hover {
color: #333;
}
.text .title {
display: block;
margin: 0;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
font-size: 14px;
margin-bottom: 5px;
}
.text sub,.text sup{
bottom: auto;
top: auto;
display: inline-block;
margin-right: 10px;
}
.text sub{
text-decoration: line-through;
font-weight: 300;
}
.image {
overflow: hidden;
height: auto;
a {
display: block;
}
}
.pro-btn-add {
opacity: 0;
transform: translate3d(100%, 0, 0);
transition: all 0.5s;
}
&:hover {
box-shadow: 0 3px 30px rgba(0, 0, 0, 0.1);
position: relative;
z-index: 22;
.pro-btn-add {
opacity: 1;
transform: translate3d(0, 0, 0);
}
.info > span {
transform: scale(1);
}
}
.info {
display: none;
position: absolute;
width: 35px;
right: 15px;
top: 15px;
margin-right: 0;
margin-top: 5px;
z-index: 3;
a {
position: relative;
display: inline-block;
padding: 0 5px;
background-color: dimgray;
color: white;
text-align: center;
border-radius: 30px;
width: 30px;
height: 30px;
line-height: 30px;
margin-bottom: 5px;
}
a:hover {
background-color: #000000;
color: white;
}
a:hover:after {
position: absolute;
content: attr(data-title);
padding: 5px 6px;
right: 110%;
top: 3px;
white-space: nowrap;
z-index: 20;
background-color: #000000;
color: #fff;
font-size: 10px;
border-radius: 5px;
line-height: normal;
}
.add-favorite.added {
transform: scale(1);
a {
background-color: #e71d36;
}
a:hover:after {
content: attr(data-title-added);
background-color: inherit;
}
}
> span {
display: block;
transition: all 0.3s;
transform: scale(0);
}
> span:nth-child(1) {
transition-delay: 0.1s;
}
> span:nth-child(2) {
transition-delay: 0.2s;
}
> span:nth-child(3) {
transition-delay: 0.3s;
}
}
.figure-list {
display: table;
width: 100%;
}
.figure-list .image,.figure-list .text{
display: table-cell;
vertical-align: middle;
width: 50%;
}
.figure-list .image{
width: 40%;
}
.figure-list .text {
width: 60%;
position: relative;
padding: 0 20px;
vertical-align: top;
padding-top: 20px;
.title {
white-space: inherit;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.description {
display: block;
margin-top: 15px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.price{
position: absolute;
right: 0px;
top: 10px;
}
}
.figure-grid {
.text .description {
display: none;
}
}
.figure-block{
.text .description {
position: relative;
display: none;
height: 80px;
overflow: hidden;
z-index: 1;
padding-top: 5px;
}
.text .description:after {
background: -moz-linear-gradient(top, rgba(255, 255, 255, 0) 0%, white 100%);
/* FF3.6-15 */
background: -webkit-linear-gradient(top, rgba(255, 255, 255, 0) 0%, white 100%);
/* Chrome10-25,Safari5.1-6 */
background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, white 100%);
/* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00ffffff', endColorstr='#ffffff',GradientType=0 );
/* IE6-9 */
position: absolute;
bottom: 0;
width: 100%;
height: 75px;
content: "";
display: block;
z-index: 2;
}
}
.container {
padding-left: 15px;
padding-right: 15px;
}
.title {
font-weight: 600;
position: relative;
}
.title small {
display: block;
text-transform: none;
color: black;
font-size: 40%;
margin: 5px 0;
}
.price {
margin-bottom: 20px;
}
.pro-btn {
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
display: inline-block;
font-weight: 400;
color: #212529;
text-align: center;
vertical-align: middle;
user-select: none;
background-color: transparent;
border: 1px solid transparent;
padding: 0.375rem 0.75rem;
font-size: 1rem;
line-height: 1.5;
border-radius: 12px;
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
.pro-btn.pro-btn-add {
background: #3c5570;
position: absolute;
overflow: hidden;
color: white;
bottom: 20px;
right: 10px;
border: 0;
font-size: 12px;
cursor: pointer;
z-index: 9;
}
.pro-btn.pro-btn-add:hover {
color: white;
}
.pro-btn:hover {
color: #212529;
text-decoration: none;
}
}
}
@media (min-width: 992px) {
.v-module-products article {
box-shadow: 0 3px 30px rgba(0, 0, 0, 0.1);
.info a {
margin-bottom: 10px;
}
.info {
display: block;
}
.figure-list .image {
padding: 0;
}
}
}
@media (min-width: 768px) {
.v-module-products article .badge {
top: 20px;
left: 20px;
}
}
</style>
<script>
import gotoUrl from "../mixins/gotoUrl";
export default {
name: "e-module-products",
data() {
return {}
},
props:{
image:String,
isScale:{
type:Boolean,
default:false
},
imageHeight:{
type:[String,Number],
default:80
},
title:String,
price:[String,Number],
description:[String,Number],
type:{
type:String,
default:'grid'
}
},
mixins:[gotoUrl],
watch: {},
computed: {
showType(){
switch (this.type) {
case 'grid':
return 'figure-grid';
default:
return 'figure-list';
}
}
},
methods: {
},
created() {
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,86 @@
<template>
<div class="MKPlayer-progress-box" @mousedown="mousedown">
<span class="MKPlayer-progress-slot"></span>
<span class="MKPlayer-progress-progress" :style="{width:value+'%'}"></span>
<span class="MKPlayer-progress-postion" :style="{left:value+'%'}"></span>
</div>
</template>
<style type="text/scss" lang="scss">
</style>
<script>
var {addEventListener} = require('add-dom-event-listener')
export default {
name: "progress",
data:function () {
return {
offset:{
x:0,
y:0,
width:0
},
isMove:false,
};
},
props:{
value:[Number],
lock:[Boolean]
},
methods:{
offsetLeft (element) {
var actualLeft = element.offsetLeft;
var current = element.offsetParent;
while (current) {
actualLeft += current.offsetLeft;
current = current.offsetParent;
}
return actualLeft;
},
mousedown (e) {
//
if(this.lock)return;
this.isMove = true;
this.offset.x = e.pageX;
this.offset.y = e.pageY;
this.offset.width = this.$el.offsetWidth;
this.offset.left = this.offsetLeft(this.$el)
},
mousemove(e){
var offset = this.offset;
var pageX = e.pageX;
var posX = pageX;
if(posX > offset.left + offset.width){
posX = offset.left + offset.width;
}
if(posX < offset.left)
{
posX = offset.left;
}
posX -= offset.left;
//
var val = ((posX / offset.width) * 100).toFixed(2);
this.$emit('input' , val)
this.$emit('changed' , val)
},
},
mounted() {
this.handlerMove = addEventListener(document.body , 'mousemove' , (e)=>{
if(!this.isMove){return;}
this.mousemove(e);
});
this.handlerUp = addEventListener(document.body , 'mouseup' , (e)=>{
if(!this.isMove){return;}
this.mousemove(e);
this.isMove = false;
});
},
beforeDestroy() {
this.handlerMove.remove();
this.handlerUp.remove();
}
}
</script>

@ -0,0 +1,55 @@
<template>
<el-radio-group v-model="select" @change="changeSelect" :disabled="disabled">
<el-radio v-for="v in list" :label="v.zimu"> {{ v.zimu }} {{ v.title }} </el-radio>
</el-radio-group>
</template>
<script>
import {findObject} from "@/utils/utils";
export default {
name: "t-radio",
data () {
return {
select:'',
}
},
props:{
obj:Object,
paper:String,
daan:String,
disabled:{
type:Boolean,
default:false
}
},
computed:{
list(){
if(!this.paper){
return [];
}
return eval("("+this.paper+")")
}
},
methods:{
changeSelect(val){
if(val){
var obj = findObject(this.list , r=> r.zimu == val );
this.obj.zimu = obj.zimu;
this.obj[this.daan] = obj.title;
this.obj.defen = obj.point === undefined ? obj.defen : obj.point;
}else{
this.obj.zimu = '';
this.obj[this.daan] = '';
this.obj.defen = 0;
}
}
}
}
</script>
<style scoped>
</style>

@ -0,0 +1,176 @@
<template>
<div class="e-select-list">
<div class="select-update">
<div>
<el-select @change="$emit('input' , $event)" :value="value" filterable>
<el-option :value="0" label="请选择"></el-option>
<el-option :value="v.id" :label="getLabel(v)" v-for="v in list" :key="v.id"></el-option>
</el-select>
</div>
<div>
关键词
<el-input style="width: 150px" v-model="searchMsg.keyword" />
</div>
<div>
<slot name="search"></slot>
</div>
<!--<div class="search-list" ref="search">
</div>-->
<div class="search-btn">
<el-button icon="el-icon-search" @click="searchTable(true)">
搜索
</el-button>
</div>
</div>
<div class="" v-if="value!=0">
<slot>
</slot>
</div>
</div>
</template>
<style type="text/scss" lang="scss">
.e-select-list{
.select-update{
display: flex;
flex-wrap:wrap;
>div{
margin-right: 10px;
}
>div:last-child{
margin-right: 0px;
}
}
.search-list{
}
}
</style>
<script>
import api from "@/api";
import { empty, isArray ,isObject} from "@/utils/extend";
import {findObject} from "@/utils/utils";
export default {
name: "e-select-list",
data() {
return {
list:[],
searchMsg:{
keyword:''
}
}
},
props:{
value:[String,Number],
model:{
type:Object,
required:true
},
module:{
type:String,
required: true
},
selectUpdate:[String,Array],
searchUpdate:{
type:[String,Array],
default:''
},
showField:{
type:[String,Array]
}
},
watch: {
value(val){
this.selectOption(val);
}
},
computed: {
},
methods: {
selectOption(value){
var v = findObject(this.list , r=>r.id == value );
if( v !== false ){
this.updateModel(v);
}else{
if(value == 0){
this.updateModel({});
}else{
this.$post(api.search.table , {id:value}).then(res=>{
if(!empty(res) && isObject(res)){
this.list.push(res);
this.updateModel(res);
}
}).catch(err=>{
this.$message.error(err.message)
})
}
}
},
updateModel(v){
var field = isArray(this.selectUpdate) ? this.selectUpdate : this.selectUpdate.split(',');
for (var i=0;i<field.length;i++)
{
var f = field[i];
if( f ){
var def = /(^[0-9]+$)/.test(this.model[f]) && this.model[f].length<11 ? 0 : '';
this.model[f] = v[f] !== undefined ? v[f] : def;
}
}
},
getLabel(v){
var result = '';
var field = [];
if(this.showField){
field = isArray(this.showField) ? this.showField : this.showField.split(',').filter(v=>!empty(v))
}else{
field = isArray(this.selectUpdate) ? this.selectUpdate : this.selectUpdate.split(',')
}
//var field = isArray(this.selectUpdate) ? this.selectUpdate : this.selectUpdate.split(',')
for (var i=0;i<field.length;i++)
{
var f = field[i];
if(f && v[f]){
result += v[f]+' - ';
}
}
return result;
},
searchTable(isEmit){
var where = {};
var field = isArray(this.selectUpdate) ? this.selectUpdate : this.selectUpdate.split(',')
var ext = isArray(this.searchUpdate) ? this.searchUpdate : this.searchUpdate.split(',')
var fs = field.concat(ext).filter(f=>f!='');
where[fs.join('|')] = [ 'like' , '%'+this.searchMsg.keyword+'%'];
this.$emit('update-where' , where);
return new Promise((resolve, reject) => {
this.$post(api.search.select , {
table:this.module,
where:JSON.stringify(where)
}).then(res=>{
if(isEmit){
this.$emit('input' , 0);
}
this.list = res;
resolve(res)
}).catch(err=>{
reject(err.message);
});
});
}
},
created() {
this.searchTable().then(res=>{
if(this.value){
this.selectOption(this.value)
}
});
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,69 @@
<template>
<span class="e-select-view">
{{content}}
</span>
</template>
<style type="text/scss" lang="scss">
</style>
<script>
import api from "@/api";
export default {
name: "e-select-view",
data() {
return {
content:''
}
},
props:{
value:[String,Number],
module:{
type:String,
required:true
},
select:{
type:[String,Number],
required: true
},
show:{
type:[String,Number],
required: true
}
},
watch: {
value(){
this.getValue();
}
},
computed: {},
methods: {
getValue(){
if(this.value){
this.$post(api.search.selectView , {
table:this.module,
key:this.select,
value:this.value
}).then(res=>{
if(res.code == api.code.OK && res.data)
{
this.content = res.data[this.show];
}else{
this.content = '';
}
})
}else{
this.content = '';
}
}
},
created() {
this.getValue();
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,33 @@
<template>
<div class="e-shangpinban">
<el-carousel indicator-position="outside">
<el-carousel-item v-for="item in items" v-if="item" :key="item">
<e-img :src="item"></e-img>
</el-carousel-item>
</el-carousel>
</div>
</template>
<style type="text/scss" lang="scss">
</style>
<script>
export default {
name: "e-shangpinban",
data() {
return {}
},
props:{
images:String
},
watch: {},
computed: {
items(){
if(this.images) {
return this.images.split(",")
}
return [];
}
},
}
</script>

@ -0,0 +1,35 @@
<template>
<div class="e-spec">
<el-select v-model="values" multiple
filterable
allow-create
default-first-option
placeholder="请设置"></el-select>
</div>
</template>
<style type="text/scss" lang="scss">
</style>
<script>
import {empty} from "@/utils/extend";
export default {
name: "e-spec",
data() {
return {}
},
props:{
value:String
},
computed: {
values:{
get(){
return this.value.split(',').filter(v=>!empty(v))
},
set(val){
this.$emit('input' , val.join(','))
}
}
}
}
</script>

@ -0,0 +1,23 @@
<template>
<el-input v-model="obj.daan" type="textarea" />
</template>
<script>
export default {
name: "t-textarea",
props:{
obj:Object
},
created(){
var obj = this.obj;
this.$set(obj , 'defen' , -1);
this.$set(obj , 'zimu' , '');
this.$set(obj , 'daan' , '');
}
}
</script>
<style scoped>
</style>

@ -0,0 +1,107 @@
<template>
<div class="e-tree">
<tree-select
:options="list"
placeholder="请选择分类..."
:value="value"
@input="$emit('input' , $event)"
/>
</div>
</template>
<style type="text/scss" lang="scss">
</style>
<script>
import api from "@/api";
import {each, empty} from "@/utils/extend";
import TreeSelect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
export default {
name: "e-tree",
data() {
return {
list:[]
}
},
components:{
TreeSelect
},
props:{
value:[String,Number],
module:{
type:String,
required:true
},
isParent:{
type:Boolean,
default:false
},
parentName:{
type:String,
default:'顶级分类'
},
label:{
type:String,
required: true
},
pid:{
type:String,
required: true
}
},
watch: {},
computed: {},
methods: {
loadSelectList(){
this.$post(api.search.all,{
table:this.module,
order:'id asc'
}).then(res=>{
if(res.code == api.code.OK)
{
var result = this.loadChildren(res.data , 0);
if(this.isParent){
result.unshift({
id:'0',
label:this.parentName
});
}
this.list = result
}
});
},
loadChildren( list , parentid ){
var result = this.getChild(list , parentid);
//var length = list.length;
each(result , (i,obj)=>{
var child = this.loadChildren(list , obj.id);
if(!empty(child)){
obj.isDefaultExpanded = true;
obj.children = child;
}
})
return result;
},
getChild(list , parentid){
var result = [];
//var length = list.length;
each(list , (i,obj)=>{
if(obj[this.pid] == parentid)
{
obj.label = obj[this.label];
result.push(obj);
}
})
return result;
}
},
created() {
this.loadSelectList();
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,64 @@
<template>
<el-upload
v-loading="loading"
class="upload-file"
element-loading-text="上传中"
drag
action="https://127.0.0.1"
:before-upload="beforeUpload"
:multiple="multiple" :show-file-list="false">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<div class="el-upload__text success" v-if="value!=''"><i class="el-icon-success"></i>已上传</div>
</el-upload>
</template>
<style type="text/scss" lang="scss">
.upload-file{
.success{
color: #108210!important;
font-size: 18px!important;
}
}
</style>
<script>
import api from "@/api";
export default {
name: "e-upload-file",
data() {
return {
loading:false
}
},
props:{
value:String,
multiple:{
type:Boolean,
default:false
}
},
watch: {},
computed: {},
methods: {
beforeUpload(file){
this.loading = true;
api.attachment.upload(file).then(file=>{
this.loading = false;
this.$emit('input' , file)
}).catch(err=>{
this.loading = false;
this.$message.error(err);
});
return false;
}
},
created() {
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,120 @@
<template>
<div v-loading="loading" element-loading-text="上传中" class="avatar-uploader">
<el-upload
action="https://127.0.0.1"
drag
:show-file-list="false"
:before-upload="beforeAvatarUpload">
<e-img v-if="value" :src="value" class="avatar"/>
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
<div contentEditable="true" ref="divimg" @keydown="hookKey" @keyup="hookKey" @paste.prevent.stop="Paste">点我按Ctrl+V粘贴</div>
</div>
</template>
<style type="text/scss" lang="scss">
$width:150px;
.avatar-uploader{
width: $width;
}
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
.el-upload-dragger{
width: auto;
height: auto;
}
}
.avatar-uploader .el-upload:hover {
border-color: #409EFF;
}
.avatar-uploader-icon {
font-size: 38px;
color: #8c939d;
width: $width;
height: $width;
line-height: $width;
text-align: center;
}
.avatar {
width: $width;
height: $width;
display: block;
}
</style>
<script>
import api from "@/api";
import EImg from "@/components/image/img";
export default {
name: "e-upload-image",
components: {EImg},
data() {
return {
loading:false,
//imageUrl:''
}
},
props: {
value:String
},
computed: {},
methods: {
beforeAvatarUpload(file) {
this.loading = true;
api.attachment.upload(file).then(file=>{
this.loading = false;
this.$emit('input' , file);
}).catch(err=>{
this.loading = false;
this.$message.error(err);
})
return false;
},
hookKey(e){
if(!e.ctrlKey){
e.preventDefault();
}
},
Paste(e){
var items = this.getPasteImage(e);
if(items){
for (var i=0;i<items.length;i++)
{
var file = items[i];
if (file.getAsFile) file = file.getAsFile();
if (file && file.type && /^image\//.test(file.type) && file.size > 0) {
this.beforeAvatarUpload(file);
}
}
}
},
getPasteImage(e) {
var ret = false;
if (e.clipboardData && e.clipboardData.items) {
for (var i = 0; i < e.clipboardData.items.length; i++) {
if (/^image\//.test(e.clipboardData.items[i].type)) {
ret = true;
break;
}
}
}
return ret ? e.clipboardData.items : null;
}
},
created() {
},
mounted() {
},
beforeDestroy() {
}
}
</script>

@ -0,0 +1,124 @@
<template>
<div class="e-upload-images" v-loading="loading">
<el-upload list-type="picture-card" :show-file-list="false" action="#" multiple :before-upload="beforeUpload">
<i slot="trigger" class="el-icon-plus"></i>
<draggable class="el-upload-list el-upload-list--picture-card" element="ul" v-model="fileList" :options="dragOptions" @start="isDragging=true" @end="isDragging=false">
<li tabindex="0" class="el-upload-list__item is-ready" v-for="img in imagesUrl()" :key="img">
<div>
<e-img :src="img" alt="" class="el-upload-list__item-thumbnail" />
<div class="el-upload-list__item-actions">
<span class="el-upload-list__item-preview" @click="Preview(img)"><i class="el-icon-zoom-in"></i></span>
<span class="el-upload-list__item-delete" @click="download(img)"><i class="el-icon-download"></i></span>
<el-popconfirm title="确定删除该图片?" @confirm="deleteImage(img)" @onConfirm="deleteImage(img)">
<span class="el-upload-list__item-delete" slot="reference"><i class="el-icon-delete"></i></span>
</el-popconfirm>
</div>
</div>
</li>
</draggable>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<e-img width="100%" :src="dialogImageUrl" alt=""/>
</el-dialog>
</div>
</template>
<style type="text/scss" scoped lang="scss">
.e-upload-images {
.el-upload-list{
margin-left: 10px;
}
.el-upload {
margin-right: 20px;
margin-bottom: 20px;
text-align: center;
img {
max-width: 100%;
max-height: 100%;
}
}
}
</style>
<script>
import {isArray} from "@/utils/extend";
import api from "@/api";
import EImg from "@/components/image/img";
import {formatImageSrc} from "@/utils/utils";
import draggable from 'vuedraggable'
const path = require('path')
export default {
name: "e-upload-images",
components: {EImg,draggable},
data() {
return {
dragOptions:{
},
isDragging:false,
dialogVisible:false,
dialogImageUrl:'',
loading: false
}
},
props: {
value: [String, Array]
},
computed:{
fileList:{
get(){
return this.imagesUrl();
},
set(val){
this.$emit('input' , val.join(','))
}
}
},
watch: {},
methods: {
Preview(file){
this.dialogImageUrl = file;
this.dialogVisible = true;
},
download(file){
var a = document.createElement('a');
a.href = formatImageSrc(file);
a.setAttribute("download" , path.basename(file));
a.target = '_blank'
a.click();
},
deleteImage( file ){
var images = this.imagesUrl().filter( f=>f!=file )
this.$emit('input' , images.join(','))
},
imagesUrl() {
var images = this.value;
if (!isArray(images)) {
images = images.split(",");
}
return images.filter(s => s != '');
},
beforeUpload(file) {
this.loading = true;
api.attachment.upload(file).then(f => {
this.loading = false;
var images = this.imagesUrl();
images.push(f);
this.$emit('input', images.join(','));
}).catch(err => {
this.loading = false;
this.$message.error(err);
})
return false;
}
},
created() {
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,78 @@
<template>
<div class="e-video" style="width: 100%;height: 100%">
<video-player :playsinline="true" style="width: 100%;height: 100%" :options="playerOption"></video-player>
</div>
</template>
<style type="text/scss" lang="scss">
</style>
<script>
import {formatImageSrc} from "@/utils/utils";
export default {
name: "e-video",
data() {
return {
playerOption: {
muted: false,
autoplay: true,
loop: false,
preload: 'auto',
aspectRatio: '16:9',
fluid: true,
width: '100%',
height: '100%',
language: 'zh-CN',
playbackRate: 1.0,
playbackRates: [0.7, 1.0, 1.5, 2.0],
sources: '',
poster: require('./poster.jpg'),
controlBar: {
timeDivider: true,
durationDisplay: true,
remainingTimeDisplay: false,
fullscreenToggle: true //
}
}
}
},
props:{
src:String,
poster:String,
autoplay:{
type:Boolean,
default:true
},
},
watch: {
autoplay:{
handler(val){
this.playerOption.autoplay = val;
},
immediate:true
},
src:{
handler(val){
this.playerOption.sources = formatImageSrc(val)
},
immediate:true
},
poster:{
handler(val){
this.playerOption.poster = val;
},
immediate:true
}
},
computed: {},
methods: {},
created() {
},
mounted() {
},
destroyed() {
}
}
</script>

@ -0,0 +1,240 @@
<template>
<article class="single_product v-module-xiezi">
<figure>
<div class="product_thumb" @click="$gotoUrl">
<div class="label_product">
<span class="label_new" v-if="isNew"></span>
<span class="label_sale" v-if="isBest"></span>
</div>
<a class="primary_img img-box" :class="['pb'+imageHeight , (isScale?'img-scale':'')]" href="javascript:;">
<div class="img" :style="{'background-image': 'url('+$getImage(image)+')'}">
</div>
</a>
<a class="secondary_img img-box" v-if="image2" :class="['pb'+imageHeight , (isScale?'img-scale':'')]" href="javascript:;">
<div class="img" :style="{'background-image': 'url('+$getImage(image2)+')'}">
</div>
</a>
</div>
<figcaption class="product_content">
<h4 class="product_name"><a href="javascript:;" @click="$gotoUrl"> {{title}}</a></h4>
<div class="price_box" v-if="price">
<span class="current_price" v-if="price">{{price}}</span>
<span class="old_price" v-if="oldPrice">{{oldPrice}}</span>
</div>
<div class="add_to_cart">
<a href="javascript:;" title="查看详情">查看详情</a>
</div>
</figcaption>
</figure>
</article>
</template>
<style type="text/scss" scoped lang="scss">
.v-module-xiezi{
figure{
padding: 0px;
margin: 0px;
}
&.single_product{
border: 1px solid #e5e5e5;
border-radius: 30px;
transition: .3s;
background: #ffffff;
.product_name{
margin: 0px;
padding: 0px;
height: 45px;
line-height: 18px;
overflow: hidden;
}
.product_thumb {
position: relative;
overflow: hidden;
border-top-left-radius: 30px;
border-top-right-radius: 30px;
text-align: center;
a.secondary_img {
position: absolute;
top: 0;
left: 0;
right: 0;
opacity: 0;
visibility: hidden;
-moz-transition: all 0.3s ease-in-out 0s;
transition: all 0.3s ease-in-out;
}
a {
display: inline-block;
}
}
.add_to_cart {
position: absolute;
left: 0;
right: 0;
bottom: 20px;
opacity: 0;
visibility: hidden;
transition: .3s;
a {
font-size: 13px;
font-weight: 500;
line-height: 36px;
border: 1px solid #e5e5e5;
color: #454545;
background: #fff;
padding: 0 30px;
border-radius: 25px;
display: inline-block;
text-align: center;
text-transform: uppercase;
font-family: "Oswald", sans-serif;
}
a:hover {
color: #fff;
background: #F53737;
border-color: #F53737;
}
}
.label_product {
span {
position: absolute;
z-index: 9;
}
span.label_sale {
top: 15px;
right: 13px;
text-transform: uppercase;
color: #ffffff;
background: #F53737;
font-size: 12px;
font-weight: 600;
height: 24px;
line-height: 24px;
width: 56px;
text-align: center;
display: block;
border-radius: 18px;
}
span.label_new {
top: 15px;
left: 13px;
text-transform: uppercase;
color: #ffffff;
background: #46ce91;
font-size: 12px;
font-weight: 600;
height: 24px;
line-height: 24px;
width: 56px;
text-align: center;
display: block;
border-radius: 18px;
}
}
.product_content {
text-align: center;
padding: 17px 15px 40px 15px;
position: relative;
h4 {
font-size: 14px;
line-height: 24px;
font-weight: 500;
text-transform: capitalize;
margin: 0;
a:hover {
color: #F53737;
}
}
}
.price_box {
margin-top: 17px;
span {
line-height: 16px;
font-family: "Oswald", sans-serif;
}
span.old_price {
text-decoration: line-through;
font-weight: 400;
font-size: 14px;
margin-left: 5px;
}
span.current_price {
font-weight: 500;
font-size: 16px;
color: #F53737;
}
}
&:hover {
box-shadow: 0 0 9px 1px rgba(0, 0, 0, 0.12);
.add_to_cart {
opacity: 1;
visibility: visible;
bottom: 27px;
}
.product_thumb a.secondary_img {
opacity: 1;
visibility: visible;
-moz-transition: all 0.3s ease-in-out 0s;
transition: all 0.3s ease-in-out;
}
.swatches-colors {
opacity: 1;
visibility: visible;
}
}
}
}
</style>
<script>
import gotoUrl from "../mixins/gotoUrl";
export default {
name: "e-module-xiezi",
data() {
return {}
},
mixins:[gotoUrl],
props:{
image:String,
image2:String,
isScale:{
type:Boolean,
default:false
},
imageHeight:{
type:[String,Number],
default:80
},
title:String,
price:[String,Number],
oldPrice:[String,Number],
isNew:{
type:Boolean,
default:false
},
isBest:{
type:Boolean,
default:false
}
},
watch: {},
computed: {},
methods: {},
created() {
},
mounted() {
},
destroyed() {
}
}
</script>
Loading…
Cancel
Save