提交 6b32c113 编写于 作者: M maguohua

add a lot code

上级 5a3beddd
# project
此项目是 [后台项目node-elm](https://github.com/bailicangdu/node-elm) 的数据管理系统。配合[前台项目vue2-elm](https://github.com/bailicangdu/vue2-elm)组成一个 后台系统 + 数据管理 + 前台展示 的完整流程。
此项目是后台项目[node-elm](https://github.com/bailicangdu/node-elm) 的数据管理系统。配合前台项目[vue2-elm](https://github.com/bailicangdu/vue2-elm)组成一个 后台系统 + 数据管理 + 前台展示 的完整流程。
# 说明
......@@ -49,11 +49,11 @@ npm run dev
- [x] 登陆/注销
- [x] 添加商铺
- [x] 添加商品
- [x] 数据展示
- [x] 管理用户
- [x] 管理商铺
- [x] 食品管理
- [ ] 权限验证
- [ ] 数据展示
- [ ] 管理用户
- [ ] 管理商铺
- [ ] 地区管理
- [ ] 管理员设置
- [ ] 图表📈
- [ ] 上传文件
......
......@@ -43,5 +43,115 @@ const addCategory = data => fetch('/shopping/addcategory', data, 'POST');
const addFood = data => fetch('/shopping/addfood', data, 'POST');
export { cityGuess, addShop, searchplace, getCategory, addCategory, addFood }
/**
* category 种类列表
*/
const foodCategory = (latitude, longitude) => fetch('/shopping/v2/restaurant/category');
/**
* 获取餐馆列表
*/
const getResturants = data => fetch('/shopping/restaurants', data);
/**
* 获取餐馆详细信息
*/
const getResturantDetail = restaurant_id => fetch('/shopping/restaurant/' + restaurant_id);
/**
* 获取餐馆数量
*/
const getResturantsCount = () => fetch('/shopping/restaurants/count');
/**
* 更新餐馆信息
*/
const updateResturant = data => fetch('/shopping/updateshop', data, 'POST');
/**
* 删除餐馆
*/
const deleteResturant = restaurant_id => fetch('/shopping/restaurant/' + restaurant_id, {}, 'DELETE');
/**
* 获取食品列表
*/
const getFoods = data => fetch('/shopping/v2/foods', data);
/**
* 获取食品数量
*/
const getFoodsCount = data => fetch('/shopping/v2/foods/count', data);
/**
* 获取menu列表
*/
const getMenu = data => fetch('/shopping/v2/menu', data);
/**
* 获取menu列表
*/
const getMenuById = category_id => fetch('/shopping/v2/menu/' + category_id);
/**
* 更新食品信息
*/
const updateFood = data => fetch('/shopping/v2/updatefood', data, 'POST');
/**
* 删除食品
*/
const deleteFood = food_id => fetch('/shopping/v2/food/' + food_id, {}, 'DELETE');
/**
* 获取用户列表
*/
const getUserList = data => fetch('/v1/users/list', data);
/**
* 获取用户数量
*/
const getUserCount = data => fetch('/v1/users/count', data);
/**
* 获取订单列表
*/
const getOrderList = data => fetch('/bos/orders', data);
/**
* 获取订单数量
*/
const getOrderCount = data => fetch('/bos/orders/count', data);
/**
* 获取订单数量
*/
const getUserInfo = user_id => fetch('/v1/user/' + user_id);
/**
* 获取订单数量
*/
const getAddressById = address_id => fetch('/v1/addresse/' + address_id);
export { cityGuess, addShop, searchplace, getCategory, addCategory, addFood, foodCategory ,getResturants, getResturantDetail, getResturantsCount, updateResturant, deleteResturant, getFoods, getFoodsCount, getMenu, updateFood, getMenuById, deleteFood, getUserList, getUserCount, getOrderList, getOrderCount, getUserInfo, getAddressById}
......@@ -3,20 +3,21 @@
*
* baseUrl: 域名地址
* routerMode: 路由模式
* baseImgPath: 图片存放地址
*
*/
let baseUrl;
let routerMode;
let routerMode = 'hash';
let baseImgPath = 'http://images.cangdu.org/';
if (process.env.NODE_ENV == 'development') {
baseUrl = 'http://localhost:8001';
routerMode = 'hash'
}else{
baseUrl = 'http://cangdu.org:8001';
routerMode = 'hash'
}
export {
baseUrl,
routerMode,
baseImgPath
}
\ No newline at end of file
......@@ -50,11 +50,11 @@
<el-form-item label="上传店铺头像">
<el-upload
class="avatar-uploader"
:action="baseUrl + '/shopping/addimg/food'"
:action="baseUrl + '/v1/addimg/food'"
:show-file-list="false"
:on-success="uploadImg"
:before-upload="beforeImgUpload">
<img v-if="foodForm.image_path" :src="baseUrl + foodForm.image_path" class="avatar">
<img v-if="foodForm.image_path" :src="baseImgPath + foodForm.image_path" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
......@@ -137,12 +137,13 @@
<script>
import headTop from '@/components/headTop'
import {getCategory, addCategory, addFood} from '@/api/getData'
import {baseUrl} from '@/config/env'
import {baseUrl, baseImgPath} from '@/config/env'
export default {
data(){
return {
baseUrl,
restaurant_id: 3,
baseImgPath,
restaurant_id: null,
categoryForm: {
categoryList: [],
categorySelect: '',
......@@ -188,10 +189,19 @@
}
}
},
beforeRouteEnter (to, from, next) {
if (to.query.restaurant_id) {
next()
}else{
alert('请先选择店铺');
next('/shopList');
}
},
components: {
headTop,
},
mounted(){
created(){
this.restaurant_id = this.$route.query.restaurant_id;
this.initData();
},
computed: {
......
......@@ -26,6 +26,13 @@
<el-form-item label="店铺标语" prop="promotion_info">
<el-input v-model="formData.promotion_info"></el-input>
</el-form-item>
<el-form-item label="店铺分类">
<el-cascader
:options="categoryOptions"
v-model="selectedCategory"
change-on-select
></el-cascader>
</el-form-item>
<el-form-item label="店铺特点" style="white-space: nowrap;">
<span>品牌保证</span>
<el-switch on-text="" off-text="" v-model="formData.is_premium"></el-switch>
......@@ -69,36 +76,37 @@
}">
</el-time-select>
</el-form-item>
<el-form-item label="上传店铺头像">
<el-upload
class="avatar-uploader"
:action="baseUrl + '/shopping/addimg/shop'"
:action="baseUrl + '/v1/addimg/shop'"
:show-file-list="false"
:on-success="handleShopAvatarScucess"
:before-upload="beforeAvatarUpload">
<img v-if="formData.image_path" :src="baseUrl + formData.image_path" class="avatar">
<img v-if="formData.image_path" :src="baseImgPath + formData.image_path" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
<el-form-item label="上传营业执照">
<el-upload
class="avatar-uploader"
:action="baseUrl + '/shopping/addimg/shop'"
:action="baseUrl + '/v1/addimg/shop'"
:show-file-list="false"
:on-success="handleBusinessAvatarScucess"
:before-upload="beforeAvatarUpload">
<img v-if="formData.business_license_image" :src="baseUrl + formData.business_license_image" class="avatar">
<img v-if="formData.business_license_image" :src="baseImgPath + formData.business_license_image" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
<el-form-item label="上传餐饮服务许可证">
<el-upload
class="avatar-uploader"
:action="baseUrl + '/shopping/addimg/shop'"
:action="baseUrl + '/v1/addimg/shop'"
:show-file-list="false"
:on-success="handleServiceAvatarScucess"
:before-upload="beforeAvatarUpload">
<img v-if="formData.catering_service_license_image" :src="baseUrl + formData.catering_service_license_image" class="avatar">
<img v-if="formData.catering_service_license_image" :src="baseImgPath + formData.catering_service_license_image" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
......@@ -156,8 +164,8 @@
<script>
import headTop from '@/components/headTop'
import {cityGuess, addShop, searchplace} from '@/api/getData'
import {baseUrl} from '@/config/env'
import {cityGuess, addShop, searchplace, foodCategory} from '@/api/getData'
import {baseUrl, baseImgPath} from '@/config/env'
export default {
data(){
return {
......@@ -183,6 +191,7 @@
image_path: '',
business_license_image: '',
catering_service_license_image: '',
},
rules: {
name: [
......@@ -216,6 +225,9 @@
description: '满30减5,满60减8',
}],
baseUrl,
baseImgPath,
categoryOptions: [],
selectedCategory: ['快餐便当', '简餐']
}
},
components: {
......@@ -228,6 +240,27 @@
async initData(){
try{
this.city = await cityGuess();
const categories = await foodCategory();
categories.forEach(item => {
if (item.sub_categories.length) {
const addnew = {
value: item.name,
label: item.name,
children: []
}
item.sub_categories.forEach((subitem, index) => {
if (index == 0) {
return
}
addnew.children.push({
value: subitem.name,
label: subitem.name,
})
})
this.categoryOptions.push(addnew)
}
})
}catch(err){
console.error(err);
}
......@@ -251,7 +284,7 @@
addressSelect(address){
this.formData.latitude = address.latitude;
this.formData.longitude = address.longitude;
console.log(address)
console.log(this.formData.latitude, this.formData.longitude)
},
handleShopAvatarScucess(res, file) {
if (res.status == 1) {
......@@ -351,7 +384,9 @@
submitForm(formName) {
this.$refs[formName].validate(async (valid) => {
if (valid) {
Object.assign(this.formData, {activities: this.activities})
Object.assign(this.formData, {activities: this.activities}, {
category: this.selectedCategory.join('/')
})
try{
let result = await addShop(this.formData);
if (result.status == 1) {
......
<template>
<div class="fillcontain">
area
</div>
</template>
<script>
export default {
}
</script>
<style lang="less">
@import '../style/mixin';
</style>
<template>
<div class="fillcontain">
<head-top></head-top>
<div class="table_container">
<el-table
:data="tableData"
@expand='expand'
style="width: 100%">
<el-table-column type="expand">
<template scope="props">
<el-form label-position="left" inline class="demo-table-expand">
<el-form-item label="食品名称">
<span>{{ selectTable.name }}</span>
</el-form-item>
<el-form-item label="餐馆名称">
<span>{{ selectTable.restaurant_name }}</span>
</el-form-item>
<el-form-item label="食品 ID">
<span>{{ selectTable.item_id }}</span>
</el-form-item>
<el-form-item label="餐馆 ID">
<span>{{ selectTable.restaurant_id }}</span>
</el-form-item>
<el-form-item label="食品介绍">
<span>{{ selectTable.description }}</span>
</el-form-item>
<el-form-item label="餐馆地址">
<span>{{ selectTable.restaurant_address }}</span>
</el-form-item>
<el-form-item label="食品评分">
<span>{{ selectTable.rating }}</span>
</el-form-item>
<el-form-item label="食品分类">
<span>{{ selectTable.category_name }}</span>
</el-form-item>
<el-form-item label="月销量">
<span>{{ selectTable.month_sales }}</span>
</el-form-item>
</el-form>
</template>
</el-table-column>
<el-table-column
label="食品名称"
prop="name">
</el-table-column>
<el-table-column
label="食品介绍"
prop="description">
</el-table-column>
<el-table-column
label="评分"
prop="rating">
</el-table-column>
<el-table-column label="操作" width="160">
<template scope="scope">
<el-button
size="small"
@click="handleEdit(scope.row)">编辑</el-button>
<el-button
size="small"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="Pagination">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-size="20"
layout="total, prev, pager, next"
:total="count">
</el-pagination>
</div>
<el-dialog title="修改食品信息" v-model="dialogFormVisible">
<el-form :model="selectTable">
<el-form-item label="食品名称" label-width="100px">
<el-input v-model="selectTable.name" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="食品介绍" label-width="100px">
<el-input v-model="selectTable.description"></el-input>
</el-form-item>
<el-form-item label="食品分类" label-width="100px">
<el-select v-model="selectIndex" :placeholder="selectMenu.label" @change="handleSelect">
<el-option
v-for="item in menuOptions"
:key="item.value"
:label="item.label"
:value="item.index">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="食品图片" label-width="100px">
<el-upload
class="avatar-uploader"
:action="baseUrl + '/v1/addimg/food'"
:show-file-list="false"
:on-success="handleServiceAvatarScucess"
:before-upload="beforeAvatarUpload">
<img v-if="selectTable.image_path" :src="baseImgPath + selectTable.image_path" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
</el-form>
<el-row style="overflow: auto; text-align: center;">
<el-table
:data="specs"
style="margin-bottom: 20px;"
:row-class-name="tableRowClassName">
<el-table-column
prop="specs"
label="规格">
</el-table-column>
<el-table-column
prop="packing_fee"
label="包装费">
</el-table-column>
<el-table-column
prop="price"
label="价格">
</el-table-column>
<el-table-column label="操作" >
<template scope="scope">
<el-button
size="small"
type="danger"
@click="deleteSpecs(scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-button type="primary" @click="specsFormVisible = true" style="margin-bottom: 10px;">添加规格</el-button>
</el-row>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="updateFood">确 定</el-button>
</div>
</el-dialog>
<el-dialog title="添加规格" v-model="specsFormVisible">
<el-form :rules="specsFormrules" :model="specsForm">
<el-form-item label="规格" label-width="100px" prop="specs">
<el-input v-model="specsForm.specs" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="包装费" label-width="100px">
<el-input-number v-model="specsForm.packing_fee" :min="0" :max="100"></el-input-number>
</el-form-item>
<el-form-item label="价格" label-width="100px">
<el-input-number v-model="specsForm.price" :min="0" :max="10000"></el-input-number>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="specsFormVisible = false">取 消</el-button>
<el-button type="primary" @click="addspecs">确 定</el-button>
</div>
</el-dialog>
</div>
</div>
</template>
<script>
import headTop from '../components/headTop'
import {baseUrl, baseImgPath} from '@/config/env'
import {getFoods, getFoodsCount, getMenu, updateFood, deleteFood, getResturantDetail, getMenuById} from '@/api/getData'
export default {
data(){
return {
baseUrl,
baseImgPath,
restaurant_id: null,
city: {},
offset: 0,
limit: 20,
count: 0,
tableData: [],
currentPage: 1,
selectTable: {},
dialogFormVisible: false,
menuOptions: [],
selectMenu: {},
selectIndex: null,
specsForm: {
specs: '',
packing_fee: 0,
price: 20,
},
specsFormrules: {
specs: [
{ required: true, message: '请输入规格', trigger: 'blur' },
],
},
specsFormVisible: false,
}
},
created(){
this.restaurant_id = this.$route.query.restaurant_id;
this.initData();
},
computed: {
specs: function (){
let specs = [];
if (this.selectTable.specfoods) {
this.selectTable.specfoods.forEach(item => {
specs.push({
specs: item.specs_name,
packing_fee: item.packing_fee,
price: item.price,
})
})
}
return specs
}
},
components: {
headTop,
},
methods: {
async initData(){
try{
const countData = await getFoodsCount({restaurant_id: this.restaurant_id});
if (countData.status == 1) {
this.count = countData.count;
}else{
throw new Error('获取数据失败');
}
this.getFoods();
}catch(err){
console.log('获取数据失败', err);
}
},
async getMenu(){
this.menuOptions = [];
try{
const menu = await getMenu({restaurant_id: this.selectTable.restaurant_id, allMenu: true});
menu.forEach((item, index) => {
this.menuOptions.push({
label: item.name,
value: item.id,
index,
})
})
}catch(err){
throw new Error('获取食品种类失败', err);
}
},
async getFoods(){
const Foods = await getFoods({offset: this.offset, limit: this.limit, restaurant_id: this.restaurant_id});
this.tableData = [];
Foods.forEach(item => {
const tableData = {};
tableData.name = item.name;
tableData.item_id = item.item_id;
tableData.description = item.description;
tableData.rating = item.rating;
tableData.month_sales = item.month_sales;
tableData.restaurant_id = item.restaurant_id;
tableData.category_id = item.category_id;
tableData.image_path = item.image_path;
tableData.specfoods = item.specfoods;
this.tableData.push(tableData);
})
},
tableRowClassName(row, index) {
if (index === 1) {
return 'info-row';
} else if (index === 3) {
return 'positive-row';
}
return '';
},
addspecs(){
this.specs.push({...this.specsForm});
this.specsForm.specs = '';
this.specsForm.packing_fee = 0;
this.specsForm.price = 20;
this.specsFormVisible = false;
},
deleteSpecs(index){
this.specs.splice(index, 1);
},
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
},
handleCurrentChange(val) {
this.currentPage = val;
this.offset = (val - 1)*this.limit;
this.getFoods()
},
expand(row, status){
if (status) {
this.getSelectItemData(row)
}
},
handleEdit(row) {
this.getSelectItemData(row, 'edit')
this.dialogFormVisible = true;
},
async getSelectItemData(row, type){
const restaurant = await getResturantDetail(row.restaurant_id);
const category = await getMenuById(row.category_id)
this.selectTable = {...row, ...{restaurant_name: restaurant.name, restaurant_address: restaurant.address, category_name: category.name}};
this.selectMenu = {label: category.name, value: row.category_id}
if (type == 'edit' && this.restaurant_id != row.restaurant_id) {
this.getMenu();
}
},
handleSelect(index){
this.selectIndex = index;
this.selectMenu = this.menuOptions[index];
},
async handleDelete(index, row) {
try{
const res = await deleteFood(row.item_id);
if (res.status == 1) {
this.$message({
type: 'success',
message: '删除食品成功'
});
this.tableData.splice(index, 1);
}else{
throw new Error('删除食品失败')
}
}catch(err){
this.$message({
type: 'error',
message: '删除食品失败'
});
console.error('删除食品失败')
}
},
handleServiceAvatarScucess(res, file) {
if (res.status == 1) {
this.selectTable.image_path = res.image_path;
}else{
this.$message.error('上传图片失败!');
}
},
beforeAvatarUpload(file) {
const isRightType = (file.type === 'image/jpeg') || (file.type === 'image/png');
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isRightType) {
this.$message.error('上传头像图片只能是 JPG 格式!');
}
if (!isLt2M) {
this.$message.error('上传头像图片大小不能超过 2MB!');
}
return isRightType && isLt2M;
},
async updateFood(){
this.dialogFormVisible = false;
try{
const subData = {new_category_id: this.selectMenu.value, specs: this.specs};
const postData = {...this.selectTable, ...subData};
const res = await updateFood(postData)
if (res.status == 1) {
this.$message({
type: 'success',
message: '更新食品信息成功'
});
this.getFoods();
}else{
this.$message({
type: 'error',
message: '更新食品信息失败'
});
throw new Error('更新餐馆信息失败')
}
}catch(err){
console.log('更新餐馆信息失败', err);
}
},
},
}
</script>
<style lang="less">
@import '../style/mixin';
.demo-table-expand {
font-size: 0;
}
.demo-table-expand label {
width: 90px;
color: #99a9bf;
}
.demo-table-expand .el-form-item {
margin-right: 0;
margin-bottom: 0;
width: 50%;
}
.table_container{
padding: 20px;
}
.Pagination{
display: flex;
justify-content: flex-end;
margin-top: 8px;
}
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #20a0ff;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 120px;
height: 120px;
line-height: 120px;
text-align: center;
}
.avatar {
width: 120px;
height: 120px;
display: block;
}
</style>
......@@ -8,7 +8,8 @@
<template slot="title"><i class="el-icon-document"></i>数据管理</template>
<el-menu-item index="userList">用户列表</el-menu-item>
<el-menu-item index="shopList">商家列表</el-menu-item>
<el-menu-item index="area">地区管理</el-menu-item>
<el-menu-item index="foodList">食品列表</el-menu-item>
<el-menu-item index="orderList">订单列表</el-menu-item>
<el-menu-item index="adminList">管理员列表</el-menu-item>
</el-submenu>
<el-submenu index="3">
......
<template>
<div class="fillcontain">
<head-top></head-top>
<div class="table_container">
<el-table
:data="tableData"
@expand='expand'
style="width: 100%">
<el-table-column type="expand">
<template scope="props">
<el-form label-position="left" inline class="demo-table-expand">
<el-form-item label="用户名">
<span>{{ selectTable.user_name }}</span>
</el-form-item>
<el-form-item label="店铺名称">
<span>{{ selectTable.restaurant_name }}</span>
</el-form-item>
<el-form-item label="收货地址">
<span>{{ selectTable.address }}</span>
</el-form-item>
<el-form-item label="店铺 ID">
<span>{{ selectTable.restaurant_id }}</span>
</el-form-item>
<el-form-item label="店铺地址">
<span>{{ selectTable.restaurant_address }}</span>
</el-form-item>
</el-form>
</template>
</el-table-column>
<el-table-column
label="订单 ID"
prop="id">
</el-table-column>
<el-table-column
label="总价格"
prop="total_amount">
</el-table-column>
<el-table-column
label="订单状态"
prop="status">
</el-table-column>
</el-table>
<div class="Pagination" style="text-align: right;margin-top: 10px;">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-size="20"
layout="total, prev, pager, next"
:total="count">
</el-pagination>
</div>
</div>
</div>
</template>
<script>
import headTop from '../components/headTop'
import {getOrderList, getOrderCount, getResturantDetail, getUserInfo, getAddressById} from '@/api/getData'
export default {
data(){
return {
tableData: [],
currentRow: null,
offset: 0,
limit: 20,
count: 0,
currentPage: 1,
restaurant_id: null,
selectTable: {},
}
},
components: {
headTop,
},
created(){
this.restaurant_id = this.$route.query.restaurant_id;
this.initData();
},
methods: {
async initData(){
try{
const countData = await getOrderCount({restaurant_id: this.restaurant_id});
if (countData.status == 1) {
this.count = countData.count;
}else{
throw new Error('获取数据失败');
}
this.getOrders();
}catch(err){
console.log('获取数据失败', err);
}
},
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
},
handleCurrentChange(val) {
this.currentPage = val;
this.offset = (val - 1)*this.limit;
this.getOrders()
},
async getOrders(){
const Orders = await getOrderList({offset: this.offset, limit: this.limit, restaurant_id: this.restaurant_id});
this.tableData = [];
Orders.forEach(item => {
const tableData = {};
tableData.id = item.id;
tableData.total_amount = item.total_amount;
tableData.status = item.status_bar.title;
tableData.user_id = item.user_id;
tableData.restaurant_id = item.restaurant_id;
tableData.address_id = item.address_id;
this.tableData.push(tableData);
})
},
async expand(row, status){
if (status) {
const restaurant = await getResturantDetail(row.restaurant_id);
const userInfo = await getUserInfo(row.user_id);
const addressInfo = await getAddressById(row.address_id);
this.selectTable = {...row, ...{restaurant_name: restaurant.name, restaurant_address: restaurant.address, address: addressInfo.address, user_name: userInfo.username}};
}
},
},
}
</script>
<style lang="less">
@import '../style/mixin';
.table_container{
padding: 20px;
}
.demo-table-expand {
font-size: 0;
}
.demo-table-expand label {
width: 90px;
color: #99a9bf;
}
.demo-table-expand .el-form-item {
margin-right: 0;
margin-bottom: 0;
width: 50%;
}
</style>
<template>
<div class="fillcontain">
<head-top></head-top>
<div class="table_container">
<el-table
:data="tableData"
style="width: 100%">
<el-table-column type="expand">
<template scope="props">
<el-form label-position="left" inline class="demo-table-expand">
<el-form-item label="店铺名称">
<span>{{ props.row.name }}</span>
</el-form-item>
<el-form-item label="店铺地址">
<span>{{ props.row.address }}</span>
</el-form-item>
<el-form-item label="店铺介绍">
<span>{{ props.row.description }}</span>
</el-form-item>
<el-form-item label="店铺 ID">
<span>{{ props.row.id }}</span>
</el-form-item>
<el-form-item label="联系电话">
<span>{{ props.row.phone }}</span>
</el-form-item>
<el-form-item label="评分">
<span>{{ props.row.rating }}</span>
</el-form-item>
<el-form-item label="销售量">
<span>{{ props.row.recent_order_num }}</span>
</el-form-item>
<el-form-item label="分类">
<span>{{ props.row.category }}</span>
</el-form-item>
</el-form>
</template>
</el-table-column>
<el-table-column
label="店铺名称"
prop="name">
</el-table-column>
<el-table-column
label="店铺地址"
prop="address">
</el-table-column>
<el-table-column
label="店铺介绍"
prop="description">
</el-table-column>
<el-table-column label="操作" width="200">
<template scope="scope">
<el-button
size="mini"
@click="handleEdit(scope.$index, scope.row)">编辑</el-button>
<el-button
size="mini"
type="Success"
@click="addFood(scope.$index, scope.row)">添加食品</el-button>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="Pagination">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-size="20"
layout="total, prev, pager, next"
:total="count">
</el-pagination>
</div>
<el-dialog title="修改店铺信息" v-model="dialogFormVisible">
<el-form :model="selectTable">
<el-form-item label="店铺名称" label-width="100px">
<el-input v-model="selectTable.name" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="详细地址" label-width="100px">
<el-autocomplete
v-model="address.address"
:fetch-suggestions="querySearchAsync"
placeholder="请输入地址"
style="width: 100%;"
@select="addressSelect"
></el-autocomplete>
<span>当前城市:{{city.name}}</span>
</el-form-item>
<el-form-item label="店铺介绍" label-width="100px">
<el-input v-model="selectTable.description"></el-input>
</el-form-item>
<el-form-item label="联系电话" label-width="100px">
<el-input v-model="selectTable.phone"></el-input>
</el-form-item>
<el-form-item label="店铺分类" label-width="100px">
<el-cascader
:options="categoryOptions"
v-model="selectedCategory"
change-on-select
></el-cascader>
</el-form-item>
<el-form-item label="商铺图片" label-width="100px">
<el-upload
class="avatar-uploader"
:action="baseUrl + '/v1/addimg/shop'"
:show-file-list="false"
:on-success="handleServiceAvatarScucess"
:before-upload="beforeAvatarUpload">
<img v-if="selectTable.image_path" :src="baseImgPath + selectTable.image_path" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="updateShop">确 定</el-button>
</div>
</el-dialog>
</div>
</div>
</template>
<script>
import headTop from '../components/headTop'
import {baseUrl, baseImgPath} from '@/config/env'
import {cityGuess, getResturants, getResturantsCount, foodCategory, updateResturant, searchplace, deleteResturant} from '@/api/getData'
export default {
data(){
return {
baseUrl,
baseImgPath,
city: {},
offset: 0,
limit: 20,
count: 0,
tableData: [],
currentPage: 1,
selectTable: {},
dialogFormVisible: false,
categoryOptions: [],
selectedCategory: [],
address: {},
}
},
created(){
this.initData();
},
components: {
headTop,
}
},
methods: {
async initData(){
try{
this.city = await cityGuess();
const countData = await getResturantsCount();
if (countData.status == 1) {
this.count = countData.count;
}else{
throw new Error('获取数据失败');
}
this.getResturants();
}catch(err){
console.log('获取数据失败', err);
}
},
async getCategory(){
try{
const categories = await foodCategory();
categories.forEach(item => {
if (item.sub_categories.length) {
const addnew = {
value: item.name,
label: item.name,
children: []
}
item.sub_categories.forEach((subitem, index) => {
if (index == 0) {
return
}
addnew.children.push({
value: subitem.name,
label: subitem.name,
})
})
this.categoryOptions.push(addnew)
}
})
}catch(err){
throw new Error('获取商铺种类失败', err);
}
},
async getResturants(){
const {latitude, longitude} = this.city;
const restaurants = await getResturants({latitude, longitude, offset: this.offset, limit: this.limit});
this.tableData = [];
restaurants.forEach(item => {
const tableData = {};
tableData.name = item.name;
tableData.address = item.address;
tableData.description = item.description;
tableData.id = item.id;
tableData.phone = item.phone;
tableData.rating = item.rating;
tableData.recent_order_num = item.recent_order_num;
tableData.category = item.category;
tableData.image_path = item.image_path;
this.tableData.push(tableData);
})
},
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
},
handleCurrentChange(val) {
this.currentPage = val;
this.offset = (val - 1)*this.limit;
this.getResturants()
},
handleEdit(index, row) {
this.selectTable = row;
this.address.address = row.address;
this.dialogFormVisible = true;
this.selectedCategory = row.category.split('/');
if (!this.categoryOptions.length) {
this.getCategory();
}
},
addFood(index, row){
this.$router.push({ path: 'addGoods', query: { restaurant_id: row.id }})
},
async handleDelete(index, row) {
try{
const res = await deleteResturant(row.id);
if (res.status == 1) {
this.$message({
type: 'success',
message: '删除店铺成功'
});
this.tableData.splice(index, 1);
}else{
throw new Error('删除店铺失败')
}
}catch(err){
this.$message({
type: 'error',
message: '删除店铺失败'
});
console.error('删除店铺失败')
}
},
async querySearchAsync(queryString, cb) {
if (queryString) {
try{
const cityList = await searchplace(this.city.id, queryString);
if (cityList instanceof Array) {
cityList.map(item => {
item.value = item.address;
return item;
})
cb(cityList)
}
}catch(err){
console.error(err)
}
}
},
addressSelect(vale){
const {address, latitude, longitude} = vale;
this.address = {address, latitude, longitude};
},
handleServiceAvatarScucess(res, file) {
if (res.status == 1) {
this.selectTable.image_path = res.image_path;
}else{
this.$message.error('上传图片失败!');
}
},
beforeAvatarUpload(file) {
const isRightType = (file.type === 'image/jpeg') || (file.type === 'image/png');
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isRightType) {
this.$message.error('上传头像图片只能是 JPG 格式!');
}
if (!isLt2M) {
this.$message.error('上传头像图片大小不能超过 2MB!');
}
return isRightType && isLt2M;
},
async updateShop(){
this.dialogFormVisible = false;
try{
Object.assign(this.selectTable, this.address);
this.selectTable.category = this.selectedCategory.join('/');
const res = await updateResturant(this.selectTable)
if (res.status == 1) {
this.$message({
type: 'success',
message: '更新店铺信息成功'
});
this.getResturants();
}else{
this.$message({
type: 'error',
message: '更新店铺信息失败'
});
throw new Error('更新餐馆信息失败')
}
}catch(err){
console.log('更新餐馆信息失败', err);
}
},
},
}
</script>
<style lang="less">
@import '../style/mixin';
.demo-table-expand {
font-size: 0;
}
.demo-table-expand label {
width: 90px;
color: #99a9bf;
}
.demo-table-expand .el-form-item {
margin-right: 0;
margin-bottom: 0;
width: 50%;
}
.table_container{
padding: 20px;
}
.Pagination{
display: flex;
justify-content: flex-end;
margin-top: 8px;
}
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #20a0ff;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 120px;
height: 120px;
line-height: 120px;
text-align: center;
}
.avatar {
width: 120px;
height: 120px;
display: block;
}
</style>
<template>
<div class="fillcontain">
<head-top></head-top>
<div class="table_container">
<el-table
:data="tableData"
highlight-current-row
style="width: 100%">
<el-table-column
type="index"
width="50">
</el-table-column>
<el-table-column
property="registe_time"
label="注册日期"
width="200">
</el-table-column>
<el-table-column
property="username"
label="用户姓名"
width="120">
</el-table-column>
<el-table-column
property="city"
label="注册地址">
</el-table-column>
</el-table>
<div class="Pagination" style="text-align: right;margin-top: 10px;">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-size="20"
layout="total, prev, pager, next"
:total="count">
</el-pagination>
</div>
</div>
</div>
</template>
<script>
import headTop from '../components/headTop'
import {getUserList, getUserCount} from '@/api/getData'
export default {
data(){
return {
tableData: [{
registe_time: '2016-05-02',
username: '王小虎',
city: '上海市普陀区金沙江路 1518 弄'
}, {
registe_time: '2016-05-04',
username: '王小虎',
city: '上海市普陀区金沙江路 1517 弄'
}, {
registe_time: '2016-05-01',
username: '王小虎',
city: '上海市普陀区金沙江路 1519 弄'
}, {
registe_time: '2016-05-03',
username: '王小虎',
city: '上海市普陀区金沙江路 1516 弄'
}],
currentRow: null,
offset: 0,
limit: 20,
count: 0,
currentPage: 1,
}
},
components: {
headTop,
}
},
created(){
this.initData();
},
methods: {
async initData(){
try{
const countData = await getUserCount();
if (countData.status == 1) {
this.count = countData.count;
}else{
throw new Error('获取数据失败');
}
this.getUsers();
}catch(err){
console.log('获取数据失败', err);
}
},
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
},
handleCurrentChange(val) {
this.currentPage = val;
this.offset = (val - 1)*this.limit;
this.getUsers()
},
async getUsers(){
const Users = await getUserList({offset: this.offset, limit: this.limit});
this.tableData = [];
Users.forEach(item => {
const tableData = {};
tableData.username = item.username;
tableData.registe_time = item.registe_time;
tableData.city = item.city;
this.tableData.push(tableData);
})
}
},
}
</script>
<style lang="less">
@import '../style/mixin';
.table_container{
padding: 20px;
}
</style>
......@@ -10,7 +10,8 @@ const addShop = r => require.ensure([], () => r(require('@/page/addShop')), 'add
const addGoods = r => require.ensure([], () => r(require('@/page/addGoods')), 'addGoods');
const userList = r => require.ensure([], () => r(require('@/page/userList')), 'userList');
const shopList = r => require.ensure([], () => r(require('@/page/shopList')), 'shopList');
const area = r => require.ensure([], () => r(require('@/page/area')), 'area');
const foodList = r => require.ensure([], () => r(require('@/page/foodList')), 'foodList');
const orderList = r => require.ensure([], () => r(require('@/page/orderList')), 'orderList');
const adminList = r => require.ensure([], () => r(require('@/page/adminList')), 'adminList');
const visitor = r => require.ensure([], () => r(require('@/page/visitor')), 'visitor');
const newMember = r => require.ensure([], () => r(require('@/page/newMember')), 'newMember');
......@@ -52,9 +53,13 @@ export default new Router({
component: shopList,
meta: ['数据管理', '商家列表'],
},{
path: '/area',
component: area,
meta: ['数据管理', '地区管理'],
path: '/foodList',
component: foodList,
meta: ['数据管理', '食品列表'],
},{
path: '/orderList',
component: orderList,
meta: ['数据管理', '订单列表'],
},{
path: '/adminList',
component: adminList,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册