Authored by 张文文

merge

Showing 45 changed files with 814 additions and 160 deletions
... ... @@ -5,6 +5,7 @@ import {createStore} from './store';
import 'filters';
import 'directives';
import titleMixin from './mixins/title';
import downloadMixin from './mixins/download';
import pluginCore from './plugins/core';
import lazyload from 'vue-lazyload';
import reportError from 'report-error';
... ... @@ -19,6 +20,7 @@ Vue.use(lazyload, {
});
Vue.use(pluginCore);
Vue.mixin(titleMixin);
Vue.mixin(downloadMixin);
dayjs.locale('zh-cn');
dayjs.extend(relativeTime);
... ...
function queryString() {
var vars = {},
hash,
i;
var hashes = window.location.search.slice(1).split('&');
for (i = 0; i < hashes.length; i++) {
hash = hashes[i].split('=');
vars[decodeURIComponent(hash[0])] = decodeURIComponent(hash[1]);
}
return vars;
}
const getAppPath = () => {
let appPath = document.getElementById('main-wrap').dataset.apppath || 'yohobuy://yohobuy.com/goapp?openby:yohobuy={"action":"go.home","params":{"gender":"1","channel":"2"}}';
let params = queryString();
let openbyYohobuy = params['openby:yohobuy'] || '';
let appPath = '';
if (openbyYohobuy) {
appPath = 'yohobuy://yohobuy.com/goapp?openby:yohobuy=' + openbyYohobuy;
} else {
appPath =
document.getElementById('main-wrap').dataset.apppath ||
'yohobuy://yohobuy.com/goapp?openby:yohobuy={"action":"go.home","params":{"gender":"1","channel":"2"}}';
}
return appPath;
};
const u = navigator.userAgent;
// eslint-disable-next-line no-unused-vars
const isFromYOHO = /m\.yohobuy\.com/i.test(document.referrer);
const isApp = /yoho/i.test(u) ||
const isApp =
/yoho/i.test(u) ||
!!window.yohoInterface ||
/app_version=/i.test(location.search) ||
/openrefer=/i.test(location.search);
const isiOS = /(iPhone|iPad|iPod|iOS)/i.test(u); // ios终端
const isAndroid = /Android/i.test(u); // android终端
const isWechat = /MicroMessenger/i.test(navigator.userAgent);
const isMobileQQ = /MQQBrowser.+QQ/i.test(navigator.userAgent);
const isWechatDevtool = /wechatdevtools/i.test(u); // 微信开发者工具
// eslint-disable-next-line no-unused-vars
const nodownload = document.getElementById('no-download'); // 页面不需要下载
const getIOSVersion = () => {
... ... @@ -22,17 +50,22 @@ const getIOSVersion = () => {
return verion ? parseInt(verion[1], 10) : 0;
};
const ua = navigator.userAgent;
const isOriginalChrome = /chrome\/[\d.]+ Mobile Safari\/[\d.]+/i.test(ua) &&
const isOriginalChrome =
/chrome\/[\d.]+ Mobile Safari\/[\d.]+/i.test(ua) &&
isAndroid &&
ua.indexOf('Version') < 0;
const getFallUrl = (schemeUrl) => {
const appPath = (schemeUrl || '').replace('yohobuy://yohobuy.com/goapp?', '') || 'openby:yohobuy={"action":"go.home","params":{"gender":"1","channel":"2"}}';
const getFallUrl = schemeUrl => {
const appPath =
(schemeUrl || '').replace('yohobuy://yohobuy.com/goapp?', '') ||
'openby:yohobuy={"action":"go.home","params":{"gender":"1","channel":"2"}}';
return `https://union.yoho.cn/union/app-downloads.html?${appPath}`;
};
const checkOpenFall = (url, callFunc, noFall) => {
let time = Date.now();
callFunc();
const fallUrl = getFallUrl(url);
... ... @@ -41,30 +74,51 @@ const checkOpenFall = (url, callFunc, noFall) => {
return;
}
window.location.href = fallUrl;
window.setTimeout(function() {
if (Date.now() - time < 1200) {
window.location.href = fallUrl;
}
}, 1000);
};
const callIframe = (url, noFall) => {
checkOpenFall(url, () => {
window.location.href = url;
}, noFall);
checkOpenFall(
url,
() => {
const ifr = document.createElement('iframe');
ifr.src = url;
ifr.style.display = 'none';
document.body.appendChild(ifr);
},
noFall,
);
};
const callUrl = (url, noFall) => {
checkOpenFall(url, () => {
}, noFall);
checkOpenFall(
url,
() => {
window.location.href = url;
},
noFall,
);
};
const callA = (url, noFall) => {
checkOpenFall(url, () => {
const ca = document.createElement('a');
ca.setAttribute('href', url);
ca.style.display = 'none';
document.body.appendChild(ca);
ca.click();
}, noFall);
checkOpenFall(
url,
() => {
const ca = document.createElement('a');
ca.setAttribute('href', url);
ca.style.display = 'none';
document.body.appendChild(ca);
ca.click();
},
noFall,
);
};
const toAppPage = (appUrl, noFall) => {
... ... @@ -82,16 +136,23 @@ const toAppPage = (appUrl, noFall) => {
};
const canOpenApp = () => {
if (isWechatDevtool || isApp || isFromYOHO || nodownload) {
if (isWechatDevtool || isApp) {
return false;
}
return isAndroid || isiOS;
};
export default () => {
export default function openApp() {
if (canOpenApp()) {
let appPath = getAppPath();
setTimeout(function() {
let appPath = getAppPath();
toAppPage(appPath, false);
toAppPage(appPath, false);
}, 3000);
}
};
}
// 在 android 中,不在微信和QQ和App中,打开页面
if (isAndroid && !(isMobileQQ || isWechat) && !isApp) {
openApp();
}
... ...
... ... @@ -59,6 +59,7 @@ const yoho = {
isAndroid: /Android/i.test(navigator.userAgent || ''),
isYohoBuy: isYohoBuy,
isWechat: /MicroMessenger/i.test(navigator.userAgent),
isMobileQQ: /QQ/i.test(navigator.userAgent),
isLocal: window.location.protocol === 'yoho-protocol:' || /yoho-protocol/i.test(navigator.userAgent || ''),
appVersion: getAppVersion(navigator.userAgent, ';') || getAppVersion(document.cookie, ';'),
... ...
<template>
<div class="comment-item">
<ImageFormat :lazy="false" :src="parentComment.headIco" :width="80" :height="80" class="comment-user-avatar" @click.native="toUserPage"></ImageFormat>
<ImageFormat :lazy="false" :src="parentComment.headIco" :width="80" :height="80" class="comment-user-avatar"
@click.native="toUserPage"></ImageFormat>
<div class="comment">
<div class="comment-nav">
<div class="comment-nav-left">
... ... @@ -20,20 +21,26 @@
</div>
</div>
<CommentPlaceholder
<CommentPlaceholderActionSheet
class="comment-cont"
:dest-id="parentComment.id"
:root-id="parentComment.id"
:pos-id="posId"
:article-id="articleId"
:add-type="1"
:user="parentComment.userName"
:column-type="columnType"
:share="share"
@on-comment="onReply">
:authorUid="authorUid"
:commentUid="parentComment.uid"
commentType="parent"
@on-comment="onReply"
@remove-comment="onRemoveComment"
>
{{parentComment.content}}
</CommentPlaceholder>
</CommentPlaceholderActionSheet>
<div class="reply-main" v-if="replayShowList.length">
<CommentPlaceholder
<CommentPlaceholderActionSheet
tag="p"
class="reply-item"
v-for="(reply, replyIndex) in replayShowList"
... ... @@ -44,13 +51,19 @@
:user="reply.userName"
:column-type="columnType"
:share="share"
@on-comment="onReplyChildren">
:authorUid="authorUid"
:commentUid="reply.uid"
:article-id="articleId"
commentType="child"
@on-comment="onReplyChildren"
@remove-comment="onRemoveComment"
>
<span class="reply-user">{{reply.userName}}</span>
<template v-if="reply.parentUserName">
<span>回复</span><em class="reply-to-user">@{{reply.parentUserName}}</em>
</template>:
<span>{{reply.content}}</span>
</CommentPlaceholder>
</CommentPlaceholderActionSheet>
<p class="reply-more" v-if="moreReplyNum > 0" @click="onShowMore">
{{replyMoreText}}
<i class="iconfont icon-right" v-if="!isShowAllReply"></i>
... ... @@ -61,11 +74,14 @@
</template>
<script>
import {createNamespacedHelpers} from 'vuex';
const {mapActions} = createNamespacedHelpers('comment');
import { createNamespacedHelpers } from 'vuex';
import CommentPlaceholderActionSheet from './comment-placeholder-actionsheet';
const { mapActions } = createNamespacedHelpers('comment');
export default {
name: 'CommentItem',
components: { CommentPlaceholderActionSheet },
props: {
parentComment: Object,
childrenComments: Array,
... ... @@ -75,7 +91,8 @@ export default {
},
share: Boolean,
posId: Number,
articleId: Number
articleId: Number,
authorUid: Number
},
data() {
return {
... ... @@ -138,6 +155,16 @@ export default {
});
}, 300);
},
onRemoveComment({ commentId, commentType, articleId }) {
let subCount = 0;
if (commentType === 'parent') {
subCount = this.childrenComments.length + 1;
} else {
subCount = 1;
}
this.$emit('remove-comment', { commentId, commentType, articleId, subCount});
}
}
};
</script>
... ...
... ... @@ -5,14 +5,16 @@
<div class="loading" v-if="firstLoading">
<Loading></Loading>
</div>
<Scroll v-else ref="scroll" :data="commentList" :scroll-events="['scroll', 'scroll-end']" :options="scrollOption" @scroll="onScrollHandle" @scroll-end="onScrollEndHandle" @pulling-up="onPullingUp">
<Scroll v-else ref="scroll" :data="commentList" :scroll-events="['scroll', 'scroll-end']"
:options="scrollOption" @scroll="onScrollHandle" @scroll-end="onScrollEndHandle"
@pulling-up="onPullingUp">
<CommentEmpty v-if="empty"></CommentEmpty>
<div v-else ref="commentList" class="comment-list">
<div ref="commentListTop" class="comment-list-top">
<div ref="commentPre" class="comment-pre-list">
<div
v-for="(comments, index) in commentPreList"
:key="commentPreList.length - index">
v-for="(comments, index) in commentPreList"
:key="commentPreList.length - index">
<CommentItem
v-for="comment in comments"
:key="comment.parentComment.id"
... ... @@ -21,8 +23,12 @@
:column-type="columnType"
:pos-id="posId"
:article-id="articleId"
:authorUid="authorUid"
:commentUid="comment.parentComment.uid"
@on-reply="onReply"
@on-close="onClose">
@on-close="onClose"
@remove-comment="onRemoveComment"
>
</CommentItem>
</div>
</div>
... ... @@ -36,34 +42,42 @@
:column-type="columnType"
:pos-id="posId"
:article-id="articleId"
:authorUid="authorUid"
:commentUid="comment.parentComment.uid"
@on-reply="onReply"
@on-close="onClose">
@on-close="onClose"
@remove-comment="onRemoveComment"
>
</CommentItem>
</div>
</Scroll>
</div>
</div>
<div class="comment-footer" v-if="!firstLoading">
<CommentPlaceholder
<CommentPlaceholderActionSheet
class="comment-input"
:dest-id="destId"
:pos-id="posId"
:article-id="articleId"
:add-type="0"
:column-type="columnType"
:authorUid="authorUid"
@on-comment="onComment">
参与评论
</CommentPlaceholder>
</CommentPlaceholderActionSheet>
</div>
</div>
</template>
<script>
import CommentItem from './comment-item.vue';
import {Scroll, Loading} from 'cube-ui';
import {get, throttle} from 'lodash';
import {createNamespacedHelpers} from 'vuex';
const {mapActions} = createNamespacedHelpers('comment');
import { Scroll, Loading } from 'cube-ui';
import { get, throttle, findIndex } from 'lodash';
import { createNamespacedHelpers } from 'vuex';
import CommentPlaceholderActionSheet from './comment-placeholder-actionsheet';
const { mapActions } = createNamespacedHelpers('comment');
const {mapMutations: articleMapMutations } = createNamespacedHelpers('article');
export default {
name: 'CommentList',
... ... @@ -75,7 +89,7 @@ export default {
},
posId: Number,
articleId: Number,
commentId: Number
authorUid: Number
},
data() {
return {
... ... @@ -105,6 +119,7 @@ export default {
},
methods: {
...mapActions(['fetchCommentList', 'fetchReplayList', 'postComment']),
...articleMapMutations(['SUB_ARTICLE_COMMENT_COUNT']),
async fetchCommentsAsync(pre) {
let params = {
destId: this.destId,
... ... @@ -113,7 +128,7 @@ export default {
};
if (params.page < 1 || params.page > this.totalPage) {
return {code: 200};
return { code: 200 };
}
if (this.commentId && (this.prePage === this.page)) {
... ... @@ -208,7 +223,7 @@ export default {
type: 'warn',
time: 1000
}).show();
this.$emit('on-page-ready', {success: false});
this.$emit('on-page-ready', { success: false });
}
return result;
},
... ... @@ -249,7 +264,7 @@ export default {
this.totalPage = 1;
this.$refs.scroll.scrollTo(0, 0, 200);
this.fetchComments();
this.$emit('on-comment', {destId: this.destId});
this.$emit('on-comment', { destId: this.destId });
},
async init() {
this.page = 1;
... ... @@ -259,7 +274,7 @@ export default {
this.firstLoading = true;
this.fetchComments();
},
async onReply({destId, parentId}) {
async onReply({ destId, parentId }) {
const commentId = parentId || destId;
if (!commentId) {
... ... @@ -286,9 +301,42 @@ export default {
},
onClose() {
this.$emit('on-close');
}
},
onRemoveComment({ commentId, subCount }) {
for (let comments of this.commentPreList) {
for (let [index, comment] of Object.entries(comments)) {
if (comment.parentComment && +comment.parentComment.id === +commentId) {
comments.splice(index, 1);
break;
}
const childrenIndex = findIndex(comment.childrenComments, { id: +commentId });
if ((+index !== -1) && (childrenIndex !== -1)) {
comments[index].childrenComments.splice(childrenIndex, 1);
break;
}
}
}
for (let [index, comment] of Object.entries(this.commentList)) {
if (comment.parentComment && +comment.parentComment.id === +commentId) {
this.commentList.splice(index, 1);
break;
}
const childrenIndex = findIndex(comment.childrenComments, { id: +commentId });
if ((+index !== -1) && childrenIndex !== -1) {
this.commentList[index].childrenComments.splice(childrenIndex, 1);
break;
}
}
this.SUB_ARTICLE_COMMENT_COUNT({ articleId: this.articleId, subCount });
},
},
components: {Scroll, CommentItem, Loading}
components: { CommentPlaceholderActionSheet, Scroll, CommentItem, Loading }
};
</script>
... ...
<template>
<div class="actionsheet" @click.capture.stop="onClick">
<CommentPlaceholder ref="placeholder" v-bind="$attrs" v-on="$listeners">
<slot></slot>
</CommentPlaceholder>
</div>
</template>
<script>
import { createNamespacedHelpers } from 'vuex';
import CommentPlaceholder from './comment-placeholder';
import { get } from 'lodash';
const { mapActions } = createNamespacedHelpers('comment');
const ITEM = {
comment: '回复',
remove: '删除',
report: '举报'
};
export default {
name: 'CommentPlaceholderActionSheet',
components: { CommentPlaceholder },
data() {
return {};
},
methods: {
...mapActions(['setCommentStatus']),
async onClick() {
const authorUid = this.$attrs.authorUid;
const commentUid = this.$attrs.commentUid;
const uid = get(await this.$sdk.getUser(), 'uid', 0);
const commentId = this.$attrs['dest-id'];
const articleId = this.$attrs['article-id'];
const commentType = this.$attrs.commentType;
let menu = [];
if (authorUid === uid || commentUid === uid) {
menu = [
{
content: ITEM.comment
},
{
content: ITEM.remove
},
{
content: ITEM.report
}
];
} else {
menu = [
{
content: ITEM.comment
},
{
content: ITEM.report
}
];
}
this.$createActionSheet({
data: menu,
zIndex: 200,
onSelect: item => {
switch (item.content) {
case ITEM.comment: {
this.$refs.placeholder.openComentInput();
break;
}
case ITEM.remove: {
this.setCommentStatus({ type: 1, commentId }).then(result => {
if (result.code === 200) {
this.$createToast({
txt: '已删除',
type: 'correct',
time: 2000
}).show();
this.$emit('remove-comment', { commentId, commentType, articleId });
} else {
this.$createToast({
txt: '删除失败,请重试',
type: 'warn',
time: 2000
}).show();
}
});
break;
}
case ITEM.report: {
this.setCommentStatus({ type: 2, commentId }).then(result => {
if (result.code === 200) {
this.$createToast({
txt: '已举报',
type: 'correct',
time: 2000
}).show();
} else {
this.$createToast({
txt: '举报失败,请重试',
type: 'warn',
time: 2000
}).show();
}
});
break;
}
default: {
// pass
}
}
}
}).show();
}
}
};
</script>
<style lang="scss">
.cube-action-sheet-panel {
margin-left: 15px;
margin-right: 15px;
margin-bottom: 17px;
border-radius: 10px;
overflow: hidden;
}
.cube-action-sheet-item {
color: #222 !important;
font-weight: bold !important;
}
.cube-action-sheet-cancel {
span {
color: #222 !important;
font-weight: bold !important;
}
}
.cube-action-sheet-space {
height: 1px !important;
background-color: rgb(235, 235, 235) !important;
}
</style>
... ...
... ... @@ -115,10 +115,10 @@ export default {
};
if (result.code === 200) {
this.UPDATE_ARTICLE_COMMENT_COUNT({articleId: this.destId});
this.UPDATE_ARTICLE_COMMENT_COUNT({articleId: this.articleId});
if (this.autoUpdate && this.addType === 0) {
await this.fetchArticleUpdate({articleId: this.destId});
await this.fetchArticleUpdate({articleId: this.articleId});
}
this.$emit('on-comment', {
... ...
... ... @@ -6,7 +6,7 @@
<i class="iconfont icon-close icon" @touchend.prevent="onClose"></i>
</template>
</LayoutHeader>
<CommentList ref="commentList" :dest-id="destId" :pos-id="posId" :article-id="articleId" :comment-id="commentId" :column-type="1001" @on-page-change="onPageChange" @on-comment="onComment" @on-page-ready="onPageReady" @on-close="onClose"></CommentList>
<CommentList ref="commentList" :dest-id="destId" :pos-id="posId" :article-id="articleId" :comment-id="commentId" :column-type="1001" @on-page-change="onPageChange" @on-comment="onComment" @on-page-ready="onPageReady" @on-close="onClose" :authorUid="authorUid"></CommentList>
</Layout>
</template>
... ... @@ -24,7 +24,8 @@ export default {
posId: Number,
articleId: Number,
commentId: Number,
commentCount: Number
commentCount: Number,
authorUid: Number
},
data() {
return {
... ...
... ... @@ -2,10 +2,12 @@ import Comment from './comment';
import CommentItem from './comment-item';
import CommentEmpty from './comment-empty';
import CommentPlaceholder from './comment-placeholder';
import CommentPlaceholderActionSheet from './comment-placeholder-actionsheet';
export default [
Comment,
CommentItem,
CommentEmpty,
CommentPlaceholder
CommentPlaceholder,
CommentPlaceholderActionSheet
];
... ...
... ... @@ -2,7 +2,7 @@ export default {
name: 'AuthComponent',
props: {
tag: String,
auth: {
requiredAuth: {
type: Boolean,
default: true
}
... ... @@ -15,17 +15,17 @@ export default {
this._lastTime = e.timeStamp;
if (!this.auth) {
return this.$emit('click');
}
if (this.requiredAuth) {
const user = await this.$sdk.getUser();
const user = await this.$sdk.getUser();
if (user && user.uid) {
this.$emit('click', {uid: user.uid});
if (user && user.uid) {
this.$emit('click', {uid: user.uid});
} else {
this.$emit('cancel');
this.$sdk.goLogin();
}
} else {
this.$emit('cancel');
this.$sdk.goLogin();
return this.$emit('click');
}
}
},
... ...
<template>
<AuthComponent class="btn-follow hover-opacity" :class="followClass" :auth="isAuth" @click="onFollow">
<AuthComponent class="btn-follow hover-opacity" :class="followClass" :requiredAuth="isAuth" @click="onFollow">
<span>{{followText}}</span>
</AuthComponent>
</template>
<script>
import {createNamespacedHelpers} from 'vuex';
import { createNamespacedHelpers } from 'vuex';
import YAS from 'utils/yas-constants';
const {mapActions} = createNamespacedHelpers('user');
const { mapActions } = createNamespacedHelpers('user');
export default {
name: 'WidgetFollow',
props: {
authorUid: [Number, String],
follow: Boolean,
follow: [String, Boolean],
authorType: {
type: [Number, String],
default: 1
... ... @@ -25,12 +26,12 @@ export default {
data() {
return {
loading: false,
followStatus: this.follow
followStatus: this.follow === 'Y' || this.follow === 'O'
};
},
watch: {
follow(val) {
this.followStatus = val;
this.followStatus = val === 'Y' || val === 'O';
}
},
computed: {
... ... @@ -41,7 +42,20 @@ export default {
};
},
followText() {
return this.followStatus ? '已关注' : '关注';
switch (this.follow) {
case 'Y': {
return '已关注';
}
case 'N': {
return '关注';
}
case 'O': {
return '已相互关注';
}
default: {
return '关注';
}
}
},
isAuth() {
return !this.share;
... ... @@ -85,7 +99,7 @@ export default {
}).show();
this.reportFellow();
}
this.$emit('on-follow', this.followStatus);
this.$emit('on-follow', this.followStatus ? 'Y' : 'N');
} else {
this.$createToast && this.$createToast({
txt: result.message || '服务器开小差了',
... ... @@ -140,5 +154,12 @@ export default {
> span {
line-height: 1;
}
.each-follow {
width: 110px;
height: 50px;
background-image: url("~statics/image/userpage/follow.png");
background-size: cover;
}
}
</style>
... ...
<template>
<div class="icon-btn" :class="{'btn-selected': viewOption.selected}" :style="btnStyle">
<AuthComponent :auth="isAuth" class="click-wrap" @click="onClick"></AuthComponent>
<AuthComponent :requiredAuth="isAuth" class="click-wrap" @click="onClick"></AuthComponent>
<i class="iconfont" :class="iconClass" :style="iconStyle">
<div v-if="type === 'fav'" class="praise-lottie">
<WidgetLottie ref="lottie" class="praise-lottie-wrap" :options="lottieOptions"></WidgetLottie>
... ... @@ -244,10 +244,11 @@ export default {
return Promise.resolve({code: 404});
}
},
onClick(evt) {
async onClick(evt) {
if (this.share) {
return this.$links.toDownloadApp();
}
if (this.syncing) {
return;
}
... ...
... ... @@ -14,6 +14,10 @@ import sdk from 'common/sdk';
import links from 'utils/links';
import openApp from 'common/open-app';
if (process.env.NODE_ENV === 'development') {
require('./utils/debug');
}
import {initClient, getYohoState} from 'utils/init-client';
import 'statics/scss/common.scss';
import 'statics/scss/grass-prompt.scss';
... ...
const serverDownloadMixin = {
methods: {
async isDownloadBarHide() {
return true;
},
async isMiniapp() {
return false;
},
openByBrowser() {
}
}
};
const clientDownloadMixin = {
methods: {
async isDownloadBarHide() {
let isMiniapp = await this.isMiniapp();
if (isMiniapp) {
return true;
}
return document.getElementById('no-download');
},
isMiniapp() {
/* eslint-disable-next-line */
return this.$store.$context.env.isMiniApp;
},
sleep(ns) {
return new Promise(resolve => {
setTimeout(resolve, ns);
});
},
openByBrowser() {
let appPathUrl = window.location.pathname;
const query = Object.assign({}, this.$route.query, {
headerid: -1,
toplayoutByH5: 'Y'
});
const openBy = {
action: 'go.h5',
params: {
url: 'http://m.yohobuy.com' + appPathUrl,
param: JSON.stringify(query)
}
};
this.$router.push({
name: 'openByBrowser',
query: {
'openby:yohobuy': encodeURIComponent(JSON.stringify(openBy)),
share: false
}
});
}
}
};
export default process.env.VUE_ENV === 'server' ?
serverDownloadMixin :
clientDownloadMixin;
... ...
... ... @@ -20,7 +20,7 @@ export default {
return;
}
let shareData = getDetailShareData(article);
let shareData = getDetailShareData(article, this.$yoho.appVersion);
document && (document.title = shareData.title);
... ...
... ... @@ -3,7 +3,7 @@
<ArticleDetailHeader ref="header" class="article-detail-header" v-show="!share" :data="articleInfo" :step="headerAnimateStep" :title-step="headerTitleAnimateStep">
<div v-if="articleInfo.articleId && !articleInfo.empty" class="title-main">
<div class="title-info" :style="`transform: translate3d(0, ${viewMoreArticles ? '-50%' : '0'}, 0)`">
<ArticleItemHeader class="title-info-author" :share="share" :data="authorData" :more="false" @on-follow="onFollowAuthor"></ArticleItemHeader>
<ArticleItemHeader class="title-info-author" :share="false" :data="authorData" :more="false" @on-follow="onFollowAuthor"></ArticleItemHeader>
<div class="title-info-rec">{{listTitle}}</div>
</div>
</div>
... ... @@ -13,7 +13,7 @@
<ClientOnly>
<Download v-if="share"></Download>
</ClientOnly>
<ArticleDeatilLong
<ArticleDetailLong
v-if="articleInfo.sort == 2"
ref="detailLong"
:data="articleInfo"
... ... @@ -24,8 +24,8 @@
:pos-id="posId"
@on-show-more="onShowMore"
@on-follow="onFollowAuthor">
</ArticleDeatilLong>
<ArticleDeatilNote
</ArticleDetailLong>
<ArticleDetailNote
v-else
ref="detailNote"
:data="articleInfo"
... ... @@ -37,7 +37,7 @@
@on-show-more="onShowMore"
@on-follow="onFollowAuthor"
@on-praise="onPraise">
</ArticleDeatilNote>
</ArticleDetailNote>
</template>
<template class="article-item" #item="{ data }">
<ArticleItem2
... ... @@ -92,8 +92,8 @@ import {getDetailShareData} from 'utils/share-handler';
import YAS from 'utils/yas-constants';
import ArticleDetailHeader from './components/detail/article-header';
import ArticleItemHeader from './components/article/article-item-header';
import ArticleDeatilLong from './components/detail/article-long';
import ArticleDeatilNote from './components/detail/article-note';
import ArticleDetailLong from './components/detail/article-long';
import ArticleDetailNote from './components/detail/article-note';
import ArticleItem2 from './components/article/article-item2';
import ArticleDetailFooter from './components/detail/article-footer';
import Download from './components/download-top';
... ... @@ -383,7 +383,7 @@ export default {
return;
}
Share.setShareInfo(getDetailShareData(article));
Share.setShareInfo(getDetailShareData(article, this.$yoho.appVersion));
},
reportArticleShow(items) {
if (!items || !items.length) {
... ... @@ -469,8 +469,8 @@ export default {
ReplaceToHome,
ArticleDetailHeader,
ArticleItemHeader,
ArticleDeatilLong,
ArticleDeatilNote,
ArticleDetailLong,
ArticleDetailNote,
ArticleItem2,
MoreActionSheet,
ArticleDetailFooter,
... ...
... ... @@ -10,7 +10,7 @@
</div>
</div>
<div class="opts">
<WidgetFollow :class="invisibleClass" v-if="data.hasAttention" :share="share" :author-uid="data.authorUid" :authorType="data.authorType" :follow="data.hasAttention === 'Y'" @on-follow="onFollow" :pos-id="posId"></WidgetFollow>
<WidgetFollow :class="invisibleClass" v-if="data.hasAttention" :share="share" :author-uid="data.authorUid" :authorType="data.authorType" :follow="data.hasAttention" @on-follow="onFollow" :pos-id="posId"></WidgetFollow>
<i v-if="more" class="iconfont icon-more1" @click="onMore"></i>
</div>
</div>
... ...
... ... @@ -173,7 +173,7 @@ export default {
this.reportLabel(topicId);
},
onShare() {
this.$yoho.share(getDetailShareData(this.data));
this.$yoho.share(getDetailShareData(this.data, this.$yoho.appVersion));
},
onExpanding() {
if (this.data.articleType === 2) {
... ...
... ... @@ -137,8 +137,15 @@ export default {
this.reportClickAvatar();
},
toArticlePage() {
if (this.share) {
return this.$links.toDownloadApp();
if (this.isMiniapp()) {
let url = `http://m.yohobuy.com/grass/article/${this.data.articleId}`;
let h5url = `http://m.yohobuy.com?openby:yohobuy={"action":"go.h5","params":{"h5back":"${encodeURIComponent(url)}"}}`;
/* eslint-disable-next-line */
wx.miniProgram.navigateTo({
url: '/pages/common/webback?url=' + encodeURIComponent(h5url)
});
return;
}
this.$router.push({
... ...
... ... @@ -258,7 +258,7 @@ export default {
},
onFollow(data, follow) {
if (data.authorUid === this.currentAuthor.authorUid) {
this.currentAuthor.hasAttention = follow ? 'Y' : 'N';
this.currentAuthor.hasAttention = follow === 'Y' || follow === 'O' ? 'Y' : 'N';
}
this.CHANGE_AUTHOR_FOLLOW({authorUid: data.authorUid, authorType: data.authorType, follow, type: this.type});
},
... ...
... ... @@ -86,7 +86,7 @@ export default {
}
},
onShare() {
const share = getDetailShareData(this.data);
const share = getDetailShareData(this.data, this.$yoho.appVersion);
keys(this.data.atUserInfo).forEach(k => {
share.desc = share.desc.replace(new RegExp(`@${k}#`, 'gm'), `${this.data.atUserInfo[k]}`);
... ...
... ... @@ -31,6 +31,7 @@
:commentCount="articleState.commentCount"
:share="share"
:pos-id="posId"
:authorUid="data.authorUid"
@on-close="onCloseComment"
@on-comment="onActionComment"></Comment>
</YohoActionSheet>
... ... @@ -46,7 +47,7 @@ import ArticleItemSlideImage from '../article/article-item-slide-image';
import ArticleDetailHeader from './article-header';
import YAS from 'utils/yas-constants';
import {mapState, mapMutations, createNamespacedHelpers} from 'vuex';
const {mapState: mapArticleState} = createNamespacedHelpers('article');
const {mapState: mapArticleState, mapActions} = createNamespacedHelpers('article');
let timeOutEvent = null;
... ... @@ -74,6 +75,8 @@ export default {
recomendProduct: [],
showCommentAction: false,
showCommentActioning: false,
productSknList: [],
productEleList: []
};
},
mounted() {
... ... @@ -149,6 +152,7 @@ export default {
},
methods: {
...mapMutations(['SET_STATUS_BAR_COLOR']),
...mapActions(['fetchProductBySknList']),
tStart(e) {
if (e.target.src) {
timeOutEvent = setTimeout(() => {
... ...
... ... @@ -22,7 +22,7 @@
<i class="iconfont icon-more1" @click="onMore"></i>
</div>
</div>
<ArticleDetailCommentList ref="commentList" v-if="data.articleId" :article-id="data.articleId" :share="share" :comment-count="articleState.commentCount" :has-comment="data.hasComment"></ArticleDetailCommentList>
<ArticleDetailCommentList ref="commentList" v-if="data.articleId" :article-id="data.articleId" :share="share" :comment-count="articleState.commentCount" :has-comment="data.hasComment" :authorUid="data.authorUid"></ArticleDetailCommentList>
</div>
<div v-if="listTitle" class="rec-article-title">
... ...
... ... @@ -14,6 +14,9 @@
:share="share"
:pos-id="0"
:article-id="articleId"
:authorUid="authorUid"
:commentUid="comment.parentComment.uid"
@remove-comment="onRemoveComment"
@on-reply="onReply">
</CommentItem>
</div>
... ... @@ -30,11 +33,11 @@
</template>
<script>
import {get, forEach, find} from 'lodash';
import {Loading} from 'cube-ui';
import {mapState as mapYohoState, mapActions as mapYohoActions, createNamespacedHelpers} from 'vuex';
import { get, forEach, find, findIndex } from 'lodash';
import { Loading } from 'cube-ui';
import { mapState as mapYohoState, mapActions as mapYohoActions, createNamespacedHelpers } from 'vuex';
const {mapActions} = createNamespacedHelpers('comment');
const { mapActions } = createNamespacedHelpers('comment');
export default {
name: 'ArticleDetailCommentList',
... ... @@ -46,7 +49,8 @@ export default {
default: 1001
},
share: Boolean,
hasComment: Boolean
hasComment: Boolean,
authorUid: Number
},
data() {
return {
... ... @@ -128,29 +132,50 @@ export default {
this.onFetching = false;
}, this.page > 1 ? 800 : 0);
},
onReply({comment}) {
async onReply({ comment }) {
const uid = (await this.$sdk.getUser()).uid;
forEach(this.commentList, (val) => {
if (val.parentComment && +val.parentComment.id === +comment.parentId) {
if (val.parentComment && +val.parentComment.id === +comment.rootId) {
val.childrenComments.unshift(Object.assign(comment, {
id: comment.destId,
destId: this.articleId,
headIco: this.yoho.context.userHeadIco,
userName: this.yoho.context.userName,
parentUserName: get(find(val.childrenComments, {id: comment.parentId}), 'userName', '')
uid,
parentUserName: +val.parentComment.id === +comment.parentId ?
val.parentComment.userName :
get(find(val.childrenComments, { id: +comment.parentId }), 'userName', '')
}));
}
});
},
addComment(comment) {
async addComment(comment) {
this.commentList.unshift({
childrenComments: [],
parentComment: Object.assign(comment, {
id: comment.destId,
destId: this.articleId,
headIco: this.yoho.context.userHeadIco,
userName: this.yoho.context.userName
userName: this.yoho.context.userName,
uid: (await this.$sdk.getUser()).uid
})
});
},
onRemoveComment({ commentId }) {
for (let [index, val] of Object.entries(this.commentList)) {
if (val.parentComment && +val.parentComment.id === +commentId) {
this.commentList.splice(index, 1);
break;
}
const childrenIndex = findIndex(val.childrenComments, { id: +commentId });
if ((+index !== -1) && (childrenIndex !== -1)) {
this.commentList[index].childrenComments.splice(childrenIndex, 1);
break;
}
}
}
},
components: {
... ...
<template>
<a class="openapp-btn hover-opacity" href="javascript:;" @click="toDownloadPage">
<a v-if="visible" class="openapp-btn hover-opacity" href="javascript:;" @click="toDownloadPage">
<span class="avatar-block">
<div class="avatar"></div>
</span>
... ... @@ -10,9 +10,25 @@
<script>
export default {
data() {
return {
visible: true
};
},
async mounted() {
let isHide = await this.isDownloadBarHide();
if (isHide) {
this.visible = false;
}
},
methods: {
toDownloadPage() {
this.$openApp();
if (this.$yoho.isAndroid && (this.$yoho.isWechat || this.$yoho.isMobileQQ)) {
this.openByBrowser();
} else {
this.$openApp();
}
}
}
};
... ...
... ... @@ -11,11 +11,18 @@ export default {
visible: true
};
},
mounted() {
async mounted() {
const isHide = await this.isDownloadBarHide();
if (isHide) {
this.visible = false;
return;
}
this.getDownloadElem((elem) => {
const newElem = this.handleElem(elem.cloneNode(true));
// elem.parentNode.removeChild(elem);
elem.parentNode.removeChild(elem);
this.$el.appendChild(newElem);
});
},
... ... @@ -34,6 +41,13 @@ export default {
checkForDownload();
},
openApp() {
if (this.$yoho.isAndroid && (this.$yoho.isWechat || this.$yoho.isMobileQQ)) {
this.openByBrowser();
} else {
this.$openApp();
}
},
handleElem(elem) {
const vm = this;
const miniElem = elem.querySelector('#mini-app-open');
... ... @@ -54,7 +68,7 @@ export default {
}
case 'download-go': {
// 尝试打开app
vm.$openApp();
vm.openApp();
e.stopPropagation();
e.preventDefault();
... ... @@ -62,7 +76,7 @@ export default {
}
case 'download-go-wechat': {
// 尝试打开app
vm.$openApp();
vm.openApp();
e.stopPropagation();
e.preventDefault();
... ...
... ... @@ -113,7 +113,6 @@ export default {
}
},
mounted() {
this.share = !this.$yoho.isApp;
this.scrollEvent = throttle(this.onDounceScroll.bind(this), throttleTime);
... ...
import Article from './article';
import Common from './common';
import UserPage from './userpage';
import OpenApp from './openapp';
export default [...Article, ...UserPage, ...Common];
export default [...Article, ...UserPage, ...Common, ...OpenApp];
... ...
export default [{
path: '/openapp.html',
name: 'openByBrowser',
component: () => import(/* webpackChunkName: "openapp" */ './openapp')
}];
... ...
<template>
<div class="bg" v-if="image">
<div class="guide"></div>
<a class="btn" href="http://a.app.qq.com/o/simple.jsp?pkgname=com.yoho&g_f=995445"></a>
</div>
</template>
<script>
export default {
name: 'openByBrowser',
title: 'Yoho!Buy有货|年轻人潮流购物中心 ',
mounted() {
if (!(this.$yoho.isWechat || this.$yoho.isMobileQQ)) {
this.$nextTick().then(() => {
this.$openApp();
});
}
},
computed: {
image() {
return this.$yoho.isWechat || this.$yoho.isMobileQQ;
}
}
};
</script>
<style lang="scss" scoped>
.bg {
background-color: white;
width: 100%;
height: 100%;
overflow: hidden;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.guide {
width: 610px;
height: 852px;
margin: 50px 60px 0 92px;
background-image: url("~statics/image/openapp/guide.png");
background-size: cover;
}
.btn {
display: block;
width: 440px;
height: 88px;
margin-left: 92px;
margin-top: 30px;
background-image: url("~statics/image/openapp/download.png");
background-size: cover;
}
</style>
... ...
<template>
<Layout class="author-fans-page">
<LayoutHeader slot='header' :hide="noHeader" theme="white" class="author-page-header" :title="(isMine ? '我' : 'TA') + '的粉丝'"></LayoutHeader>
<UserList ref="userList" :follow-name="isMine ? '回粉' : '关注'" :on-fetch="onFetch"></UserList>
<UserList ref="userList" type="fans" :follow-name="isMine ? '回粉' : '关注'" :on-fetch="onFetch"></UserList>
</Layout>
</template>
... ...
... ... @@ -5,7 +5,7 @@
<TabBlock @on-change-tab="onChangeTab"></TabBlock>
</template>
</LayoutHeader>
<UserList ref="userList" :on-fetch="onFetch">
<UserList ref="userList" type="follow" :on-fetch="onFetch">
<template v-if="activeType == 0" #item="{ data }">
<TopicItem :data="data"></TopicItem>
</template>
... ...
... ... @@ -165,7 +165,7 @@ export default {
return this.authorStates[`${this.authorInfo.authorUid}-${this.authorInfo.authorType}`] || this.authorBaseData;
},
isAttention() {
return this.authorState.hasAttention === 'Y';
return this.authorState.hasAttention;
},
list() {
if (this.activeIndex === 0) {
... ...
... ... @@ -12,7 +12,8 @@
<div v-for="(item, index) in list" :key="index" class="item">
<slot name="item" :data="item">
<div class="user-item">
<WidgetAvatar class="head-ico" :src="item.headIcon" :group="item.authGroupId" :width="100" :height="100" @click.native="toUserPage(item)"></WidgetAvatar>
<WidgetAvatar class="head-ico" :src="item.headIcon" :group="item.authGroupId" :width="100" :height="100"
@click.native="toUserPage(item)"></WidgetAvatar>
<div class="user-info" @click="toUserPage(item)">
<p class="name">{{item.nickName}}</p>
<p v-if="item.articleCount || item.fansCount" class="extra">
... ... @@ -20,9 +21,18 @@
<span v-if="item.fansCount">粉丝·{{item.fansCount}}</span>
</p>
</div>
<div class="option-btn" :class="{'follow': item.isAttention}">
<WidgetFollow class="click-wrap" :author-uid="item.userId" :author-type="item.userType" :follow="item.isAttention" @on-follow="follow => onFollow(follow, index)"></WidgetFollow>
{{item.isAttention ? '已关注' : followName}}
<div class="option-btn" :class="{'follow': item.isAttention === 'Y', 'rm-padding': item.isAttention === 'O'}">
<WidgetFollow class="click-wrap" :author-uid="item.userId" :author-type="item.userType"
:follow="item.isAttention" @on-follow="follow => onFollow(follow, index)"></WidgetFollow>
<template v-if="item.isAttention === 'Y'">
{{'已关注'}}
</template>
<template v-else-if="item.isAttention === 'N'">
{{'关注'}}
</template>
<template v-else-if="item.isAttention === 'O'">
<div class="each-follow"></div>
</template>
</div>
</div>
</slot>
... ... @@ -36,8 +46,8 @@
</template>
<script>
import {get} from 'lodash';
import {Scroll, Loading} from 'cube-ui';
import { get } from 'lodash';
import { Scroll, Loading } from 'cube-ui';
export default {
props: {
... ... @@ -48,7 +58,8 @@ export default {
onFetch: {
type: Function,
required: true
}
},
type: String
},
data() {
return {
... ... @@ -100,7 +111,7 @@ export default {
}
list.forEach(val => {
val.isAttention = val.hasAttention === 'Y';
val.isAttention = val.hasAttention;
});
this.list = this.list.concat(list);
... ... @@ -118,7 +129,17 @@ export default {
});
},
onFollow(follow, index) {
this.list[index].isAttention = follow;
if (this.type === 'fans') {
// 粉丝是已关注的列表,你关注他,就变成互相关注
if (follow === 'Y') {
this.list[index].isAttention = 'O';
} else {
this.list[index].isAttention = follow;
}
} else {
this.list[index].isAttention = follow;
}
},
toUserPage(item) {
this.$router.push({
... ... @@ -178,6 +199,11 @@ export default {
border-color: #b0b0b0;
}
&.rm-padding {
padding: 0;
border: none;
}
.click-wrap {
width: 140%;
height: 180%;
... ... @@ -189,6 +215,13 @@ export default {
font-size: 0;
opacity: 0;
}
.each-follow {
width: 110px;
height: 50px;
background-image: url("~statics/image/userpage/follow.png");
background-size: cover;
}
}
}
... ...
... ... @@ -276,33 +276,33 @@ export default {
commit(Types.GUANG_CHANGE_PRODUCT_FAV, favsList);
},
async reportArticle(actions, {articleId}) {
const result = await this.$api.post('/api/grass/reportIllegalArticle', {articleId});
async reportArticle(actions, { articleId }) {
const result = await this.$api.post('/api/grass/reportIllegalArticle', { articleId });
return result;
},
async deleteArticle(actions, {articleId}) {
const result = await this.$api.post('/api/grass/deleteGrassArticle', {articleId});
async deleteArticle(actions, { articleId }) {
const result = await this.$api.post('/api/grass/deleteGrassArticle', { articleId });
return result;
},
async fetchTopicSimpleInfo({ commit, state }, {topicId, thumb}) {
async fetchTopicSimpleInfo({ commit, state }, { topicId, thumb }) {
if (state.fetchTopicInfo) {
return Promise.resolve({});
}
commit(Types.FETCH_TOPIC_INFO_REQUEST);
const result = await this.$api.post('/api/grass/getGrassTopicSimpleInfo', {topicId});
const result = await this.$api.post('/api/grass/getGrassTopicSimpleInfo', { topicId });
if (result.code === 200) {
commit(Types.FETCH_TOPIC_INFO_SUCCESS, {topicId, data: result.data, thumb});
commit(Types.FETCH_TOPIC_INFO_SUCCESS, { topicId, data: result.data, thumb });
} else {
commit(Types.FETCH_TOPIC_INFO_FAILD, {});
}
return result;
},
async fetchTopicRelatedArticles({ commit, state }, {topicId, page, type}) {
async fetchTopicRelatedArticles({ commit, state }, { topicId, page, type }) {
commit(Types.FETCH_ARTICLE_TOPIC_REQUEST, { page });
const result = await this.$api.post('/api/grass/topicRelatedArticles', {
topicId,
... ... @@ -342,7 +342,7 @@ export default {
return result;
},
async fetchFindNiceGoodsArticles({ commit, state }, { page, limit, thumb}) {
async fetchFindNiceGoodsArticles({ commit, state }, { page, limit, thumb }) {
commit(Types.FETCH_NICE_GOODS_REQUEST, { page });
const result = await this.$api.post('/api/grass/findGoodsList', {
page,
... ... @@ -365,7 +365,7 @@ export default {
return result;
},
async fetchTopicList({ commit, state }, {page, limit}) {
async fetchTopicList({ commit, state }, { page, limit }) {
if (state.fetchTopicList) {
return {};
}
... ... @@ -391,5 +391,17 @@ export default {
}
return result;
}
},
async fetchProductBySknList(ctx, { productSknList }) {
const productSkn = productSknList.join(',');
const result = await this.$api.post('/api/grass/product', {
productSkn
});
return get(result, 'data.product_list', []);
},
};
... ...
... ... @@ -212,6 +212,14 @@ export default {
updateArticleState(state, article);
}
},
[Types.SUB_ARTICLE_COMMENT_COUNT](state, {articleId, subCount}) {
let article = state.articleStates[articleId];
if (article) {
article.commentCount = subCount ? (article.commentCount - subCount) : (articleId.commentCount - 1);
updateArticleState(state, article);
}
},
[Types.ASYNC_ARTICLE_COMMENT](state, {articleId, type}) {
state[articlefield(type)].forEach(article => {
if (article.articleId === articleId) {
... ...
... ... @@ -26,6 +26,7 @@ export const CHANGE_ARTICLE_LIST_SLIDE = 'CHANGE_ARTICLE_LIST_SLIDE';
export const UPDATE_ARTICLE_STATE = 'UPDATE_ARTICLE_STATE';
export const UPDATE_ARTICLE_COMMENT_COUNT = 'UPDATE_ARTICLE_COMMENT_COUNT';
export const SUB_ARTICLE_COMMENT_COUNT = 'SUB_ARTICLE_COMMENT_COUNT';
export const ASYNC_ARTICLE_COMMENT = 'ASYNC_ARTICLE_COMMENT';
export const CHANGE_ARTICLE_LIST_INTRO = 'CHANGE_ARTICLE_LIST_INTRO';
export const CHANGE_ARTICLE_LIST_INTRO_HEIGHT = 'CHANGE_ARTICLE_LIST_INTRO_HEIGHT';
... ...
... ... @@ -69,5 +69,17 @@ export default {
});
return result;
},
async setCommentStatus(ctx, {type, commentId}) {
if (type === 1) {
return this.$api.post('/api/grass/deleteComment', {
commentId
});
} else if (type === 2) {
return this.$api.post('/api/grass/reportComment', {
commentId
});
}
}
};
... ...
import {get, first} from 'lodash';
import { get, first } from 'lodash';
const DEFAULT_SHARE_IMAGE = 'http://static.yohobuy.com/m/v1/img/touch/apple-touch-icon-144x144-precomposed-new.png';
function _version2num(version) {
if (!version) {
return 0;
}
let [m, j, b] = version.split(',');
return +m * 10000 + +j * 100 + +b;
}
function versionCompare(left, right) {
let leftNum = _version2num(left);
let rightNum = _version2num(right);
if (leftNum === rightNum) {
return 0;
} else if (leftNum > rightNum) {
return 1;
} else {
return -1;
}
}
const DEFAULT_SHARE_IMAGE =
'http://static.yohobuy.com/m/v1/img/touch/apple-touch-icon-144x144-precomposed-new.png';
function handleProtocol(url) {
if (url.indexOf('//') < 0 || url.indexOf('http') >= 0) {
... ... @@ -13,7 +37,7 @@ function handleProtocol(url) {
return url.join('//');
}
const getDetailShareData = (article) => {
const getDetailShareData = (article, app_version = '6.9.11') => {
let shareImage = '';
let desc = '';
... ... @@ -27,45 +51,76 @@ const getDetailShareData = (article) => {
} else {
let blockList = get(article, 'blockList', []);
shareImage = get(first(blockList.filter(block => block.templateKey === 'image')), 'contentData', '');
desc = get(blockList.filter(block => block.templateKey === 'text'), '[0].contentData', '');
shareImage = get(
first(blockList.filter(block => block.templateKey === 'image')),
'contentData',
'',
);
desc = get(
blockList.filter(block => block.templateKey === 'text'),
'[0].contentData',
'',
);
}
if (shareImage && shareImage.indexOf('//') >= 0) {
shareImage = `${window ? window.location.protocol : ''}//${shareImage.split('//')[1]}`;
shareImage = `${window ? window.location.protocol : ''}//${
shareImage.split('//')[1]
}`;
}
const requiredVersion = '6.9.11';
// let hideType = ['7', '8', '9'];
let hideType = ['8', '9'];
// if (versionCompare(app_version, requiredVersion) >= 0) {
// hideType = ['8', '9'];
// }
return {
title: `@${article.authorName} 在有货社区上发了一篇内容,快点开看看!`,
imgUrl: handleProtocol(get(shareImage.split('?'), '[0]') || DEFAULT_SHARE_IMAGE),
link: handleProtocol(`${window ? window.location.origin : ''}/grass/article/${article.articleId}?share=true`),
imgUrl: handleProtocol(
get(shareImage.split('?'), '[0]') || DEFAULT_SHARE_IMAGE,
),
link: handleProtocol(
`${window ? window.location.origin : ''}/grass/article/${
article.articleId
}?share=true`,
),
desc,
hideType: ['7', '8', '9']
hideType,
shareType: 'grassDetail',
userName: article.authorName,
userIcon: article.authorHeadIco,
articleId: article.articleId,
};
};
const getTopicShareData = (topic) => {
const getTopicShareData = topic => {
return {
title: topic.topicName,
imgUrl: handleProtocol(topic.topicImageUrl),
link: handleProtocol(`${location.origin}/grass/topic/${topic.topicId}?share=true`),
link: handleProtocol(
`${location.origin}/grass/topic/${topic.topicId}?share=true`,
),
desc: '我在有货的社区发现一个热门话题。' + topic.topicDesc,
hideType: ['7', '8', '9']
hideType: ['7', '8', '9'],
};
};
const getAuthorShareData = (author) => {
const getAuthorShareData = author => {
return {
title: `@${author.nickName} YO!社区,一起来玩潮流!`,
imgUrl: handleProtocol(get(author, 'headIco', '').split('?')[0] || DEFAULT_SHARE_IMAGE),
link: handleProtocol(`${location.origin}/grass/author/${author.authorType}/${author.authorUid}?share=true`),
imgUrl: handleProtocol(
get(author, 'headIco', '').split('?')[0] || DEFAULT_SHARE_IMAGE,
),
link: handleProtocol(
`${location.origin}/grass/author/${author.authorType}/${author.authorUid}?share=true`,
),
desc: author.signature || '',
hideType: ['7', '8', '9']
hideType: ['7', '8', '9'],
};
};
export {
getDetailShareData,
getTopicShareData,
getAuthorShareData
};
export { getDetailShareData, getTopicShareData, getAuthorShareData };
... ...
... ... @@ -275,5 +275,24 @@ module.exports = {
params: {
articleId: {type: Number}
}
},
'/api/grass/product': {
api: 'h5.product.batch',
params: {
productSkn: {type: String}
}
},
'/api/grass/reportComment': {
api: 'app.grass.reportIllegalArticle',
params: {
commentId: {type: Number}
}
},
'/api/grass/deleteComment': {
api: 'app.grass.delArticleComment',
auth: true,
params: {
commentId: {type: Number}
}
}
};
... ...
... ... @@ -67,7 +67,8 @@ const getContext = (req) => {
isWeibo: req.yoho.isWeibo,
isYohoBuy: req.yoho.isYohoApp,
isChat: req.yoho.isChat,
clientIp: req.yoho.clientIp,
isMiniApp: req.yoho.isMiniApp,
clientIp: req.yoho.clientIp
},
ua: req.get('user-agent'),
hostname: os.hostname(),
... ...
... ... @@ -14,6 +14,7 @@
<script type="text/javascript">
(function(d,c){var e=d.documentElement,a="orientationchange" in window?"orientationchange":"resize",b=function(){var f=e.clientWidth;if(!f){return}if(f>=750){e.style.fontSize="40px"}else{e.style.fontSize=40*(f/750)+"px"}};if(!d.addEventListener){return}b();c.addEventListener(a,b,false);d.addEventListener("DOMContentLoaded",b,false)})(document,window);
</script>
<script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.3.2.js"></script>
<link rel="dns-prefetch" href="//cdn.yoho.cn">
<link rel="dns-prefetch" href="imgsocial.yohobuy.com">
<link rel="dns-prefetch" href="flv01.static.yhbimg.com">
... ...