Vue-Element和YII搭建后台
花3周空余时间做了一件事:看vue的官方文档然后用vue开发后台页面,更熟练了vue一些语法等感觉核心有两块:数据绑定,组件;
然后看公司的一位同事在用vue-element开发新后台,然后我自己就想着用vue-element去开发一套后台系统,然后就去看vue-element的文档,网上有一整套的vue-element-admin后台系统在自己的电脑上安装运行了,但是这套后台系统的数据需要请求接口去完成(现实中不太可能去开发后台接口),我自己将原来用YII框架搭建的后台植入vue-element,需要注意的几个问题:
1.vue-element对变量的类型(整数/字符串)有区分限制;
2.axios({.....}) 跨域问题,Vue支持axios和ajax两种写法;
3.尽量不要用watch方法来监听数据变化,据说耗性能;
4.请求url报错400,是我YII对POST和FILE的安全过滤;
5.POST请求有3种请求头:application/json;charset=UTF-8;application/x-www-form-urlencoded;等
主要功能:增删改查:列表,搜索,分页,二级下拉联动,导出,时间控件,弹层,上传图片,保存,外链等常用基本功能:
vue官方文档地址:https://cn.vuejs.org/v2/guide/
vue-element官方文档地址:https://element.faas.ele.me/#/zh-CN/component/layout
建议大家先看文档,我大概看了2遍吧;先看一下效果:
搜索后:
编辑:联动下拉框,上传多张图,各种开关按钮,时间控件(vue-element提供源码和示例)等
弹层:
由于代码较多,我这里就只上传前端页面,稍后我会把相关代码上传到github上。
php代码我就不贴出来了,我就简单贴出列表页面前端代码(并附上注释说明):index.html
<?php
use yii\helpers\Url;
$this->title = '测试》测试订单列表';
$this->params['breadcrumbs'][] = $this->title;
?>
<style>
.filter-container {
padding-bottom: 10px;
padding-top: 10px;
}
.filter-container .filter-item {
display: inline-block;
vertical-align: middle;
margin-bottom: 10px;
}
.user {
background: #f0f9eb;
}
.parent {
background: #F9F9EB;
}
.total {
/*background: #F9F2EB;*/
}
</style>
<div id="app">
<div class="filter-container">
<el-form :inline="true" :model="listQuery" class="demo-form-inline" >
<el-form-item label="用户id">
<el-input v-model="listQuery.user_id" placeholder="user_id" clearable></el-input>
</el-form-item>
<programme-select :detail="true" :programme_id.sync="listQuery.programme_id"
:programme_child_id.sync="listQuery.level_id"></programme-select>
<el-form-item label="操作时间">
<date-picker class="filter-item" :start_time.sync="listQuery.start_time" :end_time.sync="listQuery.end_time"/>
</el-form-item>
<el-form-item>
<!--点击事件@click.....-->
<el-button type="primary" @click="fetchData" icon="el-icon-search">查询</el-button>
<el-button type="warning" @click="exportData" icon="el-icon-download">导出</el-button>
</el-form-item>
</el-form>
</div>
<div>
<el-table v-loading="listLoading" :data="list" style="width: 100%;"
:cell-class-name="cellClassName">
<el-table-column align="center" label="订单id" width="60">
<template slot-scope="scope">{{scope.row.serial_id}}</template>
</el-table-column>
<el-table-column align="center" label="支付状态">
<template slot-scope="scope">
<el-tag :type="scope.row.pay_status | opClass"> {{scope.row.pay_status | opFilter }}</el-tag>
</template>
</el-table-column>
<el-table-column align="center" label="用户昵称">
<template slot-scope="scope">
{{ scope.row.nick_name?scope.row.nick_name :'-'}}
</template>
</el-table-column>
<el-table-column align="center" label="用户信息">
<el-table-column align="center" label="user_id" width="120">
<template slot-scope="scope">
<a target="_blank" :href="'/fxuser/index?user_id='+ scope.row.user_id" v-if="scope.row.user_id">
<el-button type="text" > {{scope.row.user_id}}</el-button>
</a>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column align="center" label="手机号">
<template slot-scope="scope">
{{scope.row.mobile_phone_number?scope.row.mobile_phone_number:'-'}}
</template>
</el-table-column>
</el-table-column>
<el-table-column align="center" label="分销信息">
<el-table-column align="center" label="等级id">
<template slot-scope="scope">
{{scope.row.mobile_phone_number?scope.row.level_id:0}}
</template>
</el-table-column>
<el-table-column align="center" label="等级名称">
<template slot-scope="scope">
{{scope.row.mobile_phone_number?scope.row.level_name:'-'}}
</template>
</el-table-column>
<el-table-column align="center" label="等级值">
<template slot-scope="scope">
{{scope.row.mobile_phone_number?scope.row.level_nums:'-'}}
</template>
</el-table-column>
</el-table-column>
<el-table-column align="center" label="下单时间">
<template slot-scope="scope">
{{ scope.row.create_time | parseTime }}
</template>
</el-table-column>
<el-table-column align="center" label="操作" width="350">
<template slot-scope="scope">
<el-button size="mini" @click="deleteData(scope.row.serial_id)" icon="el-icon-delete-solid">删除</el-button>
<a :href="'/user/edit-info?serial_id='+ scope.row.serial_id">
<el-button size="mini" icon="el-icon-edit">编辑</el-button>
</a>
<el-button size="mini" icon="el-icon-tickets">弹层</el-button>
<a target="_blank" :href="'/user/link-target?user_id='+ scope.row.serial_id">
<el-button size="mini" icon="el-icon-link">链接</el-button>
</a>
</template>
</el-table-column>
</el-table>
<!--这里分页 总数一定要整数型 字符串会出不来-->
<pagination :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit"
@pagination="fetchData"/>
</div>
</div>
<script type="module">
new Vue({
el: '#app',
components: { //引用外部组件: 分页/事件/公共模块(封装方法httpVueLoader来导入)
Pagination: httpVueLoader('/vue/common/pagination.vue'),
DatePicker: httpVueLoader('/vue/common/datepicker.vue'),
ProgrammeSelect: httpVueLoader('/vue/common/programme_select.vue'),
},
filters: {
opFilter(pay_status) { //数据格式化
switch (parseInt(pay_status)) {
case 0:
return '支付成功';
case 1:
return '支付失败';
default:
return '未知';
}
},
opClass(pay_status) {
switch (parseInt(pay_status)) {
case 0:
return 'warning';
case 1:
return 'danger';
default:
return 'info';
}
}
},
data() {
return {
list: [],
total: 0,
listLoading: false,
listQuery: {
page: 1,
limit: 10,
user_id: undefined,
start_time: undefined,
end_time: undefined,
nickname: undefined,
programme_id: -1,
level_id: undefined
}
}
},
created() {
const user_id = "<?=$user_id?>"
if (user_id) {
this.listQuery.user_id = user_id
}
this.fetchData()
this.$ELEMENT.size = size
},
methods: {
fetchData() {
this.listLoading = true
axios({ //ajax写法 比ajax简单,参数有三种请求头header
method: 'get',
url: "<?=Url::toRoute(['user/orders'])?>",
params: this.listQuery
}).then(response => {
console.log(response);
const data = response.data
if (data.code !== 200) {
this.$notify.error({
title: '错误1122',
message: data.msg
});
this.listLoading = false
return
}
this.list = data.list
this.total = data.total
this.listLoading = false
}).catch(error => {
this.listLoading = false
this.$message.error(error.message)
});
},
cellClassName({row, column, rowIndex, columnIndex}) { //列的颜色
if (columnIndex >= 3 && columnIndex < 5) {
return 'parent'
}
if (columnIndex >= 5 && columnIndex < 8) {
return 'user'
}
return 'total'
},
exportData() { //导出
const query = this.listQuery
this.$notify.success({
title: 'Success',
message: '正在导出,请稍等...',
onClose: function () {
query.limit = undefined
query.page = undefined
const p = JSON.stringify(query)
const url = p ? "<?=Url::toRoute(['user/export?'])?>" + p : '/fx/user/export'
let link = document.createElement('a')
link.style.display = 'none'
link.href = url
document.body.appendChild(link)
link.click()
},
duration: 0.5 * 1000
});
},
deleteData(serial_id) {
console.log(serial_id); //31378
this.listLoading = true
axios({
method: 'get',
url: "<?=Url::toRoute(['user/delete-data?serial_id='])?>" + serial_id,
params: this.listQuery
}).then(response => {
console.log(response);
if (response.data.code !== 200) {
this.$notify.error({
title: '错误1122',
message: response.data.msg
});
this.listLoading = false
return
}else{
this.$notify.success({
title: 'Success',
message: '删除成功',
});
//location.reload() //刷新当前页面 jquery写法
this.fetchData() //再次调取列表函数
}
}).catch(error => {
this.listLoading = false
this.$message.error(error.message)
});
}
}
})
</script>
上面只是列表分页的html,编辑页面在附件里,大家可以去vue-element官网去看一下文档有实例和代码还是很方便的不是太难,https://element.faas.ele.me/#/zh-CN/component/layout