Authored by htoooth

Merge remote-tracking branch 'origin/feature/ufo' into feature/ufo

10.3.0
\ No newline at end of file
... ...
... ... @@ -5,7 +5,7 @@ import {
} from 'store/yoho/types';
import {createApp} from './app';
import {createApi} from 'create-api';
import {Style, Toast} from 'cube-ui'; //eslint-disable-line
import {Style, Toast, Dialog} from 'cube-ui'; //eslint-disable-line
import Lazy from 'vue-lazyload';
import 'statics/scss/common.scss';
import 'statics/font/iconfont.css';
... ... @@ -19,6 +19,7 @@ if (window.__INITIAL_STATE__) {
// Vue.prop('yoho', yoho);
Vue.use(Toast);
Vue.use(Dialog);
Vue.prop('api', createApi());
Vue.use(Lazy, {error: ''});
... ...
... ... @@ -64,7 +64,7 @@ export default {
right: 0;
background-color: rgba(0, 0, 0, 0.4);
height: 100%;
z-index: 1000;
z-index: 99;
&-hidden {
display: none;
... ... @@ -88,7 +88,7 @@ export default {
right: 0;
bottom: 0;
left: 0;
z-index: 1000;
z-index: 99;
-webkit-overflow-scrolling: touch;
outline: 0;
}
... ...
... ... @@ -27,6 +27,7 @@ import {debounce} from 'lodash';
import InputUfo from '../../components/input-ufo';
import Modal from '../../components/modal.vue';
import {createNamespacedHelpers} from 'vuex';
import {get} from 'lodash';
const {mapActions} = createNamespacedHelpers('ufo/order');
... ... @@ -52,6 +53,9 @@ export default {
methods: {
...mapActions(['postCalcPrice']),
show({skc, product}) {
this.chgPrice = '';
this.errorTip = '';
this.prices = [];
this.skc = skc;
this.product = product;
this.visiable = true;
... ... @@ -71,16 +75,26 @@ export default {
product_id: this.product.productId,
storage_id: this.skc.storageId,
new_price: price,
old_price: this.skc.goodPrice,
old_price: this.skc.price,
num: this.skc.storageNum
});
if (result && result.code === 200) {
this.prices = [{
label: '平台费用:',
money: get(result, 'data.platformFee.amount', '')
}, {
label: '银行转账费用:',
money: get(result, 'data.bankTransferFee', '')
}, {
label: '实际收入:',
money: get(result, 'data.income', ''),
total: true
}];
} else {
this.$createToast({
txt: result.message || '计算失败',
type: 'warn',
zIndex: 1000
}).show();
}
},
... ... @@ -94,6 +108,14 @@ export default {
this.errorTip = '价格只能为正整数';
} else if (!/9$/.test(price)) {
this.errorTip = '出售价格必须以9结尾';
} else if (price < this.skc.minPrice) {
this.errorTip = '您的出价过低';
} else if (price > this.skc.maxPrice) {
this.errorTip = '您的出价格过高';
} else if (price === this.skc.price) {
this.errorTip = '前后价格没有变化';
} else if (price === this.skc.price) {
this.errorTip = '前后价格没有变化'; //TODO
} else {
this.errorTip = '';
valid = true;
... ... @@ -105,7 +127,6 @@ export default {
this.$createToast({
txt: this.errorTip,
type: 'warn',
zIndex: 1000
}).show();
} else {
this.$emit('on-change-price', {skc: this.skc, price: this.chgPrice});
... ...
... ... @@ -30,21 +30,42 @@ export default {
data() {
return {
visiable: false,
skc: {},
unStockNum: 1,
storageNum: 1,
};
},
methods: {
show({storageNum}) {
this.storageNum = storageNum;
show({skc}) {
this.skc = skc;
this.unStockNum = 1;
this.storageNum = skc.storageNum;
this.visiable = true;
},
hide() {
this.skc = {};
this.storageNum = 1;
this.unStockNum = 1;
this.visiable = false;
},
onSure() {
this.$emit('on-no-sale', this.unStockNum);
this.$createDialog({
type: 'confirm',
content: '您确定不卖此商品吗?',
confirmBtn: {
text: '确定',
active: true,
disabled: false,
},
cancelBtn: {
text: '取消',
active: false,
disabled: false,
},
onConfirm: () => {
this.$emit('on-no-sale', {skc: this.skc, num: this.unStockNum});
},
}).show();
},
onInput(val) {
this.$emit('input', val);
... ...
... ... @@ -5,7 +5,7 @@
<div class="info">
<div class="left">
<span class="size">{{value.goodsInfo.sizeName}}</span>
<span class="l-size">1/3</span>
<span class="l-size"></span>
<span class="unit">码</span>
</div>
<div class="middle">
... ... @@ -88,7 +88,7 @@ export default {
return;
}
if (0 - distance > 20 && !this.move) {
if (0 - distance > 20) {
this.$emit('on-slide', this.value);
this.move = true;
}
... ...
<template>
<div class="product-group">
<ProductItem
v-for="(skc, i) in skcs"
:key="i"
v-for="skc in skcs"
:key="skc.goodsInfo.storageId"
:value="skc"
:slideValue="slideSkc"
@on-change-price="onChangePrice"
... ... @@ -37,6 +37,10 @@ export default {
},
onSlide(val) {
this.slideSkc = val;
},
reset() {
console.log('this.slideSkc')
this.slideSkc = {};
}
},
components: {ProductItem}
... ...
... ... @@ -17,6 +17,7 @@
</p>
</div>
<ProductList
ref="productList"
:skcs="skcs"
@on-change-price="onChangePrice"
@on-no-sale="onNoSale"
... ... @@ -59,6 +60,7 @@ export default {
classes: {},
page: 1,
modalLoad: false,
pageSize: 10,
};
},
mounted() {
... ... @@ -72,25 +74,47 @@ export default {
},
methods: {
...mapActions(['fetchProduct', 'postChangePrice', 'postNoSale']),
onPullingUp() {
this.fetchProduct({
async onPullingUp() {
const beginCount = this.skcs.length;
await this.fetchProduct({
productId: this.$route.params.orderId,
page: this.page + 1
page: this.page + 1,
pageSize: this.pageSize
});
const afterCount = this.skcs.length;
if (afterCount > beginCount) {
this.page++;
}
this.$refs.scroll.forceUpdate();
},
onChangePrice(skc) {
this.$refs.modalPrice.show({skc, product: this.productInfo});
},
onNoSale(productInfo) {
this.$refs.modalUnstock.show(productInfo);
onNoSale(skc) {
this.$refs.modalUnstock.show({skc});
},
refreshProduct(storageId) {
const findInx = this.skcs.findIndex(skc => skc.goodsInfo.storageId === storageId);
const findPage = parseInt(findInx / this.pageSize, 10) + ((findInx % this.pageSize) ? 1 : 0);
console.log(findInx, findPage)
this.fetchProduct({
productId: this.$route.params.orderId,
page: findPage,
refresh: false,
storageId
});
},
async onChangePriceSure({skc, price}) {
this.refreshProduct(skc.storageId);
return;
const result = await this.postChangePrice({
product_id: this.productInfo.productId,
storage_id: skc.storageId,
new_price: price,
old_price: skc.goodPrice,
old_price: skc.price,
num: skc.storageNum
});
... ... @@ -99,36 +123,35 @@ export default {
this.$createToast({
txt: '调价成功',
type: 'success',
zIndex: 1000
}).show();
this.refreshProduct(skc.storageId);
} else {
this.$createToast({
txt: result.message || '调价失败',
type: 'warn',
zIndex: 1000
}).show();
}
},
async onNoSaleSure({skc, price}) {
async onNoSaleSure({skc, num}) {
const result = await this.postNoSale({
product_id: this.productInfo.productId,
storage_id: skc.storageId,
new_price: price,
old_price: skc.goodPrice,
num: skc.storageNum
old_price: skc.price,
num: num
});
if (result.code === 200) {
this.$refs.modalUnstock.hide();
this.$refs.productList.reset();
this.$createToast({
txt: '下架成功',
type: 'correct'
}).show();
this.refreshProduct(skc.storageId);
} else {
this.$createToast({
txt: result.message || '下架失败',
type: 'warn',
zIndex: 1000
}).show();
}
this.slideSkc = {};
... ...
@charset "utf-8";
/* stylelint-disable */
/*! normalize.css v4.1.1 | MIT License | github.com/necolas/normalize.css */
... ...
@require "~cube-ui/src/common/stylus/var/color.styl"
// action-sheet
$action-sheet-color := $color-grey
$action-sheet-active-color := $color-orange
$action-sheet-bgc := $color-white
$action-sheet-active-bgc := $color-light-grey-opacity
$action-sheet-title-color := $color-dark-grey
$action-sheet-space-bgc := $color-mask-bg
/// picker style
$action-sheet-picker-cancel-color := $color-light-grey
$action-sheet-picker-cancel-active-color := $color-light-grey-s
// bubble
// button
$btn-color := $color-white
$btn-bgc := $color-regular-blue
$btn-bdc := $color-regular-blue
$btn-active-bgc := $color-blue
$btn-active-bdc := $color-blue
$btn-disabled-color := $color-white
$btn-disabled-bgc := $color-light-grey-s
$btn-disabled-bdc := $color-light-grey-s
/// primary
$btn-primary-color := $color-white
$btn-primary-bgc := $color-orange
$btn-primary-bdc := $color-orange
$btn-primary-active-bgc := $color-dark-orange
$btn-primary-active-bdc := $color-dark-orange
/// light
$btn-light-color := $color-grey
$btn-light-bgc := $color-light-grey-sss
$btn-light-bdc := $color-light-grey-sss
$btn-light-active-bgc := $color-active-grey
$btn-light-active-bdc := $color-active-grey
/// outline
$btn-outline-color := $color-grey
$btn-outline-bgc := transparent
$btn-outline-bdc := $color-grey
$btn-outline-active-bgc := $color-grey-opacity
$btn-outline-active-bdc := $color-grey
/// outline-primary
$btn-outline-primary-color := $color-orange
$btn-outline-primary-bgc := transparent
$btn-outline-primary-bdc := $color-orange
$btn-outline-primary-active-bgc := $color-orange-opacity
$btn-outline-primary-active-bdc := $color-dark-orange
// toolbar
$toolbar-bgc := $color-light-grey-sss
$toolbar-active-bgc := $color-active-grey
// checkbox
$checkbox-color := $color-grey
$checkbox-icon-color := $color-light-grey-s
/// checked
$checkbox-checked-icon-color := $color-orange
$checkbox-checked-icon-bgc := $color-white
/// disabled
$checkbox-disabled-icon-color := $color-light-grey-ss
$checkbox-disabled-icon-bgc := $color-light-grey-ss
// checkbox hollow
$checkbox-hollow-checked-icon-color := $color-orange
$checkbox-hollow-disabled-icon-color := $color-light-grey-ss
// checkbox-group
$checkbox-group-bgc := $color-white
$checkbox-group-horizontal-bdc := $color-light-grey-s
// radio
$radio-group-bgc := $color-white
$radio-group-horizontal-bdc := $color-light-grey-s
$radio-color := $color-grey
$radio-icon-color := $color-light-grey-s
/// selected
$radio-selected-icon-color := $color-white
$radio-selected-icon-bgc := $color-orange
/// disabled
$radio-disabled-icon-bgc := $color-light-grey-ss
// radio hollow
$radio-hollow-selected-icon-color := $color-orange
$radio-hollow-disabled-icon-color := $color-light-grey-ss
// dialog
$dialog-color := $color-grey
$dialog-bgc := $color-white
$dialog-icon-color := $color-regular-blue
$dialog-icon-bgc := $color-background
$dialog-title-color := $color-dark-grey
$dialog-close-color := $color-light-grey
$dialog-btn-color := $color-light-grey
$dialog-btn-bgc := $color-white
$dialog-btn-active-bgc := $color-light-grey-opacity
$dialog-btn-highlight-color := #000
$dialog-btn-highlight-active-bgc := rgba(0, 0, 0, .04)
$dialog-btn-disabled-color := $color-light-grey
$dialog-btn-disabled-active-bgc := transparent
$dialog-btns-split-color := $color-row-line
// index-list
$index-list-bgc := $color-white
$index-list-title-color := $color-dark-grey
$index-list-anchor-color := $color-light-grey
$index-list-anchor-bgc := #f7f7f7
$index-list-item-color := $color-dark-grey
$index-list-item-active-bgc := $color-light-grey-opacity
$index-list-nav-color := $color-grey
$index-list-nav-active-color := $color-orange
// loading
// picker
$picker-bgc := $color-white
$picker-title-color := $color-dark-grey
$picker-subtitle-color := $color-light-grey
$picker-confirm-btn-color := $color-orange
$picker-confirm-btn-active-color := $color-light-orange
$picker-cancel-btn-color := $color-light-grey
$picker-cancel-btn-active-color := $color-light-grey-s
$picker-item-color := $color-dark-grey
// popup
$popup-mask-bgc := rgb(37, 38, 45)
$popup-mask-opacity := .4
//scroll
// slide
$slide-dot-bgc := $color-light-grey-s
$slide-dot-active-bgc := $color-orange
// time-picker
// tip
$tip-color := $color-white
$tip-bgc := $color-dark-grey-opacity
// toast
$toast-color := $color-light-grey-s
$toast-bgc := rgba(37, 38, 45, 0.9)
// upload
$upload-btn-color := $color-grey
$upload-btn-bgc := $color-white
$upload-btn-active-bgc := $color-light-grey-opacity
$upload-btn-box-shadow := 0 0 6px 2px $color-grey-opacity
$upload-btn-border-color := #e5e5e5
$upload-file-bgc := $color-white
$upload-file-remove-color := rgba(0, 0, 0, .8)
$upload-file-remove-bgc := $color-white
$upload-file-state-bgc := $color-mask-bg
$upload-file-success-color := $color-orange
$upload-file-error-color := #f43530
$upload-file-status-bgc := $color-white
$upload-file-progress-color := $color-white
// switch
$switch-on-bgc := $color-orange
$switch-off-bgc := $color-white
$switch-off-border-color := #e4e4e4
// input
$input-color := $color-grey
$input-bgc := $color-white
$input-border-color := $color-row-line
$input-focus-border-color := $color-orange
$input-placeholder-color := $color-light-grey-s
$input-clear-icon-color := $color-light-grey
//textarea
$textarea-color := $color-grey
$textarea-bgc := $color-white
$textarea-border-color := $color-row-line
$textarea-focus-border-color := $color-orange
$textarea-outline-color := $color-orange
$textarea-placeholder-color := $color-light-grey-s
$textarea-indicator-color := $color-light-grey-s
// validator
$validator-msg-def-color := #e64340
// select
$select-color := $color-grey
$select-bgc := $color-white
$select-disabled-color := #b8b8b8
$select-disabled-bgc := $color-light-grey-opacity
$select-border-color := $color-light-grey-s
$select-border-active-color := $color-orange
$select-icon-color := $color-light-grey
$select-placeholder-color := $color-light-grey-s
// swipe
$swipe-btn-color := $color-white
// form
$form-color := $color-grey
$form-bgc := $color-white
$form-invalid-color := #e64340
$form-group-legend-color := $color-light-grey
$form-group-legend-bgc := $color-background
$form-label-required-color := #e64340
// drawer
$drawer-color := $color-dark-grey
$drawer-title-bdc := $color-light-grey-ss
$drawer-title-bgc := $color-white
$drawer-panel-bgc := $color-white
$drawer-item-active-bgc := $color-light-grey-opacity
// scroll-nav
$scroll-nav-bgc := $color-white
$scroll-nav-color := $color-grey
$scroll-nav-active-color := $color-orange
// image-preview
$image-preview-counter-color := $color-white
// tab-bar & tab-panel
$tab-color := $color-grey
$tab-active-color := $color-dark-orange
$tab-slider-bgc := $color-dark-orange
\ No newline at end of file
... ...
import * as Types from './types';
export default {
async fetchProduct({commit}, {productId, page = 1, refresh}) {
async fetchProduct({commit}, {productId, page = 1, refresh = false, storageId}) {
commit(Types.FETCH_ORDER_PRODUCT_REQUEST);
const result = await this.$api.get('/api/ufo/seller/entryGoodsSizeList', {
... ... @@ -12,7 +12,8 @@ export default {
if (result && result.code === 200) {
commit(Types.FETCH_ORDER_PRODUCT_SUCCESS, {
order: result.data,
refresh
refresh,
storageId
});
} else {
commit(Types.FETCH_ORDER_PRODUCT_FAILD);
... ...
... ... @@ -8,14 +8,22 @@ export default {
[Types.FETCH_ORDER_PRODUCT_FAILD](state) {
state.fetchingPro = false;
},
[Types.FETCH_ORDER_PRODUCT_SUCCESS](state, {order, refresh}) {
[Types.FETCH_ORDER_PRODUCT_SUCCESS](state, {order, refresh, storageId}) {
state.fetchingPro = false;
if (state.productInfo.productId !== order.productInfo.productId) {
if (order.productInfo && state.productInfo.productId !== order.productInfo.productId) {
state.productInfo = order.productInfo;
}
if (refresh) {
state.skcs = order.data;
} else {
} else if (order.data && storageId) {
const findData = order.data.find(skc => skc.goodsInfo.storageId === storageId);
const findInx = state.skcs.findIndex(skc => skc.goodsInfo.storageId === storageId);
if (findData) {
state.skcs[findInx] = findData;
state.skcs = state.skcs.map(skc => skc);
}
} else if (order.data) {
state.skcs = state.skcs.concat(order.data);
}
},
... ...
... ... @@ -6,7 +6,7 @@ const webpack = require('webpack');
const clientConfig = require('./webpack.client.conf');
const serverConfig = require('./webpack.server.conf');
const pkg = require('../package.json');
const distDir = path.join(__dirname, `../public/dist/${pkg.name}`);
const distDir = path.join(__dirname, `../dist/${pkg.name}`);
rm(path.join(clientConfig.output.path), err => {
... ... @@ -25,22 +25,17 @@ rm(path.join(clientConfig.output.path), err => {
chunkModules: false
}) + '\n\n');
rm(path.join(distDir, './static'), rmerr => {
if (err) {
throw rmerr;
webpack(serverConfig, (serverErr, serverStats) => {
if (serverErr) {
throw serverErr;
}
webpack(serverConfig, (serverErr, serverStats) => {
if (serverErr) {
throw serverErr;
}
process.stdout.write(serverStats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false
}) + '\n\n');
});
process.stdout.write(serverStats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false
}) + '\n\n');
});
});
});
... ...
const shelljs = require('shelljs');
const path = require('path');
const pkg = require('../package.json');
const distDir = path.join(__dirname, '../dist/node');
shelljs.rm('-rf', distDir);
shelljs.mkdir('-p', distDir);
const cpPaths = [
'favicon.ico',
'.nvmrc',
'.npmrc',
'process.json',
'Dockerfile',
'yarn.lock',
'package.json',
'*.js',
'config',
'doraemon',
'utils',
'apps/index.html',
`dist/${pkg.name}/yoho-ssr-client-${pkg.version}.json`,
`dist/${pkg.name}/yoho-ssr-server-${pkg.version}.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(() => { // 验证文件正确性
if (!shelljs.test('-e', path.join(distDir, `yoho-ssr-client-${pkg.version}.json`))) {
console.error('error:check yoho-ssr-client.json faild');
return process.exit(1); //eslint-disable-line
}
if (!shelljs.test('-e', path.join(distDir, `yoho-ssr-server-${pkg.version}.json`))) {
console.error('error:check yoho-ssr-server.json faild');
return process.exit(1); //eslint-disable-line
}
}).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
});
... ...
... ... @@ -6,13 +6,13 @@ var TransformModulesPlugin = require('webpack-transform-modules-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const pkg = require('../package.json');
const isProd = process.env.NODE_ENV === 'production';
const distDir = path.join(__dirname, `../dist/${pkg.name}/bundle`);
const distDir = path.join(__dirname, `../dist/${pkg.name}`);
const webpackConfig = {
mode: isProd ? 'production' : 'development',
output: {
filename: 'static/js/[name].[chunkhash].js',
path: `${distDir}`,
path: distDir,
chunkFilename: 'static/js/[name].[chunkhash].js',
publicPath: '/'
},
... ...
const webpack = require('webpack');
const merge = require('webpack-merge');
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const VueSSRClientPlugin = require('vue-server-renderer/client-plugin');
... ... @@ -69,7 +70,8 @@ const webpackConfig = merge(baseConfig, {
loader: 'stylus-loader',
options: {
sourceMap: isProd,
'resolve url': true
'resolve url': true,
import: [path.resolve(__dirname, '../apps/statics/scss/theme.styl')]
}
}]
}, {
... ...
... ... @@ -18,10 +18,10 @@ let renderer;
let serverBundle;
if (!isDev) {
const template = fs.readFileSync(path.join(__dirname, '../../apps/index.html'), 'utf-8');
const template = fs.readFileSync(path.join(__dirname, '../../index.html'), 'utf-8');
serverBundle = require(`../../dist/yohoblk-wap/bundle/yoho-ssr-server-${pkg.version}.json`);
const clientManifest = require(`../../dist/yohoblk-wap/bundle/yoho-ssr-client-${pkg.version}.json`);
serverBundle = require(`../../yoho-ssr-server-${pkg.version}.json`);
const clientManifest = require(`../../yoho-ssr-client-${pkg.version}.json`);
renderer = createBundleRenderer(serverBundle, {
runInNewContext: false,
... ...
No preview for this file type
{
"name": "yohoblk-wap",
"name": "yoho-app",
"version": "2.0.50",
"private": true,
"description": "A New Yohobuy Project With Express",
"repository": {
"type": "git",
"url": "http://git.yoho.cn/fe/yohoblk-wap.git"
"url": "http://git.yoho.cn/fe/yoho-app.git"
},
"scripts": {
"start": "NODE_ENV=production node app.js",
... ... @@ -14,6 +14,7 @@
"client": "NODE_ENV=production webpack --config ./build/webpack.client.conf.js",
"server": "NODE_ENV=production webpack --config ./build/webpack.server.conf.js",
"build": "NODE_ENV=production node ./build/build.js",
"build:node": "node ./build/node-build.js",
"lint-js": "eslint -c .eslintrc --cache --fix .",
"lint-css": "stylelint --syntax scss --config .stylelintrc public/scss/**/*.css",
"lint-vue": "eslint -c .eslintrc --cache --fix public/vue/**/*.vue || stylelint --syntax scss --extract --config .stylelintrc public/vue/**/*.vue"
... ...
{
"apps": [
{
"name": "yohoblk-wap",
"name": "yoho-app",
"script": "app.js",
"instances": "4",
"max_memory_restart": "300M",
"instances": "1",
"exec_mode": "cluster",
"wait_ready": true,
"merge_logs": true,
"log_date_format": "YYYY-MM-DD HH:mm:ss Z",
"error_file": "/Data/logs/node/yohoblk-wap-err.log",
"out_file": "/Data/logs/node/yohoblk-wap-out.log",
"error_file": "/Data/logs/node/yoho-app-node-err.log",
"out_file": "/Data/logs/node/yoho-app-node-out.log",
"env": {
"PORT": 6004
"TZ": "Asia/Shanghai",
"PORT": 6001
}
}
]
}
\ No newline at end of file
}
... ...