Authored by 李奇

Merge branch 'feature/product-return' into release/2.0

# Conflicts:
#	app/pages/repository/index.js
<template>
<Select v-model="brandId" @on-change="selectChange">
<Option :value="-1">全部</Option>
<Select v-model="brandId" @on-change="selectChange" clearable>
<Option v-for="option in optionList" :value="option.brandId" :key="option.brandId">
{{option.brandName}}
</Option>
... ...
import Vue from 'vue';
import moneyShort from './money-short';
import timeFormat from './time-format';
Vue.filter('moneyShort', moneyShort);
Vue.filter('timeFormat', timeFormat);
... ...
import _ from 'lodash';
import moment from 'moment';
export default (value) => {
let format;
let unixStamp;
const isNum = _.isFinite(value);
const isObj = _.isPlainObject(value);
const defaultFmt = 'YYYY-MM-DD HH:mm:ss';
if (isNum) {
unixStamp = value;
format = defaultFmt;
} else if (isObj) {
unixStamp = value.time;
format = value.format || defaultFmt;
} else {
unixStamp = 'Invalid value.';
}
return moment.unix(unixStamp).format(format);
};
... ...
... ... @@ -74,7 +74,7 @@ export default function() {
label: '选择品牌',
labelSpan: 6,
fieldSpan: 18,
model: -1
model: ''
},
verifyStatus: {
... ...
... ... @@ -209,7 +209,7 @@ export default function() {
label: '选择品牌',
labelSpan: 6,
fieldSpan: 18,
model: -1
model: ''
},
verifyStatus: {
label: '审核状态',
... ...
... ... @@ -61,7 +61,7 @@
<script>
import _ from 'lodash';
import service from 'product-service';
import {SelectBrand, SelectCategory} from 'components/select';
import {SelectCategory} from 'components/select';
import {CellImage, CellInfo, CellPrice} from 'components/cell';
import vipStore from './store';
... ... @@ -270,7 +270,6 @@
}
},
components: {
SelectBrand,
SelectCategory,
CellImage,
CellInfo,
... ...
import diff from './diff-iframe';
import jit from './jit';
import prodReturn from './return';
import supplement from './supplement';
import prodReturn from './prod-return';
import invoice from './invoice';
export default {
... ...
const page = r => require.ensure([], () => r(require('./return')), 'repository.return');
export default {
path: '/prodReturn.html',
name: 'prodReturn',
component: page,
meta: {
pageName: '商品退库'
}
};
<template>
<LayoutBody>
<LayoutFilter>
<FilterItem>
<Button type="primary" @click="backList">返回列表</Button>
<Button type="primary" @click="exportDetail">导出</Button>
</FilterItem>
<FilterItem>
<p>请退单号:<span class="no">{{returnId}}</span>供应商:<span class="supplier">{{supplierName}}</span></p>
</FilterItem>
</LayoutFilter>
<LayoutList>
<Table border :columns="columns"
@on-selection-change="selectChange" :data="dataList"></Table>
</LayoutList>
</LayoutBody>
</template>
<script>
import store from './store/detail';
import rs from 'return-service';
export default {
data() {
return store.apply(this);
},
created() {
const returnId = this.$route.params.returnId;
const supplierId = this.$route.params.supplierId;
const supplierName = this.$route.params.supplierName;
const params = { supplierId, returnedSupplierId: returnId };
this.returnId = returnId;
this.supplierName = supplierName;
this.$Loading.start();
rs.detail(params).then(res => {
this.$Loading.finish();
this.resolveRes(res.data);
});
},
methods: {
resolveRes(data) {
this.dataList = data.records;
},
backList() {
this.$router.push({ name: 'repository.prodReturn.list' });
},
exportDetail() {
}
}
};
</script>
<style lang="scss">
.no,
.supplier {
padding: 5px;
color: #f00;
background-color: #f9f3f5;
border-radius: 2px;
}
.no {
margin-right: 20px;
}
</style>
... ...
const list = r => require.ensure([], () => r(require('./list')), 'repository.prodReturn');
const detail = r => require.ensure([], () => r(require('./detail')), 'repository.prodReturn');
export default [{
path: '/list.html',
name: 'list',
component: list,
meta: {
pageName: '请退单列表'
}
}, {
path: '/detail/:id.html',
name: 'detail',
component: detail,
meta: {
pageName: '请退单详情'
}
}];
... ...
... ... @@ -5,46 +5,32 @@
<Input v-model.trim.number="filters.sknCode.model"
:placeholder="filters.sknCode.holder" :maxlength="9"></Input>
</FilterItem>
<FilterItem :label="filters.prodCode.label">
<Input v-model.trim="filters.prodCode.model"
:placeholder="filters.prodCode.holder"></Input>
<FilterItem :label="filters.skuCode.label">
<Input v-model.trim.number="filters.skuCode.model"
:placeholder="filters.skuCode.holder" :maxlength="9"></Input>
</FilterItem>
<FilterItem :label="filters.prodBarCode.label">
<Input v-model.trim="filters.prodBarCode.model"
:placeholder="filters.prodBarCode.holder"></Input>
<Input v-model.trim.number="filters.prodBarCode.model"
:placeholder="filters.prodBarCode.holder" :maxlength="9"></Input>
</FilterItem>
<FilterItem :label="filters.priceStatus.label">
<Select v-model.trim="filters.priceStatus.model">
<Option v-for="option in filters.priceStatus.options"
:value="option.value"
:key="option.value">{{option.label}}</Option>
</Select>
<FilterItem :label="filters.reqNum.label">
<Input v-model.trim.number="filters.reqNum.model"
:placeholder="filters.reqNum.holder" :maxlength="9"></Input>
</FilterItem>
<FilterItem :label="filters.saleStatus.label">
<Select v-model.trim="filters.saleStatus.model">
<Option v-for="option in filters.saleStatus.options"
:value="option.value"
:key="option.value">{{option.label}}</Option>
</Select>
<FilterItem :label="filters.reqTime.label">
<Input v-model.trim.number="filters.reqTime.model"
:placeholder="filters.reqTime.holder" :maxlength="9"></Input>
</FilterItem>
<FilterItem :label="filters.stockStatus.label">
<Select v-model.trim="filters.stockStatus.model">
<Option v-for="option in filters.stockStatus.options"
:value="option.value"
:key="option.value">{{option.label}}</Option>
</Select>
</FilterItem>
<FilterItem label="选择类目">
<SelectCategory :value="categoryValue"
@select-change="sortChange"></SelectCategory>
<FilterItem :label="filters.resTime.label">
<Input v-model.trim.number="filters.resTime.model"
:placeholder="filters.resTime.holder" :maxlength="9"></Input>
</FilterItem>
<FilterItem>
<Button type="primary" @click="filterSearch">筛选</Button>
<Button type="primary">导出</Button>
<Button @click="clearFilter">清空条件</Button>
<Button>导出</Button>
</FilterItem>
</LayoutFilter>
<LayoutList>
<Table border :columns="columns"
@on-selection-change="selectChange" :data="dataList"></Table>
... ... @@ -56,33 +42,15 @@
<script>
import _ from 'lodash';
import service from 'product-service';
import {SelectBrand, SelectCategory} from 'components/select';
import {CellImage, CellInfo, CellPrice} from 'components/cell';
import vipStore from './store';
import rs from 'return-service';
import listStore from './store/list';
export default {
data() {
return {
columns: [],
dataList: {},
page: {},
filters: {},
batchRows: [],
submitting: false,
enableFilter: false,
categoryValue: []
};
return listStore.apply(this);
},
created() {
const vip = vipStore.apply(this);
const params = this.filterValues();
this.productList(params);
this.filters = vip.filterFields;
this.columns = vip.tableCols;
this.dataList = vip.tableData;
this.page = vip.pageData;
this.returnList();
},
methods: {
filterValues() {
... ... @@ -124,21 +92,12 @@
this.enableFilter = true;
params = this.filterValues();
this.productList(params);
this.returnList(params);
this.page.current = 1;
},
clearFilter() {
let params = {};
const store = vipStore.apply(this);
this.filters = store.filterFields;
this.enableFilter = false;
params = this.filterValues();
this.productList(params);
this.page.current = 1;
this.categoryValue = [];
},
productList(params) {
returnList(params) {
if (_.isObject(params) &&
typeof params.productSkn !== 'undefined' &&
!_.isFinite(+params.productSkn)) {
... ... @@ -147,7 +106,7 @@
}
this.$Loading.start();
service.vipProductList(params)
rs.list()
.then(res => {
this.$Loading.finish();
if (res.code === 200) {
... ... @@ -155,126 +114,44 @@
}
});
},
reloadList() {
let params = {};
if (this.enableFilter) {
params = this.filterValues();
}
_.merge(params, {
page: 1,
size: 20
});
this.productList(params);
this.page.current = 1;
},
resolveData(data) {
this.dataList = data.list;
this.dataList = data.records;
this.page.total = data.total;
},
enableVipPrice(row) {
const skn = row.productSKN;
const canOpen = row.canOpenFlag;
if (canOpen) {
this.setPriceStatus([{
skn
}], 1);
} else {
this.$Message
.error('与平台签订vip会员价格相关合同后,才能开启', 3);
}
},
disableVipPrice(row) {
const skn = row.productSKN;
this.setPriceStatus([{
skn
}], 2);
},
batchSetVip(status) {
let list = [];
const vsMap = {
1: '启用',
2: '禁用'
};
const len = this.batchRows.length;
if (len) {
_.each(this.batchRows, item => {
list.push({
skn: item.productSKN,
status: item.productVipStatus
});
});
this.setPriceStatus(list, status);
} else {
this.$Message.error(`请先勾选要${vsMap[status]}的商品`, 3);
}
},
setPriceStatus(list, status) {
let sknList = [];
let params = {};
const vsMap = {
1: '启用',
2: '禁用'
};
list = _.filter(list, item => {
return item.status !== status;
});
if (!list.length) {
this.$Message.error(`当前选中的商品中,不包含要${vsMap[status]}的商品`, 3);
return;
}
_.each(list, item => {
sknList.push(item.skn);
});
params.productSknList = sknList;
params.productVipStatus = status;
if (sknList.length) {
if (this.submitting) {
return;
}
this.submitting = true;
service.setVipPriceStatus(params)
.then(() => {
this.reloadList();
this.submitting = false;
this.$Message.success('VIP价格状态变更成功');
});
}
},
sortChange({max, mid, min}) {
this.filters.maxSort.model = max || null;
this.filters.midSort.model = mid || null;
this.filters.minSort.model = min || null;
},
pageChange(page) {
let params = this.filterValues();
params.page = page;
this.page.current = page;
this.productList(params);
this.returnList(params);
},
selectChange(rows) {
this.batchRows = rows;
},
goDetail(row) {
const returnId = row.returnedSupplierId;
const supplierId = row.supplierId;
const supplierName = row.supplierName;
this.$router.push({
name: 'repository.prodReturn.detail',
params: {
returnId,
supplierId,
supplierName
}
});
}
},
components: {
SelectBrand,
SelectCategory,
CellImage,
CellInfo,
CellPrice
}
components: {}
};
</script>
<style lang="scss">
.action-column {
.action-btn {
margin-right: 10px;
}
}
</style>
... ...
/**
* repository return data
* @author: qi.li <qi.li@yoho.cn>
* @date: 2017/06/01
*/
export default function() {
return {
returnId: '',
supplierName: '',
columns: [
{
title: 'SKN',
align: 'center',
key: 'productSkn'
},
{
title: 'SKC(颜色)',
align: 'center',
render: (h, params) => {
const row = params.row;
return (
<span>{row.productSkc}({row.colorName})</span>
);
}
},
{
title: 'SKU(尺码)',
align: 'center',
render: (h, params) => {
const row = params.row;
return (
<span>{row.productSku}({row.sizeName})</span>
);
}
},
{
title: '条码',
align: 'center',
key: 'factoryCode'
},
{
title: '品牌',
align: 'center',
key: 'brandName'
},
{
title: '库存',
align: 'center',
key: 'stockNum'
},
{
title: '占用库存',
align: 'center',
key: 'occupiedNum'
},
{
title: '请退数量',
align: 'center',
key: 'nums'
},
{
title: '已退数量',
align: 'center',
key: 'outNums'
},
{
title: '货位',
align: 'center',
key: 'seatCodeString'
},
{
title: '批次',
align: 'center',
key: 'batchId'
},
{
title: '库存类型',
align: 'center',
key: 'propertyName'
},
{
title: '退货原因',
align: 'center',
key: 'returndReason'
},
{
title: '物流单号',
align: 'center',
key: 'expressCode'
},
{
title: '承担方',
align: 'center',
key: 'feeTypeCn'
},
{
title: '请退时间',
align: 'center',
key: 'createTime'
},
{
title: '退库时间',
align: 'center',
key: 'outTime'
}
],
dataList: []
};
}
... ...
... ... @@ -4,9 +4,43 @@
* @date: 2017/06/01
*/
import timeFormat from 'filters/time-format';
export default function() {
return {
tableCols: [
filters: {
sknCode: {
label: 'SKN编码',
model: '',
holder: ''
},
skuCode: {
label: 'SKU编码',
model: '',
holder: ''
},
prodBarCode: {
label: '商品条码',
model: '',
holder: ''
},
reqNum: {
label: '请退单号',
model: '',
holder: ''
},
reqTime: {
label: '请退时间',
model: '',
holder: ''
},
resTime: {
label: '退库时间',
model: '',
holder: ''
}
},
columns: [
{
type: 'selection',
width: 60,
... ... @@ -14,15 +48,39 @@ export default function() {
},
{
title: '请退单号',
align: 'center'
align: 'center',
key: 'returnedSupplierId'
},
{
title: '供应商',
align: 'center',
key: 'supplierName'
},
{
title: '品牌',
align: 'center'
align: 'center',
key: 'brandName'
},
{
title: '已退/请退数量',
align: 'center'
align: 'center',
render: (h, params) => {
const row = params.row;
const outNum = row.totalOutNums;
const num = row.totalNums;
let percent = 100;
if (num) {
percent = outNum / num * 100;
}
return (
<div>
<i-progress percent={percent} hide-info></i-progress>
<span>{outNum}/{num}</span>
</div>
);
}
},
{
title: '物流信息',
... ... @@ -30,7 +88,8 @@ export default function() {
},
{
title: '备注',
align: 'center'
align: 'center',
key: 'remarks'
},
{
title: '审核状态',
... ... @@ -38,7 +97,12 @@ export default function() {
},
{
title: '请退/退库时间',
align: 'center'
align: 'center',
render: (h, params) => {
return (
<span>{timeFormat(params.row.createTime)}</span>
);
}
},
{
title: '申请人',
... ... @@ -46,45 +110,30 @@ export default function() {
},
{
title: '操作',
align: 'center'
align: 'center',
width: 140,
render: (h, params) => {
const row = params.row;
return (
<div>
<span class="action-btn">
<i-button type="success" size="small"
onClick={() => this.goDetail(row)}>
详情
</i-button>
</span>
<span><i-button type="primary" size="small">导出</i-button></span>
</div>
);
},
className: 'action-column'
}
],
tableData: [],
pageData: {
dataList: [],
page: {
total: 0,
current: 1
},
filterFields: {
sknCode: {
label: 'SKN编码',
model: '',
holder: ''
},
skuCode: {
label: 'SKU编码',
model: '',
holder: ''
},
prodBarCode: {
label: '商品条码',
model: '',
holder: ''
},
reqNum: {
label: '请退单号',
model: '',
holder: ''
},
reqTime: {
label: '请退时间',
model: '',
holder: ''
},
resTime: {
label: '退库时间',
model: '',
holder: ''
}
}
};
}
... ...
import request from 'axios';
const apiUrl = {
list: '/erp/invoiceList',
detail: '/erp/goodsList',
};
function list(params) {
return request.post(apiUrl.listOrder, params)
.then(res => res.data);
}
function detail(params) {
return request.post(apiUrl.listOrder, params)
.then(res => res.data);
}
export default {
list,
detail
};
... ...
/**
* 商品退库service
* @author: qi.li <qi.li@yoho.cn>
* @date: 2017/06/05
*/
import axios from 'axios';
const apiUrl = {
list: '/erp/returnSupplierList',
detail: '/erp/returnSupplierDetail',
};
function list(params) {
return axios.post(apiUrl.list, params)
.then(res => res.data);
}
function detail(params) {
return axios.post(apiUrl.detail, params)
.then(res => res.data);
}
export default {
list,
detail
};
... ...
... ... @@ -16,6 +16,8 @@ let domainApis = {
allotExpressCompList: '/erp-shop-web/express/getExpressList',
allotExportList: '/erp-shop-web/export/exportForPurchaseForm',
allotPrintExpressDetail: '/erp-shop-web/purchase/queryExpressListByExpressNumber',
returnSupplierList: '/erp-shop-web/logistics/returnedSupploer/list',
returnSupplierDetail: '/erp-shop-web/logistics/returnedSupploer/detail',
jitProductList: '/erp-shop-web/product/jitProductList',
getJitStorageListBySkn: '/erp-shop-web/product/getJitStorageListBySkn',
importJitStorage: '/erp-shop-web/product/importJitStorage',
... ...