一、项目简述
本系统功能包括: 微信小程序物业管理系统,微信朝胞括以下几个模 块: 社区公告、报修、信息采集、生活缴费、二手置换 微信小程序后台管理界面可以增删改查社区公告、问卷、 问卷问题、问题选项等 在微信小程序前端,用户提交信息后,可在我的界面查看 提交的信息,管理员可以在微信小程序后台管理界面查看 所有用户提交的信息。
二、项目运行
环境配置: jdk8+tomcat8+mysql5.7+lntelliJ IDEA+maven( Eclispe ,sts myEclispe 都支持)
项目技术: spring+spring mvc+mybatis+layui等等。
物料控制器代码:
/**
* @category 物料控制器
*/
@Controller
public class SuppliesController {
@Autowired
SuppliesService suppliesService;
@RequestMapping("/suppliesselectall")
public String SuppliesSelectAll(Model model) {
List<Supplies> list1 =suppliesService.find();
System.out.println("===================="+list1.size());
model.addAttribute("SuppliesSelectAll", list1);
return "supplieslist";
}
//模糊查询控制器
@RequestMapping("/suppliesSelectLike")
public String suppliesSelectLike(String like,Model model) {
List<Supplies> list2 =suppliesService.findByLike(like);
model.addAttribute("SuppliesSelectAll", list2);
return "supplieslist";
}
//添加物料控制器
@RequestMapping("/suppliesadd")
public String suppliesadd(Supplies supplies) {
boolean flag=suppliesService.insert(supplies);
return "suppliesadd";
}
//添加物料返回查找页面
@RequestMapping("/suppliesaddsave")
public String suppliesaddsave(Model model) {
List<Supplies> list =suppliesService.find();
model.addAttribute("SuppliesSelectAll", list);
return "redirect:suppliesselectall.action";
}
//更新物料控制器
@RequestMapping("/suppliesupdate")
public String suppliesupdate(int suppliesid,Model model) {
Supplies supplies=suppliesService.findById(suppliesid);
model.addAttribute("supplies", supplies);
return "updatesupplies";
}
//更新物料返回查找页面
@RequestMapping("suppliesupdatesave")
public String suppliesupdatesave(Model model) {
List<Supplies> list =suppliesService.find();
model.addAttribute("SuppliesSelectAll", list);
return "redirect:suppliesselectall.action";
}
//删除物料控制器,返回查找页面
@RequestMapping("/suppliesdelete")
public String deletesupplies(int[] suppliesids) {
boolean flag=suppliesService.delete(suppliesids);
return "redirect:suppliesselectall.action";
}
}
品类页面:
<template>
<div class="app-container">
<!-- 查询和其他操作 -->
<div class="filter-container">
<el-input v-model="listQuery.id" clearable class="filter-item" style="width: 200px;" placeholder="请输入类目ID"/>
<el-input v-model="listQuery.name" clearable class="filter-item" style="width: 200px;" placeholder="请输入类目名称"/>
<el-button v-permission="['GET /admin/category/list']" class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
<el-button v-permission="['POST /admin/category/create']" class="filter-item" type="primary" icon="el-icon-edit" @click="handleCreate">添加</el-button>
<el-button :loading="downloadLoading" class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload">导出</el-button>
</div>
<!-- 查询结果 -->
<el-table v-loading="listLoading" :data="list" size="small" element-loading-text="正在查询中。。。" border fit highlight-current-row>
<el-table-column align="center" label="类目ID" prop="id"/>
<el-table-column align="center" label="类目名" prop="name"/>
<el-table-column align="center" property="iconUrl" label="类目图标">
<template slot-scope="scope">
<img v-if="scope.row.iconUrl" :src="scope.row.iconUrl" width="40">
</template>
</el-table-column>
<el-table-column align="center" property="picUrl" label="类目图片">
<template slot-scope="scope">
<img v-if="scope.row.picUrl" :src="scope.row.picUrl" width="80">
</template>
</el-table-column>
<el-table-column align="center" label="关键字" prop="keywords"/>
<el-table-column align="center" min-width="100" label="简介" prop="desc"/>
<el-table-column align="center" label="级别" prop="level">
<template slot-scope="scope">
<el-tag :type="scope.row.level === 'L1' ? 'primary' : 'info' ">{
{ scope.row.level === 'L1' ? '一级类目' : '二级类目' }}</el-tag>
</template>
</el-table-column>
<el-table-column align="center" label="父类目ID" prop="pid"/>
<el-table-column align="center" label="操作" width="200" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button v-permission="['POST /admin/category/update']" type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
<el-button v-permission="['POST /admin/category/delete']" type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" />
<!-- 添加或修改对话框 -->
<el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
<el-form ref="dataForm" :rules="rules" :model="dataForm" status-icon label-position="left" label-width="100px" style="width: 400px; margin-left:50px;">
<el-form-item label="类目名称" prop="name">
<el-input v-model="dataForm.name"/>
</el-form-item>
<el-form-item label="关键字" prop="keywords">
<el-input v-model="dataForm.keywords"/>
</el-form-item>
<el-form-item label="级别" prop="level">
<el-select v-model="dataForm.level" @change="onLevelChange">
<el-option label="一级类目" value="L1"/>
<el-option label="二级类目" value="L2"/>
</el-select>
</el-form-item>
<el-form-item v-if="dataForm.level === 'L2'" label="父类目" prop="pid">
<el-select v-model="dataForm.pid">
<el-option v-for="item in catL1" :key="item.value" :label="item.label" :value="item.value"/>
</el-select>
</el-form-item>
<el-form-item label="类目图标" prop="iconUrl">
<el-upload
:headers="headers"
:action="uploadPath"
:show-file-list="false"
:on-success="uploadIconUrl"
class="avatar-uploader"
accept=".jpg,.jpeg,.png,.gif">
<img v-if="dataForm.iconUrl" :src="dataForm.iconUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"/>
</el-upload>
</el-form-item>
<el-form-item label="类目图片" prop="picUrl">
<el-upload
:headers="headers"
:action="uploadPath"
:show-file-list="false"
:on-success="uploadPicUrl"
class="avatar-uploader"
accept=".jpg,.jpeg,.png,.gif">
<img v-if="dataForm.picUrl" :src="dataForm.picUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"/>
</el-upload>
</el-form-item>
<el-form-item label="类目简介" prop="desc">
<el-input v-model="dataForm.desc"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取消</el-button>
<el-button v-if="dialogStatus=='create'" type="primary" @click="createData">确定</el-button>
<el-button v-else type="primary" @click="updateData">确定</el-button>
</div>
</el-dialog>
</div>
</template>
<style>
.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: 145px;
height: 145px;
display: block;
}
</style>
<script>
import { listCategory, listCatL1, createCategory, updateCategory, deleteCategory } from '@/api/category'
import { uploadPath } from '@/api/storage'
import { getToken } from '@/utils/auth'
import Pagination from '@/components/Pagination' // Secondary package based on el-pagination
export default {
name: 'Category',
components: { Pagination },
data() {
return {
uploadPath,
list: undefined,
total: 0,
listLoading: true,
listQuery: {
page: 1,
limit: 20,
id: undefined,
name: undefined,
sort: 'add_time',
order: 'desc'
},
catL1: {},
dataForm: {
id: undefined,
name: '',
keywords: '',
level: 'L2',
pid: undefined,
desc: '',
iconUrl: undefined,
picUrl: undefined
},
dialogFormVisible: false,
dialogStatus: '',
textMap: {
update: '编辑',
create: '创建'
},
rules: {
name: [{ required: true, message: '类目名不能为空', trigger: 'blur' }]
},
downloadLoading: false
}
},
computed: {
headers() {
return {
'X-Dts-Admin-Token': getToken()
}
}
},
created() {
this.getList()
this.getCatL1()
},
methods: {
getList() {
this.listLoading = true
listCategory(this.listQuery)
.then(response => {
this.list = response.data.data.items
this.total = response.data.data.total
this.listLoading = false
})
.catch(() => {
this.list = []
this.total = 0
this.listLoading = false
})
},
getCatL1() {
listCatL1().then(response => {
this.catL1 = response.data.data
})
},
handleFilter() {
this.listQuery.page = 1
this.getList()
},
resetForm() {
this.dataForm = {
id: undefined,
name: '',
keywords: '',
level: 'L2',
pid: undefined,
desc: '',
iconUrl: undefined,
picUrl: undefined
}
},
onLevelChange: function(value) {
if (value === 'L1') {
this.pid = undefined
}
},
handleCreate() {
this.resetForm()
this.dialogStatus = 'create'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
uploadIconUrl: function(response) {
this.dataForm.iconUrl = response.data.url
},
uploadPicUrl: function(response) {
this.dataForm.picUrl = response.data.url
},
createData() {
this.$refs['dataForm'].validate(valid => {
if (valid) {
createCategory(this.dataForm)
.then(response => {
this.list.unshift(response.data.data)
// 更新L1目录
this.getCatL1()
this.dialogFormVisible = false
this.$notify.success({
title: '成功',
message: '创建成功'
})
})
.catch(response => {
this.$notify.error({
title: '失败',
message: response.data.errmsg
})
})
}
})
},
handleUpdate(row) {
this.dataForm = Object.assign({}, row)
this.dialogStatus = 'update'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
updateData() {
this.$refs['dataForm'].validate(valid => {
if (valid) {
updateCategory(this.dataForm)
.then(() => {
for (const v of this.list) {
if (v.id === this.dataForm.id) {
const index = this.list.indexOf(v)
this.list.splice(index, 1, this.dataForm)
break
}
}
// 更新L1目录
this.getCatL1()
this.dialogFormVisible = false
this.$notify.success({
title: '成功',
message: '更新成功'
})
})
.catch(response => {
this.$notify.error({
title: '失败',
message: response.data.errmsg
})
})
}
})
},
handleDelete(row) {
deleteCategory(row)
.then(response => {
// 更新L1目录
this.getCatL1()
this.$notify.success({
title: '成功',
message: '删除成功'
})
const index = this.list.indexOf(row)
this.list.splice(index, 1)
})
.catch(response => {
this.$notify.error({
title: '失败',
message: response.data.errmsg
})
})
},
handleDownload() {
this.downloadLoading = true
import('@/vendor/Export2Excel').then(excel => {
const tHeader = [
'类目ID',
'名称',
'关键字',
'级别',
'父类目ID',
'类目图标',
'类目图片',
'简介'
]
const filterVal = [
'id',
'name',
'keywords',
'level',
'pid',
'iconUrl',
'picUrl',
'desc'
]
excel.export_json_to_excel2(
tHeader,
this.list,
filterVal,
'商品类目信息'
)
this.downloadLoading = false
})
}
}
}
</script>
商品服务类业务:
@Service
public class AdminGoodsService {
private static final Logger logger = LoggerFactory.getLogger(AdminGoodsService.class);
@Autowired
private DtsGoodsService goodsService;
@Autowired
private DtsGoodsSpecificationService specificationService;
@Autowired
private DtsGoodsAttributeService attributeService;
@Autowired
private DtsGoodsProductService productService;
@Autowired
private DtsCategoryService categoryService;
@Autowired
private DtsBrandService brandService;
@Autowired
private DtsCartService cartService;
@Autowired
private DtsOrderGoodsService orderGoodsService;
@Autowired
private QCodeService qCodeService;
public Object list(String goodsSn, String name, Integer page, Integer limit, String sort, String order) {
List<DtsGoods> goodsList = goodsService.querySelective(goodsSn, name, page, limit, sort, order);
long total = PageInfo.of(goodsList).getTotal();
Map<String, Object> data = new HashMap<>();
data.put("total", total);
data.put("items", goodsList);
logger.info("【请求结束】商品管理->商品管理->查询,响应结果:{}", JSONObject.toJSONString(data));
return ResponseUtil.ok(data);
}
private Object validate(GoodsAllinone goodsAllinone) {
DtsGoods goods = goodsAllinone.getGoods();
String name = goods.getName();
if (StringUtils.isEmpty(name)) {
return ResponseUtil.badArgument();
}
String goodsSn = goods.getGoodsSn();
if (StringUtils.isEmpty(goodsSn)) {
return ResponseUtil.badArgument();
}
// 品牌商可以不设置,如果设置则需要验证品牌商存在
Integer brandId = goods.getBrandId();
if (brandId != null && brandId != 0) {
if (brandService.findById(brandId) == null) {
return ResponseUtil.badArgumentValue();
}
}
// 分类可以不设置,如果设置则需要验证分类存在
Integer categoryId = goods.getCategoryId();
if (categoryId != null && categoryId != 0) {
if (categoryService.findById(categoryId) == null) {
return ResponseUtil.badArgumentValue();
}
}
DtsGoodsAttribute[] attributes = goodsAllinone.getAttributes();
for (DtsGoodsAttribute attribute : attributes) {
String attr = attribute.getAttribute();
if (StringUtils.isEmpty(attr)) {
return ResponseUtil.badArgument();
}
String value = attribute.getValue();
if (StringUtils.isEmpty(value)) {
return ResponseUtil.badArgument();
}
}
DtsGoodsSpecification[] specifications = goodsAllinone.getSpecifications();
for (DtsGoodsSpecification specification : specifications) {
String spec = specification.getSpecification();
if (StringUtils.isEmpty(spec)) {
return ResponseUtil.badArgument();
}
String value = specification.getValue();
if (StringUtils.isEmpty(value)) {
return ResponseUtil.badArgument();
}
}
DtsGoodsProduct[] products = goodsAllinone.getProducts();
for (DtsGoodsProduct product : products) {
Integer number = product.getNumber();
if (number == null || number < 0) {
return ResponseUtil.badArgument();
}
BigDecimal price = product.getPrice();
if (price == null) {
return ResponseUtil.badArgument();
}
String[] productSpecifications = product.getSpecifications();
if (productSpecifications.length == 0) {
return ResponseUtil.badArgument();
}
}
return null;
}
/**
* 编辑商品
* <p>
* TODO 目前商品修改的逻辑是 1. 更新Dts_goods表 2.
* 逻辑删除Dts_goods_specification、Dts_goods_attribute、Dts_goods_product 3.
* 添加Dts_goods_specification、Dts_goods_attribute、Dts_goods_product
* <p>
* 这里商品三个表的数据采用删除再添加的策略是因为 商品编辑页面,支持管理员添加删除商品规格、添加删除商品属性,因此这里仅仅更新是不可能的,
* 只能删除三个表旧的数据,然后添加新的数据。 但是这里又会引入新的问题,就是存在订单商品货品ID指向了失效的商品货品表。
* 因此这里会拒绝管理员编辑商品,如果订单或购物车中存在商品。 所以这里可能需要重新设计。
*/
@Transactional
public Object update(GoodsAllinone goodsAllinone) {
Object error = validate(goodsAllinone);
if (error != null) {
return error;
}
DtsGoods goods = goodsAllinone.getGoods();
DtsGoodsAttribute[] attributes = goodsAllinone.getAttributes();
DtsGoodsSpecification[] specifications = goodsAllinone.getSpecifications();
DtsGoodsProduct[] products = goodsAllinone.getProducts();
Integer id = goods.getId();
// 检查是否存在购物车商品或者订单商品
// 如果存在则拒绝修改商品。
if (orderGoodsService.checkExist(id) || cartService.checkExist(id)) {
logger.error("商品管理->商品管理->编辑错误:{}", GOODS_UPDATE_NOT_ALLOWED.desc());
return AdminResponseUtil.fail(GOODS_UPDATE_NOT_ALLOWED);
}
// 将生成的分享图片地址写入数据库
String url = qCodeService.createGoodShareImage(goods.getId().toString(), goods.getPicUrl(), goods.getName(),goods.getCounterPrice(),goods.getRetailPrice());
goods.setShareUrl(url);
// 商品基本信息表Dts_goods
if (goodsService.updateById(goods) == 0) {
logger.error("商品管理->商品管理->编辑错误:{}", "更新数据失败");
throw new RuntimeException("更新数据失败");
}
Integer gid = goods.getId();
specificationService.deleteByGid(gid);
attributeService.deleteByGid(gid);
productService.deleteByGid(gid);
// 商品规格表Dts_goods_specification
for (DtsGoodsSpecification specification : specifications) {
specification.setGoodsId(goods.getId());
specificationService.add(specification);
}
// 商品参数表Dts_goods_attribute
for (DtsGoodsAttribute attribute : attributes) {
attribute.setGoodsId(goods.getId());
attributeService.add(attribute);
}
// 商品货品表Dts_product
for (DtsGoodsProduct product : products) {
product.setGoodsId(goods.getId());
productService.add(product);
}
//qCodeService.createGoodShareImage(goods.getId().toString(), goods.getPicUrl(), goods.getName());
logger.info("【请求结束】商品管理->商品管理->编辑,响应结果:{}", "成功!");
return ResponseUtil.ok();
}
@Transactional
public Object delete(DtsGoods goods) {
Integer id = goods.getId();
if (id == null) {
return ResponseUtil.badArgument();
}
Integer gid = goods.getId();
goodsService.deleteById(gid);
specificationService.deleteByGid(gid);
attributeService.deleteByGid(gid);
productService.deleteByGid(gid);
logger.info("【请求结束】商品管理->商品管理->删除,响应结果:{}", "成功!");
return ResponseUtil.ok();
}
@Transactional
public Object create(GoodsAllinone goodsAllinone) {
Object error = validate(goodsAllinone);
if (error != null) {
return error;
}
DtsGoods goods = goodsAllinone.getGoods();
DtsGoodsAttribute[] attributes = goodsAllinone.getAttributes();
DtsGoodsSpecification[] specifications = goodsAllinone.getSpecifications();
DtsGoodsProduct[] products = goodsAllinone.getProducts();
String name = goods.getName();
if (goodsService.checkExistByName(name)) {
logger.error("商品管理->商品管理->上架错误:{}", GOODS_NAME_EXIST.desc());
return AdminResponseUtil.fail(GOODS_NAME_EXIST);
}
// 商品基本信息表Dts_goods
goodsService.add(goods);
// 将生成的分享图片地址写入数据库
String url = qCodeService.createGoodShareImage(goods.getId().toString(), goods.getPicUrl(), goods.getName(),goods.getCounterPrice(),goods.getRetailPrice());
if (!StringUtils.isEmpty(url)) {
goods.setShareUrl(url);
if (goodsService.updateById(goods) == 0) {
logger.error("商品管理->商品管理->上架错误:{}", "更新数据失败");
throw new RuntimeException("更新数据失败");
}
}
// 商品规格表Dts_goods_specification
for (DtsGoodsSpecification specification : specifications) {
specification.setGoodsId(goods.getId());
specificationService.add(specification);
}
// 商品参数表Dts_goods_attribute
for (DtsGoodsAttribute attribute : attributes) {
attribute.setGoodsId(goods.getId());
attributeService.add(attribute);
}
// 商品货品表Dts_product
for (DtsGoodsProduct product : products) {
product.setGoodsId(goods.getId());
productService.add(product);
}
logger.info("【请求结束】商品管理->商品管理->上架,响应结果:{}", "成功!");
return ResponseUtil.ok();
}
public Object list2() {
// http://element-cn.eleme.io/#/zh-CN/component/cascader
// 管理员设置“所属分类”
List<DtsCategory> l1CatList = categoryService.queryL1();
List<CatVo> categoryList = new ArrayList<>(l1CatList.size());
for (DtsCategory l1 : l1CatList) {
CatVo l1CatVo = new CatVo();
l1CatVo.setValue(l1.getId());
l1CatVo.setLabel(l1.getName());
List<DtsCategory> l2CatList = categoryService.queryByPid(l1.getId());
List<CatVo> children = new ArrayList<>(l2CatList.size());
for (DtsCategory l2 : l2CatList) {
CatVo l2CatVo = new CatVo();
l2CatVo.setValue(l2.getId());
l2CatVo.setLabel(l2.getName());
children.add(l2CatVo);
}
l1CatVo.setChildren(children);
categoryList.add(l1CatVo);
}
// http://element-cn.eleme.io/#/zh-CN/component/select
// 管理员设置“所属品牌商”
List<DtsBrand> list = brandService.all();
List<Map<String, Object>> brandList = new ArrayList<>(l1CatList.size());
for (DtsBrand brand : list) {
Map<String, Object> b = new HashMap<>(2);
b.put("value", brand.getId());
b.put("label", brand.getName());
brandList.add(b);
}
Map<String, Object> data = new HashMap<>();
data.put("categoryList", categoryList);
data.put("brandList", brandList);
return ResponseUtil.ok(data);
}
public Object detail(Integer id) {
DtsGoods goods = goodsService.findById(id);
List<DtsGoodsProduct> products = productService.queryByGid(id);
List<DtsGoodsSpecification> specifications = specificationService.queryByGid(id);
List<DtsGoodsAttribute> attributes = attributeService.queryByGid(id);
Integer categoryId = goods.getCategoryId();
DtsCategory category = categoryService.findById(categoryId);
Integer[] categoryIds = new Integer[] {};
if (category != null) {
Integer parentCategoryId = category.getPid();
categoryIds = new Integer[] { parentCategoryId, categoryId };
}
Map<String, Object> data = new HashMap<>();
data.put("goods", goods);
data.put("specifications", specifications);
data.put("products", products);
data.put("attributes", attributes);
data.put("categoryIds", categoryIds);
logger.info("【请求结束】商品管理->商品管理->详情,响应结果:{}", "成功!");
return ResponseUtil.ok(data);
}
}