Register
<template>
<div class="register-container">
<!-- 注册内容 -->
<div class="register">
<h3>
注册新用户
<span class="go"
>我有账号,去 <a href="login.html" target="_blank">登陆</a>
</span>
</h3>
<div class="content">
<label>手机号:</label>
<!-- <input type="text" placeholder="请输入你的手机号" v-model="phone" /> -->
<input
placeholder="请输入你的手机号"
v-model="phone"
name="phone"
v-validate="{ required: true, regex: /^1\d{10}$/ }"
:class="{ invalid: errors.has('phone') }"
/>
<span class="error-msg">{
{
errors.first("phone") }}</span>
<!-- <span class="error-msg">错误提示信息</span> -->
</div>
<div class="content">
<label>验证码:</label>
<!-- <input type="text" placeholder="请输入验证码" v-model="code" /> -->
<input
placeholder="请输入你的验证码"
v-model="code"
name="code"
v-validate="{ required: true, regex: /^\d{6}$/ }"
:class="{ invalid: errors.has('code') }"
/>
<!-- <img ref="code" src="http://182.92.128.115/api/user/passport/code" alt="code"> -->
<button style="height: 38px; width: 100px" @click="getCode">
获取验证码
</button>
<span class="error-msg">{
{
errors.first("code") }}</span>
</div>
<div class="content">
<label>登录密码:</label>
<input
placeholder="请输入你的登录密码"
v-model="password"
name="password"
v-validate="{ required: true, regex: /^[0-9A-Za-z]{8,20}$/ }"
:class="{ invalid: errors.has('password') }"
/>
<span class="error-msg">{
{
errors.first("password") }}</span>
</div>
<div class="content">
<label>确认密码:</label>
<input
placeholder="请输入你的确认密码"
v-model="password1"
name="password1"
v-validate="{ required: true, is: password }"
:class="{ invalid: errors.has('password1') }"
/>
<span class="error-msg">{
{
errors.first("password1") }}</span>
</div>
<div class="controls">
<!-- <input name="m1" type="checkbox" :checked="agree" @change="handler" /> -->
<input
v-model="agree"
name="agree"
type="checkbox"
v-validate="{ required: true, tongyi: true }"
:class="{ invalid: errors.has('agree') }"
/>
<span>同意协议并注册《尚品汇用户协议》</span>
<!-- <span class="error-msg">错误提示信息</span> -->
<span class="error-msg">{
{
errors.first("agree") }}</span>
</div>
<div class="btn">
<button @click="userRegister">完成注册</button>
</div>
</div>
<!-- 底部 -->
<div class="copyright">
<ul>
<li>关于我们</li>
<li>联系我们</li>
<li>联系客服</li>
<li>商家入驻</li>
<li>营销中心</li>
<li>手机尚品汇</li>
<li>销售联盟</li>
<li>尚品汇社区</li>
</ul>
<div class="address">地址:北京市昌平区宏福科技园综合楼6层</div>
<div class="beian">京ICP备19006430号</div>
</div>
</div>
</template>
<script>
export default {
name: "Register",
data() {
return {
phone: "",
code: "",
password: "",
password1: "",
agree: true,
};
},
methods: {
async getCode() {
let {
phone } = this;
try {
phone && (await this.$store.dispatch("getCode", phone));
this.code = this.$store.state.user.code;
} catch (error) {
alert(error.message);
}
},
async userRegister() {
const success = await this.$validator.validateAll();
if (success) {
let {
phone, code, password, password1 } = this;
try {
if (password == password1 && phone && code) {
await this.$store.dispatch("userRegister", {
phone,
code,
password,
});
this.$router.push("/login");
}
} catch (error) {
alert(error.message);
}
}
},
handler() {
console.log(this.agree);
},
},
};
</script>
<style lang="less" scoped>
.register-container {
.register {
width: 1200px;
height: 445px;
border: 1px solid rgb(223, 223, 223);
margin: 0 auto;
h3 {
background: #ececec;
margin: 0;
padding: 6px 15px;
color: #333;
border-bottom: 1px solid #dfdfdf;
font-size: 20.04px;
line-height: 30.06px;
span {
font-size: 14px;
float: right;
a {
color: #e1251b;
}
}
}
div:nth-of-type(1) {
margin-top: 40px;
}
.content {
padding-left: 390px;
margin-bottom: 18px;
position: relative;
label {
font-size: 14px;
width: 96px;
text-align: right;
display: inline-block;
}
input {
width: 270px;
height: 38px;
padding-left: 8px;
box-sizing: border-box;
margin-left: 5px;
outline: none;
border: 1px solid #999;
}
img {
vertical-align: sub;
}
.error-msg {
position: absolute;
top: 100%;
left: 495px;
color: red;
}
}
.controls {
text-align: center;
position: relative;
input {
vertical-align: middle;
}
.error-msg {
position: absolute;
top: 100%;
left: 495px;
color: red;
}
}
.btn {
text-align: center;
line-height: 36px;
margin: 17px 0 0 55px;
button {
outline: none;
width: 270px;
height: 36px;
background: #e1251b;
color: #fff !important;
display: inline-block;
font-size: 16px;
}
}
}
.copyright {
width: 1200px;
margin: 0 auto;
text-align: center;
line-height: 24px;
ul {
li {
display: inline-block;
border-right: 1px solid #e4e4e4;
padding: 0 20px;
margin: 15px 0;
}
}
}
}
</style>
Search
index.vue
<template>
<div>
<!-- 商品分类三级列表 -->
<TypeNav />
<div class="main">
<div class="py-container">
<!--bread面包屑,带有x的结构-->
<div class="bread">
<ul class="fl sui-breadcrumb">
<li>
<a href="#">全部结果</a>
</li>
</ul>
<ul class="fl sui-tag">
<!-- 分类的面包屑 -->
<li class="with-x" v-if="searchParams.categoryName">
{
{
searchParams.categoryName
}}<i @click="deleteSearchParams"> ×</i>
</li>
<!-- 关键字的面包屑 -->
<li class="with-x" v-if="searchParams.keyword">
{
{
searchParams.keyword }}<i @click="deleteKeyword"> ×</i>
</li>
<!-- 品牌的面包屑 -->
<li class="with-x" v-if="searchParams.trademark">
{
{
searchParams.trademark.split(":")[1]
}}<i @click="deleteTrademark"> ×</i>
</li>
<!-- 平台的售卖的属性值展示 -->
<li
class="with-x"
v-for="(attrValue, index) in searchParams.props"
:key="index"
>
{
{
attrValue.split(":")[1]
}}<i @click="deleteAttrValue(index)"> ×</i>
</li>
</ul>
</div>
<!--selector-->
<SearchSelector @trademarkInfo="trademarkInfo" @attrInfo="attrInfo" />
<!--details-->
<div class="details clearfix">
<div class="sui-navbar">
<div class="navbar-inner filter">
<!-- 排序的结构 -->
<ul class="sui-nav">
<li :class="{ active: isOne }" @click="changeOrder(1)">
<a href="#"
>综合<span
v-show="isOne"
class="iconfont"
:class="{
'icon-direction-up': isAsc,
'icon-down_light': isDesc,
}"
></span
></a>
</li>
<li :class="{ active: isTwo }" @click="changeOrder(2)">
<a href="#"
>价格<span
v-show="isTwo"
class="iconfont"
:class="{
'icon-direction-up': isAsc,
'icon-down_light': isDesc,
}"
></span>
</a>
</li>
</ul>
</div>
</div>
<div class="goods-list">
<!-- 销售产品列表 -->
<ul class="yui3-g">
<li
class="yui3-u-1-5"
v-for="(good, index) in goodsList"
:key="good.id"
>
<div class="list-wrap">
<div class="p-img">
<!-- <a href="item.html" target="_blank"
></a> -->
<router-link :to="`/detail/${good.id}`"
><img v-lazy="good.defaultImg"
/></router-link>
</div>
<div class="price">
<strong>
<em>¥</em>
<i>{
{
good.price }}.00</i>
</strong>
</div>
<div class="attr">
<a
target="_blank"
href="item.html"
title="促销信息,下单即赠送三个月CIBN视频会员卡!【小米电视新品4A 58 火爆预约中】"
>{
{
good.title }}</a
>
</div>
<div class="commit">
<i class="command">已有<span>2000</span>人评价</i>
</div>
<div class="operate">
<a
href="success-cart.html"
target="_blank"
class="sui-btn btn-bordered btn-danger"
>加入购物车</a
>
<a href="javascript:void(0);" class="sui-btn btn-bordered"
>收藏</a
>
</div>
</div>
</li>
</ul>
</div>
<!-- 分页器 -->
<Pagination
:pageNo="searchParams.pageNo"
:pageSize="searchParams.pageSize"
:total="total"
:continues="5"
@getPageNo="getPageNo"
/>
</div>
</div>
</div>
</div>
</template>
<script>
import SearchSelector from "./SearchSelector/SearchSelector";
import {
mapState } from "vuex";
import {
mapGetters } from "vuex";
export default {
name: "Search",
data() {
return {
searchParams: {
category1Id: "",
category2Id: "",
category3Id: "",
categoryName: "",
keyword: "",
order: "2:desc",
pageNo: 1,
pageSize: 10,
props: [],
trademark: "",
},
};
},
components: {
SearchSelector,
},
beforeMount() {
Object.assign(this.searchParams, this.$route.query, this.$route.params);
},
mounted() {
this.getData();
},
methods: {
getData() {
this.$store.dispatch("getSearchList", this.searchParams);
},
deleteSearchParams() {
this.searchParams.categoryName = undefined;
this.searchParams.category1Id = undefined;
this.searchParams.category2Id = undefined;
this.searchParams.category3Id = undefined;
this.$router.push({
name: "search", params: this.$route.params });
},
deleteKeyword() {
this.searchParams.keyword = "";
this.$bus.$emit("isclear");
this.$router.push({
name: "search", query: this.$route.query });
},
trademarkInfo(trademark) {
this.searchParams.trademark = `${
trademark.tmId}:${
trademark.tmName}`;
this.getData();
},
deleteTrademark() {
this.searchParams.trademark = undefined;
this.getData();
},
attrInfo(attr, attrValue) {
let props = `${
attr.attrId}:${
attrValue}:${
attr.attrName}`;
if (this.searchParams.props.indexOf(props) == -1) {
this.searchParams.props.push(props);
}
this.getData();
},
deleteAttrValue(index) {
this.searchParams.props.splice(index, 1);
this.getData();
},
changeOrder(flag) {
let originOrder = this.searchParams.order;
let originFlag = this.searchParams.order.split(":")[0];
let originSort = this.searchParams.order.split(":")[1];
let newOrder = "";
if (flag == originFlag) {
newOrder = `${
flag}:${
originSort == "desc" ? "asc" : "desc"}`;
}
else {
newOrder = `${
flag}:${
"desc"}`;
}
this.searchParams.order = newOrder;
this.getData();
},
getPageNo(pageNo) {
this.searchParams.pageNo = pageNo;
this.getData();
},
},
computed: {
...mapGetters(["goodsList"]),
isOne() {
return this.searchParams.order.indexOf("1") != -1;
},
isTwo() {
return this.searchParams.order.indexOf("2") != -1;
},
isAsc() {
return this.searchParams.order.indexOf("asc") != -1;
},
isDesc() {
return this.searchParams.order.indexOf("desc") != -1;
},
...mapState({
total: (state) => state.search.SearchList.total,
}),
},
watch: {
$route(to, from) {
this.searchParams.categoryName = undefined;
this.searchParams.category1Id = undefined;
this.searchParams.category2Id = undefined;
this.searchParams.category3Id = undefined;
Object.assign(this.searchParams, this.$route.query, this.$route.params);
this.getData();
},
},
};
</script>
<style lang="less" scoped>
.main {
margin: 10px 0;
.py-container {
width: 1200px;
margin: 0 auto;
.bread {
margin-bottom: 5px;
overflow: hidden;
.sui-breadcrumb {
padding: 3px 15px;
margin: 0;
font-weight: 400;
border-radius: 3px;
float: left;
li {
display: inline-block;
line-height: 18px;
a {
color: #666;
text-decoration: none;
&:hover {
color: #4cb9fc;
}
}
}
}
.sui-tag {
margin-top: -5px;
list-style: none;
font-size: 0;
line-height: 0;
padding: 5px 0 0;
margin-bottom: 18px;
float: left;
.with-x {
font-size: 12px;
margin: 0 5px 5px 0;
display: inline-block;
overflow: hidden;
color: #000;
background: #f7f7f7;
padding: 0 7px;
height: 20px;
line-height: 20px;
border: 1px solid #dedede;
white-space: nowrap;
transition: color 400ms;
cursor: pointer;
i {
margin-left: 10px;
cursor: pointer;
font: 400 14px tahoma;
display: inline-block;
height: 100%;
vertical-align: middle;
}
&:hover {
color: #28a3ef;
}
}
}
}
.details {
margin-bottom: 5px;
.sui-navbar {
overflow: visible;
margin-bottom: 0;
.filter {
min-height: 40px;
padding-right: 20px;
background: #fbfbfb;
border: 1px solid #e2e2e2;
padding-left: 0;
border-radius: 0;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
.sui-nav {
position: relative;
left: 0;
display: block;
float: left;
margin: 0 10px 0 0;
li {
float: left;
line-height: 18px;
a {
display: block;
cursor: pointer;
padding: 11px 15px;
color: #777;
text-decoration: none;
}
&.active {
a {
background: #e1251b;
color: #fff;
}
}
}
}
}
}
.goods-list {
margin: 20px 0;
ul {
display: flex;
flex-wrap: wrap;
li {
height: 100%;
width: 20%;
margin-top: 10px;
line-height: 28px;
.list-wrap {
.p-img {
padding-left: 15px;
width: 215px;
height: 255px;
a {
color: #666;
img {
max-width: 100%;
height: auto;
vertical-align: middle;
}
}
}
.price {
padding-left: 15px;
font-size: 18px;
color: #c81623;
strong {
font-weight: 700;
i {
margin-left: -5px;
}
}
}
.attr {
padding-left: 15px;
width: 85%;
overflow: hidden;
margin-bottom: 8px;
min-height: 38px;
cursor: pointer;
line-height: 1.8;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
a {
color: #333;
text-decoration: none;
}
}
.commit {
padding-left: 15px;
height: 22px;
font-size: 13px;
color: #a7a7a7;
span {
font-weight: 700;
color: #646fb0;
}
}
.operate {
padding: 12px 15px;
.sui-btn {
display: inline-block;
padding: 2px 14px;
box-sizing: border-box;
margin-bottom: 0;
font-size: 12px;
line-height: 18px;
text-align: center;
vertical-align: middle;
cursor: pointer;
border-radius: 0;
background-color: transparent;
margin-right: 15px;
}
.btn-bordered {
min-width: 85px;
background-color: transparent;
border: 1px solid #8c8c8c;
color: #8c8c8c;
&:hover {
border: 1px solid #666;
color: #fff !important;
background-color: #666;
text-decoration: none;
}
}
.btn-danger {
border: 1px solid #e1251b;
color: #e1251b;
&:hover {
border: 1px solid #e1251b;
background-color: #e1251b;
color: white !important;
text-decoration: none;
}
}
}
}
}
}
}
.page {
width: 733px;
height: 66px;
overflow: hidden;
float: right;
.sui-pagination {
margin: 18px 0;
ul {
margin-left: 0;
margin-bottom: 0;
vertical-align: middle;
width: 490px;
float: left;
li {
line-height: 18px;
display: inline-block;
a {
position: relative;
float: left;
line-height: 18px;
text-decoration: none;
background-color: #fff;
border: 1px solid #e0e9ee;
margin-left: -1px;
font-size: 14px;
padding: 9px 18px;
color: #333;
}
&.active {
a {
background-color: #fff;
color: #e1251b;
border-color: #fff;
cursor: default;
}
}
&.prev {
a {
background-color: #fafafa;
}
}
&.disabled {
a {
color: #999;
cursor: default;
}
}
&.dotted {
span {
margin-left: -1px;
position: relative;
float: left;
line-height: 18px;
text-decoration: none;
background-color: #fff;
font-size: 14px;
border: 0;
padding: 9px 18px;
color: #333;
}
}
&.next {
a {
background-color: #fafafa;
}
}
}
}
div {
color: #333;
font-size: 14px;
float: right;
width: 241px;
}
}
}
}
}
}
</style>
SearchSelector
<template>
<div class="clearfix selector">
<div class="type-wrap logo">
<div class="fl key brand">品牌</div>
<div class="value logos">
<!-- 品牌 -->
<ul class="logo-list">
<li v-for="(trademark,index) in trademarkList" :key="trademark.tmId" @click="tradeMarkHandler(trademark)">{
{
trademark.tmName}}</li>
</ul>
</div>
<div class="ext">
<a href="javascript:void(0);" class="sui-btn">多选</a>
<a href="javascript:void(0);">更多</a>
</div>
</div>
<!-- 下面的其他属性 -->
<div class="type-wrap" v-for="(attr,index) in attrsList" :key="attr.attrId">
<!-- 属性名 -->
<div class="fl key">{
{
attr.attrName}}</div>
<div class="fl value">
<!-- 属性值 -->
<ul class="type-list">
<li v-for="(attrValue,index) in attr.attrValueList" :key="index" @click="attrInfo(attr,attrValue)">
<a>{
{
attrValue}}</a>
</li>
</ul>
</div>
<div class="fl ext"></div>
</div>
</div>
</template>
<script>
import {
mapGetters} from"vuex"
export default {
name: 'SearchSelector',
computed:{
...mapGetters(['trademarkList',"attrsList"])
},
methods:{
tradeMarkHandler(trademark){
this.$emit('trademarkInfo',trademark)
},
attrInfo(attr,attrValue){
this.$emit("attrInfo",attr,attrValue);
}
}
}
</script>
<style lang="less" scoped>
.selector {
border: 1px solid #ddd;
margin-bottom: 5px;
overflow: hidden;
.logo {
border-top: 0;
margin: 0;
position: relative;
overflow: hidden;
.key {
padding-bottom: 87px !important;
}
}
.type-wrap {
margin: 0;
position: relative;
border-top: 1px solid #ddd;
overflow: hidden;
.key {
width: 100px;
background: #f1f1f1;
line-height: 26px;
text-align: right;
padding: 10px 10px 0 15px;
float: left;
}
.value {
overflow: hidden;
padding: 10px 0 0 15px;
color: #333;
margin-left: 120px;
padding-right: 90px;
.logo-list {
li {
float: left;
border: 1px solid #e4e4e4;
margin: -1px -1px 0 0;
width: 105px;
height: 52px;
text-align: center;
line-height: 52px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: 700;
color: #e1251b;
font-style: italic;
font-size: 14px;
img {
max-width: 100%;
vertical-align: middle;
}
}
}
.type-list {
li {
float: left;
display: block;
margin-right: 30px;
line-height: 26px;
a {
text-decoration: none;
color: #666;
}
}
}
}
.ext {
position: absolute;
top: 10px;
right: 10px;
.sui-btn {
display: inline-block;
padding: 2px 14px;
box-sizing: border-box;
margin-bottom: 0;
font-size: 12px;
line-height: 18px;
text-align: center;
vertical-align: middle;
cursor: pointer;
padding: 0 10px;
background: #fff;
border: 1px solid #d5d5d5;
}
a {
color: #666;
}
}
}
}
</style>
shopcart
<template>
<div class="cart">
<h4>全部商品</h4>
<div class="cart-main">
<div class="cart-th">
<div class="cart-th1">全部</div>
<div class="cart-th2">商品</div>
<div class="cart-th3">单价(元)</div>
<div class="cart-th4">数量</div>
<div class="cart-th5">小计(元)</div>
<div class="cart-th6">操作</div>
</div>
<div class="cart-body">
<ul
class="cart-list"
v-for="(cart, index) in CartInfoList"
:key="cart.id"
>
<li class="cart-list-con1">
<input
type="checkbox"
name="chk_list"
:checked="cart.isChecked == 1"
@click="handlerCheckedById(cart, $event)"
/>
</li>
<li class="cart-list-con2">
<img :src="cart.imgUrl" />
<div class="item-msg">{
{
cart.skuName }}</div>
</li>
<li class="cart-list-con4">
<span class="price">{
{
cart.skuPrice }}.00</span>
</li>
<li class="cart-list-con5">
<a
href="javascript:void(0)"
class="mins"
@click="handlerNum('minus', -1, cart)"
>-</a
>
<input
autocomplete="off"
type="text"
:value="cart.skuNum"
minnum="1"
class="itxt"
@change="handlerNum('change', $event.target.value * 1, cart)"
/>
<a
href="javascript:void(0)"
class="plus"
@click="handlerNum('add', 1, cart)"
>+</a
>
</li>
<li class="cart-list-con6">
<span class="sum">{
{
cart.skuNum * cart.skuPrice }}</span>
</li>
<li class="cart-list-con7">
<a class="sindelet" @click="deleteCartById(cart)">删除</a>
<br />
<a href="#none">移到收藏</a>
</li>
</ul>
</div>
</div>
<!-- 下部位置 -->
<div class="cart-tool">
<div class="select-all">
<input
class="chooseAll"
type="checkbox"
:checked="isAllchecked && CartInfoList.length > 0"
@change="CheckedAll($event)"
/>
<span>全选</span>
</div>
<div class="option">
<a @click="deleteAllCheckedCart">删除选中的商品</a>
<a href="#none">移到我的关注</a>
<a href="#none">清除下柜商品</a>
</div>
<div class="money-box">
<div class="chosed">已选择 <span>0</span>件商品</div>
<div class="sumprice">
<em>总价(不含运费) :</em>
<i class="summoney">{
{
totalPrice }}</i>
</div>
<div class="sumbtn">
<!-- <a class="sum-btn" target="_blank" @click="$router.push('/trade')">结算</a> -->
<router-link to="/trade" class="sum-btn">结算</router-link>
</div>
</div>
</div>
</div>
</template>
<script>
import {
mapGetters } from "vuex";
import throttle from "lodash/throttle";
export default {
name: "ShopCart",
data() {
return {
num: "50",
};
},
mounted() {
this.getData();
},
methods: {
getData() {
this.$store.dispatch("getCartList");
},
handlerNum: throttle(async function (type, disNum, cart) {
switch (type) {
case "add":
disNum = 1;
break;
case "minus":
disNum = cart.skuNum > 1 ? -1 : 0;
break;
case "change":
if (isNaN(disNum) || disNum < 1) {
disNum = 0;
} else {
disNum = parseInt(disNum) - cart.skuNum;
}
break;
}
try {
await this.$store.dispatch("addorUpdateShopCart", {
skuId: cart.skuId,
skuNum: disNum,
});
this.getData();
} catch (error) {
alert(error.message);
}
}, 1000),
async deleteCartById(cart) {
try {
await this.$store.dispatch("deleteCartListBySkuId", cart.skuId);
this.getData();
} catch (error) {
alert(error.message);
}
},
async handlerCheckedById(cart, event) {
let isTrue = event.target.checked == true ? 1 : 0;
try {
await this.$store.dispatch("checkedById", {
skuId: cart.skuId,
isChecked: isTrue,
});
this.getData();
} catch (error) {
alert(error.message);
}
},
async deleteAllCheckedCart() {
try {
await this.$store.dispatch("deleteAllCheckedCart");
this.getData();
} catch (error) {
alert(error.message);
}
},
async CheckedAll(event) {
let Checked = event.target.checked;
try {
await this.$store.dispatch("checkedAll", Checked);
this.getData();
} catch (error) {
alert(error.message);
}
},
},
computed: {
...mapGetters(["CartList"]),
CartInfoList() {
return this.CartList.cartInfoList || [];
},
totalPrice() {
let sum = 0;
this.CartInfoList.forEach((item) => {
sum += item.skuNum * item.skuPrice;
});
return sum;
},
isAllchecked() {
let res = this.CartInfoList.every((item) => {
return item.isChecked == 1;
});
return res;
},
},
};
</script>
<style lang="less" scoped>
.cart {
width: 1200px;
margin: 0 auto;
h4 {
margin: 9px 0;
font-size: 14px;
line-height: 21px;
}
.cart-main {
.cart-th {
background: #f5f5f5;
border: 1px solid #ddd;
padding: 10px;
overflow: hidden;
& > div {
float: left;
}
.cart-th1 {
width: 25%;
input {
vertical-align: middle;
}
span {
vertical-align: middle;
}
}
.cart-th2 {
width: 25%;
}
.cart-th3,
.cart-th4,
.cart-th5,
.cart-th6 {
width: 12.5%;
}
}
.cart-body {
margin: 15px 0;
border: 1px solid #ddd;
.cart-list {
padding: 10px;
border-bottom: 1px solid #ddd;
overflow: hidden;
& > li {
float: left;
}
.cart-list-con1 {
width: 15%;
}
.cart-list-con2 {
width: 35%;
img {
width: 82px;
height: 82px;
float: left;
}
.item-msg {
float: left;
width: 150px;
margin: 0 10px;
line-height: 18px;
}
}
.cart-list-con4 {
width: 10%;
}
.cart-list-con5 {
width: 17%;
.mins {
border: 1px solid #ddd;
border-right: 0;
float: left;
color: #666;
width: 6px;
text-align: center;
padding: 8px;
}
input {
border: 1px solid #ddd;
width: 40px;
height: 33px;
float: left;
text-align: center;
font-size: 14px;
}
.plus {
border: 1px solid #ddd;
border-left: 0;
float: left;
color: #666;
width: 6px;
text-align: center;
padding: 8px;
}
}
.cart-list-con6 {
width: 10%;
.sum {
font-size: 16px;
}
}
.cart-list-con7 {
width: 13%;
a {
color: #666;
}
}
}
}
}
.cart-tool {
overflow: hidden;
border: 1px solid #ddd;
.select-all {
padding: 10px;
overflow: hidden;
float: left;
span {
vertical-align: middle;
}
input {
vertical-align: middle;
}
}
.option {
padding: 10px;
overflow: hidden;
float: left;
a {
float: left;
padding: 0 10px;
color: #666;
}
}
.money-box {
float: right;
.chosed {
line-height: 26px;
float: left;
padding: 0 10px;
}
.sumprice {
width: 200px;
line-height: 22px;
float: left;
padding: 0 10px;
.summoney {
color: #c81623;
font-size: 16px;
}
}
.sumbtn {
float: right;
a {
display: block;
position: relative;
width: 96px;
height: 52px;
line-height: 52px;
color: #fff;
text-align: center;
font-size: 18px;
font-family: "Microsoft YaHei";
background: #e1251b;
overflow: hidden;
}
}
}
}
}
</style>
trade
<template>
<div class="trade-container">
<h3 class="title">填写并核对订单信息</h3>
<div class="content">
<h5 class="receive">收件人信息</h5>
<div
class="address clearFix"
v-for="(userAdd, index) in userAddress"
:key="userAdd.id"
>
<span class="username" :class="{ selected: userAdd.isDefault == 1 }">{
{
userAdd.consignee
}}</span>
<p @click="changeDefault(userAdd, userAddress)">
<span class="s1">{
{
userAdd.fullAddress }}</span>
<span class="s2">{
{
userAdd.phoneNum }}</span>
<span class="s3" v-show="userAdd.isDefault == 1">默认地址</span>
</p>
</div>
<div class="line"></div>
<h5 class="pay">支付方式</h5>
<div class="address clearFix">
<span class="username selected">在线支付</span>
<span class="username" style="margin-left: 5px">货到付款</span>
</div>
<div class="line"></div>
<h5 class="pay">送货清单</h5>
<div class="way">
<h5>配送方式</h5>
<div class="info clearFix">
<span class="s1">天天快递</span>
<p>配送时间:预计8月10日(周三)09:00-15:00送达</p>
</div>
</div>
<div class="detail">
<h5>商品清单</h5>
<ul
class="list clearFix"
v-for="(order, index) in orderInfo.detailArrayList"
:key="order.skuId"
>
<li>
<img :src="order.imgUrl" style="width: 100px; height: 100px" />
</li>
<li>
<p>
{
{
order.skuName }}
</p>
<h4>7天无理由退货</h4>
</li>
<li>
<h3>¥{
{
order.orderPrice }}.00</h3>
</li>
<li>X{
{
order.skuNum }}</li>
<li>有货</li>
</ul>
</div>
<div class="bbs">
<h5>买家留言:</h5>
<textarea
placeholder="建议留言前先与商家沟通确认"
class="remarks-cont"
v-model="msg"
></textarea>
</div>
<div class="line"></div>
<div class="bill">
<h5>发票信息:</h5>
<div>普通发票(电子) 个人 明细</div>
<h5>使用优惠/抵用</h5>
</div>
</div>
<div class="money clearFix">
<ul>
<li>
<b
><i>{
{
orderInfo.totalNum }}</i
>件商品,总商品金额</b
>
<span>¥{
{
orderInfo.totalAmount }}.00</span>
</li>
<li>
<b>返现:</b>
<span>0.00</span>
</li>
<li>
<b>运费:</b>
<span>0.00</span>
</li>
</ul>
</div>
<div class="trade">
<div class="price">
应付金额:<span>¥{
{
orderInfo.totalAmount }}.00</span>
</div>
<div class="receiveInfo">
寄送至:
<span>{
{
userDefaultAddress.fullAddress }}</span>
收货人:<span>{
{
userDefaultAddress.consignee }}</span>
<span>{
{
userDefaultAddress.phoneNum }}</span>
</div>
</div>
<div class="sub clearFix">
<!-- <router-link to="/pay"></router-link> -->
<a class="subBtn" @click="submitOrder">提交订单</a>
</div>
</div>
</template>
<script>
import {
mapState } from "vuex";
import {
reqSubmitOrder } from "@/api";
export default {
name: "Trade",
data() {
return {
msg: "",
orderId: "",
};
},
mounted() {
this.$store.dispatch("getUserAddress");
this.$store.dispatch("getOrderInfo");
},
computed: {
...mapState({
userAddress: (state) => {
return state.trade.address;
},
}),
...mapState({
orderInfo: (state) => {
return state.trade.orderInfo;
},
}),
userDefaultAddress() {
return this.userAddress.find((item) => item.isDefault == 1) || {
};
},
},
methods: {
changeDefault(userAdd, userAddress) {
userAddress.forEach((item) => {
return (item.isDefault = 0);
});
userAdd.isDefault = 1;
},
async submitOrder() {
let {
tradeNo } = this.orderInfo;
let data = {
consignee: this.userDefaultAddress.consignee,
consigneeTel: this.userDefaultAddress.phoneNum,
deliveryAddress: this.userDefaultAddress.fullAddress,
paymentWay: "ONLINE",
orderComment: this.msg,
orderDetailList: this.orderInfo.detailArrayList,
};
let res = await this.$API.reqSubmitOrder(tradeNo, data);
if (res.code == 200) {
this.orderId = res.data;
this.$router.push(`/pay?orderId=${
this.orderId}`)
}else{
alert(res.data);
console.log("trade界面的",res);
}
},
},
};
</script>
<style lang="less" scoped>
.trade-container {
.title {
width: 1200px;
margin: 0 auto;
font-size: 14px;
line-height: 21px;
}
.content {
width: 1200px;
margin: 10px auto 0;
border: 1px solid rgb(221, 221, 221);
padding: 25px;
box-sizing: border-box;
.receive,
.pay {
line-height: 36px;
margin: 18px 0;
}
.address {
padding-left: 20px;
margin-bottom: 15px;
.username {
float: left;
width: 100px;
height: 30px;
line-height: 30px;
text-align: center;
border: 1px solid #ddd;
position: relative;
}
.username::after {
content: "";
display: none;
width: 13px;
height: 13px;
position: absolute;
right: 0;
bottom: 0;
background: url(./images/choosed.png) no-repeat;
}
.username.selected {
border-color: #e1251b;
}
.username.selected::after {
display: block;
}
p {
width: 610px;
float: left;
line-height: 30px;
margin-left: 10px;
padding-left: 5px;
cursor: pointer;
.s1 {
float: left;
}
.s2 {
float: left;
margin: 0 5px;
}
.s3 {
float: left;
width: 56px;
height: 24px;
line-height: 24px;
margin-left: 10px;
background-color: #878787;
color: #fff;
margin-top: 3px;
text-align: center;
}
}
p:hover {
background-color: #ddd;
}
}
.line {
height: 1px;
background-color: #ddd;
}
.way {
width: 1080px;
height: 110px;
background: #f4f4f4;
padding: 15px;
margin: 0 auto;
h5 {
line-height: 50px;
}
.info {
margin-top: 20px;
.s1 {
float: left;
border: 1px solid #ddd;
width: 120px;
height: 30px;
line-height: 30px;
text-align: center;
margin-right: 10px;
}
p {
line-height: 30px;
}
}
}
.detail {
width: 1080px;
background: #feedef;
padding: 15px;
margin: 2px auto 0;
h5 {
line-height: 50px;
}
.list {
display: flex;
justify-content: space-between;
li {
line-height: 30px;
p {
margin-bottom: 20px;
}
h4 {
color: #c81623;
font-weight: 400;
}
h3 {
color: #e12228;
}
}
}
}
.bbs {
margin-bottom: 15px;
h5 {
line-height: 50px;
}
textarea {
width: 100%;
border-color: #e4e2e2;
line-height: 1.8;
outline: none;
resize: none;
}
}
.bill {
h5 {
line-height: 50px;
}
div {
padding-left: 15px;
}
}
}
.money {
width: 1200px;
margin: 20px auto;
ul {
width: 220px;
float: right;
li {
line-height: 30px;
display: flex;
justify-content: space-between;
i {
color: red;
}
}
}
}
.trade {
box-sizing: border-box;
width: 1200px;
padding: 10px;
margin: 10px auto;
text-align: right;
background-color: #f4f4f4;
border: 1px solid #ddd;
div {
line-height: 30px;
}
.price span {
color: #e12228;
font-weight: 700;
font-size: 14px;
}
.receiveInfo {
color: #999;
}
}
.sub {
width: 1200px;
margin: 0 auto 10px;
.subBtn {
float: right;
width: 164px;
height: 56px;
font: 700 18px "微软雅黑";
line-height: 56px;
text-align: center;
color: #fff;
background-color: #e1251b;
}
}
}
</style>
store文件夹
index.js
import Vue from "vue"
import Vuex from "vuex"
Vue.use(Vuex);
import home from "./home"
import search from "./search";
import detail from "./detail"
import shopcart from "./shopcart"
import user from "./user"
import trade from "./trade/trade.js"
export default new Vuex.Store({
modules:{
home,
search,
detail,
shopcart,
user,
trade,
}
});
detail
import {
reqGetDetailInfo, reqAddorUpdateShopCart } from "@/api"
import {
getUUID } from "@/utils/uuid_token"
const state = {
GoodInfo: [],
uuid_token: getUUID()
}
const mutations = {
GETGOODINFO(state, GoodInfo) {
state.GoodInfo = GoodInfo;
}
}
const actions = {
async GoodInfo({
commit }, id) {
let res = await reqGetDetailInfo(id)
if (res.code == 200) {
commit("GETGOODINFO", res.data)
}
},
async addorUpdateShopCart({
commit }, {
skuId, skuNum }) {
let res = await reqAddorUpdateShopCart(skuId, skuNum);
if (res.code == 200) {
return 'ok';
} else {
return Promise.reject(new Error('faile'));
}
}
}
const getters = {
categoryView() {
return state.GoodInfo.categoryView || {
};
},
skuInfo() {
return state.GoodInfo.skuInfo || {
}
},
spuSaleAttrList() {
return state.GoodInfo.spuSaleAttrList || [];
}
}
export default {
state, getters, actions, mutations
}
home
import {
reqCategoryList, reqGetBannerList, reqGetFloorList } from "@/api";
const state = {
categoryList: [],
bannerList: [],
FloorList: [],
};
const mutations = {
CATEGOTYLIST(state, categoryList) {
state.categoryList = categoryList;
},
BANNERLIST(state, bannerList) {
state.bannerList = bannerList;
},
FLOORLIST(state, FloorList) {
state.FloorList = FloorList
},
};
const actions = {
async categoryList({
commit }) {
let res = await reqCategoryList();
if (res.code == 200) {
commit("CATEGOTYLIST", res.data)
}
},
async bannerList({
commit }) {
let res = await reqGetBannerList();
if (res.code == 200) {
commit("BANNERLIST", res.data);
}
},
async FloorList(context) {
let res = await reqGetFloorList();
if (res.code == 200)
context.commit("FLOORLIST", res.data);
}
};
const getters = {
};
export default {
state,
mutations,
actions,
getters,
}
search
import {
reqGetSearchInfo } from "@/api"
const state = {
SearchList: {
},
};
const mutations = {
GETSEARCHLIST(state, SearchList) {
state.SearchList = SearchList;
}
};
const actions = {
async getSearchList({
commit}, params = {
}) {
let res = await reqGetSearchInfo(params);
if(res.code==200){
commit("GETSEARCHLIST", res.data);
}
}
};
const getters = {
goodsList(state){
return state.SearchList.goodsList||[];
},
trademarkList(state){
return state.SearchList.trademarkList;
},
attrsList(state){
return state.SearchList.attrsList;
}
};
export default {
state,
mutations,
actions,
getters,
}
shopcart
import {
reqGetCartList, reqDeleteCartById, reqCheckedById } from "@/api"
const actions = {
async getCartList({
commit }) {
let res = await reqGetCartList();
if (res.code == 200) {
commit("CARTLIST", res.data);
}
},
async deleteCartListBySkuId({
commit }, skuId) {
let res = await reqDeleteCartById(skuId);
if (res.code == 200) {
return 'ok'
} else {
return Promise.reject(new Error("Faile"));
}
},
async checkedById({
commit }, {
skuId, isChecked }) {
let res = await reqCheckedById(skuId, isChecked);
if (res.code == 200) {
return "ok"
}
else {
Promise.reject(new Error("Faile"));
}
},
deleteAllCheckedCart({
dispatch, getters }) {
let PromiseAll = [];
getters.CartList.cartInfoList.forEach((item) => {
if (item.isChecked) {
let res = dispatch("deleteCartListBySkuId", item.skuId);
PromiseAll.push(res);
}
})
return Promise.all(PromiseAll)
},
checkedAll({
dispatch,state},Checked){
let PromiseAll = [];
let isTrue=Checked?1:0
state.cartList[0].cartInfoList.forEach((item)=>{
let res = dispatch("checkedById",{
skuId:item.skuId,isChecked:isTrue})
PromiseAll.push(res);
})
return Promise.all(PromiseAll)
}
}
const mutations = {
CARTLIST(state, cartList) {
state.cartList = cartList;
}
}
const state = {
cartList: [],
}
const getters = {
CartList(state) {
return state.cartList[0] || {
};
}
}
export default {
actions, mutations, getters, state
}
trade
import {
reqAddressInfo,reqOrderInfo} from "@/api"
const actions={
async getUserAddress({
commit}){
let res= await reqAddressInfo();
if(res.code==200){
commit("GETUSERADDRESS",res.data)
}
},
async getOrderInfo({
commit}){
let res= await reqOrderInfo();
if(res.code==200){
commit("GETORDERINFO",res.data)
}
}
}
const mutations={
GETUSERADDRESS(state,address){
state.address=address;
},
GETORDERINFO(state,orderInfo){
state.orderInfo=orderInfo
}
}
const state={
address:[],
orderInfo:{
}
}
const getters={
}
export default{
actions, mutations, getters, state
}
user
import {
reqGetCode, reqUserRegister, reqUserLogin, reqUSerInfo ,reqLogout} from "@/api";
import{
setToken ,getToken,removeToken} from "@/utils/token"
const state = {
code: "",
token:getToken(),
userInfo:{
},
}
const mutations = {
GETCODE(state, code) {
state.code = code
},
USERLOGIN(state, token) {
state.token = token;
},
GETUSERINFO(state, userInfo) {
state.userInfo = userInfo;
},
CLEAR(state){
state.userInfo={
};
state.token='';
removeToken();
}
}
const actions = {
async getCode({
commit }, phone) {
let res = await reqGetCode(phone);
if (res.code == 200) {
commit("GETCODE", res.data)
return "ok"
} else {
return Promise.reject(new Error("faile"))
}
},
async userRegister({
commit }, user) {
let res = await reqUserRegister(user);
if (res.code == 200) {
return 'ok'
} else {
return Promise.reject(new Error("faile"))
}
},
async userLogin({
commit }, data) {
let res = await reqUserLogin(data);
if (res.code == 200) {
commit("USERLOGIN", res.data.token);
setToken(res.data.token);
return "ok"
} else {
return Promise.reject(new Error("faile"))
}
},
async getUserInfo({
commit }) {
let res = await reqUSerInfo();
if (res.code == 200) {
commit("GETUSERINFO", res.data)
return "ok"
} else {
return Promise.reject(new Error("faile"))
}
},
async userLogout({
commit}){
let res= await reqLogout();
if(res.code==200){
commit("CLEAR")
return "ok"
}else{
return Promise.reject(new Error("faile"))
}
}
}
const getters = {
}
export default {
actions, mutations, getters, state
}