Authored by TaoHuang

Merge remote-tracking branch 'origin/develop' into develop

... ... @@ -109,7 +109,7 @@ export const createApi = (context, store) => {
})
.then(resolve({ context, store, reqParams }))
.catch(err => {
console.log('---------------', err);
console.log('----create----api--server--get---', err);
});
},
post(url, reqParams = {}) {
... ... @@ -121,7 +121,7 @@ export const createApi = (context, store) => {
})
.then(resolve({ context, store, reqParams }))
.catch(err => {
console.log('---------------', err);
console.log('----create----api--server--post---', err);
});
},
};
... ...
... ... @@ -5,8 +5,7 @@
</template>
<script>
import Layout from "../../components/layout/layout-app";
import RadioGroup from "./components/radio-group";
import Layout from "../../../components/layout/layout-app";
import AddressItem from "./components/address-item";
import axios from "axios";
... ... @@ -19,7 +18,6 @@ export default {
name: "addressManager",
components: {
LayoutApp: Layout,
RadioGroup,
AddressItem
},
data() {
... ...
<template>
<LayoutApp title="添加地址" :show-back="true">
<div class="pane-body">
<FormItem>
<CInput label="收货人" place-holder="请写姓名" v-model="model.receiverName"></CInput>
</FormItem>
<FormItem>
<CInput label="手机号" place-holder="请填写手机号" v-model="model.receiverMobile"></CInput>
</FormItem>
<template>
<FormItem>
<div class="wrapper-area">
<label class="input-label">所在区域</label>
<div class="wrapper-arrow">
<template v-if="model.receiverArea">
<label class="text-label">江苏省南京市三山区</label>
</template>
<template v-else>
<label class="choose-area" @click="chooseArea">请选择</label>
</template>
<div class="arrow"></div>
</div>
</div>
</FormItem>
</template>
<FormItem>
<CInput label="详细地址" place-holder="请输入详细地址" v-model="model.receiverAddress"></CInput>
</FormItem>
<label
ref="labelTags"
class="wrapper-tag"
action="radio_submit"
method="get"
accept-charset="utf-8"
>
<p class="tag-text">设置标签:</p>
<label class="label-text">
<input type="radio" name="tag" value="1" class="label-tag" v-model="model.tagType" /> 家
</label>
<label class="label-text">
<input type="radio" name="tag" value="2" class="label-tag" v-model="model.tagType" /> 公司
</label>
<label class="label-text">
<input type="radio" name="tag" value="3" class="label-tag" v-model="model.tagType" /> 学校
</label>
<label class="label-text">
<input type="radio" name="tag" value="4" class="label-tag" v-model="model.tagType" /> 其他
</label>
</label>
<Radio
class="radio"
:label="{text: '设为默认地址', value: 1}"
style="flex: 0 1 100%;"
v-model="model.defaultType"
></Radio>
<div :class="submitClass" @touchend="onSubmit">确定</div>
</div>
</LayoutApp>
</template>
<script>
import Layout from "../../../components/layout/layout-app";
import Input from "./components/input";
import FormItem from "./components/form-item";
import Radio from "./components/radio";
import { createNamespacedHelpers } from "vuex";
const { mapState, mapMutations, mapActions } = createNamespacedHelpers(
"address/address"
);
export default {
name: "addressEdit",
components: {
LayoutApp: Layout,
CInput: Input,
FormItem,
Radio
},
data() {
return {
model: {
receiverName: "",
receiverMobile: "",
receiverArea: "",
receiverAddress: "",
tagType: 0,
defaultType: false
}
};
},
computed: {
...mapState(["addressList"]),
submitClass() {
return [
"sure-btn",
{
active: this.inNotEmpty
}
];
},
inNotEmpty() {
return true;
}
},
methods: {
...mapMutations({}),
...mapActions([""]),
async onSubmit() {
console.log("被选中的值为:" + this.model.tagType);
console.log("被选中的值为:" + this.model.defaultType);
if (!this.inNotEmpty) {
return;
}
},
chooseArea() {}
},
mounted() {}
};
</script>
<style lang="scss" scoped>
.pane-body {
height: 100%;
overflow-y: auto;
padding-top: 12px;
padding-left: 40px;
padding-right: 40px;
}
.wrapper-area {
display: flex;
flex-direction: column;
.input-label {
font-size: 36px;
display: inline-block;
font-weight: bold;
margin-bottom: 30px;
}
.text-label {
font-size: 28px;
color: #444444;
display: inline-block;
}
.choose-area {
font-size: 28px;
color: #cccccc;
}
.wrapper-arrow {
display: flex;
justify-content: space-between;
}
.arrow {
height: 44px;
width: 44px;
background: url("~statics/image/order/arrow-right.png");
background-size: cover;
}
}
.wrapper-tag {
display: flex;
flex-direction: row;
margin: 30px 0;
align-items: center;
.tag-text {
font-size: 36px;
display: inline-block;
font-weight: bold;
}
.label-text {
margin-left: 20px;
font-size: 30px;
color: #444444;
line-height: 44px;
}
.label-tag {
display: inline-block;
vertical-align: middle;
}
}
.radio {
margin: 30px 0;
}
.sure-btn {
height: 120px;
line-height: 120px;
font-size: 28px;
text-align: center;
background-color: #cccccc;
color: white;
position: absolute;
left: 40px;
right: 40px;
bottom: 40px;
&.active {
background-color: #002b47;
}
}
</style>
... ...
<template>
<div class="radio-group">
<div class="form-item">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'Radio-Group',
name: 'FormItem',
props: {
value: {
type: [String, Number]
model: {
type: String
}
},
data() {
return {
labelList: []
items: []
};
},
methods: {
getLabels() {
return this.$children.forEach(i => i.$options.name === 'Radio');
validate() {
let result = true;
this.items.forEach(i => {
if (!i.validate()) {
result = false;
}
});
return result;
},
updateLabel() {
getItem() {
this.items = this.$children.filter(i => i.$options.name === 'CUpload' || i.$options.name === 'CInput' || i.$options.name === 'CDatePick');
}
},
mounted() {
this.getItem();
}
};
</script>
<style lang="scss" scoped>
.radio-group {
display: flex;
.form-item {
border-bottom: 2px solid #eee;
padding: 30px 0;
}
</style>
... ...
<template>
<div class="input-class">
<div class="wrapper-label" v-if="label">
<label class="input-label">{{label}}</label>
<span class="tip" v-if="showRequired">{{ required ? tip.required : tip.optional}}</span>
<span class="error" v-if="showError">{{error}}</span>
</div>
<slot>
<input
ref="input"
:type="type"
class="wrapper-input"
:placeholder="placeHolder"
:value="inputValue"
@input="onInputChange"
@blur="validate"
:maxlength="maxLength"
/>
</slot>
</div>
</template>
<script>
const NUMREG = /^[0-9]+([.]{1}[0-9]+){0,1}$/;
export default {
name: "CInput",
props: {
value: {
type: [String, Number],
default() {
return "";
}
},
label: {
type: String,
default() {
return "";
}
},
type: {
type: String,
default() {
return "";
}
},
placeHolder: {
type: String,
default() {
return "";
}
},
showRequired: {
type: Boolean,
default() {
return false;
}
},
required: {
type: Boolean,
default() {
return false;
}
},
maxLength: {
type: Number,
default() {
return 100;
}
}
},
data() {
return {
inputValue: this.value,
tipError: "不能为空",
numTipError: "只能为数字",
error: "不能为空",
showError: false,
tip: {
required: "(必填)",
optional: "(选填)"
}
};
},
methods: {
onInputChange() {
if (this.$refs.input.value.length > this.maxLength) {
this.$refs.input.value = this.$refs.input.value.slice(
0,
this.maxLength
);
}
this.inputValue = this.$refs.input.value;
this.$emit("input", this.$refs.input.value);
},
setShowError(status = true) {
this.showError = status;
},
validate() {
if (!this.required) {
return true;
}
if (!this.inputValue) {
this.error = this.tipError;
this.showError = true;
return false;
} else {
if (this.type === "number") {
if (NUMREG.test(this.inputValue)) {
this.showError = false;
return true;
} else {
this.error = this.numTipError;
this.showError = true;
return false;
}
} else {
this.showError = false;
return true;
}
}
}
}
};
</script>
<style lang="scss" scoped>
.input-label {
font-size: 36px;
display: inline-block;
font-weight: bold;
}
.wrapper-label {
margin-bottom: 30px;
}
.wrapper-input {
font-size: 28px;
width: 100%;
/*line-height: 1;*/
line-height: normal;
}
.error {
margin-left: 12px;
color: #d0021b;
}
.tip {
font-size: 20px;
}
::-webkit-input-placeholder {
color: #aaa;
}
</style>
... ...
<template>
<label class="container" @click.stop.prevent="onClickLabel">
<span :class="classes"></span>
<span :class="labelClasses">{{label.text}}</span>
</label>
</template>
<script>
export default {
name: "CRadio",
props: {
value: {
type: [String, Number, Boolean],
default() {
return "";
}
},
label: {
type: Object,
default() {
return { text: "", value: false };
}
},
active: {
type: false,
default() {
return false;
}
}
},
data() {
return {
checked: false
};
},
methods: {
updateLabel() {
this.updateStatus();
},
onClickLabel() {
if (this.$parent.$options.name !== "Radio-Group") {
this.checked = !this.checked;
this.$emit("input", this.checked);
return;
}
this.$emit("input", this.label.value);
},
updateStatus() {
if (this.value === this.label.value) {
this.checked = true;
} else {
this.checked = false;
}
}
},
computed: {
classes() {
return [
"checkmark",
{
"cubeic-round-border": !this.checked,
"cubeic-right": this.checked
}
];
},
labelClasses() {
return [
"radio-label",
{
active: this.checked || this.active,
ml5: this.active
}
];
}
},
watch: {
value() {
this.updateStatus();
}
},
created() {
// this.updateLabel();
this.updateStatus();
}
};
</script>
<style lang="scss" scoped>
.container {
font-size: 28px;
display: flex;
align-content: center;
}
.checkmark {
font-size: 40px;
display: flex;
align-items: center;
}
.radio-label {
display: inline-block;
height: 55px;
font-size: 28px;
line-height: 55px;
margin-left: 20px;
color: #999;
&.active {
color: black;
}
&.ml5 {
margin-left: 10px;
}
}
</style>
... ...
export default [{
name: 'address',
path: '/xianyu/address',
component: () => import('./address')
},
{
name: 'addressEdit',
path: '/xianyu/address/edit',
component: () => import('./addressEdit')
}
];
... ...
export default [{
name: 'address',
path: '/xianyu/address',
component: () => import('./address')
}];
import Address from './address';
export default [...Address];
... ...
<!--买家求购确认页-->
<template>
<LayoutApp :show-back="true">
<div class="body" ref="body">
<div class="topContainer">
<div class="topView">
<div class="title">出价求购</div>
</div>
<!--商品信息-->
<div class="productDetail">
<div class="productImageWrapper">
<!--<ImageFormat class="image" :lazy="lazy" :src="" :width="136" :height="180"></ImageFormat>-->
</div>
<div class="productPrice">
<span class="size">{{sizeInfo}}</span>
<div class="pricedetail">
<span class="priceTitle">最低售价</span>
<span class="price">{{''}}</span>
</div>
</div>
</div>
<div class="inputView">
<span class="inputViewIcon">
¥
</span>
<Input class="wordText" v-model="inputPrice" clearable="true" type="number" placeholder="定价需以9为结尾,例如1999"></Input>
</div>
<div>
<div class="sales">
<span class="tipHeaderText">需要支付保证金:</span>
<span class="tipPriceText">¥{{''}}</span>
</div>
</div>
<div class="saleDetailTips">
{{terms}}
</div>
<div class="space"></div>
<div class="line"></div>
<div class="space"></div>
<div>
<span>商品金额:</span>
<span>{{''}}</span>
</div>
<div>
<span>运费:</span>
<span>{{''}}</span>
</div>
<div>
<span>预计实付金额:</span>
<span>{{''}}</span>
</div>
<order-address></order-address>
<div class="line"></div>
<div class="space"></div>
<day-choose></day-choose>
<div class="space"></div>
<div class="line"></div>
<div class="bottomContainer">
<Button type="submit" disabled="true">提交</Button>
</div>
</div>
</div>
</LayoutApp>
</template>
<script>
import {Input, Button} from 'cube-ui';
import OrderAddress from './components/confirm/address';
import DayChoose from './components/askorder/day-choose';
export default {
name: 'BuyerAskOrder',
components: {Button, DayChoose, OrderAddress},
props: {
lazy: Boolean,
product: Object,
},
component: {
Input,
OrderAddress,
Button,
},
data() {
return {
inputPrice: '',
terms: '求购须支付定金。\n卖家接单后,你需要在24小时内支付商品款。卖家将在你付款后36小时内发货。'
};
},
computed: {
sizeInfo: {
get() {
return '44'
// return goodsInfo ? goodsInfo.colorName + ',' + goodsInfo.sizeName : ''
}
}
}
};
</script>
<style lang="scss" scoped>
.body {
height: 100%;
position: relative;
}
.topContainer {
height: calc(100% - 100px);
padding-left: 20px;
padding-right: 20px;
}
.topView {
width: 100%;
height: 167px;
display: flex;
align-items: flex-start;
background-color: white;
}
.title {
font-weight: bold;
font-size: 34px;
color: #000;
letter-spacing: 0.41px;
line-height: 41px;
margin-left: 20px;
margin-top: 5px;
}
.productDetail {
display: flex;
flex-direction: row;
width: calc(100% - 40);
height: 120px;
margin-left: 20px;
align-items: center;
margin-top: 5px;
background-color: white;
}
.productImageWrapper {
width: 120px;
height: 120px;
background-color: white;
display: flex;
justify-content: center;
align-items: center;
}
.productImage {
width: 110px;
height: 110px;
}
.productPrice {
width: calc(100% - 120px - 40px - 10px);
height: 120px;
margin-left: 10px;
}
.size {
margin-top: 37px;
font-family: "PingFang SC";
font-size: 12px;
color: #999;
letter-spacing: 0;
}
.pricedetail {
display: flex;
flex-direction: row;
height: 30px;
margin-top: 5px;
align-items: flex-end;
}
.priceTitle {
font-family: "PingFang SC";
font-size: 14px;
color: #000;
letter-spacing: 0;
}
.price {
font-family: "DIN Alternate";
font-size: 14px;
color: #000;
line-height: 20.5px;
letter-spacing: 0px;
}
.priceTip {
font-family: "PingFang SC";
font-size: 12px;
color: #D0021B;
letter-spacing: 0px;
width: 80px;
text-align: right;
}
.inputView {
width: calc(100% - 40px);
height: 50px;
border-radius: 5px;
display: flex;
flex-direction: row;
align-items: center;
background-color: #f5f5f5;
}
.inputViewIcon{
line-height: 50px;
font-size: 20px;
color: #000;
margin-left: 10px;
}
.wordText {
margin-left: 10px;
font-family: "DIN Alternate";
font-size: 16px;
color: #000;
width: 100%;
background-color: transparent;
}
.sales {
display: flex;
flex-direction: row;
align-items: center;
}
.tipHeaderText {
font-family: "PingFang SC";
font-size: 14px;
color:#000;
letter-spacing: 0;
margin-left: 20px;
margin-top: 15px;
}
.tipPriceText {
font-family: "PingFang SC";
font-size: 14px;
color: #D0021B;
letter-spacing: 0;
margin-top: 15px;
}
.saleDetailTips {
font-family: "PingFang SC";
font-size: 12px;
color: #999;
letter-spacing: 0px;
margin-top: 5px;
margin-left: 20px;
width: calc(100% - 40px);
}
.space {
width: 100%;
background-color: white;
height: 20px;
}
.line {
width: 100%;
height: 1px;
background-color: #eee;
}
.priceCell {
display: flex;
width: 100%;
height: 25px;
align-items: center;
justify-content: space-between;
}
.bottomContainer {
position: absolute;
bottom: 0px;
height: 100px;
display: flex;
align-items: stretch;
width: 100%;
left: 0px;
}
</style>
... ...
<!--求购时限选择-->
<template>
<div class="customSelectWrapper">
<div class="customSelectTextWrapper">
<span class="leftText">求购期限:</span>
<div class="rightWrapper">
<span class="rightText">{{value}}</span>
<i class="cubeic-arrow" ></i>
</div>
</div>
<Select
v-model="value"
:title="title"
:options="options"
@change="change"
class="customSelect"
/>
</div>
</template>
<script>
import {Select} from 'cube-ui';
export default {
name: 'DayChoose',
components: {Select},
data() {
return {
options: ['1天', '3天', '7天', '15天', '30天'],
value: '7天',
title: '选择求购时限',
};
},
methods: {
change(value, index, text) {
console.log('change', value, index, text);
}
}
};
</script>
<style lang="scss" scoped>
.customSelectWrapper {
position: relative;
height: 60px;
padding-top: 10px;
}
.customSelectTextWrapper {
position: absolute;
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
}
.leftText {
font-family: PingFang-SC-Regular;
font-size: 14px;
color: #000000;
letter-spacing: 0;
}
.rightWrapper {
}
.rightText {
font-family: PingFang-SC-Regular;
font-size: 14px;
color: #000000;
letter-spacing: 0;
}
.customSelect {
position: relative;
opacity: 0 !important;
}
</style>
... ...
... ... @@ -13,6 +13,11 @@ export default [
component: () => import(/* webpackChunkName: "order" */ './confirm'),
props: true
},
{
name: 'buyerAskOrder', //买家求购确认
path: '/xianyu/order/buyeraskorder.html',
component: () => import('./buyer-ask-order')
},
...PriceChange,
...OrderList,
];
... ...
/* eslint-disable operator-linebreak */
const serviceApi = global.yoho.ServiceAPI;
const ufoAPI = global.yoho.UfoAPI;
const checkParams = require('../../utils/check-params');
... ... @@ -5,11 +6,12 @@ const handleResult = require('../../utils/handle-result');
const apiMaps = require('../../config/api-map');
const errorHandler = require('./error-handler');
module.exports = async(req, res, next) => {
// eslint-disable-next-line space-before-function-paren
module.exports = async (req, res, next) => {
res.set({
'Cache-Control': 'no-cache',
Pragma: 'no-cache',
Expires: (new Date(1900, 0, 1, 0, 0, 0, 0)).toUTCString()
Expires: new Date(1900, 0, 1, 0, 0, 0, 0).toUTCString(),
});
const apiInfo = apiMaps[req.path];
... ... @@ -19,7 +21,7 @@ module.exports = async(req, res, next) => {
const baseParams = {};
req.route = {
path: req.path
path: req.path,
};
if (!apiInfo.service) {
... ... @@ -32,15 +34,23 @@ module.exports = async(req, res, next) => {
return req.user.uid;
},
sessionKey: req.user.sessionKey,
appSessionType: req.user.appSessionType
appSessionType: req.user.appSessionType,
};
}
}
if (process.env.NODE_ENV !== 'production') {
baseParams.debug = 'XYZ';
}
try {
const reqParams = Object.assign({}, req.query, req.body, baseParams);
const params = checkParams.getParams(reqParams, apiInfo, req);
const cache = (req.method.toLowerCase() !== 'get' || apiInfo.auth) ? false : apiInfo.cache;
const cache =
req.method.toLowerCase() !== 'get' || apiInfo.auth
? false
: apiInfo.cache;
let method = req.method.toLowerCase() === 'post' ? 'post' : 'get';
... ... @@ -55,7 +65,7 @@ module.exports = async(req, res, next) => {
data: params,
param: {
cache: cache,
}
},
});
} else if (apiInfo.ufo) {
result = await apiCtx[method]({
... ... @@ -63,25 +73,26 @@ module.exports = async(req, res, next) => {
url: apiInfo.path || '',
data: params,
param: {
cache: cache
}
cache: cache,
},
});
} else {
result = await apiCtx[method]({
data: params,
url: apiInfo.path || '',
param: {
cache: cache
}
cache: cache,
},
});
}
if (result) {
return res.json(handleResult(result, apiInfo));
}
return res.json({
code: 400
code: 400,
});
} catch (error) {
console.error('------ssr-api------', error);
return errorHandler.serverError(error, req, res, next);
}
};
... ...