wangfukang 2 weeks ago
parent
commit
b7ebe29f91
  1. 6
      package2/IdleTrad/chat.vue
  2. 24
      package2/IdleTrad/detail.vue
  3. 4
      package2/IdleTrad/sessionList.vue
  4. 6
      package2/IdleTrad/wantList.vue
  5. 114
      package2/group/groupBuyList.vue
  6. 66
      package2/group/groupBuySingle.vue
  7. 876
      package2/group/groupPendingList.vue
  8. 88
      package2/group/studentStoreList.vue
  9. 52
      package2/login/login.vue
  10. 68
      package2/myCenter/campusPartner.vue
  11. 8
      package2/myCenter/couponList.vue
  12. 4
      package2/myCenter/myPost.vue
  13. 30
      package2/myCenter/partTimeJobRegister.vue
  14. 2
      package2/myCenter/wallet.vue

6
package2/IdleTrad/chat.vue

@ -4,7 +4,7 @@
<view class="back" @tap="back"><uni-icons type="left" size="24" color="#15362f"></uni-icons></view>
<view class="nav-main">
<view class="nav-title">{{peerName}}</view>
<view class="nav-sub">校园二手咨询 · 独立聊天</view>
<view class="nav-sub">二手咨询 · 独立聊天</view>
</view>
</view>
@ -109,8 +109,8 @@
return this.isWant ? (this.goods.expectedPrice || 0) : (this.goods.price || 0)
},
peerName() {
if (!this.goods) return '校园同学'
return this.goods.userName || (this.isWant ? '求购同学' : '卖家同学')
if (!this.goods) return '区域好友'
return this.goods.userName || (this.isWant ? '求购' : '卖家')
},
peerAvatar() {
return this.defaultAvatar

24
package2/IdleTrad/detail.vue

@ -39,7 +39,7 @@
<view class="meta">
<text>{{goods.createTime || ''}}</text>
<text>{{goods.browseCount || 0}}浏览</text>
<text>{{goods.regionName || '本'}}</text>
<text>{{goods.regionName || '本区域'}}</text>
</view>
<view class="tag-list" v-if="tagList.length || isWant">
<text v-if="isWant">求购</text>
@ -82,13 +82,13 @@
<image :src="item.userAvatar || defaultAvatar" mode="aspectFill"></image>
<view class="comment-main">
<view class="comment-name">
{{item.userName || '校园同学'}}
{{item.userName || '区域好友'}}
<text v-if="item.sellerReply">卖家</text>
</view>
<view class="comment-content">{{item.content}}</view>
<view class="reply-list" v-if="item.replies && item.replies.length">
<view class="reply-item" v-for="reply in item.replies" :key="reply.id">
<text class="reply-name">{{reply.userName || '校园同学'}}</text>
<text class="reply-name">{{reply.userName || '区域好友'}}</text>
<text class="seller-badge" v-if="reply.sellerReply">卖家</text>
<text class="reply-target" v-if="reply.replyToUserName"> 回复 {{reply.replyToUserName}}</text>
<text>{{reply.content}}</text>
@ -115,7 +115,7 @@
<view class="comment-popup">
<view class="comment-popup-title">{{replyTarget.id ? '回复评论' : '发表评论'}}</view>
<view class="comment-popup-desc" v-if="replyTarget.id">
回复 {{replyTarget.userName || '校园同学'}}
回复 {{replyTarget.userName || '区域好友'}}
<text @tap="cancelReply">取消回复</text>
</view>
<view class="comment-popup-desc" v-else>友善交流评论内容会进行审核</view>
@ -257,7 +257,7 @@
return this.imageHeights[this.currentImageIndex] || 560
},
commentPlaceholder() {
return this.replyTarget && this.replyTarget.id ? '回复 ' + (this.replyTarget.userName || '校园同学') : '写下你的评论'
return this.replyTarget && this.replyTarget.id ? '回复 ' + (this.replyTarget.userName || '区域好友') : '写下你的评论'
},
favoriteCountText() {
return this.goods && this.goods.favoriteCount ? this.goods.favoriteCount : 0
@ -339,7 +339,7 @@
profile: profile || {},
actionText,
authDialog: {
badge: '校园二手',
badge: '二手',
title: '实名认证',
content: '根据法律法规要求,对应流程需要调用阿里云实名认证。半径里不会存储您的实名信息。',
steps: []
@ -350,20 +350,20 @@
},
async focusComment() {
if (this.isWant) return
const verified = await this.ensureVerified('在校园二手评论')
const verified = await this.ensureVerified('在二手评论')
if (!verified) return
this.replyTarget = {}
this.openCommentPopup()
},
async replyComment(parent, target) {
if (this.isWant) return
const verified = await this.ensureVerified('回复校园二手评论')
const verified = await this.ensureVerified('回复二手评论')
if (!verified) return
this.replyTarget = {
id: target.id,
parentId: parent.parentId || parent.id,
userId: target.userId,
userName: target.userName || '校园同学'
userName: target.userName || '区域好友'
}
this.openCommentPopup()
},
@ -499,7 +499,7 @@
},
async consult() {
if (!this.goods) return
const verified = await this.ensureVerified(this.isWant ? '响应校园二手求购' : '咨询校园二手商品')
const verified = await this.ensureVerified(this.isWant ? '响应二手求购' : '咨询二手商品')
if (!verified) return
if (this.isWant) {
createFishWantChatSession(this.id).then(session => {
@ -530,8 +530,8 @@
// #endif
},
buildShareInfo() {
const title = this.goods && this.goods.title ? this.goods.title : (this.isWant ? '校园二手求购' : '校园二手商品')
const prefix = this.isWant ? '同学正在求购:' : '校园二手好物:'
const title = this.goods && this.goods.title ? this.goods.title : (this.isWant ? '二手求购' : '二手商品')
const prefix = this.isWant ? '同学正在求购:' : '二手好物:'
const typeQuery = this.isWant ? '&type=want' : ''
const targetPath = `/package2/IdleTrad/detail?id=${this.id || ''}${typeQuery}`
return {

4
package2/IdleTrad/sessionList.vue

@ -24,7 +24,7 @@
<image class="cover" :src="item.goodsCover || defaultCover" mode="aspectFill"></image>
<view class="main">
<view class="top-row">
<view class="goods-title">{{item.goodsTitle || '校园二手商品'}}</view>
<view class="goods-title">{{item.goodsTitle || '区域二手商品'}}</view>
<view class="role-tag" :class="{ seller: item.role == 'seller' }">{{item.roleText}}</view>
<view class="card-badge" v-if="item.unreadCount > 0">{{formatBadgeCount(item.unreadCount)}}</view>
</view>
@ -202,7 +202,7 @@
goodsCover: comment.displayCover || '',
goodsPrice: comment.displayPrice !== undefined && comment.displayPrice !== null ? comment.displayPrice : '',
displayTime: this.formatDisplayTime(comment.createTime),
desc: (comment.replyToUserName ? (comment.userName || '校园同学') + ' 回复 ' + comment.replyToUserName + ':' : '') + (comment.content || '')
desc: (comment.replyToUserName ? (comment.userName || '区域同学') + ' 回复 ' + comment.replyToUserName + ':' : '') + (comment.content || '')
}
})
},

6
package2/IdleTrad/wantList.vue

@ -5,7 +5,7 @@
<view class="back" @tap="back"><uni-icons type="left" size="22" color="#15362f"></uni-icons></view>
<view class="title-wrap">
<view class="title">求购广场</view>
<view class="subtitle">看看同学们正在找什么</view>
<view class="subtitle">看看大家正在找什么</view>
</view>
</view>
<view class="search-bar">
@ -209,7 +209,7 @@
},
normalizeRecords(records) {
const area = this.getArea()
const fallbackRegionName = area.title || area.name || uni.getStorageSync('schoolName') || '本'
const fallbackRegionName = area.title || area.name || uni.getStorageSync('schoolName') || '本区域'
return (Array.isArray(records) ? records : []).map(item => {
const images = this.parseJsonList(item.images)
const imageList = item.imageList && item.imageList.length ? item.imageList : images
@ -220,7 +220,7 @@
text: item.title || '',
price: item.expectedPrice || 0,
icon: item.userAvatar || this.defaultCover,
shopName: item.userName || '校园同学',
shopName: item.userName || '区域好友',
regionName: item.regionName || item.schoolName || item.areaName || fallbackRegionName,
category: item.categoryName || '',
browseCount: item.browseCount || 0

114
package2/group/groupBuyList.vue

@ -9,7 +9,7 @@
</view>
<view class="title-name" :style="{'padding-top': menuButtonInfo.top +'px'}">
饭团
<text>宿舍拼饭局</text>
<text>{{pageSubtitle}}</text>
</view>
<view class="title-search" :style="{'margin-top': menuButtonInfo.top +'px'}">
<uni-icons type="search" size="16" color="#08735d"></uni-icons>
@ -36,7 +36,7 @@
<!-- <view class="banner-desc">楼下热乎的那口凑个饭搭子就出发</view> -->
<view class="banner-bubbles">
<swiper class="banner-live-swiper" vertical circular autoplay :interval="2600" :duration="1500">
<swiper-item v-for="(item,index) in liveFeeds" :key="index">
<swiper-item v-for="(item,index) in displayLiveFeeds" :key="index">
<view class="banner-live-bubble">
<view class="live-avatar">{{item.avatar}}</view>
<view class="live-copy">
@ -56,11 +56,11 @@
</view>
<view class="interest-card" :class="{'interest-card-expanded': categoryExpanded}">
<view class="section-head">
<text>校园美食兴趣入口</text>
<text>{{interestSectionTitle}}</text>
<text @tap.stop="toggleCategory">{{categoryExpanded ? '收起' : '展开更多'}}</text>
</view>
<view class="menu-box">
<view class="menu-list" v-for="(item,index) in menuBtn" :key="index" @tap="goDetail('search',item)">
<view class="menu-list" v-for="(item,index) in displayMenuBtn" :key="index" @tap="goDetail('search',item)">
<view class="menu-icon-wrap">
<img :src="item.url" alt="" />
<text class="menu-sticker">{{item.sticker}}</text>
@ -69,7 +69,7 @@
</view>
</view>
<view class="menu-box menu-box-second" v-if="categoryExpanded">
<view class="menu-list" v-for="(item,index) in menuBtn1" :key="index" @tap="goDetail('search',item)">
<view class="menu-list" v-for="(item,index) in displayMenuBtn1" :key="index" @tap="goDetail('search',item)">
<view class="menu-icon-wrap">
<img :src="item.url" alt="" />
<text class="menu-sticker">{{item.sticker}}</text>
@ -91,12 +91,12 @@
</view>
<view class="sort-member">
<view class="sort-text" @tap="searchShop('score','')">
同学最爱 <text style="font-size: 20rpx;"></text>
{{scoreSortLabel}} <text style="font-size: 20rpx;"></text>
</view>
</view>
<view class="sort-member" style="position: relative;">
<view class="sort-text" @tap="checkArea">
宿舍附近 <text style="font-size: 20rpx;"></text>
{{areaSortLabel}} <text style="font-size: 20rpx;"></text>
</view>
<view class="sort-value" v-if="isArea">
<view class="sort-value1" v-for="(item,index) in shopArea" :key="index"
@ -192,7 +192,7 @@
<swiper class="zaixian-swiper" vertical circular :autoplay="true"
:interval="onlineWorkerInterval" :duration="onlineWorkerDuration">
<swiper-item v-if="onlineWorkerAreaList.length === 0">
<view class="zaixian-item">宿舍群正在等一个饭搭子</view>
<view class="zaixian-item">{{emptyOnlineText}}</view>
</swiper-item>
<swiper-item v-for="(item,index) in onlineWorkerAreaList" :key="index">
<view class="zaixian-item">{{formatOnlineWorkerText(item)}}</view>
@ -245,6 +245,7 @@
orderSale: ''
},
shopList: [],
areaKind: 1,
searchHotWords: ['🍜 今晚吃啥', '🥤 奶茶续命拼团', '🔥 还差1人', '🍱 宿舍套餐热拼'],
liveSlogans: ['谁在偷吃夜宵', '差个饭搭子', '隔壁宿舍已开拼'],
liveFeeds: [{
@ -268,6 +269,27 @@
dorm: '回寝路上',
food: '今晚适合来点汤汤水水'
}],
socialLiveFeeds: [{
avatar: '🍜',
name: '晚八点定律',
dorm: '小区门口',
food: '麻辣烫一出现就想下楼'
}, {
avatar: '🥤',
name: '奶茶续命',
dorm: '街角便利店',
food: '下班前先喝一口甜的'
}, {
avatar: '🍢',
name: '宵夜雷达',
dorm: '公园边',
food: '风一吹就闻到烧烤味'
}, {
avatar: '🥟',
name: '热乎党',
dorm: '回家路上',
food: '今晚适合来点汤汤水水'
}],
groupAvatars: ['🍜', '🥤', '🍢', '🍔', '🥟', '🍗'],
menuBtn: [{
name: '美食',
@ -351,6 +373,52 @@
},
components: {
},
computed: {
isSocialArea() {
return Number(this.areaKind) === 2
},
pageSubtitle() {
return this.isSocialArea ? '好友拼饭局' : '宿舍拼饭局'
},
interestSectionTitle() {
return this.isSocialArea ? '周边美食兴趣入口' : '校园美食兴趣入口'
},
scoreSortLabel() {
return this.isSocialArea ? '好友最爱' : '同学最爱'
},
areaSortLabel() {
return this.isSocialArea ? '附近区域' : '宿舍附近'
},
emptyOnlineText() {
return this.isSocialArea ? '好友群正在等一个饭搭子' : '宿舍群正在等一个饭搭子'
},
displayLiveFeeds() {
return this.isSocialArea ? this.socialLiveFeeds : this.liveFeeds
},
displayMenuBtn() {
if (!this.isSocialArea) return this.menuBtn
return this.menuBtn.map((item) => {
const next = Object.assign({}, item)
if (item.name === '超市便利') {
next.displayName = '家里囤货'
} else if (item.name === '同学小店') {
next.displayName = '好友小店'
next.sticker = '友'
}
return next
})
},
displayMenuBtn1() {
if (!this.isSocialArea) return this.menuBtn1
return this.menuBtn1.map((item) => {
const next = Object.assign({}, item)
if (item.name === '早点') {
next.displayName = '元气早餐'
}
return next
})
}
},
filters: {
sliceMsg(val) {
@ -385,10 +453,12 @@
},
onLoad() {
this.syncAreaKind()
this.enableShareMenu()
this.getShopList();
},
onShow() {
this.syncAreaKind()
this.enableShareMenu()
this.menuButtonInfo = uni.getMenuButtonBoundingClientRect()
this.searchForm.regionId = JSON.parse(uni.getStorageSync('area')).id
@ -409,6 +479,19 @@
}
},
methods: {
syncAreaKind(areaObj) {
let area = areaObj
if (!area) {
try {
const cached = uni.getStorageSync('area')
area = cached ? (typeof cached === 'string' ? JSON.parse(cached) : cached) : null
} catch (e) {
area = null
}
}
const kind = area ? Number(area.areaKind) : 1
this.areaKind = kind === 2 ? 2 : 1
},
enableShareMenu() {
if (!uni.showShareMenu) return
uni.showShareMenu({
@ -418,7 +501,9 @@
},
buildShareInfo() {
return {
title: '饭团宿舍拼饭局,约同学一起省钱吃',
title: this.isSocialArea
? '饭团好友拼饭局,约好友一起省钱吃'
: '饭团宿舍拼饭局,约同学一起省钱吃',
path: buildHomeSharePath(SHARE_TARGET_PATH),
imageUrl: 'https://jewel-shop.oss-cn-beijing.aliyuncs.com/f7227759d693497a8beab87ff437a875.png'
}
@ -629,7 +714,9 @@
const selfDeliveryTime = Number(item.shopDeliveryDuration)
const transferTimeValue = Number(item.transferDeliveryDuration)
const transferTime = item.supportTransferDelivery == 1 && !isNaN(transferTimeValue) && transferTimeValue > 0 ? transferTimeValue : 0
item._groupTip = ['还差1人就成团', '刚下课,大家都在拼', '这口热乎的很适合夜宵', '附近同学想一起点'][index % 4]
item._groupTip = this.isSocialArea
? ['还差1人就成团', '刚下班,大家都在拼', '这口热乎的很适合夜宵', '附近好友想一起点'][index % 4]
: ['还差1人就成团', '刚下课,大家都在拼', '这口热乎的很适合夜宵', '附近同学想一起点'][index % 4]
let baseDeliveryTime
if (item.supportShopDelivery == 1 && !isNaN(selfDeliveryTime) && selfDeliveryTime > 0) {
baseDeliveryTime = cookingTime + selfDeliveryTime
@ -690,7 +777,9 @@
formatSelfDeliveryTag(item) {
const fee = parseFloat(item.orderBkge || 0)
const feeText = fee > 0 ? `¥${fee.toFixed(1)}` : '免配送费'
const locationText = item.shopDeliveryLocation == 1 ? '送宿舍' : '送楼下'
const locationText = item.shopDeliveryLocation == 1
? (this.isSocialArea ? '送上门' : '送宿舍')
: (this.isSocialArea ? '送门口' : '送楼下')
return `商家自配送 · ${feeText} · ${locationText}`
},
shouldShowBaseDeliveryFee(item) {
@ -698,7 +787,8 @@
return !!(item && item.supportShopDelivery != 1 && !isNaN(fee) && fee > 0)
},
formatOnlineWorkerText(item) {
return `${item.areaName} 附近 ${item.onlineWorkerCount} 位同学在线接单`
const people = this.isSocialArea ? '位骑手' : '位同学'
return `${item.areaName} 附近 ${item.onlineWorkerCount} ${people}在线接单`
},
formatAmountText(value) {
const amount = parseFloat(value)

66
package2/group/groupBuySingle.vue

@ -40,7 +40,7 @@
{{shopItem.shopName}}
</view>
<view class="shop-subtitle">
{{isStoreGroupOrder ? '到店核销,约上同学一起拼更划算' : '约上室友同学一起拼,越快成团越快开吃'}}
{{shopSubtitle}}
</view>
<view class="shop-status-row">
<text :class="{'shop-status-disabled': !hasOpenKitchenVideo(shopItem)}" @tap.stop="goDetail('openKitchen')">
@ -92,7 +92,7 @@
<view class="live-card-header">
<view class="live-title-wrap">
<image class="live-title-gif" src="https://jewel-shop.oss-cn-beijing.aliyuncs.com/f7227759d693497a8beab87ff437a875.png" mode="aspectFit"></image>
<view class="live-title">你知道吗拼团和期末不挂科一样重要</view>
<view class="live-title">{{liveSlogan}}</view>
</view>
<view class="live-pill" v-if="orderListWait.length > 0">去凑团</view>
</view>
@ -372,7 +372,7 @@
<uni-icons type="close" size="30" color="#fff"></uni-icons>
</view>
<view class="popup-rally-title" v-if="isPintuan">
<view class="popup-rally-main">{{isStoreGroupOrder ? '到店团购搭子哪里找-同校同学一起省!' : '拼团搭子哪里找-隔壁宿舍全是宝!'}}
<view class="popup-rally-main">{{popupRallyMain}}
</view>
</view>
<view class="goods-top popup-product-card">
@ -907,16 +907,53 @@
popupPageStyle: '',
bottomPopupOpenCount: 0,
autoWaitRuleKnown: false,
hasAutoOpenedWaitPopup: false
hasAutoOpenedWaitPopup: false,
areaKind: 1
}
},
components: {
},
computed: {
isSocialArea() {
return Number(this.areaKind) === 2
},
isStoreGroupOrder() {
return this.orderScene === 'storeGroup' || this.shopItem.merchantType == 2;
},
shopSubtitle() {
if (this.isStoreGroupOrder) {
return this.isSocialArea
? '到店核销,约上好友一起拼更划算'
: '到店核销,约上同学一起拼更划算'
}
return this.isSocialArea
? '约上好友一起拼,越快成团越快开吃'
: '约上室友同学一起拼,越快成团越快开吃'
},
liveSlogan() {
return this.isSocialArea
? '你知道吗?拼团和柴米油盐一样重要!'
: '你知道吗?拼团和期末不挂科一样重要!'
},
popupRallyMain() {
if (this.isStoreGroupOrder) {
return this.isSocialArea
? '到店团购搭子哪里找-同城好友一起省!'
: '到店团购搭子哪里找-同校同学一起省!'
}
return this.isSocialArea
? '拼团搭子哪里找-同城好友全是宝!'
: '拼团搭子哪里找-隔壁宿舍全是宝!'
},
regionSelectToast() {
return this.isSocialArea ? '请先选择区域' : '请先选择校区'
},
regionMismatchContent() {
return this.isSocialArea
? '当前商家不在本区域范围,请切换区域后下单'
: '当前商家不在本校区范围,请切换校区后下单'
},
cartTotalCount() {
return this.cartItems.reduce((acc, curr) => acc + curr.quantity, 0);
},
@ -984,6 +1021,7 @@
}
},
onLoad(option) {
this.syncAreaKind();
this.initWaitRuleKnown();
this.type = option.type;
this.orderScene = option.orderScene || '';
@ -1031,6 +1069,7 @@
},
onShow() {
if (this.regionMismatchRedirecting) return;
this.syncAreaKind();
this.menuButtonInfo = uni.getMenuButtonBoundingClientRect();
this.fetchCoupons();
// (menuButton)
@ -1113,6 +1152,19 @@
return '';
}
},
syncAreaKind(areaObj) {
let area = areaObj
if (!area) {
try {
const cached = uni.getStorageSync('area')
area = cached ? (typeof cached === 'string' ? JSON.parse(cached) : cached) : null
} catch (e) {
area = null
}
}
const kind = area ? Number(area.areaKind) : 1
this.areaKind = kind === 2 ? 2 : 1
},
normalizeRegionId(value) {
return value === undefined || value === null ? '' : String(value).trim();
},
@ -1128,7 +1180,7 @@
this.clearShareRedirectCache();
uni.showModal({
title: '提示',
content: '当前商家不在本校区范围,请切换校区后下单',
content: this.regionMismatchContent,
showCancel: false,
confirmText: '我知道了',
success: () => {
@ -1221,7 +1273,7 @@
regionId = area ? JSON.parse(area).id : '';
} catch (e) {}
if (!regionId) {
this.tui.toast('请先选择校区');
this.tui.toast(this.regionSelectToast);
return;
}
this.tui.request("/app/shop/getShopInfoById", "POST", {
@ -1929,7 +1981,7 @@
let packageFee = parseFloat(this.currentItem.lunchBox || 0);
let regionId = this.getCurrentRegionId();
if (!regionId) {
this.tui.toast('请先选择校区');
this.tui.toast(this.regionSelectToast);
return null;
}

876
package2/group/groupPendingList.vue

@ -1,879 +1,25 @@
<template>
<view class="pending-page" :class="{'store-scene': isStoreScene}">
<view class="pending-fixed">
<view class="nav-row">
<view class="back-btn" @tap="back">
<uni-icons type="left" size="28" :color="searchIconColor"></uni-icons>
</view>
<view class="nav-title">加入立即省钱</view>
</view>
<view class="tab-card">
<view class="tab-item" v-for="item in tabs" :key="item.scene"
:class="{'tab-item-active': scene === item.scene}" @tap="switchScene(item.scene)">
<text>{{item.label}}</text>
</view>
</view>
<view class="search-row">
<view class="search-card">
<view class="search-box">
<uni-icons type="search" size="18" :color="searchIconColor"></uni-icons>
<input type="text" v-model="query.keyWord" confirm-type="search" placeholder="搜索商品或商家"
@confirm="searchGroup" />
<view class="search-btn" @tap="searchGroup">搜索</view>
</view>
</view>
<view class="seckill-entry" @tap="goSeckillGroup">
<view class="heat-dot heat-dot-a"></view>
<view class="heat-dot heat-dot-b"></view>
<view class="seckill-entry-light"></view>
<view class="seckill-entry-info">
<view class="seckill-entry-title">秒杀团</view>
</view>
<view class="seckill-entry-btn"></view>
</view>
</view>
</view>
<view class="hero-holder"></view>
<view class="list-wrap">
<view class="empty-card" v-if="groupList.length === 0 && loadStatus !== 'loading'">
<view class="empty-icon"></view>
<view class="empty-title">暂时没有待成团</view>
<view class="empty-sub">换个关键词试试或者稍后再来看看同学们的新团</view>
</view>
<view class="group-card" v-for="(item,index) in groupList" :key="item.id" @tap="joinGroup(item)">
<view class="rank-pill">热拼 {{index + 1}}</view>
<view class="shop-row">
<view class="shop-img">
<image :src="item.uiShopIcon" mode="aspectFill"></image>
<view class="scene-mark">{{isStoreScene ? '团' : '饭'}}</view>
</view>
<view class="shop-info">
<view class="shop-name">{{item.uiShopName}}</view>
<view class="product-name">{{item.uiProductName}}</view>
<view class="tag-row">
<text>{{item.uiShopType}}</text>
<text>{{item.uiTargetMembers}}人成团</text>
<text>还差{{item.uiMissingMembers}}</text>
</view>
</view>
</view>
<view class="product-row">
<image :src="item.uiProductImage" mode="aspectFill"></image>
<view class="product-copy">
<view class="price-row">
<text class="group-label">拼团价</text>
<text class="price">¥{{item.uiGroupPrice}}</text>
</view>
<view class="progress-bar">
<view class="progress-inner" :style="item.uiProgressStyle"></view>
</view>
<view class="progress-copy">{{item.uiCurrentMembers}}人已拼 · 点击参与这一团</view>
</view>
</view>
<view class="card-bottom">
<view class="time-copy">{{item.uiExpireText}}</view>
<view class="join-btn">{{isStoreScene ? '参与到店团' : '参与拼饭局'}}</view>
</view>
</view>
<uni-load-more :status="loadStatus" v-if="groupList.length > 0" />
</view>
</view>
<home-group-pending ref="pendingPanel" :embedded="false" />
</template>
<script>
import { requireLoginToCurrentPage } from '@/utils/authRedirect.js'
import homeGroupPending from '@/components/tab-bar/homeGroupPending.vue'
export default {
data() {
return {
scene: 'takeaway',
tabs: [{
label: '饭团',
scene: 'takeaway'
}, {
label: '团购',
scene: 'storeGroup'
}],
loadStatus: 'more',
navPaddingStyle: '',
totalPages: 1,
query: {
regionId: '',
status: 0,
isFace: 0,
merchantType: 1,
pageNumber: 1,
pageSize: 10,
keyWord: ''
},
groupList: []
}
},
computed: {
isStoreScene() {
return this.scene === 'storeGroup'
},
searchIconColor() {
return this.isStoreScene ? '#f0642f' : '#08735d'
}
components: {
homeGroupPending
},
onLoad(option) {
this.scene = this.normalizeScene(option && option.scene)
this.query.merchantType = this.isStoreScene ? 2 : 1
this.initRegion()
this.$nextTick(() => {
if (this.$refs.pendingPanel && this.$refs.pendingPanel.init) {
this.$refs.pendingPanel.init(option)
}
})
},
onReachBottom() {
if (this.loadStatus === 'loading' || this.query.pageNumber >= this.totalPages) return
this.query.pageNumber += 1
this.getGroupList()
},
methods: {
normalizeScene(scene) {
return scene === 'storeGroup' ? 'storeGroup' : 'takeaway'
},
initRegion() {
const area = uni.getStorageSync('area')
if (!area) {
this.tui.toast('请先选择区域')
return
}
try {
const areaInfo = typeof area === 'string' ? JSON.parse(area) : area
this.query.regionId = areaInfo.id || ''
} catch (e) {
this.query.regionId = ''
}
if (!this.query.regionId) {
this.tui.toast('请先选择区域')
return
}
this.getGroupList()
},
searchGroup() {
this.query.pageNumber = 1
this.totalPages = 1
this.groupList = []
this.getGroupList()
},
switchScene(scene) {
const nextScene = this.normalizeScene(scene)
if (this.scene === nextScene) return
this.scene = nextScene
this.query.merchantType = this.isStoreScene ? 2 : 1
this.query.keyWord = ''
this.query.pageNumber = 1
this.totalPages = 1
this.groupList = []
this.loadStatus = 'more'
this.getGroupList()
},
getGroupList() {
if (!this.query.regionId) return
this.loadStatus = 'loading'
this.tui.request('/mall/admin/orderGroup/page', 'POST', this.query, false, false).then((res) => {
if (res.code == 200) {
const result = res.result || {}
const list = Array.isArray(result.records) ? result.records.map(item => this.formatGroupItem(item)) : []
if (this.query.pageNumber === 1) {
this.groupList = list
} else {
this.groupList = [...this.groupList, ...list]
}
this.totalPages = result.pages || result.totalPages || 1
this.loadStatus = this.query.pageNumber >= this.totalPages ? 'nomore' : 'more'
} else {
this.loadStatus = 'nomore'
this.tui.toast(res.message)
}
}).catch(() => {
this.loadStatus = 'nomore'
})
},
joinGroup(item) {
if (!requireLoginToCurrentPage()) return
const shopItem = item.shopItem || {}
if (!shopItem.id) {
this.tui.toast('商家信息缺失,暂时无法参团')
return
}
const sceneQuery = this.isStoreScene ? '&orderScene=storeGroup' : ''
const shopItemStr = encodeURIComponent(JSON.stringify(shopItem))
uni.navigateTo({
url: '/package2/group/groupBuySingle?type=shop&item=' + shopItemStr +
'&groupId=' + item.id +
'&targetMembers=' + (item.targetMembers || 2) +
'&isFaceToFace=0' + sceneQuery
})
},
goSeckillGroup() {
if (!requireLoginToCurrentPage()) return
uni.navigateTo({
url: '/package3/seckill/seckillGroup'
})
},
getShopIcon(item) {
return (item.shopItem && item.shopItem.shopIcon) || item.productPicture || '/static/images/img/shangpintu.png'
},
formatGroupItem(item) {
return {
...item,
uiShopIcon: this.getShopIcon(item),
uiProductImage: item.productPicture || this.getShopIcon(item),
uiShopName: this.getShopName(item),
uiProductName: item.productName || '同学发起的拼团',
uiShopType: this.getShopType(item),
uiTargetMembers: item.targetMembers || 2,
uiCurrentMembers: item.currentMembers || 0,
uiMissingMembers: this.missingMembers(item),
uiGroupPrice: this.formatPrice(item.groupPrice),
uiExpireText: this.formatExpireText(item),
uiProgressStyle: this.buildProgressStyle(item)
}
},
getShopName(item) {
return (item.shopItem && item.shopItem.shopName) || item.shopName || '未知商家'
},
getShopType(item) {
const shopItem = item.shopItem || {}
return shopItem.shopTypeTitle || (shopItem.shopTakeaway && shopItem.shopTakeaway.type) || (this.isStoreScene ? '团购' : '美食')
},
missingMembers(item) {
const target = Number(item.targetMembers || 2)
const current = Number(item.currentMembers || 0)
return Math.max(target - current, 0)
},
buildProgressStyle(item) {
const target = Number(item.targetMembers || 2)
const current = Number(item.currentMembers || 0)
const percent = target > 0 ? Math.min(100, Math.max(12, Math.round(current / target * 100))) : 12
return 'width: ' + percent + '%;'
},
formatPrice(price) {
const num = Number(price || 0)
return num ? num.toFixed(2) : '--'
},
formatExpireText(item) {
if (!item.expireTime) return '24小时内成团'
const expire = new Date(item.expireTime).getTime()
const diff = expire - Date.now()
if (isNaN(expire) || diff <= 0) return '即将结束'
const hours = Math.floor(diff / 3600000)
const minutes = Math.floor((diff % 3600000) / 60000)
return hours > 0 ? '剩余约' + hours + '小时' + minutes + '分' : '剩余约' + minutes + '分'
},
back() {
uni.navigateBack()
if (this.$refs.pendingPanel && this.$refs.pendingPanel.loadMore) {
this.$refs.pendingPanel.loadMore()
}
}
}
</script>
<style lang="scss" scoped>
.pending-page {
min-height: 100vh;
padding-bottom: 140rpx;
background:
radial-gradient(circle at 12% 8%, rgba(197, 255, 153, 0.5), transparent 34%),
radial-gradient(circle at 90% 18%, rgba(175, 255, 231, 0.48), transparent 36%),
linear-gradient(180deg, #f6ffea 0%, #f7fff9 42%, #fff9ef 100%);
color: #06382f;
box-sizing: border-box;
}
.store-scene {
background:
radial-gradient(circle at 82% 120rpx, rgba(255, 241, 210, 0.86) 0, rgba(255, 241, 210, 0) 260rpx),
radial-gradient(circle at 10% 260rpx, rgba(255, 190, 185, 0.3) 0, rgba(255, 190, 185, 0) 240rpx),
linear-gradient(180deg, #ffd0b8 0%, #ffe6d6 260rpx, #fff7ef 560rpx, #fffaf6 100%);
color: #3f2618;
}
.pending-fixed {
width: 100%;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1000;
padding: 88rpx 26rpx 22rpx;
box-sizing: border-box;
background: rgba(247, 255, 249, 0.94);
box-shadow: 0 12rpx 30rpx rgba(20, 115, 88, 0.08);
backdrop-filter: blur(18rpx);
}
.store-scene .pending-fixed {
background: rgba(255, 249, 243, 0.96);
box-shadow: 0 12rpx 30rpx rgba(178, 102, 48, 0.1);
}
.hero-holder {
width: 100%;
height: 396rpx;
}
.nav-row {
position: relative;
display: flex;
align-items: center;
height: 64rpx;
}
.back-btn {
display: flex;
align-items: center;
justify-content: center;
width: 64rpx;
height: 64rpx;
border-radius: 999rpx;
background: rgba(255, 255, 255, 0.96);
border: 1rpx solid rgba(255, 255, 255, 0.82);
box-shadow: 0 8rpx 18rpx rgba(0, 45, 29, 0.08);
box-sizing: border-box;
flex-shrink: 0;
}
.nav-title {
position: absolute;
left: 50%;
width: 220rpx;
height: 64rpx;
color: #073d33;
font-size: 34rpx;
font-weight: 900;
line-height: 64rpx;
text-align: center;
transform: translateX(-50%);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.store-scene .nav-title {
color: #3f2618;
}
.tab-card {
display: flex;
height: 76rpx;
margin-top: 24rpx;
padding: 8rpx;
border-radius: 999rpx;
background: rgba(255, 255, 255, 0.72);
box-shadow: inset 0 0 0 1rpx rgba(255, 255, 255, 0.82);
box-sizing: border-box;
}
.tab-item {
flex: 1;
height: 60rpx;
border-radius: 999rpx;
color: rgba(7, 61, 51, 0.56);
font-size: 27rpx;
font-weight: 900;
line-height: 60rpx;
text-align: center;
}
.tab-item-active {
background: linear-gradient(90deg, #dcff9c, #baffec);
color: #08735d;
box-shadow: 0 10rpx 24rpx rgba(13, 114, 82, 0.14);
}
.store-scene .tab-item {
color: rgba(84, 43, 22, 0.56);
}
.store-scene .tab-item-active {
background: linear-gradient(135deg, #ff7444 0%, #ffae53 100%);
color: #fff;
box-shadow: 0 10rpx 24rpx rgba(255, 126, 39, 0.2);
}
.search-row {
width: 100%;
margin: 18rpx auto 0;
display: flex;
align-items: center;
}
.search-card {
flex: 1;
min-width: 0;
margin-right: 14rpx;
height: 60rpx;
padding: 0;
border-radius: 999rpx;
background: rgba(255, 255, 255, 0.76);
box-shadow: 0 18rpx 42rpx rgba(20, 115, 88, 0.12);
box-sizing: border-box;
position: relative;
z-index: 3;
}
.store-scene .search-card {
box-shadow: 0 18rpx 42rpx rgba(178, 102, 48, 0.12);
}
.search-box {
height: 60rpx;
padding: 0 12rpx;
border-radius: 999rpx;
background: #fff;
display: flex;
align-items: center;
}
.search-box input {
flex: 1;
min-width: 0;
height: 60rpx;
margin-left: 10rpx;
font-size: 22rpx;
color: #243d36;
}
.search-btn {
width: 74rpx;
height: 38rpx;
border-radius: 999rpx;
background: linear-gradient(90deg, #dcff9c, #baffec);
color: #08735d;
font-size: 20rpx;
font-weight: 900;
line-height: 38rpx;
text-align: center;
}
.store-scene .search-btn {
background: linear-gradient(135deg, #ff7444 0%, #ffae53 100%);
color: #fff;
}
.seckill-entry {
width: 172rpx;
height: 60rpx;
padding: 0 10rpx;
border-radius: 999rpx;
border: 1rpx solid rgba(255, 255, 255, 0.52);
background:
radial-gradient(circle at 18% 4%, rgba(255, 255, 255, 0.55) 0, rgba(255, 255, 255, 0) 76rpx),
linear-gradient(135deg, #ff4b27 0%, #ff8b18 48%, #ffd257 100%);
box-shadow: 0 16rpx 30rpx rgba(255, 91, 39, 0.24), 0 0 40rpx rgba(255, 188, 80, 0.26);
box-sizing: border-box;
display: flex;
align-items: center;
flex-shrink: 0;
position: relative;
overflow: hidden;
}
.seckill-entry:active {
transform: scale(0.96);
}
.seckill-entry-light {
width: 190rpx;
height: 120rpx;
background: linear-gradient(105deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.76) 46%, rgba(255, 255, 255, 0) 100%);
position: absolute;
top: -20rpx;
left: -220rpx;
transform: rotate(12deg);
animation: seckillEntrySweep 4.8s ease-in-out infinite;
}
.seckill-entry-info {
flex: 1;
min-width: 0;
padding-left: 14rpx;
position: relative;
z-index: 1;
color: #fff;
}
.seckill-entry-title {
font-size: 26rpx;
font-weight: 900;
line-height: 60rpx;
letter-spacing: 1rpx;
text-shadow: 0 3rpx 8rpx rgba(183, 35, 0, 0.24);
}
.seckill-entry-btn {
width: 42rpx;
height: 42rpx;
border-radius: 50%;
background: #fff;
color: #ff3d18;
font-size: 24rpx;
font-weight: 900;
line-height: 42rpx;
text-align: center;
position: relative;
z-index: 1;
box-shadow: 0 8rpx 18rpx rgba(158, 32, 0, 0.22);
animation: seckillBtnBeat 2.8s ease-in-out infinite;
}
.heat-dot {
width: 12rpx;
height: 12rpx;
position: absolute;
border-radius: 50%;
background: rgba(255, 255, 255, 0.92);
box-shadow: 0 0 16rpx rgba(255, 255, 255, 0.88);
z-index: 1;
animation: heatParticle 3.2s ease-in-out infinite;
}
.heat-dot-a {
left: 28rpx;
top: 18rpx;
}
.heat-dot-b {
right: 64rpx;
bottom: 16rpx;
animation-delay: 0.5s;
}
.list-wrap {
width: 94%;
margin: 0 auto;
position: relative;
z-index: 1;
}
.empty-card,
.group-card {
border-radius: 34rpx;
background: rgba(255, 255, 255, 0.86);
box-shadow: 0 18rpx 44rpx rgba(19, 91, 70, 0.12);
border: 1rpx solid rgba(255, 255, 255, 0.86);
box-sizing: border-box;
}
.store-scene .empty-card,
.store-scene .group-card {
box-shadow: 0 16rpx 34rpx rgba(178, 102, 48, 0.12);
border-color: rgba(255, 221, 188, 0.72);
}
.empty-card {
min-height: 460rpx;
padding-top: 110rpx;
text-align: center;
}
.empty-icon {
width: 100rpx;
height: 100rpx;
margin: 0 auto 22rpx;
border-radius: 34rpx;
background: linear-gradient(135deg, #e8ffb8, #b8ffe9);
color: #08735d;
font-size: 34rpx;
font-weight: 900;
line-height: 100rpx;
}
.store-scene .empty-icon {
background: linear-gradient(135deg, #ff9a72 0%, #ffd38a 100%);
color: #fff;
}
.empty-title {
font-size: 30rpx;
font-weight: 900;
}
.empty-sub {
width: 78%;
margin: 14rpx auto 0;
color: rgba(0, 35, 28, 0.56);
font-size: 24rpx;
line-height: 38rpx;
}
.group-card {
margin-bottom: 22rpx;
padding: 20rpx 18rpx 18rpx;
position: relative;
overflow: hidden;
}
.rank-pill {
position: absolute;
right: 18rpx;
top: 18rpx;
z-index: 2;
padding: 5rpx 13rpx;
border-radius: 999rpx;
background: rgba(219, 255, 157, 0.72);
color: #08735d;
font-size: 18rpx;
font-weight: 900;
}
.store-scene .rank-pill {
background: #fff0dc;
color: #e96632;
}
.shop-row {
display: flex;
}
.shop-img {
width: 168rpx;
height: 168rpx;
flex-shrink: 0;
border-radius: 30rpx;
overflow: hidden;
position: relative;
background: #f4fff3;
box-shadow: 0 14rpx 28rpx rgba(20, 75, 57, 0.14);
}
.shop-img image {
width: 100%;
height: 100%;
}
.scene-mark {
width: 42rpx;
height: 42rpx;
border-radius: 50%;
background: rgba(255, 255, 255, 0.92);
color: #ff5a35;
font-size: 22rpx;
font-weight: 900;
line-height: 42rpx;
text-align: center;
position: absolute;
left: 10rpx;
top: 10rpx;
}
.shop-info {
flex: 1;
min-width: 0;
padding-left: 20rpx;
box-sizing: border-box;
}
.shop-name {
padding-right: 92rpx;
font-size: 33rpx;
line-height: 42rpx;
font-weight: 900;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.product-name {
margin-top: 10rpx;
color: rgba(0, 35, 28, 0.58);
font-size: 24rpx;
line-height: 34rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.store-scene .product-name {
color: #876247;
}
.tag-row {
margin-top: 16rpx;
overflow: hidden;
}
.tag-row text {
display: inline-block;
margin: 0 8rpx 8rpx 0;
padding: 5rpx 10rpx;
border-radius: 12rpx;
background: rgba(184, 255, 225, 0.62);
color: #08735d;
font-size: 20rpx;
font-weight: 900;
}
.store-scene .tag-row text {
background: #fff0dc;
color: #d65f2c;
}
.product-row {
margin-top: 18rpx;
padding: 14rpx;
border-radius: 26rpx;
background: rgba(255, 250, 237, 0.72);
display: flex;
}
.store-scene .product-row {
background: #fff7ee;
}
.product-row image {
width: 110rpx;
height: 110rpx;
border-radius: 22rpx;
background: #fff;
flex-shrink: 0;
}
.product-copy {
flex: 1;
min-width: 0;
padding-left: 16rpx;
box-sizing: border-box;
}
.price-row {
height: 42rpx;
display: flex;
align-items: center;
}
.group-label {
margin-right: 10rpx;
padding: 4rpx 9rpx;
border-radius: 10rpx;
background: #fff0dc;
color: #b4572d;
font-size: 19rpx;
font-weight: 900;
}
.price {
color: #f0441f;
font-size: 30rpx;
font-weight: 900;
}
.progress-bar {
height: 14rpx;
margin-top: 16rpx;
border-radius: 999rpx;
background: rgba(214, 239, 210, 0.8);
overflow: hidden;
}
.progress-inner {
height: 100%;
border-radius: 999rpx;
background: linear-gradient(90deg, #a6ffea 0%, #e3ff96 100%);
}
.store-scene .progress-inner {
background: linear-gradient(90deg, #ff7444 0%, #ffd16e 100%);
}
.progress-copy {
margin-top: 10rpx;
color: rgba(0, 35, 28, 0.52);
font-size: 21rpx;
font-weight: 800;
}
.store-scene .progress-copy {
color: #8f715b;
}
.card-bottom {
height: 58rpx;
margin-top: 16rpx;
padding-top: 12rpx;
border-top: 1rpx solid rgba(20, 90, 70, 0.08);
display: flex;
align-items: center;
}
.time-copy {
flex: 1;
color: rgba(0, 35, 28, 0.58);
font-size: 22rpx;
font-weight: 800;
}
.store-scene .time-copy {
color: #8f715b;
}
.join-btn {
width: 160rpx;
height: 50rpx;
border-radius: 999rpx;
background: linear-gradient(90deg, rgba(227, 255, 150, 1), rgba(166, 255, 234, 1));
color: #08735d;
font-size: 24rpx;
font-weight: 900;
line-height: 50rpx;
text-align: center;
box-shadow: 0 12rpx 24rpx rgba(13, 114, 82, 0.16);
}
.store-scene .join-btn {
background: linear-gradient(135deg, #ff7444 0%, #ff9f38 100%);
color: #fff;
box-shadow: 0 12rpx 24rpx rgba(255, 126, 39, 0.24);
}
@keyframes seckillEntrySweep {
0% {
left: -220rpx;
opacity: 0;
}
38% {
opacity: 0;
}
58% {
opacity: 1;
}
100% {
left: 220rpx;
opacity: 0;
}
}
@keyframes seckillBtnBeat {
0%,
100% {
transform: scale(1);
}
50% {
transform: scale(1.1);
}
}
@keyframes heatParticle {
0%,
100% {
opacity: 0.5;
transform: translateY(0) scale(1);
}
50% {
opacity: 1;
transform: translateY(-6rpx) scale(1.2);
}
}
</style>

88
package2/group/studentStoreList.vue

@ -20,7 +20,7 @@
<view class="hot-word">{{word}}</view>
</swiper-item>
</swiper> -->
<input class="hot-search-input" type="text" placeholder="输入你想拼的校园快乐" v-model="searchForm.keyWord"
<input class="hot-search-input" type="text" :placeholder="searchPlaceholder" v-model="searchForm.keyWord"
confirm-type="search" @confirm="goSearch" />
</view>
<view class="trend-badge" @tap.stop="goSearch">搜索</view>
@ -43,7 +43,7 @@
<view class="pending-entry">
<view class="pending-copy">
<view class="pending-title">查看待成团列表</view>
<view class="pending-sub">看看同校还有哪些拼团差人</view>
<view class="pending-sub">{{pendingSubText}}</view>
</view>
<view class="pending-arrow">去看看</view>
</view>
@ -59,7 +59,7 @@
<view class="interest-scroll">
<view class="interest-list">
<view class="interest-card" :class="['interest-' + (index % 6), {'active': checkedTab === item.key}]"
v-for="(item,index) in tabList" :key="item.key" @tap="switchTab(item)">
v-for="(item,index) in displayTabList" :key="item.key" @tap="switchTab(item)">
<view class="interest-icon">{{item.icon}}</view>
<view class="interest-name">{{item.name}}</view>
<view class="interest-sub">{{item.sub}}</view>
@ -70,14 +70,14 @@
<view class="sort-strip">
<view class="sort-item" :class="{'active': searchSale}" @tap="searchShop('sale','')">拼单最多</view>
<view class="sort-item" :class="{'active': searchScore}" @tap="searchShop('score','')">同学最爱</view>
<view class="sort-item" :class="{'active': searchScore}" @tap="searchShop('score','')">{{scoreSortLabel}}</view>
</view>
<view class="shop-list">
<view class="empty-card" v-if="shopList.length === 0 && loadStatus !== 'loading'">
<view class="empty-icon"></view>
<view class="empty-title">暂时没找到同款快乐</view>
<view class="empty-sub">换个关键词或分类试试新的校园店铺会出现在这里</view>
<view class="empty-sub">{{emptySubText}}</view>
</view>
<view class="shop-card community-shop-card" :class="{'shop-card-disabled': item.status != 1}"
@ -105,7 +105,7 @@
</view>
<view class="shop-content-bottom">
<view class="shop-deal">
<text>{{item.subtitle || '约上同学一起拼'}}</text>
<text>{{item.subtitle || defaultShopSubtitle}}</text>
</view>
<view class="shop-sale">已售{{item.saleCount != null ? item.saleCount : 0}}</view>
</view>
@ -242,6 +242,7 @@
sub: '更多美好'
}],
hotWords: ['🍢 宿舍夜宵拼团', '🎤 KTV四人局还差1人', '💅 周末美甲搭子', '🥩 烤肉套餐同校热拼'],
socialHotWords: ['🍢 夜宵热拼', '🎤 KTV四人局还差1人', '💅 周末美甲搭子', '🥩 烤肉套餐同城热拼'],
quickHotWords: ['夜宵', 'KTV', '美甲', '台球', '烤肉', '资料'],
sceneList: [{
icon: '课',
@ -256,7 +257,46 @@
title: '烤肉套餐',
sub: '拼桌更划算'
}],
shopList: []
shopList: [],
areaKind: 1
}
},
computed: {
isSocialArea() {
return Number(this.areaKind) === 2
},
searchPlaceholder() {
return this.isSocialArea ? '输入你想拼的周边快乐' : '输入你想拼的校园快乐'
},
pendingSubText() {
return this.isSocialArea ? '看看同城好友还有哪些拼团差人' : '看看同校还有哪些拼团差人'
},
scoreSortLabel() {
return this.isSocialArea ? '好友最爱' : '同学最爱'
},
emptySubText() {
return this.isSocialArea
? '换个关键词或分类试试,新的周边店铺会出现在这里'
: '换个关键词或分类试试,新的校园店铺会出现在这里'
},
defaultShopSubtitle() {
return this.isSocialArea ? '约上好友一起拼' : '约上同学一起拼'
},
displayTabList() {
if (!this.isSocialArea) return this.tabList
return this.tabList.map((item) => {
const next = Object.assign({}, item)
if (item.key === 'student') {
next.name = '好友小店'
next.icon = '友'
next.sub = '好友宝藏'
} else if (item.key === 'course') {
next.sub = '技能充电'
} else if (item.key === 'movie') {
next.sub = '周末约影'
}
return next
})
}
},
filters: {
@ -276,10 +316,12 @@
}
},
onLoad() {
this.syncAreaKind()
this.enableShareMenu()
this.initRegion()
},
onShow() {
this.syncAreaKind()
this.enableShareMenu()
this.menuButtonInfo = uni.getMenuButtonBoundingClientRect()
},
@ -309,11 +351,26 @@
},
buildShareInfo() {
return {
title: '团购杂货铺,同校好店一起拼',
title: this.isSocialArea
? '团购杂货铺,同城好友好店一起拼'
: '团购杂货铺,同校好店一起拼',
path: buildHomeSharePath(SHARE_TARGET_PATH),
imageUrl: 'https://jewel-shop.oss-cn-beijing.aliyuncs.com/f7227759d693497a8beab87ff437a875.png'
}
},
syncAreaKind(areaObj) {
let area = areaObj
if (!area) {
try {
const cached = uni.getStorageSync('area')
area = cached ? (typeof cached === 'string' ? JSON.parse(cached) : cached) : null
} catch (e) {
area = null
}
}
const kind = area ? Number(area.areaKind) : 1
this.areaKind = kind === 2 ? 2 : 1
},
backHome() {
uni.switchTab({
url: '/pages/index/index',
@ -323,9 +380,10 @@
})
},
initRegion() {
this.syncAreaKind()
const area = uni.getStorageSync('area')
if (!area) {
this.tui.toast('请先选择区域')
this.tui.toast(this.isSocialArea ? '请先选择区域' : '请先选择校区')
return
}
try {
@ -335,7 +393,7 @@
this.searchForm.regionId = ''
}
if (!this.searchForm.regionId) {
this.tui.toast('请先选择区域')
this.tui.toast(this.isSocialArea ? '请先选择区域' : '请先选择校区')
return
}
if (hasLogin()) {
@ -507,7 +565,7 @@
getShopType(item) {
if (item.shopTypeTitle) return item.shopTypeTitle
if (item.shopTakeaway && item.shopTakeaway.type) return item.shopTakeaway.type
return '校园生活'
return this.isSocialArea ? '同城生活' : '校园生活'
},
formatShopItem(item, index) {
const heatPercent = this.getHeatPercent(item, index)
@ -527,14 +585,18 @@
return count > 0 ? Math.min(99, count + 8 + index * 3) : 18 + index * 5
},
getDormText(index) {
const dorms = ['3号楼正在拼', '东区宿舍刚下单', '图书馆旁热拼', '操场边有人约', '北门寝室在凑']
const dorms = this.isSocialArea
? ['小区门口正在拼', '商场旁刚下单', '公园边热拼', '地铁口有人约', '写字楼旁在凑']
: ['3号楼正在拼', '东区宿舍刚下单', '图书馆旁热拼', '操场边有人约', '北门寝室在凑']
return dorms[index % dorms.length]
},
getMissingCount(index) {
return index % 3 === 0 ? '还差1' : (index % 3 === 1 ? '还差2' : '满3')
},
getLiveText(index) {
const texts = ['刚成团', '同校热拼', '搭子在等', '附近爆款']
const texts = this.isSocialArea
? ['刚成团', '同城热拼', '搭子在等', '附近爆款']
: ['刚成团', '同校热拼', '搭子在等', '附近爆款']
return texts[index % texts.length]
},
getHeatPercent(item, index) {

52
package2/login/login.vue

@ -6,7 +6,7 @@
<view class="float-bubble bubble-a">刚刚有人拼成奶茶</view>
<view class="float-bubble bubble-b">夜宵局启动中</view>
<view class="float-bubble bubble-c">附近同学正在拼饭</view>
<view class="float-bubble bubble-c">{{bubbleCText}}</view>
<view class="hero">
<view class="brand-mark">
@ -14,7 +14,7 @@
<text>半径里</text>
</view>
<view class="brand-title">拼团更省钱半径更精彩</view>
<view class="brand-subtitle">校园万物 · 皆可拼团</view>
<view class="brand-subtitle">{{brandSubtitle}}</view>
</view>
<view class="ip-stage">
@ -30,7 +30,7 @@
</view>
<view class="login-card">
<view class="card-title">进入你的校园半径</view>
<view class="card-title">{{cardTitle}}</view>
<view class="card-desc">美好 · 快乐 · 都在半径里发生</view>
<button
@ -62,7 +62,7 @@
</button>
<view class="login-tip">
{{ needPhoneAuth ? '最后一步,绑定后即可进入主页' : '轻松进入校园生活世界' }}
{{ needPhoneAuth ? '最后一步,绑定后即可进入主页' : loginTipText }}
</view>
<view class="tui-protocol" hover-class="opcity" :hover-stay-time="150">
@ -104,10 +104,35 @@
skipConfirmVisible: false,
customId: '',
saleId: '',
redirectKey: ''
redirectKey: '',
areaKind: 1
}
},
computed: {
isSocialArea() {
return Number(this.areaKind) === 2
},
bubbleCText() {
return this.isSocialArea ? '附近好友正在拼饭' : '附近同学正在拼饭'
},
brandSubtitle() {
return this.isSocialArea ? '同城万物 · 皆可拼团' : '校园万物 · 皆可拼团'
},
cardTitle() {
return this.isSocialArea ? '进入你的同城半径' : '进入你的校园半径'
},
loginTipText() {
return this.isSocialArea ? '轻松进入同城生活世界' : '轻松进入校园生活世界'
},
defaultWechatName() {
return this.isSocialArea ? '半径里好友' : '半径里同学'
},
profileDesc() {
return this.isSocialArea ? '用于完善半径里同城身份' : '用于完善半径里校园身份'
}
},
onLoad(option) {
this.syncAreaKind()
if (option.redirect) {
this.redirectKey = option.redirect
}
@ -122,6 +147,19 @@
}
},
methods: {
syncAreaKind(areaObj) {
let area = areaObj
if (!area) {
try {
const cached = uni.getStorageSync('area')
area = cached ? (typeof cached === 'string' ? JSON.parse(cached) : cached) : null
} catch (e) {
area = null
}
}
const kind = area ? Number(area.areaKind) : 1
this.areaKind = kind === 2 ? 2 : 1
},
wxLogin() {
if (!this.xieyidata) {
this.tui.toast('请阅读并同意用户协议和隐私政策')
@ -139,7 +177,7 @@
that.tui.request('/user/login', 'post', {
jsCode: loginRes.code,
customId: that.customId,
wechatName: profile.nickName || uni.getStorageSync('nickname') || '半径里同学',
wechatName: profile.nickName || uni.getStorageSync('nickname') || that.defaultWechatName,
userType: '2'
}, false, false).then((res) => {
that.loginLoading = false
@ -170,7 +208,7 @@
return new Promise((resolve) => {
if (uni.getUserProfile) {
uni.getUserProfile({
desc: '用于完善半径里校园身份',
desc: this.profileDesc,
success: (res) => resolve(res.userInfo || {}),
fail: () => resolve({})
})

68
package2/myCenter/campusPartner.vue

@ -4,7 +4,7 @@
<view class="back-btn" @tap="back">
<uni-icons type="left" size="23" color="#0C4B3E"></uni-icons>
</view>
<view class="nav-title">校园主理人</view>
<view class="nav-title">区域主理人</view>
</view>
<scroll-view scroll-y class="page-scroll">
@ -22,16 +22,16 @@
<view class="hero-main">
<view class="hero-left">
<view class="hero-kicker">
<text>正在寻找全国高校</text>
<text class="kicker-pill">校园主理人</text>
<text>正在寻找全国</text>
<text class="kicker-pill">区域主理人</text>
</view>
<view class="hero-title">
<view>让你的学校</view>
<view>让你的区域</view>
<view>拥有自己的</view>
<view class="hero-green">生活平台</view>
</view>
<view class="hero-sub">省钱 · 兼职 · 社交 · 闲置</view>
<view class="hero-desc">打造属于一所大学的数字生态</view>
<view class="hero-desc">打造属于本区域的数字生态</view>
<view class="metric-row">
<view class="metric-item" v-for="(item,index) in metrics" :key="index">
<view class="metric-dot"></view>
@ -47,13 +47,13 @@
<view class="app-top">
<view>
<view class="app-name">半径里</view>
<view class="app-small">校园生活平台</view>
<view class="app-small">区域生活平台</view>
</view>
<view class="app-school"></view>
<view class="app-school">区域</view>
</view>
<view class="app-banner">
<view class="app-banner-title">万物皆可拼团</view>
<view class="app-banner-sub">省钱 · 福利 · 校园任务</view>
<view class="app-banner-sub">省钱 · 福利 · 区域任务</view>
</view>
<view class="app-grid">
<view class="app-module" v-for="(item,index) in appModules" :key="index">
@ -78,7 +78,7 @@
<view class="section eco-section">
<view class="section-heading">
<text class="spark"></text>
<text>6校园生态0成本解决学生所有生活需求</text>
<text>6区域生态0成本解决用户所有生活需求</text>
<text class="spark"></text>
</view>
<view class="eco-grid">
@ -101,7 +101,7 @@
<view class="section role-section">
<view class="section-heading">
<text class="spark"></text>
<text>成为校园主理人你将负责</text>
<text>成为区域主理人你将负责</text>
<text class="spark"></text>
</view>
<view class="role-layout">
@ -111,7 +111,7 @@
<view class="leader-copy">
<view>你不是推广员</view>
<view>你是半径里</view>
<view class="leader-green">校园负责人</view>
<view class="leader-green">区域负责人</view>
</view>
</view>
<view class="role-cards">
@ -127,7 +127,7 @@
<view class="double-section">
<view class="half-card">
<view class="half-title">3步开启</view>
<view class="half-sub">你的校园项目</view>
<view class="half-sub">你的区域项目</view>
<view class="step-row">
<view class="step-item" v-for="(item,index) in steps" :key="index">
<view class="step-dot">{{item.no}}</view>
@ -153,14 +153,14 @@
<view class="final-mask"></view>
<view class="final-left">
<view class="final-title">
<view>四年的大学生活</view>
<view>您所在的区域</view>
<view>值得拥有一个属于自己的半径</view>
</view>
<view class="final-desc">在这里每一个瞬间都值得被记录每一份努力都能被看见</view>
</view>
<image class="final-corner-icon" src="https://jewel-shop.oss-cn-beijing.aliyuncs.com/8953e4af95944d7c94936efaffe155c6.png" mode="aspectFit"></image>
<view class="join-btn" hover-class="tap-soft" hover-stay-time="80" @tap="joinNow">电话联系 半径校园主理人计划</view>
<view class="join-btn" hover-class="tap-soft" hover-stay-time="80" @tap="joinNow">电话联系 半径区域主理人计划</view>
</view>
</view>
</scroll-view>
@ -205,7 +205,7 @@
icon: MY_CENTER_ICONS.idle
}, {
short: '圈',
name: '校园圈',
name: '区域圈',
icon: MY_CENTER_ICONS.campus
}],
ecosystems: [{
@ -213,67 +213,67 @@
short: '团',
icon: MY_CENTER_ICONS.group,
title: '万物拼团',
tagline: '校园省钱入口',
tagline: '区域省钱入口',
points: ['外卖拼团', '到店优惠', '秒杀福利'],
solve: '让学生每天消费更便宜'
solve: '让用户每天消费更便宜'
}, {
no: '02',
short: '职',
icon: MY_CENTER_ICONS.delivery,
title: '自由兼职',
tagline: '让时间产生价值',
points: ['跑腿配送', '快递代取', '校园任务'],
points: ['跑腿配送', '快递代取', '区域任务'],
solve: '学习之余,轻松赚零花'
}, {
no: '03',
short: '星',
icon: MY_CENTER_ICONS.planet,
title: '白嫖星球',
tagline: '校园福利中心',
tagline: '区域福利中心',
points: ['每日任务', '现金奖池', '学院排行'],
solve: '每天都有打开理由'
}, {
no: '04',
short: '社',
icon: MY_CENTER_ICONS.social,
title: 'IE校园社交',
tagline: '找到同的TA',
title: 'IE区域社交',
tagline: '找到同的TA',
points: ['学习搭子', '饭搭子', '运动搭子'],
solve: '让陌生校园产生连接'
solve: '让陌生区域产生连接'
}, {
no: '05',
short: '闲',
icon: MY_CENTER_ICONS.idle,
title: '校园二手',
title: '区域二手',
tagline: '让闲置重新流动',
points: ['闲置发布', '求购信息', '校园交流'],
points: ['闲置发布', '求购信息', '区域交流'],
solve: '闲置流转,循环利用'
}, {
no: '06',
short: '圈',
icon: MY_CENTER_ICONS.campus,
title: '校园圈',
tagline: '记录校园每一刻',
points: ['校园故事', '生活分享', '毕业记忆'],
solve: '用于记录学校的青春记忆'
title: '区域圈',
tagline: '记录区域每一刻',
points: ['区域故事', '生活分享', '毕业记忆'],
solve: '用于记录区域的青春记忆'
}],
responsibilities: [{
no: '01',
title: '校园商家合作',
title: '区域商家合作',
desc: '寻找优质商家,上线优惠活动'
}, {
no: '02',
title: '校园用户运营',
title: '区域用户运营',
desc: '组织拼团活动,策划福利玩法'
}, {
no: '03',
title: '校园生态建设',
desc: '打造学校自己的半径文化'
title: '区域生态建设',
desc: '打造区域自己的半径文化'
}],
steps: [{
no: '01',
title: '提交申请',
desc: '填写学校与团队信息'
desc: '填写区域与团队信息'
}, {
no: '02',
title: '平台培训',
@ -281,7 +281,7 @@
}, {
no: '03',
title: '开启运营',
desc: '上线校园商家与活动'
desc: '上线区域商家与活动'
}],
supports: [{
short: '工',

8
package2/myCenter/couponList.vue

@ -12,15 +12,15 @@
</view>
<view class="hero-copy">
<view class="hero-title">可用优惠券</view>
<view class="hero-sub">仅展示当前区未使用未锁定且未过期的优惠券</view>
<view class="hero-sub">仅展示当前区未使用未锁定且未过期的优惠券</view>
</view>
</view>
<view class="content">
<view class="summary-card">
<view class="summary-left">
<view class="summary-label">当前</view>
<view class="summary-name">{{regionName || '未选择区'}}</view>
<view class="summary-label">当前区</view>
<view class="summary-name">{{regionName || '未选择区'}}</view>
</view>
<view class="summary-count">{{totalCount}} 张可用</view>
</view>
@ -108,7 +108,7 @@
return
}
if (!this.searchForm.regionId) {
this.tui.toast('请先选择区')
this.tui.toast('请先选择区')
return
}
this.getCouponList()

4
package2/myCenter/myPost.vue

@ -2,7 +2,7 @@
<view class="my-fish-page">
<view class="header" :style="{ paddingTop: statusBarTop + 'px' }">
<view class="back" @tap="back"><uni-icons type="left" size="22"></uni-icons></view>
<view class="title">我的校园二手</view>
<view class="title">我的二手</view>
</view>
<view class="tabs">
<view class="tab" :class="{ active: activeTab == item.key }" v-for="item in visibleTabs" :key="item.key" @tap="switchTab(item.key)">
@ -338,7 +338,7 @@
if (this.activeTab == 'comments') return '我发表的评论'
if (this.activeTab == 'likes') return item.likeType == 'comment' ? '我点赞的评论' : '我点赞的商品'
if (this.activeTab == 'complaints') return '我的举报记录'
return item.goodsId || item.id || '校园二手'
return item.goodsId || item.id || '二手闲置'
},
descText(item) {
if (this.activeTab == 'favorites') return '收藏的商品'

30
package2/myCenter/partTimeJobRegister.vue

@ -22,7 +22,7 @@
</view>
</view>
<view class="box1">
<view class="box1" v-if="!isSocialArea">
<view class="reg-name">
学生证上传 <text
style="font-weight: 400;color: #777;font-size: 11px;">身份信息仅用于认证身份平台会严格保密</text>
@ -434,13 +434,17 @@
zhipaiCheck: false,
pendingNewDispatchRuleKeys: [],
workerNameAuditTip: '',
waimaFullAreaOrder: false
waimaFullAreaOrder: false,
areaKind: 1
}
},
components: {
},
computed: {
isSocialArea() {
return Number(this.areaKind) === 2
},
earningEstimate() {
const count = this.waimaRuleList.length + this.paotuiRuleList.length
const commissionPerOrder = 2
@ -464,15 +468,33 @@
}
},
onLoad() {
this.syncAreaKind()
this.getShopArea()
this.getWorkerMessage()
this.showOnboardingOnce()
this.worker = uni.getStorageSync('worker')
},
onShow() {
this.syncAreaKind()
this.menuButtonInfo = uni.getMenuButtonBoundingClientRect()
},
methods: {
syncAreaKind(areaObj) {
let area = areaObj
if (!area) {
try {
const cached = uni.getStorageSync('area')
area = cached ? (typeof cached === 'string' ? JSON.parse(cached) : cached) : null
} catch (e) {
area = null
}
}
const kind = area ? Number(area.areaKind) : 1
this.areaKind = kind === 2 ? 2 : 1
if (this.isSocialArea) {
this.formData.studentCard = ''
}
},
getCurrentRegionId() {
try {
const area = uni.getStorageSync('area')
@ -623,7 +645,7 @@
if (res.result != null) {
let data = res.result;
if (data.workerName) that.formData.name = that.limitText(data.workerName, 10);
if (data.cardPicture) that.formData.studentCard = data.cardPicture;
if (data.cardPicture && !that.isSocialArea) that.formData.studentCard = data.cardPicture;
if (data.mobile) that.formData.mobile = data.mobile;
if (data.highFloorFee !== undefined && data.highFloorFee !== null) that.formData
.highFloorFee = data.highFloorFee;
@ -983,7 +1005,7 @@
userId: uni.getStorageSync('id'),
regionId: regionId,
workerName: this.formData.name,
cardPicture: this.formData.studentCard,
cardPicture: this.isSocialArea ? '' : this.formData.studentCard,
highFloorFee: this.formatOneDecimalInput(this.formData.highFloorFee),
deliveryLocation: this.formData.deliveryLocation,
mobile: this.formData.mobile,

2
package2/myCenter/wallet.vue

@ -544,7 +544,7 @@
if (text.indexOf('提现') !== -1) return '提现至支付宝'
if (text.indexOf('配送') !== -1) return '配送订单收益'
if (text.indexOf('商家') !== -1 || text.indexOf('店铺') !== -1 || text.indexOf('结算') !== -1) return '店铺订单收益'
if (text.indexOf('抽奖') !== -1 || text.indexOf('奖励') !== -1) return '校内推广活动奖励'
if (text.indexOf('抽奖') !== -1 || text.indexOf('奖励') !== -1) return '区域推广活动奖励'
return '余额变动明细'
},
formatFlowTime(timeStr) {

Loading…
Cancel
Save