Merge branch 'feature/task1.0.0' into feature/task1.0.0-0505-ch

feature/task1.0.0-0505-ch
ch 3 years ago
commit fbbc5a8a27

@ -4,6 +4,7 @@ WORKDIR /workload
COPY nuxt.config.js /workload/nuxt.config.js
COPY package.json /workload/package.json
COPY .nuxt /workload/.nuxt
COPY static /workload/static
RUN npm config set registry https://registry.npm.taobao.org \
&& npm install

Binary file not shown.

After

Width:  |  Height:  |  Size: 823 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 532 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 188 KiB

@ -73,7 +73,7 @@
type="textarea"
:rows="3"
class="max-ipt"
maxlength="60"
maxlength="30"
></el-input>
</div>
<div class="address__msg-line flex flex-middle">
@ -93,11 +93,14 @@
:class="!isAccount ? 'flex-column' : ''"
>
<el-checkbox v-model="defaultAddress"></el-checkbox>
<div class="address__edit--btns flex flex-middle">
<div
class="address__edit--btns flex flex-middle"
:class="isAccount ? 'clearmargin' : ''"
>
<UiButton
v-if="addressList && addressList.length && !isAccount"
v-if="addressList[0].id && !isAccount"
type="grey"
@click="isOperation = false"
@click="onCanceloperation()"
>取消</UiButton
>
<UiButton type="yellow_panel" @click="onAddAddress"
@ -206,6 +209,18 @@ export default {
this.getAddressData();
},
methods: {
onCanceloperation() {
let vm = this;
vm.isOperation = false;
vm.$set(vm.selectData.area, "value", "");
vm.$set(vm.selectData.city, "value", "");
vm.$set(vm.selectData.province, "value", "");
vm.$set(vm, "detailAddress", "");
vm.$set(vm, "defaultAddress", "");
vm.$set(vm, "addressUser", "");
vm.$set(vm, "addressPhone", "");
vm.$emit("onSaveSuccess");
},
onEdit() {
let vm = this;
let curIndex = vm.addressList.findIndex(
@ -221,15 +236,13 @@ export default {
if (res.result && res.result.length) {
vm.isOperation = false;
vm.addressList = res.result;
if (!vm.addressList.length) {
vm.defaultAddress = true;
}
let curIndex = vm.addressList.findIndex((item) => item.isDefault);
vm.curAddressListItem =
curIndex > -1 ? vm.addressList[curIndex] : vm.addressList[0];
vm.$emit("getList", vm.addressList);
vm.$emit("emitAddress", vm.curAddressListItem);
} else {
vm.defaultAddress = true;
vm.isOperation = true;
}
console.log("获取收货地址", res);
@ -242,6 +255,9 @@ export default {
vm.$set(vm.selectData.area, "value", editItem.area);
vm.$set(vm.selectData.city, "value", editItem.city);
vm.$set(vm.selectData.province, "value", editItem.province);
vm.$set(vm.selectData.area, "code", editItem.areaCode);
vm.$set(vm.selectData.city, "code", editItem.cityCode);
vm.$set(vm.selectData.province, "code", editItem.provinceCode);
vm.$set(vm, "detailAddress", editItem.detailAddress);
vm.$set(vm, "defaultAddress", editItem.isDefault);
vm.$set(vm, "addressUser", editItem.name);
@ -254,11 +270,12 @@ export default {
this.dialogVisible = false;
},
onSelected(data) {
console.log(data);
this.selectData = data;
},
async onAddAddress() {
let vm = this;
let curItem = vm.addressList[vm.editIndex]
console.log(`vm.addressPhone != curItem.phone`,vm.addressPhone , curItem);
if (!vm.selectData?.area?.code) {
vm.$message.error("请选择所在区域~");
return;
@ -271,7 +288,7 @@ export default {
vm.$message.error("请输入收货人~");
return;
}
if (!IsPhone(vm.addressPhone)) {
if (!IsPhone(vm.addressPhone) && vm.addressPhone != curItem.phone) {
vm.$message.error("请输入收货人手机号码~");
return;
}
@ -410,6 +427,9 @@ export default {
margin-right: 38px;
}
}
.clearmargin {
margin: 0 0 0 20px;
}
}
}

@ -17,7 +17,7 @@
</div>
</template>
<script>
import { ApiGetRecommendedGoodsList } from "@/plugins/api/goods";
import { ApiGetGoodsList } from "@/plugins/api/goods";
import UiGoodsItem from "@/components/UiGoodsItem.vue";
export default {
components: { UiGoodsItem },
@ -32,8 +32,15 @@ export default {
methods: {
async getRecommendedGoodsList() {
let vm = this;
let res = await ApiGetRecommendedGoodsList();
vm.recommendedData = res.result;
let res = await ApiGetGoodsList({
length: 20,
pageIndex: 1,
name: "",
categoryId: "",
order: "",
});
console.log(res.result)
vm.recommendedData = res.result.records;
},
},
};

@ -167,6 +167,7 @@ export default {
this.dialogVisible = false;
this.$store.commit("setToken", result.token);
this.$store.dispatch("getUserInfo");
this.$startWebSockets()
}
}
});

@ -72,6 +72,7 @@ export default {
height: 28px;
padding: 0 10px;
color: #FF512B;
background: #FFFFFF;;
}
&__yellow_panel{
background:#FF512B;

@ -8,7 +8,7 @@
{{ item.name }}
</div>
<div class="goods-item__price">
<UiMoney :money="item.startingPrice"></UiMoney>
<strong class="goods-item__price--txt">{{ item.startingPrice }}</strong>
</div>
</div>
</template>
@ -41,9 +41,10 @@ export default {
return str;
},
onItem() {
this.$router.push({
path: "/goods/detail/" + this.item.id,
});
// this.$router.push({
// path: "/goods/detail/" + this.item.id,
// });
window.open("/goods/detail/" + this.item.id);
},
},
};
@ -55,6 +56,10 @@ export default {
cursor: pointer;
background: #ffffff;
&:hover {
box-shadow: 0px 0px 10px 1px rgba(0, 0, 0, 0.10000000149011612);
}
&__img {
width: 232px;
height: 232px;
@ -88,6 +93,15 @@ export default {
&__price {
width: 200px;
margin: 0 auto;
&--txt {
font-size: 14px;
color: #ff512b;
&::before {
content: "¥";
font-size: 14px;
}
}
}
}
</style>

@ -10,7 +10,7 @@
<div
slot="reference"
class="header-cart-popover__refrence flex flex-middle"
@click="onJumpCart"
@click="onJumCartPage"
>
<img src="~/assets/img/layout/icon-shop.png" />
<span>购物车</span>
@ -144,16 +144,13 @@ export default {
},
},
methods: {
onJumpCart() {
if (!this.$isLoginValidate()) {
return;
}
this.$router.push("/cart");
},
onJumpGoodsDetail(id) {
this.$router.push(`/goods/detail/${id}`);
},
onJumCartPage() {
if (!this.$isLoginValidate()) {
return;
}
this.$router.push("/cart");
},
},
@ -170,7 +167,7 @@ export default {
height: 42px;
line-height: 42px;
color: #999999;
border-radius: 8px 8px 8px 8px;
border-radius: 4px;
border: 1px solid #eeeeee;
cursor: pointer;
.wrap-right-cart__tip {
@ -181,16 +178,17 @@ export default {
border-radius: 50%;
color: #ffffff;
margin-left: 4px;
padding-top: 2px;
&--more {
width: unset;
padding: 0 4px;
padding: 2px 5px 0 4px;
border-radius: 7px;
}
}
img {
width: 16px;
height: 16px;
margin: 0 4px 0 10px;
margin-right: 10px;
}
}
.header-cart-popover {

@ -29,7 +29,7 @@
'menu-left__item--light': item.id === currentCategroyId,
}"
>
<img />
<img :src="item.icon" />
<span>{{ item.name }}</span>
</div>
</div>
@ -125,13 +125,9 @@ export default {
onCategoryClick(id, levelType) {
this.categroyVisible = false;
this.categroyTwoVisible = false;
this.$router.push({
path: "/goods/list",
query: {
id,
levelType,
},
});
window.open(
`${location.origin}/goods/list?id=${id}&levelType=${levelType}`
);
},
//
handleCategoryChange(val) {
@ -202,6 +198,7 @@ export default {
box-shadow: 7px 0px 10px 1px rgba(0, 0, 0, 0.1);
border: 1px solid #eeeeee;
background: #ffffff;
border-radius: 0 4px 4px 0;
.category-menu-right__wrap {
height: 36px;
margin-top: 23px;

@ -20,10 +20,10 @@
<img class="content-login-info__logo" :src="menuIcon" />
</div>
<el-dropdown-menu slot="dropdown" class="header-info-bar__dropdown">
<div class="menu-item__wrap flex flex-middle">
<!-- <div class="menu-item__wrap flex flex-middle">
<img class="menu-item-wrap__avatar" :src="userInfo.avatar" />
<span>{{ userInfo.nickname }}</span>
</div>
</div> -->
<div class="menu-item__line"></div>
<el-dropdown-item
class="flex flex-between flex-middle"
@ -47,27 +47,42 @@
<template>
<div v-if="!menuVisible" class="header-wrap-content--line"></div>
<div
class="header-wrap-content__common flex flex-middle"
class="header-wrap-content__common hover-text flex flex-middle"
@click="onJumpPersonalPage('message')"
@mouseenter="messageHover = true"
@mouseleave="messageHover = false"
>
<img src="~/assets/img/layout/icon-message.png" />
<span class="hover-text">消息</span>
<img
v-show="messageHover"
src="~/assets/img/layout/icon-message-light.png"
/>
<img
v-show="!messageHover"
src="~/assets/img/layout/icon-message.png"
/>
<span>消息</span>
<div
v-if="messageCount > 0"
v-if="unreadCount > 0"
class="wrap-content-message__tip flex flex-center flex-middle"
:class="{ 'wrap-content-message__tip--more': messageCount > 9 }"
:class="{ 'wrap-content-message__tip--more': unreadCount > 9 }"
>
{{ messageCount }}
{{ unreadCount }}
</div>
</div>
</template>
<div class="header-wrap-content--line"></div>
<div
class="header-wrap-content__common flex flex-middle"
class="header-wrap-content__common hover-text flex flex-middle"
@click="onJumpPersonalPage('order/list')"
@mouseenter="orderHover = true"
@mouseleave="orderHover = false"
>
<img src="~/assets/img/layout/icon-order.png" />
<span class="hover-text">我的订单</span>
<img
v-show="orderHover"
src="~/assets/img/layout/icon-order-light.png"
/>
<img v-show="!orderHover" src="~/assets/img/layout/icon-order.png" />
<span>我的订单</span>
</div>
<div class="header-wrap-content--line"></div>
<!-- 下载app -->
@ -76,13 +91,24 @@
placement="bottom"
width="230"
trigger="hover"
@show="phoneHover = true"
@hide="phoneHover = false"
>
<div
slot="reference"
class="header-wrap-content__common flex flex-middle"
>
<img src="~/assets/img/layout/icon-phone.png" />
<span class="hover-text">下载app</span>
<img
v-show="phoneHover"
src="~/assets/img/layout/icon-phone-light.png"
/>
<img
v-show="!phoneHover"
src="~/assets/img/layout/icon-phone.png"
/>
<span :class="{ 'wrap-content-common--light': phoneHover }"
>下载app</span
>
</div>
<div class="info-bar-popover__qrcode">
<img src="~/assets/img/common/app-qrcode.png" />
@ -106,6 +132,9 @@ export default {
data() {
return {
menuVisible: false,
orderHover: false,
phoneHover: false,
messageHover: false,
menuList: [
{
label: "个人中心",
@ -120,17 +149,19 @@ export default {
value: MENU_VALUE.LOGON_OUT,
},
],
messageCount: 0, //
};
},
computed: {
...mapState(["userInfo", "token"]),
...mapState(["userInfo", "token", "unreadCount"]),
menuIcon() {
return this.menuVisible
? require("~/assets/img/layout/icon-up-light.png")
: require("~/assets/img/layout/icon-up.png");
},
},
mounted() {
this.$startWebSockets();
},
methods: {
onLoginClick() {
this.$isLoginValidate();
@ -138,10 +169,10 @@ export default {
handleCommandClick(event) {
switch (event) {
case MENU_VALUE.PERSONAL:
this.$router.push("/account/home");
window.open(`${location.origin}/account/home`);
break;
case MENU_VALUE.ADDRESS:
this.$router.push("/account/address");
window.open(`${location.origin}/account/address`);
break;
case MENU_VALUE.LOGON_OUT:
this.$store.dispatch("logout");
@ -153,7 +184,7 @@ export default {
if (!this.$isLoginValidate()) {
return;
}
this.$router.push(`/account/${path}`);
window.open(`${location.origin}/account/${path}`);
},
},
};
@ -162,7 +193,7 @@ export default {
.header-info-bar__dropdown,
.header-info-bar__popover {
.popper__arrow {
display: none;
display: none !important;
}
}
</style>
@ -217,7 +248,7 @@ export default {
height: 30px;
color: #999999;
background: #f1f1f1;
border-radius: 0px 0px 0px 0px;
font-size: 12px;
.info-bar-header-wrap {
height: 100%;
@include layout-box;
@ -239,6 +270,8 @@ export default {
position: relative;
padding: 0 18px;
height: 30px;
font-size: 12px;
color: #999999;
cursor: pointer;
.content-login-info__logo {
width: 8px;
@ -269,6 +302,9 @@ export default {
.header-wrap-content__common {
cursor: pointer;
padding: 0 18px;
.wrap-content-common--light {
color: #ff875b;
}
img {
width: 14px;
height: 14px;

@ -8,10 +8,9 @@
>
<div class="sticky-bar-header__wrap flex flex-middle flex-between">
<div class="flex flex-middle">
<img
class="bar-header-wrap__logo"
src="~/assets/img/layout/logo-sticky.png"
/>
<div class="bar-header-wrap__logo" @click="onOpenHomePage">
<img src="~/assets/img/layout/logo-sticky.png" />
</div>
<el-menu
:default-active="tabPath"
mode="horizontal"
@ -30,7 +29,7 @@
src="~/assets/img/layout/icon-search-sticky.png"
@click="$router.push('/goods/list')"
/>
<div class="header-wrap-icons__shop" @click="$router.push('/cart')">
<div class="header-wrap-icons__shop" @click="onOpenCartPage">
<img src="~/assets/img/layout/icon-shop-sticky.png" />
<div
v-if="cartCount > 0"
@ -63,10 +62,9 @@
<div class="default-bar-header">
<div class="bar-header-box">
<div class="bar-header-box__wrap flex flex-between flex-middle">
<img
class="header-box-wrap__logo"
src="~/assets/img/layout/logo.png"
/>
<div class="header-box-wrap__logo" @click="onOpenHomePage">
<img src="~/assets/img/layout/logo.png" />
</div>
<div class="header-box-wrap__right flex flex-middle">
<div class="box-wrap-right__search flex">
<div class="search-input">
@ -74,9 +72,12 @@
v-model="searchContent"
clearable
placeholder="请输入商品名称"
></el-input>
@keyup.enter.native="onSearch"
>
</el-input>
</div>
<div
slot="suffix"
class="search-icon flex flex-center flex-middle"
@click="onSearch"
>
@ -111,6 +112,7 @@
<script>
import { mapState } from "vuex";
import { CATEGROY_LEVEL } from "@/constants";
import { ApiGetHomeSeckill } from "@/plugins/api/seckill";
import HeaderInfoBar from "./HeaderInfoBar.vue";
import HeaderCategory from "./HeaderCategory.vue";
import HeaderCart from "./HeaderCart.vue";
@ -168,14 +170,23 @@ export default {
}
},
},
created() {
this.getSeckillData();
},
methods: {
async getSeckillData() {
const { result } = await ApiGetHomeSeckill();
if (result && result.activityTimeVO) {
this.$store.commit("setSeckillTabVisible", true);
}
},
onLoginClick() {
this.$isLoginValidate();
},
onTabSelect(value) {
this.tabPath = value;
this.searchContent = "";
this.$router.push({ path: value });
window.open(`${location.origin}${value}`);
},
onSearch() {
this.$router.push({
@ -185,6 +196,15 @@ export default {
},
});
},
onOpenCartPage() {
window.open(`${location.origin}/cart`);
},
onOpenHomePage() {
if (this.$route.path === "/") {
return;
}
window.open(`${location.origin}/`);
},
},
};
</script>
@ -213,6 +233,11 @@ export default {
width: 164px;
height: 28px;
margin-right: 50px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
.bar-header-wrap__icons {
cursor: pointer;
@ -222,7 +247,7 @@ export default {
}
.header-wrap-icons__shop {
position: relative;
margin-left: 14px;
margin-left: 20px;
.wrap-icons-shop__tip {
position: absolute;
left: 18px;
@ -283,10 +308,11 @@ export default {
@include layout-box;
background: #ffffff;
.bar-header-box__wrap {
height: 42px;
height: 40px;
font-size: 14px;
margin-bottom: 38px;
padding-right: 50px;
cursor: pointer;
.header-box-wrap__logo {
width: 244px;
height: 100%;
@ -297,6 +323,7 @@ export default {
.search-input {
width: 551px;
z-index: 1;
border-radius: 4px;
/deep/.el-input__inner:focus {
border-color: #ff512b;
}
@ -305,7 +332,7 @@ export default {
width: 77px;
margin-left: -2px;
background: linear-gradient(270deg, #ffa25a 0%, #ff7f39 100%);
border-radius: 0px 8px 8px 0px;
border-radius: 0px 4px 4px 0px;
z-index: 2;
cursor: pointer;
img {
@ -327,6 +354,9 @@ export default {
font-size: 16px;
color: #666666;
cursor: pointer;
&:hover {
color: #ff875b;
}
}
}
}

@ -0,0 +1,10 @@
export default function ({ app, route, redirect }) {
if (!app.store.state.token) {
// 未登录直接打开需要登录的页面,跳转首页
const needLoginPage = [/\/account/, /\/cart/];
const result = needLoginPage.some((item) => item.test(route.path));
if (result) {
redirect("/");
}
}
}

@ -19,7 +19,7 @@ export default {
{ name: 'format-detection', content: 'telephone=no' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/logo.png' }
{ rel: 'icon', type: 'image/x-icon', href: '/logo.ico' }
]
},
router: {
@ -29,7 +29,8 @@ export default {
path: '/',
component: resolve(__dirname, 'pages/index/index.vue')
})
}
},
middleware: ['redirect']
},
// Global CSS: https://go.nuxtjs.dev/config-css
@ -45,7 +46,8 @@ export default {
'@plugins/axiosTk.js',
'@plugins/vue-inject.js',
'@/plugins/v-distpicker',
'@/plugins/router'
'@/plugins/router',
'@/plugins/im'
],
// Auto import components: https://go.nuxtjs.dev/config-components

@ -11,7 +11,7 @@
<main class="main">
<h3 class="title">消息通知</h3>
<section class="section">
<div class="section__item flex" v-for="item in msgList" :key="item.id">
<div class="section__item flex" v-for="item in socketMsgData" :key="item.id">
<img
class="section__item-img"
src="https://img1.baidu.com/it/u=3384796346,381674655&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500"
@ -19,15 +19,15 @@
/>
<div class="section__item-content flex flex-column">
<div class="section__item-content--title flex">
<span>{{ item.payload.title || `马士兵严选上新啦` }}</span>
<span>{{ JSON.parse(item.payload).title || `` }}</span>
<span class="section__item-content--time">{{
item.createTimeStamp
}}</span>
</div>
<div class="section__item-content--txt">
{{
item.payload.content ||
`马士兵严选上新啦!!走过路过不要错过,大家快来看看...`
JSON.parse(item.payload).content ||
``
}}
</div>
</div>
@ -40,58 +40,15 @@
import { mapState } from "vuex";
export default {
data() {
return {
Socket: null,
msgList: [],
};
return {};
},
computed: {
...mapState(["token"]),
},
mounted() {
// let url = `ws://192.168.10.93:8090/ws?client=eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjQwNzA4ODAwMDAsImlkIjoyLCJ0aW1lIjoxNjUyNDQyMDIyMjE4fQ.ybPvJ-pkywqzBgAK9Lv_7yme50cGhtTvzVcfp-kLyjlzKpsgcvQrhd_FhCHZo-eUEN-OuotoLblU94UMa_oKZ1TU78gjzPWeUpUO9LZVOs0HKIxeFmPbJTe0js5Ckw79p8uTNyO6p9DmZTb3TsX9OmoNoeTDkZLMiJsIXEi9eRU&type=1`;
let url = `wss://k8s-horse-gateway.mashibing.cn/ws?client=${this.token}&type=1`;
this.socket(url);
},
methods: {
socket(url) {
let vm = this;
vm.Socket = new WebSocket(url);
vm.Socket.onopen = () => {
let traceId = Math.random();
vm.Socket.send(
`{"traceId":${traceId},traceType:1,"content":{"size": 100}}`
);
};
vm.Socket.onclose = () => {
vm.Socket = null;
};
vm.Socket.onerror = () => {
if (vm.Socket.readyState !== 3) {
if (vm.reconnection > 3) {
// vm.$message.error("!");
return;
}
}
};
vm.Socket.onmessage = (e) => {
if (e.data == `pong`) {
return;
}
let msg = JSON.parse(e.data);
console.log("websocket收到消息", msg);
if (msg.traceType == 1) {
let traceId = Math.random();
let sys = msg.content.sessionVOS.find((item) => item.type != 3);
let str = `{"traceId":${traceId},traceType:2,"content":{"sessionId":${sys.id}}}`;
vm.Socket.send(str);
}
if (msg.traceType == 2) {
vm.msgList = msg.content;
}
};
...mapState(["token","socketMsgData"]),
},
mounted(){
console.log(`socketMsgData`,this.$store.state)
},
methods: {},
};
</script>
<style lang="scss" scoped>

@ -52,7 +52,7 @@
<label>运费</label>
<UiMoney :money="orderInfo.shippingAmount" float/>
</p>
<p>
<p v-if="orderInfo.orderStatus > 2">
<label>
{{orderInfo.orderStatus == 1 ? '应付款:' : '实付款:'}}
</label>

@ -0,0 +1,25 @@
<!--
* @Author: ch
* @Date: 2022-05-04 17:48:12
* @LastEditors: ch
* @LastEditTime: 2022-05-04 17:53:11
* @Description: file content
-->
<template>
<div>
</div>
</template>
<script>
export default {
data() {
return {};
},
methods: {},
};
</script>
<style lang="scss" scoped>
</style>

@ -0,0 +1,58 @@
<!--
* @Author: ch
* @Date: 2022-05-04 17:48:12
* @LastEditors: ch
* @LastEditTime: 2022-05-04 17:53:11
* @Description: file content
-->
<template>
<main class="main flex flex-column flex-middle">
<p class="main-title">售后订单</p>
<img class="main-img" src="@/assets/img/common/app-qrcode.png" alt="" />
<p class="main-txt">请前往APP查看售后订单</p>
</main>
</template>
<script>
export default {
data() {
return {};
},
methods: {},
};
</script>
<style lang="scss" scoped>
.main {
width: 100%;
border: 1px solid #dddddd;
&-title {
width: 100%;
height: 42px;
background: #f8f8f8;
border-bottom: 1px solid #dddddd;
font-size: 14px;
font-family: Source Han Sans CN-Regular, Source Han Sans CN;
font-weight: 400;
color: #333333;
line-height: 42px;
padding-left: 24px;
}
&-img {
width: 140px;
height: 140px;
margin: 110px 0 20px;
}
&-txt {
width: 100%;
text-align: center;
font-size: 14px;
font-family: Microsoft YaHei-Regular, Microsoft YaHei;
font-weight: 400;
color: #999999;
}
}
</style>

@ -92,9 +92,21 @@ export default {
computed: {
...mapState(["userInfo", "token"]),
},
created() {
watch: {
userInfo: {
deep: true,
handler(val) {
if (val && Object.keys(val).length > 0) {
this.initData();
}
},
},
},
created() {
this.getOssConfig();
if (this.userInfo && Object.keys(this.userInfo).length > 0) {
this.initData();
}
},
methods: {
initData() {

@ -1,14 +1,51 @@
<template>
<div>
<div v-if="pageLoading">
<main class="main">
<el-skeleton style="width: 100%; padding: 40px" :loading="true" animated>
<template slot="template">
<div class="flex">
<el-skeleton-item
variant="image"
style="width: 456px; height: 456px"
/>
<div style="flex: 1; padding: 0 20px">
<el-skeleton-item variant="h1" style="width: 100%" />
<el-skeleton-item
variant="h2"
style="width: 100%; height: 130px; margin-top: 20px"
/>
<el-skeleton-item
variant="h3"
style="margin-top: 34px; width: 90%"
/>
<el-skeleton-item
variant="h3"
style="margin-top: 34px; width: 70%"
/>
<el-skeleton-item
variant="h3"
style="margin-top: 34px; width: 50%"
/>
<el-skeleton-item
variant="h3"
style="margin-top: 34px; width: 50%"
/>
<el-skeleton-item
variant="h3"
style="margin-top: 34px; width: 100%"
/>
</div>
</div>
</template>
</el-skeleton>
</main>
</div>
<div v-else>
<nav class="nav flex flex-middle flex-center">
<p class="nav__crumbs">
全部商品
<i class="el-icon-arrow-right"></i>
开发书籍
<i class="el-icon-arrow-right"></i>
后端书籍
<i class="el-icon-arrow-right"></i>
Java从入门到项目实战
{{ detailData.name }}
</p>
</nav>
<main class="main flex" v-if="detailData.isEnable">
@ -67,13 +104,11 @@
<div class="main__details-msg">
<div class="main__details-msg--price flex flex-middle">
<span class="msg-txt">售价</span>
<UiMoney
:money="
<strong class="msg-price">{{
detailData.productActivityVO.isStartActivity
? detailData.productActivityVO.activityPrice
: detailData.startingPrice
"
></UiMoney>
}}</strong>
<div
v-if="
detailData.productActivityVO.isActivity &&
@ -192,7 +227,9 @@
</div>
</section>
<div class="flex flex-center">
<UiButton type="yellow_panel service-btn" @click="showService=false;"></UiButton>
<UiButton type="yellow_panel service-btn" @click="showService = false"
>确定</UiButton
>
</div>
</el-dialog>
</div>
@ -206,12 +243,13 @@ import { ApiPutAddCart } from "@/plugins/api/cart";
import {
ApiGetGoodsDetail,
ApiGetGoodsSkus,
ApiGetRecommendedGoodsList,
ApiGetGoodsList,
} from "@/plugins/api/goods";
export default {
componetns: { UiMoney, UiButton, UiGoodsItem, BsChosen },
data() {
return {
pageLoading: true,
curBuyNum: 1,
activeImg: 0,
recommendedData: [],
@ -233,13 +271,20 @@ export default {
let id = this.$route.params.id;
let res1 = await ApiGetGoodsDetail({ id });
let res2 = await ApiGetGoodsSkus({ productId: id });
let res3 = await ApiGetRecommendedGoodsList();
let res3 = await ApiGetGoodsList({
length: 3,
pageIndex: 1,
name: "",
categoryId: "",
order: "",
});
vm.detailData = res1.result;
vm.skuData = res2.result.map(i => {
i.attributeSymbolList = i.attributeSymbolList.split(',')
return i;
});
vm.recommendedData = res3.result;
vm.recommendedData = res3.result.records;
vm.pageLoading = false;
if (
vm.detailData.productActivityVO.isActivity &&
!vm.detailData.productActivityVO.isStartActivity &&
@ -337,7 +382,9 @@ export default {
vm.surplus = vm.getSurplus(vm.startTime, vm.endTime);
if (vm.surplus.lefttime <= 0) {
clearInterval(vm.timer);
location.reload();
if (location) {
location?.reload();
}
}
}, 1000);
},
@ -490,7 +537,7 @@ export default {
return false;
}
this.$message.success("加入购物车成功~");
this.$store.dispatch('getCartProducts');
this.$store.dispatch("getCartProducts");
// this.$Router.push('/cart');
},
},
@ -628,6 +675,15 @@ export default {
margin-right: 20px;
}
.msg-price {
font-size: 22px;
color: #ff512b;
&::before {
content: "¥";
font-size: 14px;
}
}
.msg-service {
font-size: 14px;
font-family: Microsoft YaHei-Regular, Microsoft YaHei;

@ -7,14 +7,42 @@
-->
<template>
<div :class="listData && listData.length ? 'page' : ''">
<div v-if="pageloading" class="main flex">
<el-skeleton
v-for="item in 5"
:key="item"
style="width: 230px;margin-right:20px;"
:loading="true"
animated
>
<template slot="template">
<el-skeleton-item variant="image" style="width: 240px; height: 240px" />
<div style="padding: 14px">
<el-skeleton-item variant="h3" style="width: 50%" />
<div
style="
display: flex;
align-items: center;
justify-items: space-between;
margin-top: 16px;
height: 16px;
"
>
<el-skeleton-item variant="text" style="margin-right: 16px" />
<el-skeleton-item variant="text" style="width: 30%" />
</div>
</div>
</template>
</el-skeleton>
</div>
<div v-else :class="listData && listData.length ? 'page' : ''">
<main class="main" v-if="listData && listData.length">
<nav class="main__nav">
<p class="main__nav-crumbs">
<!-- <p class="main__nav-crumbs">
全部商品
<i class="el-icon-arrow-right"></i>
<!-- <span v-if="levelType == 2">{{}}</span> -->
</p>
<span v-if="levelType == 2">{{}}</span>
</p> -->
<div class="main__nav-sort flex flex-middle" v-if="levelType == 1">
<span class="main__nav-sort-txt">分类 :</span>
<span
@ -70,7 +98,7 @@
<img class="main-none-img" src="@/assets/img/goods/none.png" alt="" />
<p class="main-none-txt">没有搜到你想要的商品哦换个关键词试试</p>
</main>
<BsChosen></BsChosen>
<BsChosen v-if="!listData || !listData.length"></BsChosen>
</div>
</template>
<script>
@ -81,11 +109,12 @@ import {
} from "@/plugins/api/goods";
import Sort from "./module/SortItem.vue";
import UiGoodsItem from "@/components/UiGoodsItem.vue";
import BsChosen from '@/components/BsChosen.vue';
import BsChosen from "@/components/BsChosen.vue";
export default {
components: { Sort, UiGoodsItem,BsChosen },
components: { Sort, UiGoodsItem, BsChosen },
data() {
return {
pageloading: true,
navActive: 0,
levelActive: 0,
listData: [],
@ -104,7 +133,7 @@ export default {
},
};
},
async created() {
created() {
this.init();
},
methods: {
@ -127,10 +156,8 @@ export default {
let res = await ApiGetCategoryTwoAndGoods({ categoryId: this.levelId });
this.categoryOneList = res.result;
this.getGoodsListData();
console.log(res);
},
onNavClick(i) {
console.log(i);
let vm = this;
vm.sortType = i;
vm.navActive = i;
@ -161,18 +188,21 @@ export default {
vm.$set(vm.params, "order", "starting_price:asc");
break;
case 3:
vm.$set(vm.params, "order", "create_time");
vm.$set(vm.params, "order", "create_time:desc");
break;
}
if (vm.levelType == 1) {
vm.params.categoryId = vm.categoryOneList[vm.levelActive].id;
}
if(vm.params.name){
vm.params.categoryId = ''
}
let res = await ApiGetGoodsList(vm.params);
vm.pageloading = false;
if (res.error) {
vm.$message.error(res.error.message);
return false;
}
console.log(`goodListRes`, res.result);
vm.total = res.result.total;
vm.listData = res.result.records;
},
@ -286,5 +316,4 @@ export default {
color: #999999;
}
}
</style>

@ -70,12 +70,10 @@ export default {
let seckillData = { activityTimeVO: null };
let sekillGoodsList = [];
const { result: seckillDataResult } = await ApiGetHomeSeckill();
if (seckillData) {
if (seckillDataResult) {
seckillData = seckillDataResult;
}
if (seckillData.activityTimeVO) {
store.commit("setSeckillTabVisible", true);
//
const { result } = await ApiGetSeckillGoods({
pageIndex: 1,

@ -9,12 +9,12 @@
<template>
<div class="home-banner">
<el-carousel height="360px" indicator-position="outside">
<el-carousel-item
v-for="item in bannerList"
:key="item.id"
<el-carousel-item v-for="item in bannerList" :key="item.id">
<el-image
@click="onBannerClick(item.id)"
>
<el-image :src="item.url" fit="cover"></el-image>
:src="item.url"
fit="cover"
></el-image>
</el-carousel-item>
</el-carousel>
</div>
@ -46,7 +46,7 @@ export default {
},
methods: {
onBannerClick(goodsId) {
window.open(`${location.href}/detail/${goodsId}`);
window.open(`${location.origin}/goods/detail/${goodsId}`);
},
},
};
@ -75,6 +75,7 @@ export default {
.el-image {
width: 100%;
height: 100%;
cursor: pointer;
}
}
}

@ -2,17 +2,13 @@
<div class="home-pick flex flex-between">
<!-- 甄选推荐 -->
<div v-if="showRecommend" class="home-pick-recommend">
<div
@click="onJumpGoodsList('recommend')"
class="home-pick--label flex flex-middle"
>
<div class="home-pick--label flex flex-middle">
<strong>甄选推荐</strong>
<img src="~/assets/img/common/icon-jump.png" />
</div>
<div class="home-pick-recommend__products flex flex-middle flex-between">
<!-- 左侧商品一 -->
<div
@click="onJumpGoodsDetal(recommendGoodsOne.id)"
@click="onJumpGoodsDetail(recommendGoodsOne.id)"
class="pick-recommend-products__left"
>
<strong class="home-pick-recommend--title">{{
@ -45,7 +41,7 @@
<div
v-for="(item, index) in recommendArray"
:key="index"
@click="onJumpGoodsDetal(item.id)"
@click="onJumpGoodsDetail(item.id)"
class="recommend-products-right__item"
>
<strong class="home-pick-recommend--title">{{ item.title }}</strong>
@ -74,17 +70,13 @@
</div>
<!-- 新品上架 -->
<div v-if="showNew" class="home-pick-new">
<div
@click="onJumpGoodsList('new')"
class="home-pick--label flex flex-middle"
>
<div class="home-pick--label flex flex-middle">
<strong>新品上架</strong>
<img src="~/assets/img/common/icon-jump.png" />
</div>
<div class="home-pick-new__products flex">
<!-- 左侧商品 -->
<div
@click="onJumpGoodsDetal(newGoodsOne.id)"
@click="onJumpGoodsDetail(newGoodsOne.id)"
class="pick-new-products__left"
>
<img
@ -102,7 +94,7 @@
<div
v-for="(item, index) in newArray"
:key="index"
@click="onJumpGoodsDetal(item.id)"
@click="onJumpGoodsDetail(item.id)"
class="new-products-right__wrap flex flex-middle"
>
<div class="products-right-wrap__cover">
@ -172,11 +164,8 @@ export default {
},
},
methods: {
onJumpGoodsDetal(id) {
this.$router.push(`/goods/detail/${id}`);
},
onJumpGoodsList(type) {
this.$router.push(`/goods/list?id=${type}`);
onJumpGoodsDetail(id) {
window.open(`${location.origin}/goods/detail/${id}`);
},
},
};
@ -184,11 +173,10 @@ export default {
<style lang="scss" scoped>
.home-pick {
color: #333333;
margin-top: 30px;
&--label {
font-size: 24px;
margin-bottom: 16px;
width: 150px;
cursor: pointer;
img {
width: 16px;
height: 16px;
@ -227,9 +215,9 @@ export default {
height: 340px;
padding: 16px 20px;
background: #ffffff;
border-radius: 2px;
border-radius: 4px;
&--tag-wrap {
margin-bottom: 16px;
margin-bottom: 8px;
.tag-wrap__item {
width: 40px;
height: 20px;
@ -242,18 +230,19 @@ export default {
}
&--second_kill {
color: #3083ff;
background: #3083ff;
background: rgba(48, 131, 255, 0.1);
}
&--recommended {
color: #ff875b;
background: #ff875b;
background: rgba(255, 135, 91, 0.1);
}
}
}
&--title {
display: block;
font-size: 18px;
margin-bottom: 8px;
width: 140px;
font-size: 16px;
margin-bottom: 6px;
@include ellipsis;
}
&--subtitle {
@ -290,7 +279,7 @@ export default {
height: 122px;
position: relative;
background: #f8f7f8;
padding: 14px 0 14px 20px;
padding: 10px 0 10px 20px;
}
.recommend-products-right__cover {
position: absolute;
@ -312,6 +301,7 @@ export default {
height: 340px;
padding: 14px 20px 16px 20px;
background: #ffffff;
border-radius: 4px;
&__products {
cursor: pointer;
.pick-new-products__left {

@ -36,7 +36,6 @@
<div
v-for="(itemChild, indexChild) in item"
:key="itemChild.productId"
@click.stop="onJumpGoodsDetail(itemChild.productId)"
class="carousel-goods-box flex flex-middle"
>
<div
@ -174,10 +173,7 @@ export default {
}, 1e3);
},
onJumpSeckill() {
this.$router.push("/seckill");
},
onJumpGoodsDetail(id) {
this.$router.push(`/goods/detail/${id}`);
window.open(`${location.origin}/seckill`);
},
},
};
@ -193,6 +189,7 @@ export default {
text-align: center;
color: #ffffff;
background-size: 100% 100%;
border-radius: 4px 0 0 4px;
.home-sckill-title {
display: block;
font-size: 28px;
@ -233,19 +230,27 @@ export default {
.home-sckill-carousel {
/deep/.el-carousel {
width: 1010px;
border-radius: 4px;
.el-carousel__container {
padding: 0 10px;
background: #ffffff;
.el-carousel__arrow {
border-radius: 45%;
i {
font-size: 14px;
font-weight: bold;
}
&--left {
left: -11px;
i {
margin-left: 5px;
}
}
&--right {
right: -11px;
i {
margin-right: 5px;
}
}
}
}

@ -1,5 +1,9 @@
<template>
<div class="home-tabbar-fixed flex">
<div
v-if="tabBarVisible"
class="home-tabbar-fixed flex"
:class="{ 'home-tabbar-fixed--change': appHover }"
>
<div v-show="appHover" class="home-tabbar-fixed__qrcode">
<img src="~/assets/img/common/app-qrcode.png" />
<p>扫一扫上方二维码 下载APP</p>
@ -23,11 +27,8 @@
@click="onConcatCustomer"
class="tabbar-fixed-box__common flex flex-middle"
>
<span v-show="customerHover"></span>
<img
v-show="!customerHover"
src="~/assets/img/home/icon-customer.png"
/>
<span v-show="customerHover"></span>
<img v-show="!customerHover" src="~/assets/img/home/icon-message.png" />
</div>
<div v-show="showToTop">
<div class="tabbar-fixed-box__line"></div>
@ -61,6 +62,7 @@ export default {
appHover: false,
customerHover: false,
totopHover: false,
tabBarVisible: false,
};
},
computed: {
@ -68,7 +70,16 @@ export default {
return this.scrollTop > 400;
},
},
mounted() {
this.getTabBarVisible();
},
methods: {
getTabBarVisible() {
const clientWidth = document.body.clientWidth;
if (clientWidth >= 1200) {
this.tabBarVisible = true;
}
},
onConcatCustomer() {
if (!this.$isLoginValidate()) {
return;
@ -83,9 +94,13 @@ export default {
<style lang="scss" scoped>
.home-tabbar-fixed {
position: fixed;
right: 270px;
z-index: 99;
left: 50%;
top: 568px;
z-index: 10;
margin-left: 630px;
&--change {
margin-left: 390px;
}
.home-tabbar-fixed__qrcode {
width: 230px;
height: 260px;
@ -93,7 +108,7 @@ export default {
box-shadow: 0px 4px 30px 1px rgba(0, 0, 0, 0.1);
font-size: 14px;
color: #666666;
padding: 22px;
padding: 22px 20px;
margin-right: 10px;
img {
width: 186px;

@ -50,10 +50,15 @@
@click="onJumpGoodsDetail(item.productId)"
class="seckill-products-wrap"
>
<img
:src="item.productMainPicture"
class="seckill-products-wrap__cover"
/>
<div class="seckill-products-wrap__cover">
<img :src="item.productMainPicture" />
<div
v-if="item.percentage === 100"
class="products-wrap-cover__sold flex flex-middle flex-center"
>
已售罄
</div>
</div>
<div class="seckill-products-wrap__content">
<p class="products-wrap-content__title">{{ item.productName }}</p>
<div class="products-wrap-content__price">
@ -64,10 +69,21 @@
class="products-wrap-content__footer flex flex-middle flex-between"
>
<div class="wrap-content-footer__stock">
<el-progress :percentage="40" :show-text="false"></el-progress>
<el-progress
:percentage="item.percentage"
:show-text="false"
></el-progress>
<p>仅剩{{ item.stock }}</p>
</div>
<div class="wrap-content-footer__btn">立即抢购</div>
<div
v-if="item.percentage === 100"
class="wrap-content-footer__btn wrap-content-footer__btn--gray"
>
已售罄
</div>
<div v-else class="wrap-content-footer__btn">
{{ goodsBtnText }}
</div>
</div>
</div>
</div>
@ -122,6 +138,7 @@ export default {
seckillTime: 0, //
seckillEndVisible: false, //
seckillStatus: SECKILL_STATUS.NOT_START, //
inProgressId: 0, // id
};
},
computed: {
@ -136,6 +153,11 @@ export default {
second: second < 10 ? `0${second}` : `${second}`,
};
},
goodsBtnText() {
return this.query.activityTimeId === this.inProgressId
? "立即开抢"
: "即将开抢";
},
},
watch: {
//
@ -186,10 +208,16 @@ export default {
if (result && result.length > 0) {
this.tabList = result;
const inProgressItem = result.find((item) => item.isInProgress);
this.query.activityTimeId =
(inProgressItem && inProgressItem.id) || result[0].id;
if (inProgressItem) {
this.inProgressId = inProgressItem.id;
this.query.activityTimeId = inProgressItem.id;
} else {
this.query.activityTimeId = result[0].id;
}
this.getGoodsList();
return;
}
this.seckillEndVisible = true;
},
async getGoodsList() {
this.loading = true;
@ -197,7 +225,17 @@ export default {
this.loading = false;
if (result) {
this.total = result.total;
this.goodsList = result.records;
this.goodsList = result.records.map((item) => {
//
const saleNumber = item.number - item.stock;
return {
...item,
percentage:
saleNumber === 0
? 0
: (saleNumber / item.number).toFixed(2) * 100,
};
});
}
},
@ -260,7 +298,7 @@ export default {
});
},
onJumpGoodsDetail(id) {
this.$router.push(`/goods/detail/${id}`);
window.open(`${location.origin}/goods/detail/${id}`);
},
handleCurrentChange(page) {
this.query.pageIndex = page;
@ -282,7 +320,7 @@ export default {
<style lang="scss" scoped>
.seckill {
background: #f8f8f8;
padding-bottom: 42px;
padding-bottom: 60px;
.seckill-header-sticky {
position: fixed;
left: 50%;
@ -342,9 +380,29 @@ export default {
&:not(:nth-child(4n)) {
margin-right: calc(4% / 3);
}
&:hover {
box-shadow: 0px 0px 10px 1px rgba(0, 0, 0, 0.1);
}
.seckill-products-wrap__cover {
position: relative;
width: 100%;
height: 288px;
img {
width: 100%;
height: 100%;
}
.products-wrap-cover__sold {
position: absolute;
width: 110px;
height: 110px;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.5);
font-size: 24px;
color: #ffffff;
border-radius: 50%;
}
}
.seckill-products-wrap__content {
padding: 20px 16px;
@ -384,13 +442,16 @@ export default {
background: #ff512b;
font-size: 14px;
color: #ffffff;
&--gray {
color: #999999;
background: #eeeeee;
}
}
}
}
}
}
.seckill-pagination {
margin-top: 60px;
.btn-confirm {
width: 81px;
height: 32px;

@ -25,7 +25,6 @@ export default function ({$axios, store, route}, inject) {
if(result.code === 'TOKEN_FAIL'){
store.commit('setLoginOut');
store.commit('setLoginVisible');
return result;
}
return Promise.reject(result);
}

@ -0,0 +1,65 @@
import Vue from "vue";
import { TOKEN_KEY } from "@/constants";
function guid() {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
var r = (Math.random() * 16) | 0,
v = c == "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
Vue.prototype.$startWebSockets = function () {
console.log();
let token = this.$cookies.get(TOKEN_KEY);
if (token&&!Vue.prototype.Socket) {
let url = `wss://k8s-horse-gateway.mashibing.cn/ws?client=${token}&type=1`;
Vue.prototype.Socket = new WebSocket(url);
Vue.prototype.Socket.onopen = () => {
let traceId = guid();
Vue.prototype.Socket.send(
`{"traceId":"${traceId}",traceType:1,"content":{"size": 100}}`
);
};
Vue.prototype.Socket.onclose = () => {
Vue.prototype.Socket = null;
};
// Vue.prototype.Socket.onerror = () => {
// if (Vue.prototype.Socket.readyState !== 3) {
// }
// };
Vue.prototype.Socket.onmessage = (e) => {
if (e.data == `pong`) {
return;
}
let msg = JSON.parse(e.data);
console.log("websocket收到消息", msg);
// 获取会话
if (msg.traceType == 1) {
let traceId = guid();
let sys = msg.content.sessionVOS.find((item) => item.type != 3);
let str = `{"traceId":"${traceId}",traceType:2,"content":{"sessionId":${sys.id}}}`;
Vue.prototype.Socket.send(str);
this.$store.commit("setUnreadCount", msg.content.totalUnreadCount);
}
// 获取消息列表
if (msg.traceType == 2) {
this.$store.commit("setSocketMsgData", msg.content);
setTimeout(()=>{
console.log(this.$store.state)
},500)
}
// 接收消息
if (msg.traceType == 3) {
let traceId = guid();
Vue.prototype.Socket.send(
`{"traceId":"${traceId}",traceType:1,"content":{"size": 100}}`
);
}
};
}
};

@ -1,21 +1,10 @@
export default ({ app }) => {
app.router.beforeEach((to, from, next) => {
// const { token, userInfo } = app.store.state;
// if (token) {
// if (Object.keys(userInfo).length === 0) {
// app.store.dispatch("getUserInfo");
// }
// next();
// return;
// }
// // 未登录打开需要登录的页面,跳首页
// const needLoginPage = [/\/account/, /\/cart/];
// const result = needLoginPage.some((item) => item.test(to.path));
// if (result) {
// next("/");
// return;
// }
// 获取用户信息
const { token, userInfo } = app.store.state;
if (token && Object.keys(userInfo).length === 0) {
app.store.dispatch("getUserInfo");
}
next();
});
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 763 B

@ -18,6 +18,8 @@ const state = () => ({
seckillTabVisible: false, // 公共头是否展示秒杀tab
cartProducts: [], // 购物车列表
categroyData: [], // 公共页头分类数据
unreadCount:0, //未读消息数量
socketMsgData: [], //消息数据对象
});
const mutations = {
setUserInfo(state, info) {
@ -47,6 +49,13 @@ const mutations = {
setCategroyData(state, val) {
state.categroyData = val;
},
setUnreadCount(state, val){
state.unreadCount = val;
},
setSocketMsgData(state, val){
state.socketMsgData = val;
console.log(state.socketMsgData)
}
};
const actions = {
async nuxtServerInit({ state, commit, dispatch }) {

Loading…
Cancel
Save