Unverified Commit b68151cb authored by Menethil's avatar Menethil Committed by GitHub
Browse files

Merge pull request #1 from linlinjava/master

update
parents 126d027a 02679509
import request from '@/utils/request'
export function listCart(query) {
return request({
url: '/cart/list',
method: 'get',
params: query
})
}
export function createCart(data) {
return request({
url: '/cart/create',
method: 'post',
data
})
}
export function readCart(data) {
return request({
url: '/cart/read',
method: 'get',
data
})
}
export function updateCart(data) {
return request({
url: '/cart/update',
method: 'post',
data
})
}
export function deleteCart(data) {
return request({
url: '/cart/delete',
method: 'post',
data
})
}
import request from '@/utils/request'
export function listGoodsAttribute(query) {
return request({
url: '/goods-attribute/list',
method: 'get',
params: query
})
}
export function createGoodsAttribute(data) {
return request({
url: '/goods-attribute/create',
method: 'post',
data
})
}
export function readGoodsAttribute(data) {
return request({
url: '/goods-attribute/read',
method: 'get',
data
})
}
export function updateGoodsAttribute(data) {
return request({
url: '/goods-attribute/update',
method: 'post',
data
})
}
export function deleteGoodsAttribute(data) {
return request({
url: '/goods-attribute/delete',
method: 'post',
data
})
}
import request from '@/utils/request'
export function listGoodsSpecification(query) {
return request({
url: '/goods-specification/list',
method: 'get',
params: query
})
}
export function createGoodsSpecification(data) {
return request({
url: '/goods-specification/create',
method: 'post',
data
})
}
export function readGoodsSpecification(data) {
return request({
url: '/goods-specification/read',
method: 'get',
data
})
}
export function updateGoodsSpecification(data) {
return request({
url: '/goods-specification/update',
method: 'post',
data
})
}
export function deleteGoodsSpecification(data) {
return request({
url: '/goods-specification/delete',
method: 'post',
data
})
}
export function listGoodsSpecificationVo(query) {
return request({
url: '/goods-specification/volist',
method: 'get',
params: query
})
}
......@@ -8,7 +8,15 @@ export function listGoods(query) {
})
}
export function createGoods(data) {
export function deleteGoods(data) {
return request({
url: '/goods/delete',
method: 'post',
data
})
}
export function publishGoods(data) {
return request({
url: '/goods/create',
method: 'post',
......@@ -16,15 +24,15 @@ export function createGoods(data) {
})
}
export function readGoods(data) {
export function detailGoods(id) {
return request({
url: '/goods/read',
url: '/goods/detail',
method: 'get',
data
params: { id }
})
}
export function updateGoods(data) {
export function editGoods(data) {
return request({
url: '/goods/update',
method: 'post',
......@@ -32,10 +40,9 @@ export function updateGoods(data) {
})
}
export function deleteGoods(data) {
export function listCatAndBrand() {
return request({
url: '/goods/delete',
method: 'post',
data
url: '/goods/catAndBrand',
method: 'get'
})
}
......@@ -8,33 +8,17 @@ export function listOrder(query) {
})
}
export function createOrder(data) {
export function shipOrder(data) {
return request({
url: '/order/create',
url: '/order/ship',
method: 'post',
data
})
}
export function readOrder(data) {
export function refundOrder(data) {
return request({
url: '/order/read',
method: 'get',
data
})
}
export function updateOrder(data) {
return request({
url: '/order/update',
method: 'post',
data
})
}
export function deleteOrder(data) {
return request({
url: '/order/delete',
url: '/order/refund',
method: 'post',
data
})
......
import request from '@/utils/request'
export function listProduct(query) {
return request({
url: '/product/list',
method: 'get',
params: query
})
}
export function createProduct(data) {
return request({
url: '/product/create',
method: 'post',
data
})
}
export function readProduct(data) {
return request({
url: '/product/read',
method: 'get',
data
})
}
export function updateProduct(data) {
return request({
url: '/product/update',
method: 'post',
data
})
}
export function deleteProduct(data) {
return request({
url: '/product/delete',
method: 'post',
data
})
}
import request from '@/utils/request'
export function statUser(query) {
return request({
url: '/stat/user',
method: 'get',
params: query
})
}
export function statOrder(query) {
return request({
url: '/stat/order',
method: 'get',
params: query
})
}
export function statGoods(query) {
return request({
url: '/stat/goods',
method: 'get',
params: query
})
}
......@@ -60,3 +60,6 @@ export function deleteStorage(data) {
data
})
}
const uploadPath = process.env.OS_API + '/storage/create'
export { uploadPath }
const vueSticky = {}
let listenAction
vueSticky.install = Vue => {
Vue.directive('sticky', {
inserted(el, binding) {
const params = binding.value || {}
const stickyTop = params.stickyTop || 0
const zIndex = params.zIndex || 1000
const elStyle = el.style
elStyle.position = '-webkit-sticky'
elStyle.position = 'sticky'
// if the browser support css sticky(Currently Safari, Firefox and Chrome Canary)
// if (~elStyle.position.indexOf('sticky')) {
// elStyle.top = `${stickyTop}px`;
// elStyle.zIndex = zIndex;
// return
// }
const elHeight = el.getBoundingClientRect().height
const elWidth = el.getBoundingClientRect().width
elStyle.cssText = `top: ${stickyTop}px; z-index: ${zIndex}`
const parentElm = el.parentNode || document.documentElement
const placeholder = document.createElement('div')
placeholder.style.display = 'none'
placeholder.style.width = `${elWidth}px`
placeholder.style.height = `${elHeight}px`
parentElm.insertBefore(placeholder, el)
let active = false
const getScroll = (target, top) => {
const prop = top ? 'pageYOffset' : 'pageXOffset'
const method = top ? 'scrollTop' : 'scrollLeft'
let ret = target[prop]
if (typeof ret !== 'number') {
ret = window.document.documentElement[method]
}
return ret
}
const sticky = () => {
if (active) {
return
}
if (!elStyle.height) {
elStyle.height = `${el.offsetHeight}px`
}
elStyle.position = 'fixed'
elStyle.width = `${elWidth}px`
placeholder.style.display = 'inline-block'
active = true
}
const reset = () => {
if (!active) {
return
}
elStyle.position = ''
placeholder.style.display = 'none'
active = false
}
const check = () => {
const scrollTop = getScroll(window, true)
const offsetTop = el.getBoundingClientRect().top
if (offsetTop < stickyTop) {
sticky()
} else {
if (scrollTop < elHeight + stickyTop) {
reset()
}
}
}
listenAction = () => {
check()
}
window.addEventListener('scroll', listenAction)
},
unbind() {
window.removeEventListener('scroll', listenAction)
}
})
}
export default vueSticky
import waves from './waves'
const install = function(Vue) {
Vue.directive('waves', waves)
}
if (window.Vue) {
window.waves = waves
Vue.use(install); // eslint-disable-line
}
waves.install = install
export default waves
.waves-ripple {
position: absolute;
border-radius: 100%;
background-color: rgba(0, 0, 0, 0.15);
background-clip: padding-box;
pointer-events: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-transform: scale(0);
-ms-transform: scale(0);
transform: scale(0);
opacity: 1;
}
.waves-ripple.z-active {
opacity: 0;
-webkit-transform: scale(2);
-ms-transform: scale(2);
transform: scale(2);
-webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
transition: opacity 1.2s ease-out, transform 0.6s ease-out;
transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out;
}
\ No newline at end of file
import './waves.css'
export default{
bind(el, binding) {
el.addEventListener('click', e => {
const customOpts = Object.assign({}, binding.value)
const opts = Object.assign({
ele: el, // 波纹作用元素
type: 'hit', // hit点击位置扩散center中心点扩展
color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
}, customOpts)
const target = opts.ele
if (target) {
target.style.position = 'relative'
target.style.overflow = 'hidden'
const rect = target.getBoundingClientRect()
let ripple = target.querySelector('.waves-ripple')
if (!ripple) {
ripple = document.createElement('span')
ripple.className = 'waves-ripple'
ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'
target.appendChild(ripple)
} else {
ripple.className = 'waves-ripple'
}
switch (opts.type) {
case 'center':
ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px'
ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px'
break
default:
ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + 'px'
ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.body.scrollLeft) + 'px'
}
ripple.style.backgroundColor = opts.color
ripple.className = 'waves-ripple z-active'
return false
}
}, false)
}
}
......@@ -14,7 +14,7 @@ function hasPermission(roles, permissionRoles) {
return roles.some(role => permissionRoles.indexOf(role) >= 0)
}
const whiteList = ['/login', '/authredirect']// no redirect whitelist
const whiteList = ['/login']// no redirect whitelist
router.beforeEach((to, from, next) => {
NProgress.start() // start progress bar
......@@ -33,7 +33,7 @@ router.beforeEach((to, from, next) => {
})
}).catch(() => {
store.dispatch('FedLogOut').then(() => {
Message.error('Verification failed, please login again')
Message.error('验证失败,请输入正确的用户名和密码')
next({ path: '/login' })
})
})
......
......@@ -29,7 +29,6 @@ import Layout from '../views/layout/Layout'
**/
export const constantRouterMap = [
{ path: '/login', component: _import('login/index'), hidden: true },
{ path: '/authredirect', component: _import('login/authredirect'), hidden: true },
{ path: '/404', component: _import('error/404'), hidden: true },
{ path: '/401', component: _import('error/401'), hidden: true },
{
......@@ -66,8 +65,7 @@ export const asyncRouterMap = [
{ path: 'address', component: _import('user/address'), name: 'address', meta: { title: '收货地址', noCache: true }},
{ path: 'collect', component: _import('user/collect'), name: 'collect', meta: { title: '会员收藏', noCache: true }},
{ path: 'footprint', component: _import('user/footprint'), name: 'footprint', meta: { title: '会员足迹', noCache: true }},
{ path: 'history', component: _import('user/history'), name: 'history', meta: { title: '搜索历史', noCache: true }},
{ path: 'cart', component: _import('user/cart'), name: 'cart', meta: { title: '购物车', noCache: true }}
{ path: 'history', component: _import('user/history'), name: 'history', meta: { title: '搜索历史', noCache: true }}
]
},
......@@ -100,13 +98,13 @@ export const asyncRouterMap = [
icon: 'chart'
},
children: [
{ path: 'goods', component: _import('goods/goods'), name: 'goods', meta: { title: '商品管理', noCache: true }},
{ path: 'attribute', component: _import('goods/attribute'), name: 'attribute', meta: { title: '商品参数', noCache: true }},
{ path: 'specification', component: _import('goods/specification'), name: 'specification', meta: { title: '商品规格', noCache: true }},
{ path: 'product', component: _import('goods/product'), name: 'product', meta: { title: '货品管理', noCache: true }},
{ path: 'comment', component: _import('goods/comment'), name: 'comment', meta: { title: '用户评论', noCache: true }}
{ path: 'list', component: _import('goods/list'), name: 'goodsList', meta: { title: '商品列表', noCache: true }},
{ path: 'create', component: _import('goods/create'), name: 'goodsCreate', meta: { title: '商品上架', noCache: true }},
{ path: 'edit', component: _import('goods/edit'), name: 'goodsEdit', meta: { title: '商品编辑', noCache: true }, hidden: true },
{ path: 'comment', component: _import('goods/comment'), name: 'goodsComment', meta: { title: '商品评论', noCache: true }}
]
},
{
path: '/promotion',
component: Layout,
......@@ -121,6 +119,7 @@ export const asyncRouterMap = [
{ path: 'topic', component: _import('promotion/topic'), name: 'topic', meta: { title: '专题管理', noCache: true }}
]
},
{
path: '/sys',
component: Layout,
......@@ -136,5 +135,21 @@ export const asyncRouterMap = [
]
},
{
path: '/stat',
component: Layout,
redirect: 'noredirect',
name: 'statManage',
meta: {
title: '统计',
icon: 'chart'
},
children: [
{ path: 'user', component: _import('stat/user'), name: 'statUser', meta: { title: '用户统计', noCache: true }},
{ path: 'order', component: _import('stat/order'), name: 'statOrder', meta: { title: '订单统计', noCache: true }},
{ path: 'goods', component: _import('stat/goods'), name: 'statGoods', meta: { title: '商品统计', noCache: true }}
]
},
{ path: '*', redirect: '/404', hidden: true }
]
......@@ -26,22 +26,32 @@ service.interceptors.request.use(config => {
service.interceptors.response.use(
response => {
const res = response.data
if (res.errno === 502) {
MessageBox.alert('系统内部错误,请联系管理员维护', '错误', {
if (res.errno === 501) {
MessageBox.alert('系统未登录,请重新登录', '未登录', {
confirmButtonText: '确定',
type: 'error'
})
return Promise.reject('error')
} else if (res.errno !== 0) {
MessageBox.alert('超时自动退出系统,请重新登录', '已退出', {
confirmButtonText: '重新登录',
type: 'error'
}).then(() => {
store.dispatch('FedLogOut').then(() => {
location.reload()
})
})
return Promise.reject('error')
} else if (res.errno === 502) {
MessageBox.alert('系统内部错误,请联系管理员维护', '错误', {
confirmButtonText: '确定',
type: 'error'
})
return Promise.reject('error')
} else if (res.errno === 503) {
MessageBox.alert('请求业务目前未支持', '警告', {
confirmButtonText: '确定',
type: 'error'
})
return Promise.reject('error')
} else if (res.errno !== 0) {
// 非5xx的错误属于业务错误,留给具体页面处理
return Promise.reject(response)
} else {
return response
}
......
<template>
<div class="app-container calendar-list-container">
<!-- 查询和其他操作 -->
<div class="filter-container">
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入商品ID" v-model="listQuery.goodsId">
</el-input>
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
<el-button class="filter-item" type="primary" @click="handleCreate" icon="el-icon-edit">添加</el-button>
<el-button class="filter-item" type="primary" :loading="downloadLoading" v-waves icon="el-icon-download" @click="handleDownload">导出</el-button>
</div>
<!-- 查询结果 -->
<el-table size="small" :data="list" v-loading="listLoading" element-loading-text="正在查询中。。。" border fit highlight-current-row>
<el-table-column align="center" width="150px" label="商品参数ID" prop="id" sortable>
</el-table-column>
<el-table-column align="center" min-width="100px" label="商品ID" prop="goodsId">
</el-table-column>
<el-table-column align="center" min-width="100px" label="商品参数名称" prop="attribute">
</el-table-column>
<el-table-column align="center" min-width="200px" label="商品参数值" prop="value">
</el-table-column>
<el-table-column align="center" label="操作" width="250" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
<el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="pagination-container">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listQuery.page"
:page-sizes="[10,20,30,50]" :page-size="listQuery.limit" layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
<!-- 添加或修改对话框 -->
<el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
<el-form :rules="rules" ref="dataForm" :model="dataForm" status-icon label-position="left" label-width="100px" style='width: 400px; margin-left:50px;'>
<el-form-item label="商品ID" prop="goodsId">
<el-input v-model="dataForm.goodsId"></el-input>
</el-form-item>
<el-form-item label="商品参数名" prop="attribute">
<el-input v-model="dataForm.attribute"></el-input>
</el-form-item>
<el-form-item label="商品参数值" prop="value">
<el-input v-model="dataForm.value"></el-input>
</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>
<script>
import { listGoodsAttribute, createGoodsAttribute, updateGoodsAttribute, deleteGoodsAttribute } from '@/api/goods-attribute'
import waves from '@/directive/waves' // 水波纹指令
export default {
name: 'GoodsAttribute',
directives: {
waves
},
data() {
return {
list: null,
total: null,
listLoading: true,
listQuery: {
page: 1,
limit: 10,
goodsId: undefined,
sort: '+id'
},
dataForm: {
id: undefined,
goodsId: undefined,
attribute: undefined,
value: undefined
},
dialogFormVisible: false,
dialogStatus: '',
textMap: {
update: '编辑',
create: '创建'
},
rules: {
goodsId: [{ required: true, message: '商品ID不能为空', trigger: 'blur' }],
attribute: [{ required: true, message: '商品参数名称不能为空', trigger: 'blur' }],
value: [{ required: true, message: '商品参数值不能为空', trigger: 'blur' }]
},
downloadLoading: false
}
},
created() {
this.getList()
},
methods: {
getList() {
this.listLoading = true
listGoodsAttribute(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
})
},
handleFilter() {
this.listQuery.page = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.limit = val
this.getList()
},
handleCurrentChange(val) {
this.listQuery.page = val
this.getList()
},
resetForm() {
this.dataForm = {
id: undefined,
goodsId: undefined,
attribute: undefined,
value: undefined
}
},
handleCreate() {
this.resetForm()
this.dialogStatus = 'create'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
createData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
createGoodsAttribute(this.dataForm).then(response => {
this.list.unshift(response.data.data)
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '创建成功',
type: 'success',
duration: 2000
})
})
}
})
},
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) {
updateGoodsAttribute(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
}
}
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '更新成功',
type: 'success',
duration: 2000
})
})
}
})
},
handleDelete(row) {
deleteGoodsAttribute(row).then(response => {
this.$notify({
title: '成功',
message: '删除成功',
type: 'success',
duration: 2000
})
const index = this.list.indexOf(row)
this.list.splice(index, 1)
})
},
handleDownload() {
this.downloadLoading = true
import('@/vendor/Export2Excel').then(excel => {
const tHeader = ['商品参数ID', '商品ID', '商品参数名称', '商品参数值']
const filterVal = ['id', 'goodsId', 'attribute', 'value']
excel.export_json_to_excel2(tHeader, this.list, filterVal, '商品参数信息')
this.downloadLoading = false
})
}
}
}
</script>
......@@ -7,33 +7,33 @@
</el-input>
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入商品ID" v-model="listQuery.valueId">
</el-input>
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
<el-button class="filter-item" type="primary" icon="el-icon-edit" @click="handleCreate">添加</el-button>
<el-button class="filter-item" type="primary" v-waves icon="el-icon-download" @click="handleDownload" :loading="downloadLoading">导出</el-button>
<el-button class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload" :loading="downloadLoading">导出</el-button>
</div>
<!-- 查询结果 -->
<el-table size="small" :data="list" v-loading="listLoading" element-loading-text="正在查询中。。。" border fit highlight-current-row>
<el-table-column align="center" width="150px" label="评论ID" prop="id" sortable>
<el-table-column align="center" label="用户ID" prop="userId">
</el-table-column>
<el-table-column align="center" width="100px" label="用户ID" prop="userId">
<el-table-column align="center" label="商品ID" prop="valueId">
</el-table-column>
<el-table-column align="center" width="100px" label="商品ID" prop="valueId">
<el-table-column align="center" label="评论内容" prop="content">
</el-table-column>
<el-table-column align="center" min-width="200px" label="评论内容" prop="content">
</el-table-column>
<el-table-column align="center" min-width="200px" label="评论图片" prop="picUrls">
<el-table-column align="center" label="评论图片" prop="picUrls">
<template slot-scope="scope">
<img v-for="item in scope.row.picUrls" :key="item" :src="item" width="40"/>
</template>
</el-table-column>
<el-table-column align="center" min-width="100px" label="时间" prop="addTime">
<el-table-column align="center" label="时间" prop="addTime">
</el-table-column>
<el-table-column align="center" label="操作" width="250" class-name="small-padding fixed-width">
<el-table-column align="center" label="操作" width="200" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
<el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
......@@ -98,13 +98,9 @@
<script>
import { listComment, createComment, updateComment, deleteComment } from '@/api/comment'
import { createStorage } from '@/api/storage'
import waves from '@/directive/waves' // 水波纹指令
export default {
name: 'Comment',
directives: {
waves
},
data() {
return {
list: undefined,
......@@ -115,7 +111,8 @@ export default {
limit: 20,
userId: undefined,
valueId: undefined,
sort: '+id'
sort: 'add_time',
order: 'desc'
},
dataForm: {
id: undefined,
......@@ -123,8 +120,7 @@ export default {
valueId: undefined,
content: undefined,
hasPicture: false,
picUrls: [],
addTime: undefined
picUrls: []
},
dialogFormVisible: false,
dialogStatus: '',
......@@ -174,8 +170,7 @@ export default {
userId: undefined,
valueId: undefined,
content: undefined,
picUrls: [],
addTime: undefined
picUrls: []
}
},
handleCreate() {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment