merge:合并主分支

merge-requests/8/head
张征 2 years ago
commit be7f50ddcd

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-05-05 15:39:29
* @LastEditors: ch
* @LastEditTime: 2022-05-07 10:10:29
* @LastEditTime: 2022-05-07 11:39:38
* @Description: file content
-->
# shop-pc
@ -85,4 +85,22 @@ export {
## css
- 采用BEM命名法
### 兼容CSS
``` css
/* 以下兼容方式的样式请使用util.css中的adj方法 */
.my-class{
transform: translate3d(-50%, 0, 0);
-webkit-transform: translate3d(-50%, 0, 0);
-moz-transform: translate3d(-50%, 0, 0);
-o-transform: translate3d(-50%, 0, 0);
-ms-transform: translate3d(-50%, 0, 0);
}
/* 使用以下方法 */
@import "~/assets/scss/util.scss";
.my-class{
@include adj(transform, translate3d(-50%, 0, 0));
}
```

@ -1,4 +1,6 @@
@import './flex.scss';
* {
-webkit-box-sizing: border-box; box-sizing: border-box;

@ -1,41 +1,40 @@
$baseFontSize: 100 !default;
/**/
@mixin compatible ($styleName, $value...) {
@mixin adj ($styleName, $value...) {
#{$styleName}: $value;
-webkit-#{$styleName}: $value;
-moz-#{$styleName}: $value;
-o-#{$styleName}: $value;
-ms-#{$styleName}: $value;
}
@mixin transition($value...) {
-webkit-transiton: $value;
-moz-transtion: $value;
-ms-transtion: $value;
transition: $value;
}
@mixin transition-delay($value...) {
transition-delay: $value;
-moz-transition-delay: $value; /* Firefox 4 */
-webkit-transition-delay: $value; /* Safari 和 Chrome */
-o-transition-delay: $value; /* Opera */
}
// @mixin transition($value...) {
// -webkit-transiton: $value;
// -moz-transtion: $value;
// -ms-transtion: $value;
// transition: $value;
// }
// @mixin transition-delay($value...) {
// transition-delay: $value;
// -moz-transition-delay: $value; /* Firefox 4 */
// -webkit-transition-delay: $value; /* Safari 和 Chrome */
// -o-transition-delay: $value; /* Opera */
// }
@mixin transform($value...) {
transform: $value;
-webkit-transform: $value;
-moz-transform: $value;
-o-transform: $value;
-ms-transform: $value;
}
// @mixin transform($value...) {
// transform: $value;
// -webkit-transform: $value;
// -moz-transform: $value;
// -o-transform: $value;
// -ms-transform: $value;
// }
@mixin animation($value...) {
-webkit-animation: $value;
-moz-animation: $value;
-ms-animation: $value;
animation: $value;
}
// @mixin animation($value...) {
// -webkit-animation: $value;
// -moz-animation: $value;
// -ms-animation: $value;
// animation: $value;
// }
@mixin keyframes($animationName) {
@-webkit-keyframes #{$animationName} {
@content;
@ -51,12 +50,12 @@ $baseFontSize: 100 !default;
}
}
@mixin filter($value...) {
-webkit-filter: $value;
-moz-filter: $value;
-ms-filter: $value;
filter: $value;
}
// @mixin filter($value...) {
// -webkit-filter: $value;
// -moz-filter: $value;
// -ms-filter: $value;
// filter: $value;
// }
@mixin linear-gradient($value...) {
background: -webkit-linear-gradient($value); /* Safari 5.1 - 6.0 */
@ -65,12 +64,12 @@ $baseFontSize: 100 !default;
background: linear-gradient(t$value); /* 标准的语法 */
}
@mixin boxShow($value...) {
-webkit-box-shadow: $value;
-moz-box-shadow: $value;
-ms-box-shadow: $value;
box-shadow: $value;
}
// @mixin boxShow($value...) {
// -webkit-box-shadow: $value;
// -moz-box-shadow: $value;
// -ms-box-shadow: $value;
// box-shadow: $value;
// }
@function torem($value) {
@return ($value / $baseFontSize * 1rem);

@ -1,18 +0,0 @@
<!--
* @Author: ch
* @Date: 2022-05-04 17:43:34
* @LastEditors: ch
* @LastEditTime: 2022-05-04 17:43:40
* @Description: file content
-->
<template>
<div>我是公共页头</div>
</template>
<script>
export default {
}
</script>
<style lang="scss" scoped>
</style>

@ -0,0 +1,131 @@
<!--
* @Author: ch
* @Date: 2022-05-08 00:39:50
* @LastEditors: ch
* @LastEditTime: 2022-05-08 17:25:08
* @Description: file content
-->
<template>
<el-dialog title="打开微信扫描付款" width="380px" class="box" center
:visible="visible" @open="getCodeImg" @close="close">
<div class="pay">
<span class="pay--timer" v-if="startSecondNum">{{timerTxt}}</span>
<UiMoney class="money" sufSize="14px" preSize="14px" size="20px"
float suffix prefix :money="39"/>
<div class="pay--code">
<img :src="imgUrl" v-if="imgUrl"/>
<p v-if="!startSecondNum"></p>
</div>
<p class="pay--tips">如支付后没有自动跳转请点击 <span class="pay--finish">完成付款</span></p>
</div>
</el-dialog>
</template>
<script>
import {ApiPostPayCdoeImg} from '@/plugins/api/wx'
import UiMoney from './UiMoney.vue'
export default {
components: { UiMoney },
props : {
visible : {
type : Boolean,
default : false
},
orderId : {
type : Number | String,
default : ''
},
money : {
type : String | Number,
default : 0
}
},
data(){
return {
imgUrl : 'https://pay.mashibing.com/api/scan/imgs/d2VpeGluOi8vd3hwYXkvYml6cGF5dXJsP3ByPVo4alVpUmF6eg==.png',
timerTxt : '',
timerStop : null,
startSecondNum : 1800
}
},
mounted(){
this.timer()
},
methods : {
async getCodeImg(){
this.timerStop = null;
const {error, result} = await ApiPostPayCdoeImg({orderId : this.orderId});
if(error){
return false;
}
//
if(this.timerStop){
clearTimeout(this.timerStop);
}
this.timer();
this.imgUrl = result.dataInfo.codeImgData;
},
/**
* 待付款的倒计时
*/
timer(){
if(this.startSecondNum === 0){
return false
}
this.startSecondNum--;
let minute = parseInt(this.startSecondNum / 60);
let second = parseInt(this.startSecondNum % 60);
this.timerTxt = `剩余${minute > 0 ? `${minute}` : ''} ${second}`;
this.timerStop = setTimeout(()=>this.timer(),1000)
},
close(){
this.$emit('cancel');
}
}
}
</script>
<style lang="scss" scoped>
.pay{
text-align: center;
&--code{
width: 160px;
height: 160px;
margin: 15px auto 20px;
}
&--timer{
color: #999;
display: block;
margin-bottom: 15px;
}
&--tips, &--timer{
font-size: 14px;
}
&--finish{
color: #FF512B;
cursor: pointer;
}
}
.money{
color: #FF512B;
font-weight: bold;
}
/deep/{
.el-dialog{
border-radius: 4px;
}
.el-dialog__header{
padding: 30px 0 15px;
}
.el-dialog__title{
font-size: 20px;
font-weight: bold;
}
.el-dialog__body{
padding-top: 0;
padding-bottom: 50px;
}
.el-dialog__headerbtn{
top: 32px;
right: 30px;
}
}
</style>

@ -0,0 +1,56 @@
<!--
* @Author: ch
* @Date: 2022-05-08 14:41:42
* @LastEditors: ch
* @LastEditTime: 2022-05-08 15:11:29
* @Description: file content
-->
<template>
<div class="ui-goods-info">
<div class="ui-goods-info--img">
<img :src="goods.productImageUrl"/>
</div>
<p>
<b>{{goods.productName}}</b>
<span>{{goods.skuDescribe}}{{goods.productName}}</span>
</p>
</div>
</template>
<script>
export default {
props : {
goods : {
type : Object,
default : () => ({})
}
}
}
</script>
<style lang="scss" scoped>
.ui-goods-info{
display: flex;
&--img{
width: 100px;
height: 100px;
border: 1px solid #eee;
}
p{
width: 270px;
margin: 7px 0 0 18px;
text-align: left;
b{
display: block;
line-height: 22px;
margin-bottom: 10px;
overflow: hidden;
text-overflow:ellipsis;
display:-webkit-box;
-webkit-box-orient:vertical;
-webkit-line-clamp:2;
}
span{
color: #999;
}
}
}
</style>

@ -0,0 +1,29 @@
<!--
* @Author: ch
* @Date: 2022-05-07 22:40:55
* @LastEditors: ch
* @LastEditTime: 2022-05-08 14:24:16
* @Description: file content
-->
<template>
<div class="ui-line-box">
<div class="ui-line-box--head">
<slot name="head"></slot>
</div>
<slot name="body"></slot>
</div>
</template>
<script>
export default {
}
</script>
<style lang="scss" scoped>
.ui-line-box{
border:1px solid #ddd;
&--head{
height: 42px;
background: #f8f8f8;
}
}
</style>

@ -2,17 +2,108 @@
* @Author: ch
* @Date: 2022-05-04 17:44:29
* @LastEditors: ch
* @LastEditTime: 2022-05-04 17:44:52
* @Description: file content
* @LastEditTime: 2022-05-08 17:24:29
* @Description: 金额显示UI组件金额和小数点显示大小不同以及需不需要小数点
props
money 金额 数组或字符串
float 是否需要展示小数点
prefix 是否需要把前缀单独提取到一个标签
suffix 是否需要把小数点后缀单独提取到一个标签
preSize 前缀字体大小 Strin 记得带单位 浏览器支持的单位都可以 默认12px
sufSize 小数点字体大小 Strin 记得带单位 浏览器支持的单位都可以 默认12px
size 整数数字体大小 Strin 记得带单位 浏览器支持的单位都可以 默认14px
-->
<template>
<div>我是金额展示组件</div>
<div class="ui-money">
<span v-if="prefix" :style="preStyle" class="ui-money--prefix"></span>
<span :style="style" class="ui-money--price">{{moneyStr}}</span>
<span v-if="float && suffix" :style="sufStyle" class="ui-money--suffix">.{{moneyArr[1]}}</span>
</div>
</template>
<script>
export default {
props : {
money : {
type : Number | String,
default : '0'
},
float : {
type : Boolean,
default : false
},
prefix : {
type : Boolean,
default : false
},
suffix : {
type : Boolean,
default : false
},
sufSize : {
type : String,
default : '12px'
},
preSize : {
type : String,
default : '12px'
},
size : {
type : String,
default : '14px'
}
},
computed : {
sufStyle(){
return {
fontSize : this.sufSize
}
},
preStyle(){
return {
fontSize : this.preSize
}
},
style(){
return {
fontSize : this.size
}
},
moneyStr (){
let priceStr = '',
intNum = this.moneyArr[0],
floatNum = this.moneyArr[1];
//
if(!this.prefix){
priceStr = `${intNum}`;
}else{
priceStr = intNum;
}
//
if(!this.suffix){
priceStr += floatNum ? `.${floatNum}` : '';
}
return priceStr;
},
moneyArr (){
let moneyArr = (this.money || '0').toString().split('.');
// 0 00
if(this.float){
if(!moneyArr[1]){
moneyArr[1] = '00';
}else if(moneyArr[1].length < 1){
moneyArr[1] = `${moneyArr[1]}0`;
}
}
return moneyArr;
}
}
}
</script>
<style lang="scss" scoped>
.ui-money{
font-size: 0;
}
</style>

@ -0,0 +1,10 @@
<!--
* @Author: ch
* @Date: 2022-05-07 22:57:24
* @LastEditors: ch
* @LastEditTime: 2022-05-07 22:57:39
* @Description: file content
-->
<template>
<el-radio/>
</template>

@ -2,16 +2,31 @@
* @Author: ch
* @Date: 2022-05-04 17:56:39
* @LastEditors: ch
* @LastEditTime: 2022-05-04 21:19:27
* @LastEditTime: 2022-05-08 15:53:49
* @Description: file content
-->
<template>
<div>
<Nuxt />
<div>我是版权</div>
</div>
<div class="layout">
<Header />
<div class="layout-box"><Nuxt /></div>
<div class="layout-footer"></div>
</div>
</template>
<script>
import Header from "./module/header/index.vue";
export default {
name: "Layout",
components: { Header },
};
</script>
<style lang="scss" scoped>
.layout-box {
width: 1200px;
margin: 0 auto;
}
</script>
.layout-footer{
height: 189px;
background: #ddd;
}
</style>

@ -0,0 +1,202 @@
<template>
<div class="info-bar-header">
<div
class="info-bar-header-wrap layout-center flex flex-between flex-middle"
>
<div class="header-wrap__logo">马士兵严选欢迎你</div>
<div class="header-wrap__content flex flex-middle">
<div class="header-wrap-content__login">
<div v-if="isLogin" class="wrap-content-login__text flex">
<span>请先</span>
<span class="content-login-text--light">登录/注册</span>
</div>
<el-dropdown @visible-change="menuVisible = $event">
<div class="wrap-content-login__info flex flex-middle flex-center">
<span>你好{{ userInfo.name }}</span>
<img class="content-login-info__logo" :src="menuIcon" />
</div>
<el-dropdown-menu slot="dropdown" class="dropdown-menu-self">
<div class="menu-item__wrap flex flex-middle">
<img class="menu-item-wrap__avatar" />
<span>{{ userInfo.name }}</span>
</div>
<div class="menu-item__line"></div>
<el-dropdown-item
class="flex flex-between flex-middle"
v-for="item in menuList"
:key="item.value"
>
<span> {{ item.label }}</span>
<img src="@/static/images/layout/icon-arrow.png" />
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
<template>
<div v-if="!menuVisible" class="header-wrap-content--line"></div>
<div class="header-wrap-content__common flex flex-middle">
<img src="@/static/images/layout/icon-message.png" />
<span>消息</span>
<div class="wrap-content-message__tip">33</div>
</div>
</template>
<div class="header-wrap-content--line"></div>
<div class="header-wrap-content__common flex flex-middle">
<img src="@/static/images/layout/icon-order.png" />
<span>我的订单</span>
</div>
<div class="header-wrap-content--line"></div>
<div class="header-wrap-content__common flex flex-middle">
<img src="@/static/images/layout/icon-phone.png" />
<span>下载app</span>
</div>
</div>
</div>
</div>
</template>
<script>
const MENU_VALUE = {
PERSONAL: 1,
ADDRESS: 2,
LOGON_OUT: 3,
};
export default {
data() {
return {
isLogin: false,
userInfo: {
name: "仙女广",
},
menuVisible: false,
menuList: [
{
label: "个人中心",
value: MENU_VALUE.PERSONAL,
},
{
label: "收货地址",
value: MENU_VALUE.ADDRESS,
},
{
label: "退出登录",
value: MENU_VALUE.LOGON_OUT,
},
],
};
},
computed: {
menuIcon() {
return this.menuVisible
? require("@/static/images/layout/icon-up-light.png")
: require("@/static/images/layout/icon-up.png");
},
},
methods: {
onMenuClick() {},
},
};
</script>
<style lang="scss">
.dropdown-menu-self {
width: 200px;
margin-top: 0 !important;
padding-bottom: 0;
.popper__arrow {
display: none;
}
.el-dropdown-menu__item:hover {
background: #f8f9fb;
color: #666666;
}
.el-dropdown-menu__item {
height: 42px;
font-size: 14px;
img {
width: 8px;
height: 14px;
}
}
.menu-item__wrap {
padding: 16px 24px;
font-size: 14px;
.menu-item-wrap__avatar {
width: 50px;
height: 50px;
margin-right: 13px;
border-radius: 50%;
}
}
.menu-item__line {
width: 100%;
height: 1px;
background: #eeeeee;
border-radius: 0px 0px 0px 0px;
}
}
</style>
<style lang="scss" scoped>
.info-bar-header {
height: 30px;
color: #999999;
background: #f1f1f1;
border-radius: 0px 0px 0px 0px;
.info-bar-header-wrap {
height: 100%;
width: 1200px;
margin: 0 auto;
.header-wrap__content {
.header-wrap-content__login {
.wrap-content-login__text {
.content-login-text--light {
margin-left: 6px;
color: #ff875b;
cursor: pointer;
}
}
.wrap-content-login__info:hover {
background: #ffffff !important;
color: #ff875b;
}
.wrap-content-login__info {
position: relative;
padding: 0 18px;
height: 30px;
cursor: pointer;
.content-login-info__logo {
width: 8px;
height: 4px;
margin-left: 4px;
}
}
}
.wrap-content-message__tip {
min-width: 14px;
height: 14px;
padding: 0 3px;
line-height: 14px;
font-size: 10px;
color: #ffffff;
text-align: center;
background: #ff512b;
border-radius: 50%;
margin-left: 4px;
}
.header-wrap-content--line {
width: 1px;
height: 10px;
background: #d8d8d8;
}
.header-wrap-content__common {
cursor: pointer;
padding: 0 18px;
img {
width: 14px;
height: 14px;
margin-right: 4px;
}
}
}
}
}
</style>

@ -0,0 +1,294 @@
<template>
<div>
<HeaderInfoBar />
<div class="default-header">
<div class="default-header-box">
<div class="default-header-box__wrap flex flex-between flex-middle">
<img
class="header-box-wrap__logo"
src="@/static/images/layout/logo.png"
/>
<div class="header-box-wrap__right flex flex-middle">
<div class="box-wrap-right__search flex">
<div class="search-input">
<el-input
v-model="searchContent"
placeholder="请输入商品名称"
></el-input>
</div>
<div class="search-icon flex flex-center flex-middle">
<img src="@/static/images/layout/icon-search.png" />
</div>
</div>
<div class="box-wrap-right__cart flex flex-middle">
<img src="@/static/images/layout/icon-shop.png" />
<span>购物车</span>
<div class="wrap-right-cart__tip">3</div>
</div>
</div>
</div>
<div class="default-header-box__tab flex flex-middle">
<div class="header-box-tab__category">
<div class="tab-category__label flex flex-center flex-middle">
<img src="@/static/images/layout/icon-category.png" />
<span>热门分类</span>
</div>
<div class="tab-category__menu flex flex-left">
<div class="tab-category-menu__left">
<div
v-for="item in categrayData"
:key="item.id"
@mouseenter="handleMouEnter(item.id)"
@mouseleave="categrayHoverVisible = false"
class="menu-left__item flex felx-middle"
>
<img />
<span>{{ item.name }}</span>
</div>
</div>
<div v-show="categrayHoverVisible">
<div
class="tab-category-menu__right flex flex-wrap"
@mouseenter="categrayHoverVisible = true"
>
<div
v-for="item in currentCategrayList"
:key="item.id"
class="menu-right__item"
>
{{ item.name }}
</div>
</div>
</div>
</div>
</div>
<nuxt-link
v-for="item in tabList"
:key="item.value"
class="header-box-tab__common flex flex-center flex-middle"
:class="{
'header-box-tab__common--light': item.path === $nuxt.$route.path,
}"
:to="item.path"
>
{{ item.label }}
</nuxt-link>
</div>
</div>
</div>
</div>
</template>
<script>
import HeaderInfoBar from "./HeaderInfoBar.vue";
import {
ApiGetCategoryOneList,
ApiGetCategoryTwoAndGoods,
} from "@/plugins/api/goods";
const TAB_TYPE = {
HOME: 1,
RECOMMEND: 2,
BOOK: 3,
TIME_LIMIT: 4,
};
export default {
name: "DefaultHeader",
components: { HeaderInfoBar },
data() {
return {
searchContent: "",
activityTab: TAB_TYPE.HOME,
tabList: [
{ label: "首页", value: TAB_TYPE.HOME, path: "/" },
{ label: "爆款推荐", value: TAB_TYPE.RECOMMEND, path: "/hot" },
{ label: "开发书籍", value: TAB_TYPE.BOOK, path: "/book" },
{ label: "限时秒杀", value: TAB_TYPE.TIME_LIMIT, path: "/skill" },
],
categrayData: [],
categrayHoverVisible: false,
currentCategrayId: 0,
};
},
computed: {
currentCategrayList() {
const data = this.categrayData.find(({ id }) => {
return this.currentCategrayId === id;
});
return (data && data.list) || [];
},
},
mounted() {
this.getCategroyData();
},
methods: {
handleMouEnter(id) {
this.categrayHoverVisible = true;
this.currentCategrayId = id;
},
//
async getCategroyData() {
const { result } = await ApiGetCategoryOneList();
if (result.data.length > 0) {
this.categrayData = await Promise.all(
result.data.map(async (item) => {
const { result } = await ApiGetCategoryTwoAndGoods({
categoryId: item.id,
});
if (result.data.length > 0) {
return {
...item,
list: result.data,
};
}
})
);
}
},
},
};
</script>
<style lang="scss" scoped>
.default-header {
padding-top: 32px;
position: relative;
z-index: 3;
.default-header-box {
width: 1200px;
margin: 0 auto;
background: #ffffff;
.default-header-box__wrap {
height: 42px;
font-size: 14px;
margin-bottom: 38px;
padding-right: 50px;
.header-box-wrap__logo {
width: 244px;
height: 100%;
}
.header-box-wrap__right {
.box-wrap-right__search {
margin-right: 23px;
.search-input {
width: 551px;
z-index: 1;
/deep/.el-input__inner:focus {
border-color: #ff512b;
}
}
.search-icon {
width: 77px;
margin-left: -2px;
background: linear-gradient(270deg, #ffa25a 0%, #ff7f39 100%);
border-radius: 0px 8px 8px 0px;
z-index: 2;
img {
width: 26px;
height: 26px;
}
}
}
.box-wrap-right__cart {
padding: 0 18px;
height: 42px;
line-height: 42px;
color: #999999;
border-radius: 8px 8px 8px 8px;
border: 1px solid #eeeeee;
cursor: pointer;
.wrap-right-cart__tip {
min-width: 14px;
height: 14px;
padding: 0 3px;
font-size: 10px;
line-height: 14px;
text-align: center;
background: #ff512b;
border-radius: 50%;
color: #ffffff;
}
img {
width: 16px;
height: 16px;
margin: 0 4px 0 10px;
}
}
}
}
.default-header-box__tab {
height: 38px;
.header-box-tab__category {
position: relative;
height: 100%;
.tab-category__label {
width: 190px;
height: 100%;
background: linear-gradient(270deg, #ffa25a 0%, #ff7f39 100%);
border-radius: 4px 4px 0px 0px;
font-weight: bold;
color: #ffffff;
cursor: pointer;
img {
width: 20px;
height: 20px;
margin-right: 16px;
}
}
.tab-category__menu {
position: absolute;
top: 38px;
left: 0;
font-size: 14px;
color: #333333;
.tab-category-menu__left {
width: 190px;
padding: 34px 0;
background: #ffffff;
.menu-left__item:hover {
color: #ff875b;
}
.menu-left__item {
height: 50px;
cursor: pointer;
padding: 0 24px 0 41px;
img {
width: 20px;
height: 20px;
margin-right: 16px;
}
}
}
.tab-category-menu__right {
width: 510px;
padding: 30px 26px;
box-shadow: 7px 0px 10px 1px rgba(0, 0, 0, 0.10000000149011612);
border: 1px solid #eeeeee;
background: #ffffff;
.menu-right__item:last-child {
margin-bottom: 0;
}
.menu-right__item:hover {
color: #ff875b;
}
.menu-right__item {
font-size: 12px;
color: #999999;
margin-right: 20px;
cursor: pointer;
}
}
}
}
.header-box-tab__common--light {
color: #ff7f39 !important;
}
.header-box-tab__common {
width: 160px;
height: 100%;
font-size: 16px;
color: #666666;
cursor: pointer;
}
}
}
}
</style>

@ -17,7 +17,7 @@
"@nuxtjs/axios": "^5.13.6",
"cookie-universal-nuxt": "^2.1.5",
"core-js": "^3.19.3",
"element-ui": "^2.15.6",
"element-ui": "^2.15.8",
"js-util-all": "^1.0.6",
"node-sass": "^4.14.1",
"nuxt": "^2.15.8",

@ -0,0 +1,35 @@
<!--
* @Author: ch
* @Date: 2022-05-08 17:48:36
* @LastEditors: ch
* @LastEditTime: 2022-05-08 20:03:35
* @Description: file content
-->
<template>
<div class="account">
<div class="account--nav">左侧栏</div>
<nuxt-child class="account--main"/>
</div>
</template>
<script>
export default {
}
</script>
<style lang="scss" scoped>
.account{
padding-top: 370px;
margin: 0 auto;
display: flex;
&--nav{
width: 170px;
height: 300px;
border: 1px solid #ddd;
border-radius: 4px;
margin-right: 30px;
}
&--main{
flex: 1;
}
}
</style>

@ -0,0 +1,10 @@
<!--
* @Author: ch
* @Date: 2022-05-08 01:14:03
* @LastEditors: ch
* @LastEditTime: 2022-05-08 01:14:31
* @Description: file content
-->
<template>
<div>订单详情页</div>
</template>

@ -0,0 +1,165 @@
<!--
* @Author: ch
* @Date: 2022-05-04 20:47:29
* @LastEditors: ch
* @LastEditTime: 2022-05-08 21:17:05
* @Description: file content
-->
<template>
<div>
<ul class="tab">
<li v-for="item in tabs" :key="item.value" @click="changeTab(item.value)"
:class="tabActive == item.value && 'tab__active'">
{{item.label}}
<span>6</span>
</li>
</ul>
<div class="order" v-for="item in orderList" :key="item.orderId">
<div class="order--head"></div>
<table class="order--table">
<tbody>
<tr v-for="(i, idx) in item.products" :key="i.orderProductId">
<td width="620px">
<div class="order--product">
<UIGoodsInfo :goods="i"/>
<p>{{i.realAmount}}</p>
<p>{{i.quantity}}</p>
</div>
</td>
<template v-if="!idx">
<td width="119px" :rowspan="item.products.length">{{item.payAmount}}</td>
<td width="110px" :rowspan="item.products.length">{{item.orderStatusDesc}}</td>
<td :rowspan="item.products.length">
<button v-if="item.orderStatus === 1" @click="pay(item)"></button>
<button v-if="[2,3].includes(item.orderStatus)"
@click="$router.push(`./detail?id=${item.orderId}`)">查看详情</button>
<button v-if="item.orderStatus >= 4"
@click="$router.push(`/logisitcsInfo?orderId=${item.orderId}`)">查看物流</button>
<button v-if="item.orderStatus === 4" @click="receive(item)"></button>
</td>
</template>
</tr>
</tbody>
</table>
</div>
<el-pagination v-if=" orderTotal > pageSize" background layout="prev, pager, next"
:current-page.sync="pageIndex"
:total="orderTotal" @current-change="getOrderList"></el-pagination>
</div>
</template>
<script>
import {ApiGetOrderList, ApiPutOrderReceive} from '~/plugins/api/order';
import UIGoodsInfo from '../../../../../components/UIGoodsInfo.vue';
import UiLineBox from '../../../../../components/UiLineBox.vue';
export default {
components: { UiLineBox, UIGoodsInfo },
data(){
return {
tabs : [
{label : '全部', value : -1},
{label : '待付款', value : 1},
{label : '待发货', value : 3},
{label : '待收货', value : 4},
],
tabActive : this.$route.query.type || -1,
pageIndex : 1,
pageSize : 15,
orderList : [],
orderTotal : 0
}
},
mounted(){
this.getOrderList()
},
methods : {
changeTab(val){
if(val === this.$route.query.type){
return false;
}
this.$router.replace({
query:{
type : val
}
})
this.pageIndex = 1;
this.tabActive = val;
this.getOrderList();
},
async getOrderList(){
const {error, result} = await ApiGetOrderList({
length : this.pageSize,
pageIndex : this.pageIndex,
orderStatus : this.tabActive > -1 ? this.tabActive : null
});
if(error){
this.message.warning(error.message);
return false;
}
this.orderList = result.records;
this.orderTotal = result.total
},
pageChange(){
}
}
}
</script>
<style lang="scss" scoped>
.tab {
height: 42px;
line-height: 42px;
border-bottom: 1px solid #ddd;
li{
float: left;
margin-right: 54px;
font-size: 16px;
cursor: pointer;
span{
color: #FF875B;
}
}
&__active{
color: #FF875B;
position: relative;
&::after{
display: block;
height: 2px;
width: 100%;
content: '';
background: #FF875B;
position: absolute;
bottom: 0;
}
}
}
.order{
margin: 10px 0;
&--head{
height: 42px;
color: #999;
background: #F8F8F8;
border: 1px solid #ddd;
border-bottom: 0;
}
&--table{
width: 100%;
td{
border: 1px solid #ddd;
padding: 20px;
text-align: center;
}
tr:first-child td{
border-top: 0;
}
}
&--product{
display: flex;
align-items: center;
p{
width: 96px;
text-align: center;
}
}
}
</style>

@ -6,44 +6,16 @@
* @Description: file content
-->
<template>
<div>
<h1>我是首页</h1>
<Banner />
<Seckil />
<div>时间格式化方法测试{{date}}</div>
<a href="/order/list">去订单</a>
<button @click="login"></button>
</div>
<div>
<Banner />
<!-- <Seckil /> -->
</div>
</template>
<script>
import { ApiGetGoodsList } from "~/plugins/api/goods";
import { FormatDate } from "~/plugins/utils";
import Banner from "./module/Banner.vue";
import Seckil from "./module/Seckill.vue";
export default {
components: { Banner, Seckil },
data(){
return {
date : '时间'
}
},
asyncData({ $axios }) {
ApiGetGoodsList().then((res) => {
console.log(res);
});
},
mounted() {
this.date = FormatDate(new Date() , 'yyyy年MM月dd日');
// setInterval(()=>{
// location.reload();
// },50000)
},
methods: {
login() {
this.$store.commit("SET_TOKEN", "123");
},
},
components: { Banner, Seckil },
};
</script>

@ -7,18 +7,54 @@
-->
<template>
<div>我是banner模块</div>
<div class="home-banner">
<el-carousel height="360px" indicator-position="outside">
<el-carousel-item v-for="item in bannerList" :key="item.id">
<el-image :src="item.picture"></el-image>
</el-carousel-item>
</el-carousel>
</div>
</template>
<script>
export default {
name : 'Banner',
data(){
return {
}
}
}
name: "HomtBanner",
data() {
return {
bannerList: [
{
picture:
"https://msb-edu-dev.oss-cn-beijing.aliyuncs.com/uc/account-avatar/banner4.jpg",
},
{
picture:
"https://msb-edu-dev.oss-cn-beijing.aliyuncs.com/uc/account-avatar/2banner.png",
},
],
};
},
};
</script>
<style lang="scss" scoped>
</style>
.home-banner {
/deep/.el-carousel {
.el-carousel__container {
i {
font-size: 18px;
}
}
.el-carousel__arrow {
width: 45px;
height: 45px;
}
.el-carousel__arrow--left {
left: calc(50% - 380px) !important;
}
.el-carousel__arrow--right {
right: calc(50% - 550px) !important;
}
.el-image {
width: 100%;
}
}
}
</style>

@ -1,32 +0,0 @@
<!--
* @Author: ch
* @Date: 2022-05-04 20:47:29
* @LastEditors: ch
* @LastEditTime: 2022-05-04 21:49:40
* @Description: file content
-->
<template>
<div>
<h1>我是订单列表</h1>
<a href="/">回首页</a>
</div>
</template>
<script>
import {ApiGetOrderList} from '~/plugins/api/order';
export default {
name: 'IndexPage',
asyncData(){
},
mounted(){
this.getData();
},
methods : {
async getData(){
const res = await ApiGetOrderList();
console.log(res);
}
}
}
</script>

@ -0,0 +1,14 @@
<!--
* @Author: ch
* @Date: 2022-05-08 01:11:33
* @LastEditors: ch
* @LastEditTime: 2022-05-08 01:11:40
* @Description: file content
-->
<template>
<div>
<p>支付成功</p>
<button>返回首页</button>
<button>查看订单</button>
</div>
</template>

@ -2,22 +2,140 @@
* @Author: ch
* @Date: 2022-05-04 17:30:58
* @LastEditors: ch
* @LastEditTime: 2022-05-04 17:31:12
* @LastEditTime: 2022-05-08 16:25:39
* @Description: file content
-->
<template>
<div>我是订单提交页</div>
<div style="padding-top:350px">
<h3 class="title">支付方式</h3>
<div class="pay-type">
<el-radio label="微信支付" />
<el-radio label="支付宝支付" />
</div>
<h3 class="title">确认商品信息</h3>
<OrderInfo :products="orderInfo.products" />
<Message :orderInfo="orderInfo" :message.sync="userMessage"/>
<Amount :amount="orderInfo.payAmount"/>
<div class="pay">
<button class="btn" @click="submit"></button>
</div>
<BsPay :visible.sync="payVisible" :orderId="orderId" @cancel="cancelPay"/>
</div>
</template>
<script>
import {ApiPostSubmitOrder, ApiGetBeforeOrder, ApiGetBeforeCartOrder} from '@/plugins/api/order';
import BsPay from '../../../components/BsPay.vue';
import UIGoodsInfo from '../../../components/UIGoodsInfo.vue';
import OrderInfo from './module/OrderInfo.vue';
import Message from './module/Message.vue';
import Amount from './module/Amount.vue';
export default {
components: { BsPay, UIGoodsInfo, OrderInfo, Message, Amount },
data(){
return {
address : {id:3},
orderInfo : {},
orderId : '',
userMessage : '',
payVisible : true
}
},
created(){
this.getBeforeOrder();
},
methods : {
/**
* 获取预订单信息将要提交的订单信息
*/
async getBeforeOrder(){
const query = this.$route.query;
let res = {};
//
if(query.mode === 'cart'){
res = await ApiGetBeforeCartOrder({
cartIds: query.ids,
recipientAddressId : this.address.id
})
}
//
if(query.mode === 'buyNow'){
res = await ApiGetBeforeOrder({
productSkuId : query.skuId,
quantity : query.num,
activityId : query.activityId,
activityTimeId : query.activityTimeId,
// 1 2
activityType : query.activityType,
recipientAddressId : this.address.id
});
}
if(res.error){
this.$message.error(res.error.message);
return false;
}
this.orderInfo = res.result;
},
/**
* 提交订单
*/
async submit(){
const {query} = this.$route;
if(!this.address.id){
this.$message.error('请选择收货地址');
return false;
}
const {error, result} = await ApiPostSubmitOrder({
orderSource : 4,
recipientAddressId : this.address.id,
shoppingCartIds : query.ids ? query.ids.split(',') : [],
products : this.orderInfo.products.map(i => ({
activityId : query.activityId,
activityTimeId : query.activityTimeId,
productId : i.productId,
productSkuId : i.productSkuId,
quantity : i.quantity,
activityType : query.activityType
})),
userMessage : this.userMessage
});
if(error){
this.$message.error(error.message);
return false;
}
this.payVisible = true;
this.orderId = result.orderId;
},
cancelPay(){
this.$router.replace('/order/detail')
}
}
}
</script>
<style lang="scss" scoped>
.title{
margin: 24px 0 13px;
}
.pay-type{
border: 1px solid #DDDDDD;
padding: 30px 70px;
}
.pay{
text-align: right;
padding-bottom: 50px;
.btn{
background: #FF512B;
color: #fff;
font-size: 18px;
border: none;
height: 50px;
width: 163px;
margin-top: 10px;
}
}
</style>

@ -0,0 +1,49 @@
<!--
* @Author: ch
* @Date: 2022-05-08 16:12:18
* @LastEditors: ch
* @LastEditTime: 2022-05-08 16:14:57
* @Description: file content
-->
<template>
<div class="amount">
<div>
<span>应付款</span>
<b>{{amount}}</b>
</div>
<p>北京市XXXXX区XXXX路xxxxxx小区XXX单元</p>
<p>卖火柴的灰姑凉 18888888888</p>
</div>
</template>
<script>
export default {
props : {
amount : {
type : Number,
default : 0
},
address : {
type : Object,
default : () => ({})
}
}
}
</script>
<style lang="scss" scoped>
.amount{
height: 133px;
background: #f8f8f8;
text-align: right;
padding: 20px 40px;
margin-top: 10px;
b{
font-size: 20px;
}
p{
font-size: 12px;
color: #9E9E9E;
margin-top: 15px;
}
}
</style>

@ -0,0 +1,95 @@
<!--
* @Author: ch
* @Date: 2022-05-08 16:06:28
* @LastEditors: ch
* @LastEditTime: 2022-05-08 16:18:51
* @Description: file content
-->
<template>
<div class="message">
<div class="message--left">
<label>买家留言</label>
<el-input type="textarea" class="textarea" placeholder="填写您想要备注的信息50字以内"
show-word-limit :maxlength="50" v-model="myMsg"/>
</div>
<div>
<p>
<label>商品总额</label>
<b>{{orderInfo.totalAmount}}</b>
</p>
<p>
<label>运费</label>
<b>{{orderInfo.shippingAmount}}</b>
</p>
</div>
</div>
</template>
<script>
export default {
props : {
orderInfo : {
type: Object,
defautl : ()=>({})
},
message : {
type : String,
default : ''
}
},
computed : {
myMsg : {
get(){
return this.message;
},
set(val){
this.$emit('update:message',val)
}
}
}
}
</script>
<style lang="scss" scoped>
.message{
height: 110px;
border: 1px solid #ddd;
border-top: 0;
padding: 20px 40px 20px 20px;
display: flex;
justify-content: space-between;
&--left{
display: flex;
label{
margin: 11px 16px 0 0;
}
}
label{
color: #666;
}
p{
display: flex;
justify-content: space-between;
width: 308px;
margin: 11px 0;
}
}
/deep/ {
.textarea {
display: inline-block;
width: 467px;
textarea{
height: 70px;
background: #f8f8f8;
border: none;
resize:none;
&::placeholder{
color: #999;
font-size: 12px;
}
}
span{
background: #f8f8f8;
}
}
}
</style>

@ -2,22 +2,67 @@
* @Author: ch
* @Date: 2022-05-04 17:36:46
* @LastEditors: ch
* @LastEditTime: 2022-05-04 17:49:58
* @LastEditTime: 2022-05-08 16:04:39
* @Description: file content
-->
<template>
<div>我是订单商品模块</div>
<table class="goods">
<thead>
<tr>
<th width="600">商品信息</th>
<th>单价</th>
<th>数量</th>
<th>小计</th>
</tr>
</thead>
<tbody>
<tr v-for="item in products" :key="item.productId">
<td>
<UIGoodsInfo :goods="item"></UIGoodsInfo>
</td>
<td>{{item.realPrice}}</td>
<td>{{item.quantity}}</td>
<td>{{item.realAmount}}</td>
</tr>
</tbody>
</table>
</template>
<script>
export default {
props : {
products : {
type : Array,
default : ()=>([])
}
},
data(){
return {
}
}
},
}
</script>
<style lang="scss" scoped>
.goods{
width: 100%;
border: 1px solid #ddd;
th{
height: 42px;
background: #f8f8f8;
color: #999;
font-weight: normal
};
td{
text-align: center;
padding: 10px 20px;
}
tbody tr:first-child td{
padding-top: 20px
}
tbody tr:last-child td{
padding-bottom: 20px
}
}
</style>

@ -4,10 +4,11 @@
* @Author: ch
* @Date: 2022-05-04 18:17:25
* @LastEditors: ch
* @LastEditTime: 2022-05-07 10:29:48
* @LastEditTime: 2022-05-07 23:27:49
* @Description: file content
*/
import {axiosTk} from "../axiosTk";
import {ToAsyncAwait} from "@/plugins/utils";
import ENV from '../config/env';
const BASE_URL = `${ENV.base_url}/mall/trade`;
@ -19,20 +20,20 @@ const APPID = 'wx0643970a8e86d028';
* @param {*} params
*/
export const ApiGetOrderList = (params) =>
ToAsyncAwait(axiosTk.get(`${BASE_URL}/app/tradeOrder/page`, params));
ToAsyncAwait(axiosTk.get(`${BASE_URL}/app/tradeOrder/page`, {params}));
/**
* 获取立即购买预订单
* @param {*} data
*/
export const ApiGetBeforeOrder = (data) =>
ToAsyncAwait(axiosTk.get(`${BASE_URL}/app/tradeOrder/buyAdvanceOrder`, data));
export const ApiGetBeforeOrder = (params) =>
ToAsyncAwait(axiosTk.get(`${BASE_URL}/app/tradeOrder/buyAdvanceOrder`, {params}));
/**
* 获取购物车预订单
* @param {*} data
*/
export const ApiGetBeforeCartOrder = (data) =>
ToAsyncAwait(axiosTk.get(`${BASE_URL}/app/tradeOrder/cartAdvanceOrder`, data));
export const ApiGetBeforeCartOrder = (params) =>
ToAsyncAwait(axiosTk.get(`${BASE_URL}/app/tradeOrder/cartAdvanceOrder`, {params}));
/**
* 订单详情

@ -0,0 +1,17 @@
/*
* @Author: ch
* @Date: 2022-05-08 00:44:22
* @LastEditors: ch
* @LastEditTime: 2022-05-08 00:47:55
* @Description: file content
*/
import {axiosTk} from "../axiosTk";
import {ToAsyncAwait} from "@/plugins/utils";
import ENV from '../config/env';
const BASE_URL = `${ENV.base_url}/mall/trade`;
export const ApiPostPayCdoeImg = (data) =>
ToAsyncAwait(axiosTk.post(`${BASE_URL}/pay/wxPay/nativeImage`, data));

@ -20,8 +20,8 @@ export default function({app, $axios, req}) {
})
$axios.onResponse(res => {
if (res.data.code === 200) {
return res.data.result;
if (res.status === 200) {
return res.data;
} else {
return Promise.reject(res.data.error);
}

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-05-04 17:11:07
* @LastEditors: ch
* @LastEditTime: 2022-05-04 21:50:14
* @LastEditTime: 2022-05-07 23:59:45
* @Description: file content
*/
let axiosTk = null;
@ -15,6 +15,22 @@ export default function ({$axios, store}, inject) {
config.headers.Authorization = store.state.token;
return config;
});
$axiosTk.onResponse(response => {
const result = response.data;
if(response.status === 200){
if(result.code === 'SUCCESS'){
return result.data;
}
if(result.code === 'TOKEN_FAIL'){
alert('这里要弹登录')
store.commit('SET_TOKEN', '');
return result;
}
return Promise.reject(result);
}
return Promise.reject({message:'请求出错'});
});
inject('$axiosTk', $axiosTk);
axiosTk = $axiosTk;

@ -4,7 +4,7 @@
* @Author: ch
* @Date: 2022-05-04 21:15:17
* @LastEditors: ch
* @LastEditTime: 2022-05-07 11:05:11
* @LastEditTime: 2022-05-07 22:33:57
* @Description: 服务端没有localStorage对象在Sotre中不能直接取值在plugins中统一为state做一次初始取值处理
*/
import { TOKEN } from "./config/sotrageKey";

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 542 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 611 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

@ -2,11 +2,11 @@
* @Author: ch
* @Date: 2022-05-04 20:35:20
* @LastEditors: ch
* @LastEditTime: 2022-05-04 21:39:42
* @LastEditTime: 2022-05-07 22:33:28
* @Description: file content
*/
import { TOKEN } from "../plugins/config/sotrageKey";
import { TOKEN } from "@/plugins/config/sotrageKey";
export const state = () => ({

Loading…
Cancel
Save