feat 添加商品的管理页面
This commit is contained in:
parent
34483e80f7
commit
440824c98f
@ -4,6 +4,7 @@ import Login from '../views/Login.vue'
|
||||
import NotFound from '../views/NotFound.vue'
|
||||
import AdminLayout from '../views/layout/AdminLayout.vue'
|
||||
import UserIndex from '../views/user/index.vue'
|
||||
import GoodsIndex from '../views/goods/index.vue'
|
||||
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
@ -13,11 +14,18 @@ const routes: RouteRecordRaw[] = [
|
||||
children: [
|
||||
{
|
||||
path: 'home',
|
||||
name: 'Home',
|
||||
component: Home
|
||||
},
|
||||
{
|
||||
path: 'user',
|
||||
name: 'UserIndex',
|
||||
component: UserIndex
|
||||
},
|
||||
{
|
||||
path: 'goods',
|
||||
name: 'GoodsIndex',
|
||||
component: GoodsIndex
|
||||
}
|
||||
]
|
||||
},
|
||||
|
20
admin-fe/src/service/types.d.ts
vendored
20
admin-fe/src/service/types.d.ts
vendored
@ -26,4 +26,22 @@ type UserInfoModel = {
|
||||
status: number;
|
||||
pointInfo: PointInfoModel;
|
||||
parent?: UserInfoModel | null;
|
||||
}
|
||||
}
|
||||
type GoodsModel = {
|
||||
id?: number;
|
||||
category?: number;
|
||||
type?: number;
|
||||
title?: string;
|
||||
originPrice?: number;
|
||||
price?: number;
|
||||
stock?: number;
|
||||
limitCount?: number;
|
||||
cover?: string;
|
||||
description?: string;
|
||||
notice?: string;
|
||||
onlineTime?: string;
|
||||
offlineTime?: string;
|
||||
createTime?: string;
|
||||
updateTime?: string;
|
||||
status?: number;
|
||||
}
|
||||
|
@ -42,6 +42,17 @@ class Http {
|
||||
return this.request<T>(url, data, 'get')
|
||||
}
|
||||
|
||||
put<T>(url, data = null) {
|
||||
return this.request<T>(url, data, 'put')
|
||||
}
|
||||
|
||||
remove<T>(url, data = null) {
|
||||
return this.request<T>(url, data, 'delete')
|
||||
}
|
||||
delete<T>(url, data = null) {
|
||||
return this.request<T>(url, data, 'delete')
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /xxxx?a=1&b=2
|
||||
* NAME: value
|
||||
|
178
admin-fe/src/views/goods/index.vue
Normal file
178
admin-fe/src/views/goods/index.vue
Normal file
@ -0,0 +1,178 @@
|
||||
<template>
|
||||
|
||||
<div>
|
||||
<div class="search-form">
|
||||
<span>标题:<PInput v-model="param.title" placeholder="要查询的商品标题"/></span>
|
||||
<span>
|
||||
分类:
|
||||
<select v-model="param.category">
|
||||
<option v-for="(text,value) in CategoryEnum" :key="value" :value="value">{{ text }}</option>
|
||||
</select>
|
||||
</span>
|
||||
<button @click="onReset">重置</button>
|
||||
<button @click="onSearch">搜索</button>
|
||||
</div>
|
||||
<table>
|
||||
<tr>
|
||||
<th>商品编号</th>
|
||||
<th>标题</th>
|
||||
<th>图片</th>
|
||||
<th>分类</th>
|
||||
<th>类型</th>
|
||||
<th>原价</th>
|
||||
<th>售卖价</th>
|
||||
<th>库存</th>
|
||||
<th>限购数量</th>
|
||||
<th>上架时间</th>
|
||||
<th>下架时间</th>
|
||||
<th>状态</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
<tr v-for="it in goodsList" :key="it.id">
|
||||
<td>{{ it.id }}</td>
|
||||
<td>{{ it.title }}</td>
|
||||
<td><img :src="it.cover" style="width: 32px;height: 32px;"/></td>
|
||||
<td>{{ CategoryEnum[it.category] || '未知' }}</td>
|
||||
<td>{{ TypeEnum[it.type] || '未知' }}</td>
|
||||
<td>{{ it.originPrice == 0 ? '-' : it.originPrice }}</td>
|
||||
<td>{{ it.price }}</td>
|
||||
<td>{{ it.stock }}</td>
|
||||
<td>{{ it.limitCount }}</td>
|
||||
<td>{{ it.onlineTime }}</td>
|
||||
<td>{{ it.offlineTime }}</td>
|
||||
<td>{{ StatusEnum[it.status] || '未知' }}</td>
|
||||
<td>
|
||||
<span @click="onEditData(it)">编辑</span>
|
||||
<span>禁用</span>
|
||||
<span @click="removeUser(it.id)">删除</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<Pager :total="totalCount" show-refresh @refresh="loadDataList" @page-change="onPageChange"/>
|
||||
</div>
|
||||
<Modal v-model="modalVisible">
|
||||
<div>
|
||||
<div>
|
||||
<span>昵称</span>
|
||||
<p>
|
||||
<PInput placeholder="请输入昵称" v-model="editData.nickname"/>
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<span>省份</span>
|
||||
<p>
|
||||
<PInput placeholder="请输入省份" v-model="editData.province"/>
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<span>城市</span>
|
||||
<p>
|
||||
<PInput placeholder="请输入城市" v-model="editData.city"/>
|
||||
</p>
|
||||
</div>
|
||||
<button @click="updateData">提交</button>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {onMounted, reactive, ref} from "vue";
|
||||
import http, {DataListModel} from "../../util/http";
|
||||
import message from "../../components/message";
|
||||
import Modal from "../../components/modal/modal.vue";
|
||||
import Pager from "../../components/pager/Pager.vue";
|
||||
//
|
||||
//商品类别(1:普通 2:精选 3:秒杀 4:抽奖)
|
||||
const CategoryEnum = {
|
||||
1: '普通',
|
||||
2: '精选',
|
||||
3: '秒杀',
|
||||
4: '抽奖',
|
||||
}
|
||||
//商品类型(1:实物 2:虚拟)
|
||||
const TypeEnum = {
|
||||
1: '实物',
|
||||
2: '虚拟'
|
||||
}
|
||||
|
||||
const StatusEnum = {
|
||||
1: '正常',
|
||||
2: '禁用',
|
||||
0: '已删除'
|
||||
}
|
||||
const param = reactive({
|
||||
title: null,
|
||||
category: null,
|
||||
page: 1,
|
||||
pageSize: 10
|
||||
})
|
||||
const modalVisible = ref(false)
|
||||
|
||||
const goodsList = ref<GoodsModel[]>([]);
|
||||
const editData = reactive<GoodsModel>({
|
||||
id: 0
|
||||
});
|
||||
const totalCount = ref(0)
|
||||
|
||||
function onPageChange(currentPage: number) {
|
||||
param.page = currentPage;
|
||||
loadDataList();
|
||||
}
|
||||
|
||||
function onReset() {
|
||||
param.page = 1;
|
||||
param.title = null;
|
||||
param.category = null
|
||||
loadDataList();
|
||||
}
|
||||
|
||||
function onSearch() {
|
||||
param.page = 1;
|
||||
loadDataList();
|
||||
}
|
||||
|
||||
function loadDataList() {
|
||||
http.post<DataListModel<GoodsModel>>('/admin/goods/list', param).then(res => {
|
||||
goodsList.value = res.items
|
||||
totalCount.value = res.total
|
||||
})
|
||||
}
|
||||
|
||||
function onEditData(data: GoodsModel) {
|
||||
modalVisible.value = true
|
||||
}
|
||||
|
||||
async function updateData() {
|
||||
try {
|
||||
await http.put(`/admin/goods/${editData.id}`, editData)
|
||||
modalVisible.value = false;
|
||||
message.toast('更新成功');
|
||||
loadDataList();
|
||||
} catch (e) {
|
||||
message.toast(e.message || '更新失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
* @param id 要删除的用户id
|
||||
*/
|
||||
async function removeUser(id: number) {
|
||||
if (!confirm('是否删除?')) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await http.delete(`/admin/goods/${id}`);
|
||||
message.toast('删除成功');
|
||||
loadDataList();
|
||||
} catch (e) {
|
||||
message.toast(e.message || '删除失败')
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(loadDataList)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -13,6 +13,7 @@
|
||||
<div class="title">积分管理系统</div>
|
||||
<div class="menu-list">
|
||||
<router-link active-class="active-menu" to="/home">HOME</router-link>
|
||||
<router-link active-class="active-menu" to="/goods">商品管理</router-link>
|
||||
<router-link active-class="active-menu" to="/user">用户管理</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,14 +1,15 @@
|
||||
package me.xiaoyan.point.api.controller.admin;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import me.xiaoyan.point.api.error.BizException;
|
||||
import me.xiaoyan.point.api.pojo.Goods;
|
||||
import me.xiaoyan.point.api.pojo.vo.GoodsQueryParam;
|
||||
import me.xiaoyan.point.api.pojo.vo.PageDataResult;
|
||||
import me.xiaoyan.point.api.pojo.vo.PageParam;
|
||||
import me.xiaoyan.point.api.service.GoodsService;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import me.xiaoyan.point.api.util.DataStatus;
|
||||
import org.apache.ibatis.annotations.Delete;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@ -22,4 +23,43 @@ public class GoodsAdminController {
|
||||
public PageDataResult list(@RequestBody GoodsQueryParam param) {
|
||||
return PageDataResult.convert(goodsService.queryByPage(param));
|
||||
}
|
||||
|
||||
// 新增
|
||||
@PostMapping
|
||||
public Goods create(@RequestBody Goods goods) {
|
||||
if (!goodsService.save(goods)) {
|
||||
throw BizException.saveFail();
|
||||
}
|
||||
return goods;
|
||||
}
|
||||
|
||||
// 修改
|
||||
@PutMapping("/{id}")
|
||||
public Goods update(@RequestBody Goods goods, @PathVariable("id") long id) {
|
||||
goods.setId(id);
|
||||
if (!goodsService.updateById(goods)) {
|
||||
throw BizException.saveFail();
|
||||
}
|
||||
return goods;
|
||||
}
|
||||
|
||||
// 查询
|
||||
@GetMapping("/{id}")
|
||||
public Goods get(@PathVariable("id") long id) {
|
||||
return goodsService.getById(id);
|
||||
}
|
||||
|
||||
// 删除
|
||||
@DeleteMapping("/{id}")
|
||||
public boolean remove(@PathVariable("id") long id) {
|
||||
if (id < 1) throw BizException.paramError();
|
||||
// 只是逻辑删除 -> 将状态更新未删除即可
|
||||
|
||||
return goodsService.updateById(
|
||||
Goods.builder()
|
||||
.id(id)
|
||||
.status(DataStatus.DELETE) // 状态设置为删除
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -17,11 +17,20 @@ public class BizException extends RuntimeException {
|
||||
public static BizException create(String message) {
|
||||
return new BizException(-1, message);
|
||||
}
|
||||
public static BizException create(int code,String message) {
|
||||
|
||||
public static BizException create(int code, String message) {
|
||||
return new BizException(code, message);
|
||||
}
|
||||
|
||||
public static BizException saveFail() {
|
||||
return create(1022,"保存失败");
|
||||
return create(1022, "保存失败");
|
||||
}
|
||||
|
||||
public static BizException paramError(String message) {
|
||||
return create(1201, message);
|
||||
}
|
||||
|
||||
public static BizException paramError() {
|
||||
return paramError("请求参数不正确");
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
@ -83,21 +84,25 @@ public class Goods implements Serializable {
|
||||
/**
|
||||
* 上架时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date onlineTime;
|
||||
|
||||
/**
|
||||
* 下架时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date offlineTime;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
|
@ -5,6 +5,7 @@ import java.util.Date;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
@ -39,9 +40,11 @@ public class OrderInfo {
|
||||
private Integer uid;
|
||||
//订单数据
|
||||
private String data;
|
||||
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
//订单状态(0:已删除 1:已取消 2:待确认 3:已完成)
|
||||
private Integer status;
|
||||
|
@ -2,6 +2,7 @@ package me.xiaoyan.point.api.pojo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
@ -22,6 +23,7 @@ public class Point implements Serializable {
|
||||
private Integer totalPoint;
|
||||
private Integer validPoint;
|
||||
private Integer expirePoint;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date expireTime;
|
||||
private Date updateTime;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package me.xiaoyan.point.api.pojo;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
@ -25,6 +26,8 @@ public class PointRecord implements Serializable {
|
||||
private Integer point;
|
||||
private Integer currentTotalPoint;
|
||||
private String reason;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date validTime;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date expireTime;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package me.xiaoyan.point.api.pojo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
@ -22,5 +23,7 @@ public class SignRecord implements Serializable {
|
||||
private Integer uid;
|
||||
private Integer point;
|
||||
private String ip;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
@ -58,6 +59,7 @@ public class UserInfo implements Serializable {
|
||||
/**
|
||||
* 第一次登录时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date firstLoginTime;
|
||||
private Date updateTime;
|
||||
/**
|
||||
|
@ -5,5 +5,5 @@ import lombok.Data;
|
||||
@Data
|
||||
public class GoodsQueryParam extends PageParam {
|
||||
private String title;
|
||||
private int category;
|
||||
private Integer category;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import me.xiaoyan.point.api.pojo.Goods;
|
||||
import me.xiaoyan.point.api.pojo.vo.GoodsQueryParam;
|
||||
import me.xiaoyan.point.api.service.GoodsService;
|
||||
import me.xiaoyan.point.api.mapper.GoodsMapper;
|
||||
import me.xiaoyan.point.api.util.DataStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@ -31,6 +32,11 @@ public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods>
|
||||
if (StringUtils.hasText(param.getTitle())) {
|
||||
q.eq("title", param.getTitle().trim());
|
||||
}
|
||||
if(param.getCategory() != null){
|
||||
q.eq("category", param.getCategory());
|
||||
}
|
||||
// 不查询删除状态数据
|
||||
q.ne("status", DataStatus.DELETE);
|
||||
return getBaseMapper().selectPage(param.getPage(), q);
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package me.xiaoyan.point.api.util;
|
||||
|
||||
public class DataStatus {
|
||||
public static final int NORMAL = 1;
|
||||
public static final int DISABLED = 2;
|
||||
public static final int DELETE = 0;
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user