Authored by 陈峰

Merge branch 'feature/business-board-add-field' into 'master'

增加进销存报表,商品看板增加字段



See merge request !101
... ... @@ -13,3 +13,4 @@ app/bundle
build/dll/
server/bundle/*.json
server/bundle/**/
dist
... ...
... ... @@ -4,11 +4,13 @@ import outinstore from './outinstore-iframe';
import stock from './stock-iframe';
import shop from './shop';
import product from './product';
import inventory from './inventory';
export default {
overview,
sale,
outinstore,
stock,
shop,
product
product,
inventory
};
... ...
export default {
path: '/inventory.html',
name: 'inventory',
component: () => import(/* webpackChunkName: "statistics.inventory" */'./inventory'),
meta: {
pageName: '进销存报表'
}
};
... ...
<template>
<div class="stat-shop">
<layout-body>
<p slot="title">商品看板</p>
<div class="box-filter" :inline="true" :col="1">
<Row>
<Col span="2">选择品牌:</Col>
<Col span="6">
<Select v-model="brandId" style="width: 200px;">
<Option value="0">请选择品牌</Option>
<Option v-for="item in brandList" :value="item.id" :key="item.id">
{{item.brandName}}
</Option>
</Select>
</Col>
<Col span="2">选择类目:</Col>
<Col span="6">
<select-category :value="categoryValue" @select-change="sortChange"></select-category>
</Col>
<Col span="2">货品年季:</Col>
<Col span="6">
<Select v-model="goodsYearsValue" style="width: 120px;">
<Option value="0">请选择年</Option>
<Option v-for="item in goodsYearsList" :value="item.value" :key="item.value">
{{item.name}}
</Option>
</Select>
<Select v-model="goodsSeasonsValue" style="width: 120px;">
<Option value="0">请选择季</Option>
<Option v-for="item in goodsSeasonsList" :value="item.value" :key="item.value">
{{item.name}}
</Option>
</Select>
</Col>
</Row>
<Row>
<Col span="2">时间:</Col>
<Col span="6">
<Date-picker
type="daterange"
v-model="dateRange"
format="yyyy-MM-dd"
placeholder="选择开始结束日期"></Date-picker>
</Col>
<Col span="6">
<Poptip trigger="hover" placement="bottom-end">
<div slot="content">
* 查询的时间跨度不得超过30天
</div>
<Button type="primary" @click="list">筛选</Button>
</Poptip>
<Poptip trigger="hover" placement="bottom-end">
<div slot="content">
* 仅支持历史数据,时间跨度不得超过30天
</div>
<Button type="primary" @click="exportFile">导出</Button>
</Poptip>
</Col>
</Row>
</div>
<layout-list>
<Table border :columns="tableCols" :data="tableData"></Table>
<Page :total="pageData.total" :current="pageData.current"
@on-change="pageChange" :page-size="20" show-total></Page>
</layout-list>
</layout-body>
</div>
</template>
<script>
import moment from 'moment';
import InventoryStore from './store';
import InventoryService from 'services/inventory/inventory-service';
export default {
data() {
return InventoryStore.call(this);
},
created() {
this.inventoryService = new InventoryService();
},
mounted() {
this.loadData();
},
watch: {
dateRange(newDate) {
if (!Array.isArray(newDate)) {
newDate = [];
}
if (!newDate[0]) {
newDate[0] = moment().format('YYYY-MM-DD');
}
if (!newDate[1]) {
newDate[1] = moment().format('YYYY-MM-DD');
}
this.beginDate = moment(Array.isArray(newDate) ? newDate[0] : newDate).format('YYYY-MM-DD');
this.endDate = moment(Array.isArray(newDate) ? newDate[1] : newDate).format('YYYY-MM-DD');
// this.day = this.beginDate === this.endDate === this.today ? '' : this.beginDate;
this.pageData.current = 1;
},
},
methods: {
loadData() {
this.addGoodsYears();
this.getBrandList();
this.list();
},
changeLimit(limit) {
this.dateRange = [this[`day${limit}`], this.today];
this.pageData.current = 1;
},
pageChange(page) {
this.pageData.current = page;
this.list();
},
addGoodsYears() {
let date = new Date();
let startYear = 2018;
let yearList = [];
for (let i = date.getFullYear(); i > startYear; i--) {
yearList.push({
name: i.toString() + '年',
value: i
})
}
this.goodsYearsList = yearList;
},
getBrandList() {
return this.inventoryService.queryBrandsByShopId().then(result => {
this.brandList = result.data;
})
},
sortChange(sort) {
this.maxSortId = sort.max;
this.middleSortId = sort.mid;
this.smallSortId = sort.min;
},
filterParams() {
let pageNum = this.pageData.current;
let pageSize = this.pageData.pageSize;
let brandId = parseInt(this.brandId) ? {brandId: this.brandId} : {};
let goodYear = parseInt(this.goodsYearsValue) ? {goodYear: this.goodsYearsValue} : {};
let goodSeason = parseInt(this.goodsSeasonsValue) ? {goodSeason: this.goodsSeasonsValue} : {};
let smallSortId = parseInt(this.smallSortId) ? {smallSortId: this.smallSortId} : {};
let begin = this.beginDate;
let end = this.endDate;
return Promise.resolve(Object.assign({}, {
pageNum,
pageSize,
begin,
end
}, brandId, goodYear, goodSeason, smallSortId));
},
list() {
this.$Loading.start();
return this.filterParams().then(params => {
return this.inventoryService.queryProductInvoicingOverview(params)
}).then(result => {
if (!result.data) {
result.data = {
pageNo: 1,
pageSize: 1,
totalCount: 1,
totalPage: 1,
records: []
}
}
this.pageData.total = result.data.totalCount;
this.pageData.current = result.data.pageNo;
this.tableData = result.data.records;
this.$Loading.finish();
}).catch(() => {
this.$Loading.finish();
});
},
exportFile() {
let param = {};
param.begin = this.beginDate;
param.end = this.endDate;
param.platform = '1,2,3,4';
if (this.brandId && parseInt(this.brandId)) {
param.brandId = this.brandId;
}
if (this.goodsYearsValue && parseInt(this.goodsYearsValue)) {
param.goodYear = this.goodsYearsValue;
}
if (this.goodsSeasonsValue && parseInt(this.goodsSeasonsValue)) {
param.goodSeason = this.goodsSeasonsValue;
}
if (this.smallSortId && parseInt(this.smallSortId)) {
param.smallSortId = this.smallSortId;
}
const href = '/Api/platform/exportProductInvoicingOverview?queryConf=' +
JSON.stringify(param);
window.open(href, '_blank');
}
}
};
</script>
<style lang="scss">
.stat-shop {
.ivu-tabs-tabpane {
height: 400px;
position: relative;
}
}
.layout-container {
min-height: 200px;
margin: 15px;
overflow: hidden;
background: #fff;
border-radius: 4px;
.layout-filter .line {
border-top: none;
margin-bottom: 0;
}
}
.shop-card {
margin-top: 10px;
margin-bottom: 10px;
}
.box-title {
font-weight: 700;
color: #495060;
font-size: 16px;
line-height: 22px;
margin: 5px;
&:before {
content: " ";
display: inline-block;
width: 5px;
margin-right: 2px;
height: 22px;
vertical-align: top;
background-color: #999;
}
}
.box-item {
width: 90%;
height: 50px;
padding: 0 0 0 15px;
line-height: 50px;
font-size: 14px;
overflow: hidden;
border-radius: 5px;
color: #fff;
margin-bottom: 10px;
.box-item-label {
display: inline-block;
min-width: 75px;
vertical-align: top;
font-weight: normal;
}
.box-item-value {
font-size: 20px;
font-weight: 600;
}
i {
display: inline-block;
width: 20px;
height: 20px;
font-size: 22px;
text-align: center;
margin-top: -7px;
vertical-align: middle;
margin-right: 3px;
}
}
.box-filter {
.ivu-date-picker {
margin-left: 0;
width: 220px !important;
}
.ivu-col {
height: 32px;
line-height: 32px;
text-align: center;
margin-bottom: 20px;
}
.ivu-btn {
margin: 0 10px;
}
.ivu-cascader {
max-width: 220px;
}
.quick {
display: inline-block;
margin-left: 20px;
margin-right: 50px;
a {
margin-right: 5px;
}
}
.brand-select-container {
display: inline-block;
width: 280px;
}
margin-bottom: 20px;
border-bottom: 1px solid #f0f0f0;
}
.ivu-table-cell {
padding-left: 6px;
padding-right: 6px;
}
</style>
... ...
/**
* on product page store
* @author: Gexuhui
* @date: 2017/08/23
*/
import moment from 'moment';
let curDay = moment().format('YYYY-MM-DD');
export default function() {
return {
day: curDay,
date: curDay,
dateRange: [curDay, curDay],
categoryValue: [],
maxSortId: 0,
middleSortId: 0,
smallSortId: 0,
goodsYearsValue: '0',
goodsSeasonsValue: '0',
beginDate: curDay,
endDate: curDay,
today: moment().format('YYYY-MM-DD'),
yesterday: moment().add(-1, 'days').format('YYYY-MM-DD'),
day7: moment().add(-6, 'days').format('YYYY-MM-DD'),
day30: moment().add(-29, 'days').format('YYYY-MM-DD'),
timeLimit: true,
goodsSeasonsList: [
{
name: '春',
value: 1
},
{
name: '夏',
value: 2
},
{
name: '秋',
value: 3
},
{
name: '冬',
value: 4
},
{
name: '春夏',
value: 5
},
{
name: '秋冬',
value: 6
}
],
goodsYearsList: [],
tableCols: [
{
title: 'skn',
align: 'center',
width: 70,
key: 'skn'
},
{
title: 'sku',
align: 'center',
width: 70,
key: 'sku'
},
{
title: '品牌',
align: 'center',
width: 85,
key: 'brandName'
},
{
title: '厂家编号',
align: 'center',
width: 75,
key: 'factoryCode'
},
{
title: '货品年季',
align: 'center',
width: 75,
key: 'goodYearSeason'
},
{
title: '三级品类',
align: 'center',
width: 75,
key: 'smallSortName'
},
{
title: '性别',
align: 'center',
key: 'gender'
},
{
title: '吊牌价',
align: 'center',
width: 70,
key: 'retailPrice'
},
{
title: '当前价',
align: 'center',
width: 70,
key: 'salePrice'
},
{
title: '采购入库数',
key: 'inNum',
align: 'center',
sortable: false
},
{
title: '采购入库金额',
key: 'inAmount',
align: 'center',
width: 85,
sortable: false
},
{
title: '退供应商数',
key: 'outNum',
align: 'center',
sortable: false
},
{
title: '退供应商金额',
key: 'outAmount',
align: 'center',
width: 85,
sortable: false
},
{
title: '交易数量',
key: 'postNum',
align: 'center',
sortable: false
},
{
title: '交易金额',
key: 'postAmount',
align: 'center',
sortable: false
},
{
title: '库存数量',
key: 'storageNum',
align: 'center',
sortable: false
},
{
title: '库存金额',
key: 'storageAmount',
align: 'center',
sortable: false
}
],
tableData: [],
brandList: [],
brandId: '0',
pageData: {
total: 0,
current: 1,
pageSize: 20
},
filters: {
dateRange: {
model: ''
},
begin: {
model: ''
},
end: {
model: ''
}
}
};
}
... ...
... ... @@ -13,6 +13,16 @@
<a href="javascript:;" @click="() => {changeLimit(7)}">近7天</a>
<a href="javascript:;" @click="() => {changeLimit(30)}">近30天</a>
</div>
<div class="brand-select-container">
<span>选择品牌: </span>
<Select v-model="brandId" style="width: 200px;">
<Option value="0">请选择品牌</Option>
<Option v-for="item in brandList" :value="item.id" :key="item.id">
{{item.brandName}}
</Option>
</Select>
</div>
<Poptip trigger="hover" placement="bottom-end">
<div slot="content">
* 仅支持历史数据,时间跨度不得超过30天
... ... @@ -66,11 +76,15 @@
this.day = this.beginDate === this.endDate === this.today ? '' : this.beginDate;
this.pageData.current = 1;
this.list();
},
brandId() {
this.list();
}
},
methods: {
loadData() {
this.list();
this.getBrandList();
},
changeLimit(limit) {
this.dateRange = [this[`day${limit}`], this.today];
... ... @@ -94,16 +108,34 @@
pageSize
});
},
getBrandList() {
return this.productService.queryBrandsByShopId().then(result => {
this.brandList = result.data;
})
},
list() {
this.$Loading.start();
return this.filtersParams().then((params) => {
return this.productService.getShopOverview({
let filter = {
begin: this.beginDate,
end: this.endDate,
pageNo: params.pageNo
});
pageNo: params.pageNo,
};
if (this.brandId && this.brandId !== '0') {
filter = Object.assign({}, filter, {brandId: this.brandId});
}
return this.productService.getShopOverview(filter);
}).then(result => {
if (!result.data) {
result.data = {
pageNo: 1,
pageSize: 1,
totalCount: 1,
totalPage: 1,
records: []
}
}
this.pageData.total = result.data.totalCount;
this.pageData.current = result.data.pageNo;
this.tableData = result.data.records;
... ... @@ -118,6 +150,9 @@
param.begin = this.beginDate;
param.end = this.endDate;
param.platform = '1,2,3,4';
if (this.brandId && this.brandId !== '0') {
param.brandId = this.brandId;
}
const href = '/Api/platform/exportOneShopProductOverview?queryConf=' +
JSON.stringify(param);
... ... @@ -222,6 +257,16 @@
margin-right: 5px;
}
}
.brand-select-container {
display: inline-block;
width: 280px;
}
}
.ivu-table-cell {
padding-left: 6px;
padding-right: 6px;
}
</style>
... ...
... ... @@ -22,7 +22,7 @@ export default function() {
{
title: '商品图片',
key: 'image',
width: 120,
width: '10%',
align: 'center',
render: (h, params) => {
return (
... ... @@ -31,6 +31,36 @@ export default function() {
}
},
{
title: 'skn',
align: 'center',
width: 90,
key: 'skn'
},
{
title: '厂家编号',
align: 'center',
width: 90,
key: 'factoryCode'
},
{
title: '性别',
align: 'center',
width: 80,
key: 'gender'
},
{
title: '三级品类',
align: 'center',
width: 90,
key: 'smallSortName'
},
{
title: '吊牌价',
align: 'center',
width: 90,
key: 'retailPrice'
},
/*{
title: '商品',
align: 'center',
width: 200,
... ... @@ -44,7 +74,7 @@ export default function() {
</div>
);
}
},
},*/
// {
// title: '访客数',
... ... @@ -113,6 +143,18 @@ export default function() {
sortable: true
},
{
title: '库存数',
key: 'stock',
align: 'center',
sortable: true
},
{
title: '交寄数',
key: 'completeNum',
align: 'center',
sortable: true
}
/*{
title: '订单转化率',
key: 'paymentOrderAmountUidsRate',
align: 'center',
... ... @@ -126,9 +168,11 @@ export default function() {
</div>
);
}
},
},*/
],
tableData: [],
brandList: [],
brandId: '0',
pageData: {
total: 0,
current: 1,
... ...
/**
* Created by qiujun on 2019/3/22.
*/
import InventroyService from './inventory-service';
export {
InventroyService
};
... ...
/**
* Created by qiujun on 2019/3/22.
*/
import Service from '../service';
const apiUrl = {
queryBrandsByShopId: '/platform/queryBrandsByShopId',
queryProductInvoicingOverview: '/platform/queryProductInvoicingOverview'
};
class InventroyService extends Service {
queryBrandsByShopId(params) {
return this.get(apiUrl.queryBrandsByShopId, params);
}
queryProductInvoicingOverview(params) {
return this.post(apiUrl.queryProductInvoicingOverview, params);
}
}
export default InventroyService;
... ...
... ... @@ -7,6 +7,7 @@ import Service from '../service';
const apiUrl = {
queryOneShopProductOverview: '/platform/queryOneShopProductOverview',
queryBrandsByShopId: '/platform/queryBrandsByShopId'
};
class ProductService extends Service {
... ... @@ -14,6 +15,10 @@ class ProductService extends Service {
getShopOverview(params) {
return this.post(apiUrl.queryOneShopProductOverview, params);
}
queryBrandsByShopId(params) {
return this.get(apiUrl.queryBrandsByShopId, params);
}
}
export default ProductService;
... ...
... ... @@ -6,8 +6,8 @@ module.exports = {
env: {
NODE_ENV: '"production"'
},
index: path.resolve(__dirname, `../public/dist/${pkg.name}/${pkg.version}/index.html`),
assetsRoot: path.resolve(__dirname, `../public/dist/${pkg.name}/`),
index: path.resolve(__dirname, `../dist/statics/${pkg.name}/${pkg.version}/index.html`),
assetsRoot: path.resolve(__dirname, `../dist/statics/${pkg.name}/`),
assetsSubDirectory: 'static',
assetsPublicPath: '//cdn.yoho.cn/yoho-shop-manage/',
productionSourceMap: true,
... ...
const shelljs = require('shelljs');
const path = require('path');
const distDir = path.join(__dirname, '../dist/node');
shelljs.rm('-rf', distDir);
shelljs.mkdir('-p', distDir);
const cpPaths = [
'.npmrc',
'process.json',
'Dockerfile',
'yarn.lock',
'package.json',
'server',
'manifest.json'
];
new Promise(resolve => { // 加载manifest.json文件
resolve();
}).then(() => { // 拷贝node代码
cpPaths.forEach(p => {
let dist = distDir;
let file = p;
if (typeof p === 'object') {
dist = path.join(dist, p[1]);
file = p[0];
if (!shelljs.test('-e', dist)) {
shelljs.mkdir('-p', dist);
}
}
shelljs.cp('-R', path.join(__dirname, '../', file), dist);
});
}).then(() => { // 安装依赖和清理node_modules
shelljs.cd(distDir);
if (shelljs.exec('yarn --production=true').code !== 0) {
throw 'yarn install faild';
}
}).catch(error => {
console.error(`error:${error}`);
return process.exit(1); //eslint-disable-line
});
... ...
{}
\ No newline at end of file
... ...
This diff could not be displayed because it is too large.
{
"name": "yoho-shop-manage",
"version": "1.0.38",
"version": "1.0.40",
"description": "",
"main": "app.js",
"scripts": {
... ... @@ -8,6 +8,7 @@
"dev": "nodemon --watch server server/app.js",
"static": "node ./build/dev-server.js",
"dist": "node ./build/build.js",
"build:node": "node ./build/node-build.js",
"build": "npm run build:dll --production && node ./build/build.js",
"build:dll": "rimraf build/dll && webpack --config build/webpack.dll.conf.js",
"lint-js": "lint-js",
... ...
... ... @@ -124,7 +124,10 @@ let domainApis = {
queryWarehouseProductList: '/SellerDistributionController/queryWarehouseProductList',
batchDelProduct: '/SellerDistributionController/batchDelProduct',
queryPoolProductList: '/SellerDistributionController/queryPoolProductList',
getBrandNames: '/SellerDistributionController/getBrandNames'
getBrandNames: '/SellerDistributionController/getBrandNames',
queryBrandsByShopId: '/SellerShopsBrandsController/queryBrandsByShopId', // 根据店铺Id获取品牌列表下拉框数据
queryProductInvoicingOverview: '/merchant/queryProductInvoicingOverview', // 商家进销存报表查询
exportProductInvoicingOverview: '/merchant/exportProductInvoicingOverview', // 商家进销存报表导出
},
shop: {
login: '/loginInter',
... ... @@ -134,14 +137,17 @@ let domainApis = {
// 域名列表
const domains = {
erp: 'http://192.168.103.82:9098',
/* erp: 'http://192.168.103.82:9098',
platform: 'http://192.168.102.202:8088/platform',
shop: 'http://192.168.102.211:30016'
shop: 'http://192.168.102.211:30016'*/
erp: 'http://192.168.103.48:9098',
platform: 'http://java-yoho-platform.test3.ingress.dev.yohocorp.com/platform',
shop: 'http://192.168.102.211:30016',
};
if (global.env.Test) {
domains.erp = 'http://192.168.103.82:9098';
domains.platform = 'http://192.168.102.202:8088/platform';
domains.erp = 'http://192.168.103.48:9098';
domains.platform = 'http://java-yoho-platform.test3.ingress.dev.yohocorp.com/platform';
domains.shop = 'http://192.168.102.211:30016';
}
... ...