Authored by htoooth

fix

@@ -14,7 +14,7 @@ export default { @@ -14,7 +14,7 @@ export default {
14 name: 'CheckboxSize', 14 name: 'CheckboxSize',
15 props: { 15 props: {
16 sortId: { 16 sortId: {
17 - type: String 17 + type: Number
18 }, 18 },
19 selectSizes: { 19 selectSizes: {
20 type: Array, 20 type: Array,
1 <template> 1 <template>
2 - <div>  
3 - <input type="file" accept=".xlsx" @change="handleChange"> 2 + <div @click="handleClick" style="display: inline-block;">
  3 + <input ref="input" type="file" accept=".xlsx" @change="handleChange">
4 <slot></slot> 4 <slot></slot>
5 </div> 5 </div>
6 </template> 6 </template>
@@ -9,9 +9,13 @@ @@ -9,9 +9,13 @@
9 import request from 'axios'; 9 import request from 'axios';
10 10
11 export default { 11 export default {
  12 + name: 'XlsxUpload',
12 props: { 13 props: {
13 action: { 14 action: {
14 - type: String 15 + type: String,
  16 + default() {
  17 + return '/upload/xlsx';
  18 + }
15 }, 19 },
16 onSuccess: { 20 onSuccess: {
17 type: Function, 21 type: Function,
@@ -44,6 +48,9 @@ @@ -44,6 +48,9 @@
44 }; 48 };
45 }, 49 },
46 methods: { 50 methods: {
  51 + handleClick() {
  52 + this.$refs.input.click();
  53 + },
47 handleChange(e) { 54 handleChange(e) {
48 this.files = e.target.files; 55 this.files = e.target.files;
49 this.onChange(this.files); 56 this.onChange(this.files);
@@ -110,7 +110,7 @@ @@ -110,7 +110,7 @@
110 </Form-item> 110 </Form-item>
111 111
112 <Form-item label="尺寸" prop="selectSize"> 112 <Form-item label="尺寸" prop="selectSize">
113 - <CheckboxSize v-model="table.selectedSizes" :sort-id="product.smallSortId" @on-add="addSize" @on-remove="removeSize"></CheckboxSize> 113 + <CheckboxSize v-model="product.selectSize" :sort-id="product.smallSortId" @on-add="addSize" @on-remove="removeSize"></CheckboxSize>
114 </Form-item> 114 </Form-item>
115 115
116 <Row> 116 <Row>
@@ -387,11 +387,11 @@ export default { @@ -387,11 +387,11 @@ export default {
387 salesPrice: [ 387 salesPrice: [
388 { required: true, trigger: 'blur', validator: validateMustLessRetailPrice}, 388 { required: true, trigger: 'blur', validator: validateMustLessRetailPrice},
389 ], 389 ],
390 - selectSize: [  
391 - { required: true, trigger: 'change', validator: validateColor},  
392 - ],  
393 selectColor: [ 390 selectColor: [
394 - { required: true, trigger: 'change', validator: validateSize}, 391 + { required: true, trigger: 'NONE', validator: validateColor},
  392 + ],
  393 + selectSize: [
  394 + { required: true, trigger: 'NONE', validator: validateSize},
395 ], 395 ],
396 }, 396 },
397 years: 2018 397 years: 2018
@@ -590,6 +590,8 @@ export default { @@ -590,6 +590,8 @@ export default {
590 this.refreshTable(); 590 this.refreshTable();
591 let changeSize = _.first(sizes); 591 let changeSize = _.first(sizes);
592 592
  593 + this.table.selectedSizes.push(changeSize);
  594 +
593 this.table.data.forEach((c) => { 595 this.table.data.forEach((c) => {
594 this.addSizeData(c, changeSize); 596 this.addSizeData(c, changeSize);
595 }); 597 });
@@ -613,6 +615,7 @@ export default { @@ -613,6 +615,7 @@ export default {
613 color.sizeId.splice(index, 1); 615 color.sizeId.splice(index, 1);
614 color.sizeCode.splice(index, 1); 616 color.sizeCode.splice(index, 1);
615 color.operator.splice(index, 1); 617 color.operator.splice(index, 1);
  618 + this.table.selectedSizes.splice(index, 1);
616 } 619 }
617 }, 620 },
618 addSizeData: function(color, findSize) { 621 addSizeData: function(color, findSize) {
@@ -755,22 +758,6 @@ export default { @@ -755,22 +758,6 @@ export default {
755 return this.product.maxSortName + '/' + this.product.middleSortName + '/' + this.product.smallSortName; 758 return this.product.maxSortName + '/' + this.product.middleSortName + '/' + this.product.smallSortName;
756 } 759 }
757 }, 760 },
758 - watch: {  
759 - 'table.selectedSizes': function(newVal, oldVal) {  
760 - if (newVal.length === 0) {  
761 - this.table.showValidateSize = true;  
762 - } else {  
763 - this.table.showValidateSize = false;  
764 - }  
765 - },  
766 - 'table.selectedColors': function(newVal) {  
767 - if (newVal.length === 0) {  
768 - this.table.showValidateColor = true;  
769 - } else {  
770 - this.table.showValidateColor = false;  
771 - }  
772 - }  
773 - },  
774 components: { 761 components: {
775 CheckboxAge, 762 CheckboxAge,
776 RadioSeason, 763 RadioSeason,
@@ -10,11 +10,12 @@ @@ -10,11 +10,12 @@
10 <Form-item label="上传文件:"> 10 <Form-item label="上传文件:">
11 <XlsxUpload 11 <XlsxUpload
12 ref="upload" 12 ref="upload"
13 - action="//jsonplaceholder.typicode.com/posts/"  
14 :on-success="uploadSuccess" 13 :on-success="uploadSuccess"
15 - :on-error="uploadError"> 14 + :on-error="uploadError"
  15 + :on-change="uploadChange">
16 <Button type="ghost" icon="ios-cloud-upload-outline">上传文件</Button> 16 <Button type="ghost" icon="ios-cloud-upload-outline">上传文件</Button>
17 </XlsxUpload> 17 </XlsxUpload>
  18 + <span>{{name}}</span>
18 </Form-item> 19 </Form-item>
19 <Form-item label="说明:"> 20 <Form-item label="说明:">
20 <div style="display: inline-block"> 21 <div style="display: inline-block">
@@ -22,7 +23,7 @@ @@ -22,7 +23,7 @@
22 <li>1、上传文件必须是 <span style="color: red;">.xlsx</span> 文件</li> 23 <li>1、上传文件必须是 <span style="color: red;">.xlsx</span> 文件</li>
23 <li>2、第一行为标题栏:<strong>skn | sku | 库存数量</strong></li> 24 <li>2、第一行为标题栏:<strong>skn | sku | 库存数量</strong></li>
24 <li>3、每次最多导入1000条数据</li> 25 <li>3、每次最多导入1000条数据</li>
25 - <li>4、<a href="">下载样例</a></li> 26 + <li>4、<a href="/example.xlsx">下载样例</a></li>
26 </ul> 27 </ul>
27 </div> 28 </div>
28 </Form-item> 29 </Form-item>
@@ -30,8 +31,8 @@ @@ -30,8 +31,8 @@
30 </div> 31 </div>
31 32
32 <div slot="footer" style="text-align: center"> 33 <div slot="footer" style="text-align: center">
33 - <Button type="primary" size="large" :loading="modal_loading" @click="submit">保存</Button>  
34 - <Button type="primary" size="large" @click="cancel">取消</Button> 34 + <Button type="primary" size="large" :loading="modal_loading" @click="save">保存</Button>
  35 + <Button type="primary" size="large" @click="close">取消</Button>
35 </div> 36 </div>
36 </Modal> 37 </Modal>
37 </template> 38 </template>
@@ -40,30 +41,60 @@ @@ -40,30 +41,60 @@
40 export default { 41 export default {
41 data() { 42 data() {
42 return { 43 return {
43 - url: '',  
44 - model: true, 44 + model: false,
45 modal_loading: false, 45 modal_loading: false,
  46 + fileName: ''
46 }; 47 };
47 }, 48 },
48 methods: { 49 methods: {
49 show() { 50 show() {
  51 + this.reset();
50 this.model = true; 52 this.model = true;
51 }, 53 },
52 - beforeUpload() {  
53 - if (this.$refs.upload.fileList !== 1) {  
54 - this.$refs.upload.fileList.splice(0, 1); 54 + uploadSuccess(result) {
  55 + this.modal_loading = false;
  56 +
  57 + if (result.code === 200) {
  58 + this.$Notice.success({
  59 + title: '更新库存成功',
  60 + });
  61 +
  62 + this.close();
  63 + } else {
  64 + this.$Notice.error({
  65 + title: '保存失败,请重试',
  66 + });
55 } 67 }
56 }, 68 },
57 - uploadSuccess(response, file, fileList) {  
58 - },  
59 - uploadError(error, file, fileList) { 69 + uploadError() {
  70 + this.modal_loading = false;
  71 +
  72 + this.$Notice.error({
  73 + title: '保存失败,请重试',
  74 + });
60 }, 75 },
61 - submit() { 76 + uploadChange(files) {
  77 + if (files.length === 0) {
  78 + return;
  79 + }
  80 +
  81 + this.fileName = files[0].name;
62 }, 82 },
63 - cancel() { 83 + close() {
  84 + this.model = false;
64 }, 85 },
65 save() { 86 save() {
66 - 87 + this.modal_loading = true;
  88 + return this.$refs.upload.upload();
  89 + },
  90 + reset() {
  91 + this.modal_loading = false;
  92 + this.fileName = '';
  93 + }
  94 + },
  95 + computed: {
  96 + name() {
  97 + return this.fileName || '未选择任何文件';
67 } 98 }
68 } 99 }
69 }; 100 };
@@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
15 15
16 <FilterItem> 16 <FilterItem>
17 <Button type="primary" @click="filterSearch">筛选</Button> 17 <Button type="primary" @click="filterSearch">筛选</Button>
18 - <Button type="primary" @click="showImportStore">导入库存</Button> 18 + <Button type="warning" @click="showImportStore">导入库存</Button>
19 <Button @click="clearFilter">清空条件</Button> 19 <Button @click="clearFilter">清空条件</Button>
20 </FilterItem> 20 </FilterItem>
21 </LayoutFilter> 21 </LayoutFilter>
@@ -146,11 +146,10 @@ function getProduct(skn) { @@ -146,11 +146,10 @@ function getProduct(skn) {
146 } 146 }
147 147
148 function addNoneItem(objArray) { 148 function addNoneItem(objArray) {
149 - if (objArray.inputType === 'checkbox') {  
150 - return objArray;  
151 - }  
152 -  
153 objArray.forEach(obj => { 149 objArray.forEach(obj => {
  150 + if (obj.inputType === 'checkbox') {
  151 + return;
  152 + }
154 obj.idNameList && obj.idNameList.unshift({id: 0, text: '请选择' + obj.attributeName}); 153 obj.idNameList && obj.idNameList.unshift({id: 0, text: '请选择' + obj.attributeName});
155 }); 154 });
156 155
@@ -40,6 +40,7 @@ @@ -40,6 +40,7 @@
40 "vue-html5-editor": "^1.1.1", 40 "vue-html5-editor": "^1.1.1",
41 "vue-router": "^2.2.0", 41 "vue-router": "^2.2.0",
42 "vue-template-compiler": "^2.2.6", 42 "vue-template-compiler": "^2.2.6",
  43 + "xlsx2json": "^1.0.0",
43 "yoho-cookie": "^1.2.0", 44 "yoho-cookie": "^1.2.0",
44 "yoho-md5": "^2.0.0", 45 "yoho-md5": "^2.0.0",
45 "yoho-node-lib": "^0.2.18", 46 "yoho-node-lib": "^0.2.18",
@@ -41,6 +41,7 @@ app.use(cookieSession({ @@ -41,6 +41,7 @@ app.use(cookieSession({
41 41
42 app.use(compression()); 42 app.use(compression());
43 app.use(favicon(path.join(__dirname, '/favicon.ico'))); 43 app.use(favicon(path.join(__dirname, '/favicon.ico')));
  44 +app.use(Express.static(path.join(__dirname, 'public')));
44 app.use(bodyParser.json()); 45 app.use(bodyParser.json());
45 app.use(bodyParser.urlencoded({extended: false})); 46 app.use(bodyParser.urlencoded({extended: false}));
46 app.use(cookieParser()); 47 app.use(cookieParser());
@@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
7 7
8 const Context = require('../framework/context'); 8 const Context = require('../framework/context');
9 const FileService = require('../service/file-service'); 9 const FileService = require('../service/file-service');
  10 +const XlsxService = require('../service/xlsx-service');
10 const Api = require('../common/api'); 11 const Api = require('../common/api');
11 const apiDomain = require('../common/api-domain'); 12 const apiDomain = require('../common/api-domain');
12 const fs = require('fs'); 13 const fs = require('fs');
@@ -17,6 +18,7 @@ class FileController extends Context { @@ -17,6 +18,7 @@ class FileController extends Context {
17 super(); 18 super();
18 this.api = this.instance(Api); 19 this.api = this.instance(Api);
19 this.fileService = this.instance(FileService); 20 this.fileService = this.instance(FileService);
  21 + this.xlsxService = this.instance(XlsxService);
20 } 22 }
21 uploadImage(req, res, next) { 23 uploadImage(req, res, next) {
22 let files = req.files && req.files.file || []; 24 let files = req.files && req.files.file || [];
@@ -79,6 +81,23 @@ class FileController extends Context { @@ -79,6 +81,23 @@ class FileController extends Context {
79 }).catch(next); 81 }).catch(next);
80 } 82 }
81 } 83 }
  84 + uploadXlsx(req, res, next) {
  85 + let file = req.files && req.files.file;
  86 +
  87 + return this.xlsxService.handle(file.path).then((result) => {
  88 + if (result.code === 200) {
  89 + return res.json({
  90 + code: 200,
  91 + message: '保存成功'
  92 + });
  93 + } else {
  94 + return res.json({
  95 + code: 500,
  96 + message: result.message
  97 + });
  98 + }
  99 + }).catch(next);
  100 + }
82 } 101 }
83 102
84 module.exports = FileController; 103 module.exports = FileController;
@@ -18,6 +18,7 @@ let router = Express.Router(); // eslint-disable-line @@ -18,6 +18,7 @@ let router = Express.Router(); // eslint-disable-line
18 router.post('/login', middleware(UserController, 'login')); 18 router.post('/login', middleware(UserController, 'login'));
19 router.post('/logout', middleware(UserController, 'logout')); 19 router.post('/logout', middleware(UserController, 'logout'));
20 router.post('/upload/image', multipartMiddleware, middleware(FileController, 'uploadImage')); 20 router.post('/upload/image', multipartMiddleware, middleware(FileController, 'uploadImage'));
  21 +router.post('/upload/xlsx', multipartMiddleware, middleware(FileController, 'uploadXlsx'));
21 22
22 23
23 module.exports = router; 24 module.exports = router;
  1 +/**
  2 + * Created by TaoHuang on 2017/5/17.
  3 + */
  4 +const Context = require('../framework/context');
  5 +const xlsx2json = require('xlsx2json');
  6 +const Api = require('../common/api');
  7 +const apiDomain = global.yoho.apiDomain;
  8 +const _ = require('lodash');
  9 +
  10 +const xlsxRead = (fileName) => {
  11 + return xlsx2json(fileName, {
  12 + dataStartingRow: 2,
  13 + mapping: {
  14 + productSkn: 'A',
  15 + productSku: 'B',
  16 + number: 'c'
  17 + }
  18 + });
  19 +};
  20 +
  21 +class XlsxService extends Context {
  22 + constructor() {
  23 + super();
  24 + this.api = this.instance(Api);
  25 + }
  26 +
  27 + handle(fileName) {
  28 + return xlsxRead(fileName).then((jsonArray) => {
  29 + let data = _.first(jsonArray);
  30 +
  31 + if (!data) {
  32 + return Promise.reject(new Error('数据为空'));
  33 + }
  34 +
  35 + return this.postJitStore(data);
  36 + });
  37 + }
  38 +
  39 + postJitStore(params) {
  40 + let data = {
  41 + brandAuthData: null,
  42 + authLevel: true,
  43 + storageType: 3,
  44 + virtualInventoryBos: params
  45 + };
  46 +
  47 + return this.api.post(apiDomain.erp.importJitStorage, data);
  48 + }
  49 +}
  50 +
  51 +module.exports = XlsxService;