第一次提交

This commit is contained in:
gxwebsoft
2023-08-04 13:14:48 +08:00
commit 1b923e5cff
1030 changed files with 128016 additions and 0 deletions

122
pages/article/article.vue Normal file
View File

@@ -0,0 +1,122 @@
<template>
<view class="container">
<!-- <view class="search-wrapper">
<u-search :showAction="true" actionText="搜索" :animation="true" v-model="where.keywords" @search="onSearch"></u-search>
</view> -->
<view class="user-list">
<u-list @scrolltolower="scrolltolower">
<view class="list">
<u-list-item v-for="(item, index) in list" :key="index">
<u-cell
@click="navTo('/pages/article/detail/detail',{id: item.articleId})">
<u-avatar slot="icon" size="50" :src="item.image ? `https://file.wsdns.cn/thumbnail${item.image}` : item.userAvatar" shape="square"
customStyle="margin: -3px 5px -3px 0"></u-avatar>
<view slot="title">{{ item.title }}</view>
</u-cell>
</u-list-item>
<u-empty
v-if="list.length == 0"
mode="search"
icon="http://cdn.uviewui.com/uview/empty/search.png"
>
</u-empty>
</view>
</u-list>
</view>
</view>
</template>
<script>
import * as ArticleApi from '@/api/article.js'
export default {
data() {
return {
list: [],
page: 0,
where: {},
// 控制onShow事件是否刷新订单列表
canReset: false,
disabled: false
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.where = options
this.onRefreshList()
},
methods: {
// 刷新会员列表
onRefreshList() {
const app = this
app.where.page = app.page
app.where.categoryId = 55
return new Promise((resolve, reject) => {
ArticleApi.pageArticle(app.where)
.then(result => {
const list = result.data.list
console.log("list: ",list);
// 合并新数据
app.list = app.list.concat(list)
console.log("app.list: ",app.list);
if(result.data.count > app.list.length){
app.canReset = true
}else{
app.canReset = false
}
resolve(list)
})
})
},
scrolltolower(e){
console.log("e: ",e);
},
navTo(url,userId){
this.$push(url,userId)
},
onFollow(e){
console.log("e11: ",e);
},
onSearch(){
this.list = []
this.where.page = 1
this.onRefreshList()
}
}
}
</script>
<style lang="scss" scoped>
.container {
padding: 0rpx;
background-color: #ffffff;
}
.search-wrapper {
display: flex;
height: 64rpx;
}
.user-list{
margin: 0rpx auto;
}
.follow-btn {
padding: 4rpx 20rpx;
color: #ffffff;
font-size: 26rpx;
border-radius: 50rpx;
margin-right: 10rpx;
background: linear-gradient(#47076b, #8d1a50);
image {
width: 24rpx;
height: 66rpx;
margin-right: 6rpx;
}
}
</style>

View File

@@ -0,0 +1,116 @@
<template>
<view v-if="!isLoading" class="container b-f p-b">
<!-- <view class="article-title">
<text class="f-32">{{ detail.title }}</text>
</view> -->
<view class="article-little dis-flex flex-x-between m-top10">
<!-- <view class="article-little__left">
<text class="article-views f-24 col-8">{{ detail.show_views }}次浏览</text>
</view> -->
<view class="article-little__right">
<text class="article-views f-24 col-8">{{ detail.view_time }}</text>
</view>
</view>
<view class="article-content m-top20">
<mp-html :content="detail.content" />
</view>
<!-- 快捷导航 -->
<!-- <shortcut /> -->
</view>
</template>
<script>
import Shortcut from '@/components/shortcut'
import * as ArticleApi from '@/api/article'
export default {
components: {
Shortcut
},
data() {
return {
// 当前文章ID
articleId: null,
// 加载中
isLoading: true,
// 当前文章详情
detail: null
}
},
onLoad(e){
const { id } = e
console.log("id: ",id);
this.articleId = id
},
onShow(e) {
// 获取文章详情
this.getArticleDetail()
},
methods: {
// 获取文章详情
getArticleDetail() {
const app = this
const { articleId } = this
app.isLoading = true
ArticleApi.getArticle(articleId)
.then(result => {
app.detail = result.data;
// 改写标题
uni.setNavigationBarTitle({
title: app.detail.title
})
})
.finally(() => app.isLoading = false)
}
},
/**
* 分享当前页面
*/
onShareAppMessage() {
const app = this
// 构建页面参数
const params = app.$getShareUrlParams({ articleId: app.articleId });
return {
title: app.detail.title,
path: "/pages/article/detail?" + params
}
},
/**
* 分享到朋友圈
* 本接口为 Beta 版本,暂只在 Android 平台支持,详见分享到朋友圈 (Beta)
* https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share-timeline.html
*/
onShareTimeline() {
const app = this
// 构建页面参数
const params = app.$getShareUrlParams({ articleId: app.articleId });
return {
title: app.detail.title,
path: "/pages/article/detail?" + params
}
}
}
</script>
<style lang="scss" scoped>
.container {
min-height: 90vh;
padding: 20rpx;
background: #fff;
}
.article-title{
text-align: center;
}
.article-content {
font-size: 28rpx;
}
</style>

213
pages/chat/chat.vue Normal file
View File

@@ -0,0 +1,213 @@
<template>
<view class="content">
<!-- <z-paging :height="msgListHeight + 'px'" ref="paging" v-model="dataList" use-chat-record-mode :fixed="false" > -->
<!-- 聊天item -->
<scroll-view :style="{ height: msgListHeight + 'px' }" scroll-y :scroll-top="scrollTop" scroll-with-animation>
<view class="tips">
小红娘提醒任何涉及投资理财邮寄包裹等信息都存在诈骗嫌疑请及时举报
<text class="link" @click.stop="$push('pages/article/detail/detail?id=461')">安全指南</text>
</view>
<view id="msg-box">
<view :id="`z-paging-${index}`" v-for="(item, index) in dataList" :key="index">
<chat-item @onImageClick="onImageClick(index)" :prevMsgTime="index>0?dataList[index - 1].createTime: null" :friendInfo="friendInfo" :item="item"></chat-item>
</view>
</view>
</scroll-view>
<!-- </z-paging> -->
<view id="chat-input-bar">
<chat-input-bar @heightChange="resetMsgListHeight" @send="doSend" />
</view>
</view>
</template>
<script>
import ChatInputBar from "@/components/chat-input-bar/chat-input-bar.vue"
import ChatItem from "@/components/chat-item/chat-item.vue"
import { mapGetters,mapActions} from 'vuex'
import {
USER_ID,
USER_INFO
} from '@/store/mutation-types'
import storage from '@/utils/storage'
import * as UserProfileApi from '@/api/love-user-profile.js'
import ZPMixin from '@/uni_modules/z-paging/components/z-paging/js/z-paging-mixin'
export default {
mixins: [ZPMixin],
components: {
ChatInputBar,
ChatItem
},
computed: {
...mapGetters(['conversations'])
},
data() {
return {
friendId: 1,
dataList: [],
friendInfo: {},
keyboardHeight: 0,
screenHeight: 0,
msgListHeight: 0,
inputHeight: 0,
scrollTop: 0
}
},
onLoad(options) {
this.friendId = options.friendId
this.MarkRead(this.friendId)
// this.friendInfo = this.$store.getters.friends.find(item=> item.userId = options.friendId)
},
async onReady() {
// 获取屏幕高度
uni.getSystemInfo({
success: res => {
console.log(res);
this.screenHeight = res.windowHeight
this.resetMsgListHeight()
}
})
// 监听键盘高度变化
uni.onKeyboardHeightChange(res => {
this.keyboardHeight = res.height
// this.resetMsgListHeight()
})
// 获取消息
await this.LoadFriendMessage(this.friendId)
const messages = this.conversations[this.friendId].messages || []
this.friendInfo = this.conversations[this.friendId].friendInfo || {}
uni.setNavigationBarTitle({
title: this.friendInfo.nickname
})
const list = JSON.parse(JSON.stringify(messages))
this.dataList = list
setTimeout(()=>{
this.toMsgListBottom()
}, 1000)
// this.$nextTick(()=>{
// this.toMsgListBottom()
// })
// this.$refs.paging.complete(list);
// 第一次聊天 发打招呼的卡牌
if(list.length == 0){
const userId = uni.getStorageSync('userId')
const res = await UserProfileApi.getUserProfile(userId)
console.log("第一次聊天 发打招呼的卡牌 ",res.data);
console.log(res.data.images);
const images = JSON.parse(res.data.images) || []
if(images.length > 3){
images.splice(3, images.length - 3)
}
this.SendMessage({
type: 'card',
content: JSON.stringify({
age: res.data.age,
city: res.data.city,
height: res.data.height,
yearlyPay: res.data.yearlyPay,
position: res.data.position,
files: images.map(d => {
return {
thumb: d.url,
url: d.url
}
})
}),
toUserId: this.friendId,
formUserId: this.$store.getters.userId
})
}
// 收到新消息
uni.$on('message' + this.friendId, (data)=>{
this.dataList.push(data)
this.MarkRead(this.friendId)
})
},
onUnload() {
uni.$off('message' + this.friendId)
},
onPageScroll(e) {
//如果滚动到顶部,触发加载更多聊天记录
if (e.scrollTop < 10) {
}
},
methods: {
...mapActions(['SendMessage','LoadFriendMessage','MarkRead']),
/**
* 消息列表高度
*/
resetMsgListHeight(){
const query = uni.createSelectorQuery().in(this);
query.select('#chat-input-bar').boundingClientRect(data => {
this.msgListHeight = this.screenHeight - data.height - this.keyboardHeight
uni.$u.debounce(this.toMsgListBottom, 300)
}).exec();
},
/**
* 滚动到最后一条消息
*/
toMsgListBottom() {
this.scrollTop += 9999
},
async doSend(msg){
await this.SendMessage({
type: msg.type,
content: msg.content,
toUserId: this.friendId,
formUserId: this.$store.getters.userId
})
this.toMsgListBottom()
},
onImageClick(index){
console.log("onImageClick", index);
const arr = []
let current = 0
this.dataList.forEach((item, i)=>{
if(item.type == 'image'){
arr.push(item.content)
if(index == i){
current = arr.length - 1
}
}
})
uni.previewImage({
urls: arr,
current
})
}
}
}
</script>
<style lang="scss" scoped>
.content{
height: 100vh;
.tips{
width: 660rpx;
margin: 20rpx auto;
color: #818284;
font-size: 26rpx;
padding: 20rpx;
text-align: center;
line-height: 1.3rem;
background-color: #ffffff;
border-radius: 10rpx;
box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.1);
.link{
color: #681752;
text-decoration: underline;
}
}
}
</style>

609
pages/checkout/cashier/index.vue Executable file
View File

@@ -0,0 +1,609 @@
<template>
<view>
<view v-if="!isLoading" class="container" :style="appThemeStyle">
<!-- 订单信息 -->
<view class="order-info">
<!-- 支付剩余时间 -->
<view class="order-countdown">
<text class="m-r-6">剩余时间</text>
<count-down :date="expirationTime" separator="zh" theme="text" />
</view>
<!-- 付款金额 -->
<view class="order-amount">
<text class="unit"></text>
<text class="amount">{{ totalPrice }}</text>
</view>
</view>
<!-- 支付方式 -->
<view class="payment-method">
<view v-for="(item, index) in methods" :key="index" class="pay-item dis-flex flex-x-between"
@click="handleSelectPayType(index)">
<view class="item-left dis-flex flex-y-center">
<view class="item-left_icon" :class="[item.method]">
<text class="iconfont" :class="[item.icon]"></text>
</view>
<view class="item-left_text">
<text>{{ item.method }}</text>
</view>
<view v-if="item.method === '余额支付'" class="user-balance">
<text v-if="personal">(可用{{ personal.balance }})</text>
</view>
</view>
<view class="item-right col-m" v-if="curPaymentItem && curPaymentItem.method == item.method">
<text class="iconfont icon-check"></text>
</view>
</view>
</view>
<!-- 确认按钮 -->
<view class="footer-fixed">
<view class="btn-wrapper">
<view class="btn-item btn-item-main" :class="{ disabled }" @click="handleSubmit()">确认支付</view>
</view>
</view>
<!-- 支付确认弹窗 -->
<!-- #ifdef H5 -->
<u-modal v-if="tempUnifyData" v-model="showConfirmModal" title="支付确认" show-cancel-button confirm-text="已完成支付"
:confirm-color="appTheme.mainBg" negative-top="100" :asyncClose="true"
@confirm="onTradeQuery(tempUnifyData.outTradeNo, tempUnifyData.method)">
<view class="modal-content">
<text>请在{{ PayMethodClientNameEnum[tempUnifyData.method] }}内完成支付如果您已经支付成功请点击已完成支付按钮</text>
</view>
</u-modal>
<!-- #endif -->
</view>
<empty v-else :isLoading="isLoading" tips="订单不存在" />
</view>
</template>
<script>
import storage from '@/utils/storage'
import {
inArray,
urlEncode
} from '@/utils/util'
import {
Alipay,
Wechat
} from '@/core/payment'
import CountDown from '@/components/countdown'
import {
PayMethodEnum
} from '@/common/enum/payment'
import {
PayStatusEnum
} from '@/common/enum/order'
import * as OrderApi from '@/api/order.js'
import * as PaymentApi from '@/api/payment.js'
import {
dateFormat
} from '@/utils/util.js'
import Empty from '@/components/empty'
// import * as CashierApi from '@/api/cashier'
import * as UserApi from '@/api/user.js'
// 支付方式对应的图标
const PayMethodIconEnum = {
[PayMethodEnum.WECHAT.value]: 'icon-wechat-pay',
[PayMethodEnum.ALIPAY.value]: 'icon-alipay',
[PayMethodEnum.BALANCE.value]: 'icon-balance-pay'
}
// 支付方式的终端名称
const PayMethodClientNameEnum = {
[PayMethodEnum.WECHAT.value]: '微信',
[PayMethodEnum.ALIPAY.value]: '支付宝'
}
export default {
components: {
CountDown,
Empty
},
data() {
return {
orderIds: [],
// 加载中
isLoading: true,
// 确认按钮禁用
disabled: false,
// 枚举类
PayMethodEnum,
PayMethodIconEnum,
PayMethodClientNameEnum,
// 当前选中的支付方式
curPaymentItem: {
method: '余额支付'
},
// 当前订单ID
orderId: null,
// 当前结算订单信息
order: null,
deliveryTime: null,
// 订单过期时间
expirationTime: new Date(),
// 个人信息
personal: {
balance: '0.00'
},
totalPrice: 0,
// 当前客户端的支付方式列表后端根据platform判断
methods: [
{
id: 1,
method: '余额支付',
icon: 'icon-balance-pay'
},
// {
// id: 2,
// method: '支付宝',
// icon: 'icon-alipay'
// }
],
// 支付确认弹窗
showConfirmModal: false,
// #ifdef H5
// 当前微信支付信息 (临时数据, 仅用于H5端)
tempUnifyData: {
outTradeNo: '',
method: ''
},
// #endif
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(option) {
this.orderIds = option.orderIds.split(',')
// 记录订单ID
// this.orderId = Number(orderId)
// this.deliveryTime = deliveryTime
// // 获取收银台信息
this.getCashierInfo()
},
onShow() {},
methods: {
// 获取收银台信息
getCashierInfo() {
const app = this
const { orderIds } = this
app.isLoading = true
console.log(orderIds);
// 加载订单
console.log("typeof(orderIds): ",typeof(orderIds));
const baoCanExpirationTime = uni.getStorageSync('baoCanExpirationTime')
console.log(baoCanExpirationTime);
OrderApi.listByIds(orderIds)
.then(res => {
console.log("res: ",res);
res.data.map(d => {
console.log("app.totalPrice: ",app.totalPrice);
console.log("d: ",d.payPrice);
app.totalPrice = app.totalPrice + d.payPrice
})
app.isLoading = false
// 处理订单过期时间(*1小时)
var expirationTime = new Date().getTime() + 60 * 60 * 1000 * 0.20
app.expirationTime = dateFormat('YYYY-mm-dd HH:MM:SS', new Date(expirationTime))
})
.catch(e => {
console.log("e: ", e);
})
// 查询余额
const agentUser = uni.getStorageSync('agentUser')
if(agentUser){
app.getAgentUser()
}else{
UserApi.getUser().then(res => app.personal = res.data)
}
},
getAgentUser(){
const app = this
const agentUser = uni.getStorageSync('agentUser')
if(agentUser){
UserApi.getAgentUser(agentUser.userId).then(res => {
app.personal = res.data
})
}
},
// 设置默认的支付方式
setDefaultPayType() {
const app = this
if (app.disabled) return
const defaultIndex = app.methods.findIndex(item => item.is_default == true)
defaultIndex > -1 && app.handleSelectPayType(defaultIndex)
},
// 判断当前订单是否为已支付
checkOrderPayStatus() {
const app = this
if (app.order.pay_status == PayStatusEnum.SUCCESS.value) {
app.$toast('恭喜您,订单已付款成功')
app.onSuccessNav()
}
},
// 选择支付方式
handleSelectPayType(index) {
this.curPaymentItem = this.methods[index]
console.log("this.curPaymentItem: ", this.curPaymentItem);
},
// 判断当前页面来源于浏览器返回
// #ifdef H5
performance() {
const app = this
// 判断订单状态, 异步回调会将订单状态变为已支付, 那么就不需要让用户手动查单了
if (app.order.pay_status == PayStatusEnum.PENDING.value) {
app.alipayPerformance()
app.wechatPerformance()
}
},
// H5端支付宝支付完成跳转回当前页面时触发
alipayPerformance() {
const app = this
app.tempUnifyData = Alipay.performance()
if (app.tempUnifyData) {
app.onTradeQuery(app.tempUnifyData.outTradeNo, app.tempUnifyData.method)
}
},
// H5端微信支付完成或返回时触发
wechatPerformance() {
const app = this
app.tempUnifyData = Wechat.performance(app.orderId)
if (app.tempUnifyData) {
app.showConfirmModal = true
}
},
// #endif
// 确认支付
handleSubmit() {
const app = this
const {
orderIds
} = this
// 判断是否选择了支付方式
if (!app.curPaymentItem) {
app.$toast('您还没有选择支付方式')
return
}
// 按钮禁用
if (app.disabled) return
// app.disabled = true
// .js
console.log("orderIds: ",orderIds);
console.log("curPaymentItem: ",app.curPaymentItem);
if(app.curPaymentItem.method == '余额支付'){
console.log("'ssss: ",'ssss');
PaymentApi.balanceBatch(orderIds).then(result => app.onSubmitCallback(result)).catch(err => app.$error(err.message))
}
// if(app.curPaymentItem.method == '支付宝'){
// PaymentApi.alipay(orderIds).then(result => app.onSubmitCallback(result)).catch(err => app.$error(err.message))
// }
// // 提交到后端API
// CashierApi.orderPay(app.orderId, {
// method: app.curPaymentItem.method,
// client: app.platform,
// extra: app.getExtraAsUnify(app.curPaymentItem.method)
// })
// .then(result => app.onSubmitCallback(result))
// .finally(err => setTimeout(() => app.disabled = false, 10))
},
// 获取第三方支付的扩展参数
getExtraAsUnify(method) {
if (method === PayMethodEnum.ALIPAY.value) {
return Alipay.extraAsUnify()
}
if (method === PayMethodEnum.WECHAT.value) {
return Wechat.extraAsUnify()
}
return {}
},
// 订单提交成功后回调
onSubmitCallback(result) {
const app = this
const method = app.curPaymentItem.method
const tradeNO = result.data
console.log("result订单提交成功后回调: ", tradeNO);
// 余额支付
if (method === '余额支付') {
app.onShowSuccess(result)
}
// 发起支付宝支付
if (method === '支付宝') {
my.tradePay({
// 调用统一收单交易创建接口alipay.trade.create获得返回字段支付宝交易号trade_no
tradeNO: tradeNO,
success: (res) => {
console.log("res11: ", res);
if (res.resultCode == "9000") {
payQuery(app.orderId).then(result => {
if(result.code == 0) {
app.$success('支付成功')
app.$navTo('pages/order/detail?orderId='+app.orderId)
}
})
// setPayStatus({
// orderId: app.orderId,
// payStatus: 20,
// payMethod: 20
// }).then(res => {
// console.log("updateOrder: ",res);
// app.$navTo('pages/order/index')
// })
}
if (res.resultCode == "6001") {
app.$navTo('pages/order/index')
}
// my.alert({
// content: JSON.stringify(res),
// });
},
fail: (res) => {
my.alert({
content: JSON.stringify(res),
});
}
});
// Alipay.payment(paymentData)
// .then(res => app.onPaySuccess(res))
// .catch(err => app.onPayFail(err))
}
// 发起微信支付
if (method === PayMethodEnum.WECHAT.value) {
console.log('paymentData', paymentData)
Wechat.payment({
orderKey: app.orderId,
...paymentData
})
.then(res => app.onPaySuccess(res))
.catch(err => app.onPayFail(err))
}
},
// 订单支付成功的回调方法
// 这里只是前端支付api返回结果success,实际订单是否支付成功 以后端的查单和异步通知为准
onPaySuccess({
res,
option: {
isRequireQuery,
outTradeNo,
method
}
}) {
const app = this
// 判断是否需要主动查单
// isRequireQuery为true代表需要主动查单
if (isRequireQuery) {
app.onTradeQuery(outTradeNo, method)
return true
}
this.onShowSuccess(res)
},
// 显示支付成功信息并页面跳转
onShowSuccess({
message
}) {
this.$toast(message || '订单支付成功')
this.onSuccessNav()
},
// 订单支付失败
onPayFail(err) {
console.log('onPayFail', err)
const errMsg = err.message || '订单未支付'
this.$error(errMsg)
},
// 已完成支付按钮事件: 请求后端查单
onTradeQuery(outTradeNo, method) {
const app = this
// 交易查询
// 查询第三方支付订单是否付款成功
CashierApi.tradeQuery({
outTradeNo,
method,
client: app.platform
})
.then(result => result.data.isPay ? app.onShowSuccess(result) : app.onPayFail(result))
.finally(() => app.showConfirmModal = false)
},
// 支付成功后的跳转
onSuccessNav() {
// 相应全局事件订阅: 刷新上级页面数据
uni.$emit('syncRefreshOrder', true)
// 获取上级页面
const { orderId,deliveryTime } = this
const pages = getCurrentPages()
const lastPage = pages.length < 2 ? null : pages[pages.length - 2]
const backRoutes = [
'pages/order/index',
'pages/order/detail'
]
// 取消临时报餐状态
uni.removeStorageSync('baoCanExpirationTime')
setTimeout(() => {
if (lastPage && inArray(lastPage.route, backRoutes)) {
uni.navigateBack()
} else {
this.$navTo('pages/index/index', {deliveryTime}, 'redirectTo')
}
}, 1200)
},
}
}
</script>
<style>
page {
background: #F4F4F4;
}
</style>
<style lang="scss" scoped>
.container {
background-color: #F4F4F4;
}
// 订单信息
.order-info {
padding: 80rpx 0;
text-align: center;
.order-countdown {
display: flex;
justify-content: center;
font-size: 26rpx;
color: #666666;
margin-bottom: 20rpx;
}
.order-amount {
margin: 0 auto;
max-width: 50%;
display: flex;
align-items: center;
justify-content: center;
color: #fb0f07;
.unit {
font-size: 30rpx;
margin-bottom: -18rpx;
}
.amount {
font-size: 56rpx;
}
}
}
// 支付方式
.payment-method {
width: 94%;
margin: 0 auto 20rpx auto;
padding: 0 40rpx;
background-color: #ffffff;
border-radius: 20rpx;
.pay-item {
padding: 26rpx 0;
font-size: 28rpx;
border-bottom: 1rpx solid rgb(248, 248, 248);
&:last-child {
border-bottom: none;
}
.item-left_icon {
margin-right: 20rpx;
font-size: 44rpx;
&.wechat {
color: #00c800;
}
&.alipay {
color: #009fe8;
}
&.balance {
color: #ff9700;
}
}
.item-left_text {
font-size: 28rpx;
}
.item-right {
font-size: 32rpx;
}
.user-balance {
margin-left: 20rpx;
font-size: 26rpx;
}
}
}
// 支付确认弹窗
.modal-content {
padding: 40rpx 48rpx;
font-size: 30rpx;
line-height: 50rpx;
text-align: left;
color: #606266;
// height: 620rpx;
box-sizing: border-box;
}
// 底部操作栏
.footer-fixed {
position: fixed;
bottom: var(--window-bottom);
left: 0;
right: 0;
z-index: 11;
box-shadow: 0 -4rpx 40rpx 0 rgba(151, 151, 151, 0.24);
background: #fff;
// 设置ios刘海屏底部横线安全区域
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
.btn-wrapper {
height: 120rpx;
display: flex;
align-items: center;
padding: 0 40rpx;
}
.btn-item {
flex: 1;
font-size: 28rpx;
height: 80rpx;
color: #fff;
border-radius: 50rpx;
display: flex;
justify-content: center;
align-items: center;
}
.btn-item-main {
background: linear-gradient(to right, $main-bg, $main-bg2);
color: $main-text;
// 禁用按钮
&.disabled {
opacity: 0.6;
}
}
}
</style>

787
pages/checkout/checkout.vue Normal file
View File

@@ -0,0 +1,787 @@
<template>
<view class="user-index">
<view class="page-bg"></view>
<view class="header" :style="'margin-top: ' + statusBarHeight + 'px'"></view>
<view class="main-header">
<image class="bg-image" :src="bgImage" mode="scaleToFill"></image>
<!-- 用户信息 -->
</view>
<view class="main">
<!-- 表单信息 -->
<u--form :model="form" ref="uForm">
<view class="buy-user">
<!-- 表单组件 -->
<view class="form-wrapper">
<u-cell-group :border="false">
<u-cell title="姓名" :isLink="true">
<input slot="value" class="w-input" placeholder="请填写姓名" v-model="form.realName" />
</u-cell>
<u-cell title="手机号" :isLink="true">
<input slot="value" class="w-input" placeholder="请填写手机号码" v-model="form.phone" />
</u-cell>
<u-cell title="所属区域" :isLink="true" @click="onArea">
<input slot="value" class="w-input" :disabled="true" placeholder="请选择所属区域" v-model="form.area" />
</u-cell>
<u-cell title="服务门店" :border="false" :isLink="true" @click="onMerchant">
<input slot="value" class="w-input" :disabled="true" placeholder="请选择服务门店" v-model="form.merchantName" />
</u-cell>
</u-cell-group>
</view>
</view>
<u-gap height="3"></u-gap>
<!-- 会员套餐 -->
<view class="buy-user">
<u-cell :title="form.roleName"></u-cell>
<view class="price-box">
<view class="info">
<image :src="form.icon"
mode="aspectFill"></image>
<view class="content">
{{ form.comments }}
</view>
</view>
<view class="price" v-for="(item,index) in form.price" :key="index" v-if="priceId == item.id">
<text class="reb">{{ item.price }}</text>
<text class="num">x1</text>
</view>
</view>
</view>
<view class="xieyi">
<u-icon name="checkbox-mark"></u-icon>
购买代表同意爱尚客网
<text @click="$push('pages/article/detail/detail?id=116')">人工牵线协议</text>
</view>
</u--form>
</view>
<view class="cart">
<view class="cart-info" @click="navTo('pages/menu/menu')">
<!-- <view style="position: relative;"> -->
<!-- <u-badge class="badge" size="mini" type="error" :is-center="true" :count="totalNum"></u-badge> -->
<!-- <image class="cart-logo" src="../../static/icon/cart4.png"></image> -->
<!-- </view> -->
<view class="total-price">{{ totalPrice }}</view>
<!-- <view class="clear-cart" @click="onClearCart">清空购物车</view> -->
<view class="buy">
<u-button text="立即下单" shape="circle" type="error" class="custom-style" :disabled="disabled"
@click="onBuy">
</u-button>
</view>
</view>
</view>
<!-- 地址选择器 -->
<liu-customize-sel ref="area" @change="chooseSuccess"></liu-customize-sel>
<!-- 选择店铺 -->
<u-picker :show="showMerchant" :columns="merchantList" keyName="label" @confirm="confirmMerchant"
@cancel="showMerchant = false"></u-picker>
</view>
</template>
<script>
import store from '@/store/index.js'
import storage from '@/utils/storage'
import * as UserPlanApi from '@/api/love-user-plan.js'
import * as UserPlanLogApi from '@/api/love-user-plan-log.js'
import * as MerchantApi from '@/api/merchant.js'
import {
getUser,
updateUser
} from '@/api/user.js'
import {
username
} from '@/config.js';
import {
getMobile
} from '@/utils/util.js'
import http from '@/api'
const userId = uni.getStorageSync('userId')
export default {
data() {
return {
merchantList: [],
bgImage: 'data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%221%22%20x1%3D%220%22%20x2%3D%221%22%20y1%3D%220%22%20y2%3D%220%22%20gradientTransform%3D%22matrix(6.123233995736766e-17%2C%201%2C%20-0.36308349769888226%2C%206.123233995736766e-17%2C%200.5%2C%200)%22%3E%3Cstop%20stop-color%3D%22%23101010%22%20stop-opacity%3D%221%22%20offset%3D%220.24%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23160028%22%20stop-opacity%3D%221%22%20offset%3D%221%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22url(%231)%22%3E%3C%2Frect%3E%3C%2Fsvg%3E',
statusBarHeight: 25,
// 是否已登录
isLogin: false,
disabled: false,
showMerchant: false,
// 系统设置
form: {
planId: 0,
priceId: 0,
area: '',
merchantName: ''
},
priceId: 0,
totalPrice: 0.00,
dealerId: 0
}
},
onLoad(options) {
this.form.planId = Number(options.planId)
this.priceId = Number(options.priceId)
this.totalPrice = options.price
this.getUserInfo()
this.getOrderInfo()
// 设置navbar标题、颜色options
uni.setNavigationBarColor({
frontColor: '#ffffff',
backgroundColor: '#101010'
})
},
onShow() {},
watch: {
dealerId(val,old) {
console.log("侦听根级属性侦听根级属性侦听根级属性侦听根级属性44: ",val);
this.getDealerMerchant(val)
}
},
methods: {
// 跳转页面
navTo(url) {
this.$navTo(url)
},
getUserInfo() {
const {
form
} = this
const app = this
uni.getSystemInfo({
success(data) {
if (data) {
app.statusBarHeight = data.statusBarHeight + 50
}
}
})
getUser().then(res => {
if (res.code == 0 && res.data.username != 'www') {
if(res.data){
console.log("res.data.phone: ",res.data.phone);
app.form.realName = res.data.nickname
app.form.phone = res.data.phone
app.dealerId = res.data.dealerId
// app.getDealerMerchant(res.data.dealerId)
}
app.isLogin = true
} else {
app.isLogin = false
app.$push('pages/login/index')
}
})
},
getOrderInfo(){
const app = this
const { planId } = this.form
UserPlanApi.getUserPlan(planId).then(result => {
console.log("result: ",result);
app.form = result.data
result.data.price.map(d => {
if(d.id == app.priceId){
app.form.priceId = d.id
app.totalPrice = d.price.toFixed(2)
}
})
})
},
getMerchant(){
const app = this
const form = {
region: app.form.region
}
console.log("app.planId: ",app.planId);
if(app.form.planId == 18){
form.gradeId = 18
}
MerchantApi.listMerchant(form).then(result => {
let arr = []
app.merchantList = []
result.data.map(d => {
console.log(d);
// 只收集线下门店
if(d.gradeId >= 10){
arr.push({
label: `${d.merchantName} (${d.gradeName})`,
id: d.merchantId,
code: d.merchantCode,
address: d.address
})
}
})
app.merchantList.push(arr)
})
},
// 获取推荐人的店铺信息
getDealerMerchant(dealerId){
console.log("获取推荐人的店铺信息: ",'获取推荐人的店铺信息');
const app = this
MerchantApi.pageMerchant({userId: dealerId}).then(result => {
console.log("result23123123123: ",result);
if(result.data.count > 0){
const data = result.data.list
const merchantName = data[0].merchantName
console.log("merchantName333333: ",merchantName);
const area = `${data[0].province} ${data[0].city} ${data[0].region}`
var newObj = {
...app.form
}
newObj.merchantName = merchantName
newObj.area = area
newObj.province = data[0].province
newObj.city = data[0].city
newObj.region = data[0].region
newObj.merchantId = data[0].merchantId
app.form = newObj
// app.form = ...{area,merchantName}
// app.area = region
// app.merchantName = merchantName
// app.form.merchantName = merchantName
// app.form.province = data[0].province
// app.form.city = data[0].city
// app.form.region = data[0].region
}
})
},
onArea() {
this.$refs.area.open()
},
onMerchant(){
this.showMerchant = true
},
confirmMerchant(e){
console.log("eeeeee2222: ",e);
this.form.merchantId = e.value[0].id
this.form.merchantCode = e.value[0].code
this.form.merchantName = e.value[0].label
this.form.address = e.value[0].address
this.showMerchant = false
},
//地址选择成功
chooseSuccess(e) {
const app = this
const data = e.value
if(data){
app.form.area = `${data[0].label} ${data[1].label} ${data[2].label}`
app.form.province = data[0].label
app.form.city = data[1].label
app.form.region = data[2].label
app.getMerchant()
}
},
// 跳转到服务页面
handleService({
url
}) {
if (url.slice(0, 4) == 'http') {
wx.openCustomerServiceChat({
extInfo: {
url: 'https://work.weixin.qq.com/kfid/kfc1693a8d29b84bc5e'
},
corpId: 'ww1c3f872ba0a39228',
success(res) {}
})
return;
}
if (!this.isLogin) {
return false;
}
console.log("url: ", url);
this.$navTo(url)
},
// 显示toast信息
showToast(title, duration = 2000) {
this.$refs.uToast.show({
title,
duration
})
},
handleLogout() {
// http.setConfig((config) => {
// config.header = {};
// config.header = {
// AppId: appId,
// tenantId: tenantId
// };
// return config
// })
// uni.clearStorage()
// uni.clearStorageSync()
uni.redirectTo({
url: '/pages/login/index'
})
},
onBuy() {
const app = this
const {
form
} = this
console.log("form: ",form);
if(form.realName == ''){
this.$error('请填写姓名')
return false
}
if(form.phone == ''){
this.$error('请填写手机号码')
return false
}
if(form.area == ''){
this.$error('请选择所属区域')
return false
}
if(!form.merchantId){
this.$error('请选择服务门店')
return false
}
app.disabled = true
UserPlanLogApi.addUserPlanLog({
planId: form.planId,
priceId: form.priceId,
province: form.province,
city: form.province,
region: form.region,
area: form.area,
realName: form.realName,
phone: form.phone,
merchantId: form.merchantId,
merchantCode: form.merchantCode,
merchantName: form.merchantName,
address: form.address
}).then(res => {
const orderInfo = res.data
// 调起微信支付
uni.requestPayment({
provider: orderInfo.provider, // 服务提供商
timeStamp: orderInfo.timeStamp, // 时间戳
nonceStr: orderInfo.nonceStr, // 随机字符串
package: orderInfo.package,
signType: orderInfo.signType, // 签名算法
paySign: orderInfo.paySign, // 签名
success: function(res) {
// 业务逻辑。。。
app.$success('支付成功')
setTimeout(function() {
app.showEdit = false
app.disabled = false
app.$navTo('pages/order/index')
}, 1500);
},
fail: function(err) {
console.log('支付失败', err);
app.disabled = false
}
});
}).catch(err => {
app.disabled = false
})
},
onApply() {
if (!this.isLogin) {
return false;
}
this.$navTo('pages/wallet/balance/log')
}
}
}
</script>
<style lang="scss" scoped>
.user-index {
background-color: #f3f3f3;
height: 100vh;
}
.container {
padding-bottom: 60rpx;
}
.page-bg {
width: 750rpx;
height: calc(100rpx + var(--status-bar-height));
display: block;
background-color: #101010;
position: absolute;
left: 0;
top: 0;
z-index: -100;
}
// 页面头部
.main-header {
// background-color: #FBF7EF;
position: fixed;
top: 0;
width: 100%;
height: 360rpx;
background-size: 100% 100%;
overflow: hidden;
display: flex;
align-items: center;
display: flex;
justify-content: space-between;
.bg-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
}
.star {
position: absolute;
opacity: 0.1;
color: #fff;
}
.star1 {
width: 100rpx;
height: 100rpx;
right: 80rpx;
top: 34rpx;
}
.star2 {
width: 100rpx;
height: 100rpx;
left: 40rpx;
top: 10rpx;
}
.star3 {
width: 70rpx;
height: 70rpx;
left: 130rpx;
top: 70rpx;
}
.user-info {
display: flex;
height: 120rpx;
padding-left: 30rpx;
z-index: 1;
.user-content {
display: flex;
flex-direction: column;
justify-content: center;
margin-left: 30rpx;
color: #ffffff;
.nick-name {
font-size: 30rpx;
font-weight: bold;
max-width: 270rpx;
display: flex;
flex-direction: row;
image {
margin-left: 10rpx;
width: 36rpx;
height: 36rpx;
}
}
.user-id {
font-weight: 300;
color: #efefef;
font-size: 24rpx;
}
.mobile {
margin-top: 15rpx;
font-size: 28rpx;
}
.user-grade {
align-self: baseline;
display: flex;
align-items: center;
background: #3c3c3c;
margin-top: 12rpx;
border-radius: 10rpx;
padding: 4rpx 12rpx;
.user-grade_icon .image {
display: block;
width: 32rpx;
height: 32rpx;
}
.user-grade_name {
margin-left: 5rpx;
font-size: 26rpx;
color: #EEE0C3;
}
}
.roles-box {
display: flex;
.login-tips {
margin-top: 12rpx;
margin-right: 6rpx;
font-size: 30rpx;
display: flex;
}
}
}
}
.switch {
display: flex;
color: #ffffff;
flex-direction: column;
justify-content: center;
align-items: center;
padding-right: 50rpx;
z-index: 999;
image {
width: 45rpx;
height: 45rpx;
}
.switch-text {
z-index: 9999;
color: #681752;
}
}
.setting {
color: #cecece;
position: absolute;
right: 2vh;
top: 1vh;
image {
width: 45rpx;
height: 45rpx;
}
}
}
.main {
position: fixed;
top: 80rpx;
left: 25rpx;
z-index: 999;
// 开通会员
.buy-user {
display: flex;
flex-direction: column;
margin: 22rpx auto 22rpx auto;
padding: 22rpx 0;
width: 700rpx;
box-shadow: 0 1rpx 5rpx 0px #eaebec;
border-radius: 24rpx;
background: #fff;
.desc {
padding-top: 5rpx;
padding-left: 32rpx;
font-size: 28rpx;
color: #545454;
}
.asset-right {
width: 170rpx;
border-left: 1rpx solid #eee;
}
.asset-right-item {
text-align: center;
color: #545454;
.item-icon {
font-size: 44rpx;
}
.item-name {
margin-top: 14rpx;
font-size: 28rpx;
}
}
.asset-left-item {
text-align: center;
padding-left: 28rpx;
display: flex;
.item-value {
font-size: 34rpx;
// color: #febd45;
}
.item-name {
color: #545454;
margin-top: 14rpx;
font-size: 24rpx;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
margin: 30rpx 25rpx 20rpx 0;
}
.buy-user-icon {
width: 40rpx;
margin-bottom: 8rpx;
}
}
}
}
// 退出登录
.my-logout {
display: flex;
justify-content: center;
margin-top: 50rpx;
.logout-btn {
width: 400rpx;
margin: 0 auto;
font-size: 28rpx;
color: #616161;
border-radius: 20rpx;
border: 1px solid #dcdcdc;
padding: 16rpx 0;
text-align: center;
}
}
.price-box {
padding: 30rpx;
display: flex;
justify-content: space-between;
.info {
display: flex;
image {
width: 120rpx;
height: 120rpx;
border-radius: 20rpx;
}
.content {
width: 280rpx;
padding-left: 30rpx;
font-size: 28rpx;
color: #666666;
}
}
.price {
display: flex;
flex-direction: column;
align-items: flex-end;
padding: 0 20rpx;
.reb {
color: #ff0000;
}
.num {
color: #999999;
}
}
}
.xieyi {
width: 600rpx;
font-size: 26rpx;
text-align: center;
display: flex;
justify-content: center;
margin: 50rpx auto;
color: #999999;
text {
color: #681752;
}
}
.cart {
position: fixed;
bottom: 25rpx;
z-index: 888;
width: 750rpx;
height: 80rpx;
line-height: 80rpx;
.cart-info {
background: linear-gradient(to bottom, $main-bg, $main-bg2);
width: 700rpx;
margin: auto;
display: flex;
border-radius: 100rpx;
justify-content: space-between;
position: relative;
.cart-logo {
position: absolute;
width: 90rpx;
height: 90rpx;
margin-left: 20rpx;
bottom: 10rpx;
}
.total-price {
padding-left: 30rpx;
font-size: 34rpx;
font-weight: bold;
color: #ffffff;
}
.clear-cart {
color: #ff0000;
}
.buy {
margin-right: 0;
display: flex;
flex-direction: column;
justify-content: center;
.custom-style {
padding: 0 50rpx;
color: #ffffff;
background-color: #ff0000;
// background: linear-gradient(to bottom, $main-bg, $main-bg2);
// background-color: #8b004c;
border: none;
width: 330rpx;
height: 66rpx;
font-size: 28rpx;
}
}
}
}
.w-input{
width: 400rpx;
text-align: right;
font-size: 25rpx;
color: #606266;
}
</style>

276
pages/comment/index.vue Executable file
View File

@@ -0,0 +1,276 @@
<template>
<view class="container" :style="appThemeStyle">
<mescroll-body ref="mescrollRef" :sticky="true" @init="mescrollInit" :down="{ use: false }" :up="upOption" @up="upCallback">
<!-- tab栏 -->
<u-tabs :list="tabs" :is-scroll="false" :current="curTab" :active-color="appTheme.mainBg" :duration="0.2" @change="onChangeTab" />
<!-- 商品评价列表 -->
<view class="comment-list">
<view class="comment-item" v-for="(item, index) in list.data" :key="index">
<view class="item-head">
<!-- 用户信息 -->
<view class="user-info">
<avatar-image class="user-avatar" :url="item.user.avatar_url" :width="50" />
<text class="user-name f-26">{{ item.user.nick_name }}</text>
</view>
<!-- 评星 -->
<u-rate active-color="#f4a213" :current="rates[item.score]" :disabled="true" />
<!-- 评价日期-->
<view class="flex-box f-22 col-9 t-r">{{ item.create_time }}</view>
</view>
<!-- 评价内容 -->
<view class="item-content m-top20">
<text class="f-26">{{ item.content }}</text>
</view>
<!-- 评价图片 -->
<view class="images-list clearfix" v-if="item.images.length">
<view class="image-preview" v-for="(image, imgIdx) in item.images" :key="imgIdx">
<image class="image" mode="aspectFill" :src="image.image_url" @click="onPreviewImages(index, imgIdx)">
</image>
</view>
</view>
<!-- 商品规格 -->
<view class="goods-props clearfix">
<view class="goods-props-item" v-for="(props, idx) in item.orderGoods.goods_props" :key="idx">
<text class="group-name">{{ props.group.name }}: </text>
<text>{{ props.value.name }}</text>
</view>
</view>
</view>
</view>
</mescroll-body>
</view>
</template>
<script>
import MescrollBody from '@/components/mescroll-uni/mescroll-body.vue'
import MescrollMixin from '@/components/mescroll-uni/mescroll-mixins'
import AvatarImage from '@/components/avatar-image'
import { getEmptyPaginateObj, getMoreListData } from '@/core/app'
// import * as CommentApi from '@/api/comment'
const pageSize = 15
const tabs = [{
name: `全部`,
scoreType: -1
}, {
name: `好评`,
scoreType: 10
}, {
name: `中评`,
scoreType: 20
}, {
name: `差评`,
scoreType: 30
}]
export default {
components: {
MescrollBody,
AvatarImage
},
mixins: [MescrollMixin],
data() {
return {
// 当前商品ID
goodsId: null,
// 当前标签索引
curTab: 0,
// 评价列表数据
list: getEmptyPaginateObj(),
// 评价总数量
total: { all: 0, negative: 0, praise: 0, review: 0 },
// 评星数据转换
rates: { 10: 5, 20: 3, 30: 1 },
// 标签栏数据
tabs,
// 上拉加载配置
upOption: {
// 首次自动执行
auto: true,
// 每页数据的数量; 默认10
page: { size: pageSize },
// 数量要大于4条才显示无更多数据
noMoreSize: 4,
// 空布局
empty: {
tip: '亲,暂无相关商品评价'
}
},
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
// 记录属性值
this.goodsId = options.goodsId
// 获取指定评分总数
this.getTotal()
},
methods: {
/**
* 上拉加载的回调 (页面初始化时也会执行一次)
* 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10
* @param {Object} page
*/
upCallback(page) {
const app = this
// 设置列表数据
// app.getCommentList(page.num)
// .then(list => {
// const curPageLen = list.data.length
// const totalSize = list.data.total
// app.mescroll.endBySize(curPageLen, totalSize)
// })
// .catch(() => app.mescroll.endErr())
},
// 加载评价列表数据
getCommentList(pageNo = 1) {
const app = this
return new Promise((resolve, reject) => {
CommentApi.list(app.goodsId, { scoreType: app.getScoreType(), page: pageNo }, { load: false })
.then(result => {
// 合并新数据
const newList = result.data.list
app.list.data = getMoreListData(newList, app.list, pageNo)
resolve(newList)
})
})
},
// 评分类型
getScoreType() {
return this.tabs[this.curTab].scoreType
},
// 获取指定评分总数
getTotal() {
const app = this
CommentApi.total(app.goodsId)
.then(result => {
// tab标签内容
const total = result.data.total
app.getTabs(total)
})
},
// 获取tab标签内容
getTabs(total) {
const tabs = this.tabs
tabs[0].name = `全部(${total.all})`
tabs[1].name = `好评(${total.praise})`
tabs[2].name = `中评(${total.review})`
tabs[3].name = `差评(${total.negative})`
},
// 切换标签项
onChangeTab(index) {
const app = this
// 设置当前选中的标签
app.curTab = index
// 刷新评价列表
app.onRefreshList()
},
// 刷新评价列表
onRefreshList() {
this.list = getEmptyPaginateObj()
setTimeout(() => {
this.mescroll.resetUpScroll()
}, 120)
},
// 预览评价图片
onPreviewImages(dataIdx, imgIndex) {
const app = this
const images = app.list.data[dataIdx].images
const imageUrls = images.map(item => item.image_url)
uni.previewImage({
current: imageUrls[imgIndex],
urls: imageUrls
})
}
}
}
</script>
<style lang="scss" scoped>
.comment-item {
padding: 30rpx;
box-sizing: border-box;
border-bottom: 1rpx solid #f7f7f7;
background: #fff;
}
.item-head {
display: flex;
align-items: center;
// 用户信息
.user-info {
margin-right: 15rpx;
display: flex;
align-items: center;
.user-avatar {
margin-right: 15rpx;
}
.user-name {
color: #999;
}
}
}
// 评价内容
.item-content {
font-size: 30rpx;
color: #333;
margin: 16rpx 0;
}
// 评价图片
.images-list {
&::after {
clear: both;
content: " ";
display: table;
}
.image-preview {
float: left;
margin-bottom: 15rpx;
margin-right: 15rpx;
&:nth-child(3n+0) {
margin-right: 0;
}
.image {
display: block;
width: 220rpx;
height: 220rpx;
}
}
}
// 商品规格
.goods-props {
font-size: 24rpx;
color: #999;
.goods-props-item {
float: left;
.group-name {
margin-right: 6rpx;
}
}
}
</style>

29
pages/empty.vue Executable file
View File

@@ -0,0 +1,29 @@
<template>
</template>
<script>
export default {
data() {
return {
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
},
methods: {
}
}
</script>
<style lang="scss" scoped>
</style>

150
pages/flash/index.vue Normal file
View File

@@ -0,0 +1,150 @@
<template>
<view class="page-wrap">
<view class="main">
<view class="logo">
<image src="https://file.wsdns.cn/20230801/84480e0c65b044ebb869f8f2754bc0b1.png" mode="widthFix"></image>
<!-- <image src="https://oss.jimeigroup.cn/static/flash-logo-text.png" mode="widthFix"></image> -->
<!-- <text class="logo-name">
爱尚家找房
</text> -->
</view>
<view class="btn" @click="onLogin">
<text>立即跳过({{ times }})</text>
</view>
</view>
<view class="bg"></view>
</view>
</template>
<script>
import storage from '@/utils/storage'
import {
ACCESS_TOKEN,
USER_ID,
USER_INFO
} from '@/store/mutation-types'
import {
getToken
} from '@/api/login.js'
// 倒计时时长(秒)
const times = 5
export default {
data() {
return {
times,
smsState: false
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options = {}) {
const refereeId = options.user_id
if(refereeId){
uni.setStorageSync('refereeId',refereeId)
}
this.checkLogin()
this.timer()
},
onShow() {
},
methods: {
// 执行定时器
timer() {
const app = this
app.smsState = false
const inter = setInterval(() => {
app.times = app.times - 1
if (app.times <= 0) {
app.smsState = true
app.times = 0
app.onLogin()
clearInterval(inter)
}
}, 1000)
},
checkLogin() {
const token = storage.get(ACCESS_TOKEN)
if (token) {
this.$navTo('pages/index/index')
}
},
// 1. 未登录则使用免密登录方式登录(游客身份)
onLogin() {
const token = storage.get(ACCESS_TOKEN)
if (!token) {
getToken().then(res => {
uni.reLaunch({
url: '/pages/index/index'
})
})
}
}
}
}
</script>
<style>
page{
background-color: #ffffff;
}
</style>
<style lang="scss" scoped>
.page{
min-height: 100vh;
background: linear-gradient(#47076b, #8d1a50);
}
.bg {
width: 750rpx;
height: 78vh;
// background: url('https://oss.jimeigroup.cn/static/login-bg01.png');
padding: 180rpx 0;
position: relative;
z-index: 0;
}
.main {
margin-top: 25vh;
position: fixed;
display: flex;
flex-direction: column;
justify-content: space-between;
width: 750rpx;
height: 900rpx;
z-index: 100;
.logo {
width: 750rpx;
margin: auto;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
image {
width: 300rpx;
}
.logo-name {
color: #ffffff;
font-size: 40rpx;
}
}
.btn {
width: 230rpx;
margin: auto;
padding: 20rpx 40rpx;
color: #ffffff;
font-size: 28rpx;
border-radius: 50rpx;
background: linear-gradient(#27b0fd, #3f72f4);
display: flex;
justify-content: center;
}
}
</style>

55
pages/help/xieyi.vue Executable file
View File

@@ -0,0 +1,55 @@
<template>
<view class="help">
<block v-for="(item,index) in itemList" :key="index">
<view class="content" slot="body">
<u-parse :html="item.content"></u-parse>
</view>
</block>
</view>
</template>
<script>
import { pageArticle } from '@/api/article.js'
export default {
data() {
return {
// 列表数据
itemList: [{
head: "关于我们",
body: "",
open: true,
disabled: true
}],
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
const app = this
pageArticle({
categoryId: 51
}).then(res => {
app.itemList = res.data.list
})
},
methods: {
}
}
</script>
<style lang="scss" scoped>
.help {
border-bottom: 1rpx solid #f6f6f9;
width: 750rpx;
margin: 0rpx auto;
.content{
padding: 20rpx 40rpx;
}
}
</style>

135
pages/home/home.vue Normal file
View File

@@ -0,0 +1,135 @@
<template>
<view class="index">
<view class="header" :style="'margin-top: ' + listHeight + 'px'">
<view class="pair">
<view class="search" @click="$push('pages/search/index')">
<image src="../../static/icon/search2.png" mode="widthFix"></image>
</view>
<!-- <view class="pair-btn" @click="navTo('pages/pair/pair')">
<u-button text="配对" size="small" color="linear-gradient(to bottom, #040004, #681752)"></u-button>
</view> -->
</view>
<view class="menu">
<u-tabs :list="menu" :current="currentTab" lineColor="#ff0077" :activeStyle="{
color: '#ffffff',
fontWeight: 'bold',
transform: 'scale(1.05)'
}" @click="tabChange">
</u-tabs>
</view>
</view>
<view class="list" :style="'height:' + winheight + 'px;'">
</view>
</view>
</template>
<script>
import * as UserProfileApi from '@/api/love-user-profile.js'
const menu = [{
name: '同城'
},
{
name: '推荐'
},
{
name: '关注'
}
];
export default {
data() {
return {
menu,
currentTab: 1,
where: {},
windowHeight: 0 ,
statusBarHeight: 0,
listHeight: 0
};
},
onLoad() {
// 获取可用高度
const sysInfo = uni.getSystemInfoSync()
this.windowHeight = sysInfo.windowHeight
this.statusBarHeight = sysInfo.statusBarHeight
this.listHeight = sysInfo.windowHeight - sysInfo.statusBarHeight - 44
this.queryList({
page: 1,
limit: 100
})
},
methods: {
tabChange(index) {
this.tabIndex = index;
//当切换tab或搜索时请调用组件的reload方法请勿直接调用queryList方法
this.$refs.paging.reload();
},
queryList(where) {
UserProfileApi.pageUserProfile(where).then(res => {
// this.
}).catch(res => {
this.$refs.paging.complete(false);
})
},
}
}
</script>
<style lang="scss">
page {
background-color: #0f001f !important;
}
.list{
width: 750rpx;scroll-snap-type: y mandatory;overflow-x: hidden;overflow-y: auto;
}
.header {
display: flex;
z-index: 9999;
justify-content: space-around;
align-items: center;
width: 750rpx;
height: 88rpx;
// background-color: #0f001f;
.pair {
position: absolute;
left: 30rpx;
position: absolute;
right: 30rpx;
display: flex;
.search {
image {
padding-top: 15rpx;
width: 40rpx;
height: 40rpx;
}
}
.pair-btn {
margin-left: 25rpx;
}
}
.menu {
display: flex;
justify-content: center;
// font-size: 32rpx;
// font-weight: 600;
z-index: 9999;
.link {
color: #cfd1d7;
}
.curr {
color: #ffffff;
border-bottom: 5rpx solid #ffffff;
}
}
}
</style>

290
pages/house/house.vue Normal file
View File

@@ -0,0 +1,290 @@
<template>
<view class="page">
<!-- 搜索 -->
<view class="search-fix">
<view class="search">
<u-search placeholder="请输入搜索关键词" v-model="keyword" :actionStyle="actionStyle" :showAction="false"
shape="square" bgColor="#ffffff" :animation="true"></u-search>
</view>
</view>
<view class="search-tools">
<view class="region">
<uni-data-select class="select-width" v-model="where.region" :localdata="region" placeholder="区域"
@change="onSearch"></uni-data-select>
</view>
<view class="region">
<uni-data-select class="select-width" v-model="where.price" :localdata="price" placeholder="价格区间"
@change="onSearch"></uni-data-select>
</view>
<view class="region">
<uni-data-select class="select-width" v-model="where.extent" :localdata="extent" placeholder="面积"
@change="onSearch"></uni-data-select>
</view>
<view class="region">
<uni-data-select class="select-width" v-model="where.sort" :localdata="sort" placeholder="排序"
@change="onSearch"></uni-data-select>
</view>
</view>
<scroll-view :scroll-top="scrollTop" scroll-y="true" class="scroll-Y" @scrolltoupper="upper"
@scrolltolower="lower" @scroll="onScroll">
<view class="house-list">
<block v-for="(item,index) in list" :key="index">
<view class="item" @click="$push('sub_pages/house/detail?houseId=' + item.houseId)">
<image :src="item.files[0].url" mode="widthFix">
</image>
<view class="info">
<view class="title">{{ item.houseTitle }}</view>
<view class="desc"><text>{{ item.extent }}|{{ item.toward }}</text></view>
<view class="price">{{ item.rent }}/</view>
</view>
</view>
</block>
<u-empty mode="data" icon="http://cdn.uviewui.com/uview/empty/data.png" v-if="list.length == 0">
</u-empty>
<!-- <view class="item">
<image src="https://file.wsdns.cn/20230802/8bf0658596ab458d94666cbf4b1177e9.jpg" mode="widthFix">
</image>
<view class="info">
<view class="title">整租·万科云城 2室1厅1卫整租·万科云城 2室1厅1卫整租·万科云城 2室1厅1卫</view>
<view class="desc"><text>50.8|</text></view>
<view class="price">6600/</view>
</view>
</view> -->
</view>
</scroll-view>
</view>
</template>
<script>
import * as Util from '@/utils/util.js'
import store from '@/store'
import storage from '@/utils/storage'
import * as HouseInfoApi from '@/api/house-info.js'
const menu = [{
name: '推荐',
reset: true
},
{
name: '必看房源',
reset: false
}
];
const region = [{
value: 0,
text: "青秀区"
},
{
value: 1,
text: "兴宁区"
}
];
const price = [{
value: 0,
text: "3000"
},
{
value: 1,
text: "4000"
}
];
const extent = [{
value: 0,
text: "200平"
},
{
value: 1,
text: "300平"
}
];
const sort = [{
value: 0,
text: "升序"
},
{
value: 1,
text: "降序"
}
];
const loginUserId = uni.getStorageSync('userId')
export default {
data() {
return {
list: [],
loadMore: true,
status: '加载更多',
page: 1,
where: {},
// 控制onShow事件是否刷新订单列表
canReset: false,
disabled: false,
swiperList: [
'https://file.wsdns.cn/20230802/f33f5ac239c843438b36f40941d946ef.png',
'https://file.wsdns.cn/20230802/1116a02b07904991b2ebdc2c3da4a691.png',
],
menu,
region,
price,
extent,
sort,
scrollTop: 0,
old: {
scrollTop: 0
},
actionStyle: {
background: '#3f72f4',
color: '#ffffff',
padding: '12rpx 0',
borderRadius: '12rpx'
},
};
},
onLoad() {
this.list = []
this.onRefreshList()
},
onShow() {},
onBackPress() {},
onUnload() {
},
onPageScroll(e) {
this.scrollTop = e.scrollTop
},
// 触底函数
onReachBottom() {
console.log("触底函数: ");
const app = this
if (app.loadMore) {
app.page = ++app.page;
app.onRefreshList()
}
},
methods: {
onRefreshList() {
const app = this
const userId = uni.getStorageSync('userId')
app.where.page = app.page
return new Promise((resolve, reject) => {
HouseInfoApi.pageHouseInfo(app.where)
.then(result => {
const list = result.data.list.map(d => {
d.files = JSON.parse(d.files) || []
return d
})
// 合并新数据
app.list = app.list.concat(list)
if (result.data.count > app.list.length) {
app.canReset = true
} else {
app.canReset = false
}
console.log("app.list: ",app.list);
resolve(list)
})
})
},
},
watch: {
}
};
</script>
<style lang="scss" scoped>
.page {
.search-fix {
width: 750rpx;
margin: auto;
display: flex;
.search {
width: 690rpx;
margin: 15rpx auto;
display: flex;
justify-content: space-between;
align-items: center;
}
}
.search-tools {
width: 700rpx;
margin: auto;
display: flex;
justify-content: space-around;
.region {
width: 170rpx;
background-color: #ffffff;
}
}
.fixed {
position: fixed;
top: 300rpx;
left: 125rpx;
}
.no-fixed {
position: absolute;
top: 0rpx;
left: 125rpx;
}
.tabs {
margin-top: 50rpx;
}
.house-list {
width: 700rpx;
margin: 20rpx auto;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.item {
margin-bottom: 40rpx;
border-radius: 20rpx;
// box-shadow: 0 3rpx 10rpx 0px #cccccc;
background-color: #ffffff;
width: 338rpx;
image {
border-radius: 20rpx 20rpx 0 0;
height: 420rpx;
width: 338rpx;
}
.info {
padding: 20rpx 20rpx;
display: flex;
flex-direction: column;
.title {
font-size: 30rpx;
text-overflow: -o-ellipsis-lastline;
overflow: hidden; //溢出内容隐藏
text-overflow: ellipsis; //文本溢出部分用省略号表示
display: -webkit-box; //特别显示模式
-webkit-line-clamp: 2; //行数
line-clamp: 2;
-webkit-box-orient: vertical; //盒子中内容竖直排列
}
.desc {
color: #999999;
font-size: 28rpx;
}
.price {
color: #ff0000;
font-size: 30rpx;
}
}
}
}
}
</style>

231
pages/index/index.vue Normal file
View File

@@ -0,0 +1,231 @@
<template>
<view class="page">
<!-- 搜索 -->
<u-sticky offset-top="5" zIndex="999">
<view class="search-fix fixed" v-if="scrollTop < 30">
<view class="search">
<view class="region">青秀区</view>
<view class="input">
<u-search placeholder="您想找哪里" bgColor="#ffffff" v-model="keyword" :animation="true"></u-search>
</view>
</view>
</view>
<view class="search-fix" v-else>
<view class="search">
<view class="region">青秀区</view>
<view class="input">
<u-search placeholder="您想找哪里" bgColor="#ffffff" v-model="keyword" :animation="true"></u-search>
</view>
</view>
</view>
</u-sticky>
<!-- 幻灯片 -->
<view class="swiper">
<u-swiper :list="swiperList" :height="180" :radius="0" @change="change" @click="click"></u-swiper>
</view>
<!-- 选项卡 -->
<view class="tabs">
<u-tabs :list="menu" @click="click"></u-tabs>
</view>
<scroll-view :scroll-top="scrollTop" scroll-y="true" class="scroll-Y" @scrolltoupper="upper"
@scrolltolower="lower" @scroll="onScroll">
<view class="house-list" v-if="list.length > 0">
<block v-for="(item,index) in list" :key="index">
<view class="item" @click="$push('sub_pages/house/detail?houseId=' + item.houseId)">
<image :src="item.files[0].url" mode="widthFix">
</image>
<view class="info">
<view class="title">{{ item.houseTitle }}</view>
<view class="desc"><text>{{ item.extent }}|{{ item.toward }}</text></view>
<view class="price">{{ item.rent }}/</view>
</view>
</view>
</block>
</view>
<u-empty mode="data" icon="http://cdn.uviewui.com/uview/empty/data.png" v-if="list.length == 0">
</u-empty>
</scroll-view>
</view>
</template>
<script>
import * as Util from '@/utils/util.js'
import store from '@/store'
import storage from '@/utils/storage'
import * as HouseInfoApi from '@/api/house-info.js'
const menu = [{
name: '推荐',
reset: true
},
{
name: '必看房源',
reset: false
}
];
const loginUserId = uni.getStorageSync('userId')
export default {
data() {
return {
list: [],
loadMore: true,
status: '加载更多',
page: 1,
where: {},
// 控制onShow事件是否刷新订单列表
canReset: false,
disabled: false,
swiperList: [
'https://file.wsdns.cn/20230802/f33f5ac239c843438b36f40941d946ef.png',
'https://file.wsdns.cn/20230802/1116a02b07904991b2ebdc2c3da4a691.png',
],
menu,
scrollTop: 0,
old: {
scrollTop: 0
}
};
},
onLoad() {
this.list = []
this.onRefreshList()
},
onShow() {},
onBackPress() {},
onUnload() {
},
onPageScroll(e) {
this.scrollTop = e.scrollTop
},
// 触底函数
onReachBottom() {
console.log("触底函数: ");
const app = this
if (app.loadMore) {
app.page = ++app.page;
app.onRefreshList()
}
},
methods: {
onRefreshList() {
const app = this
const userId = uni.getStorageSync('userId')
app.where.page = app.page
return new Promise((resolve, reject) => {
HouseInfoApi.pageHouseInfo(app.where)
.then(result => {
const list = result.data.list.map(d => {
d.files = JSON.parse(d.files) || []
return d
})
// 合并新数据
app.list = app.list.concat(list)
if (result.data.count > app.list.length) {
app.canReset = true
} else {
app.canReset = false
}
resolve(list)
})
})
},
},
watch: {
}
};
</script>
<style lang="scss" scoped>
.page {
.search-fix {
width: 500rpx;
margin: auto;
background-color: #ffffff;
display: flex;
border-radius: 100rpx;
box-shadow: 0 3rpx 10rpx 0px #cccccc;
.search {
width: 400rpx;
margin: 15rpx auto;
display: flex;
justify-content: space-between;
align-items: center;
.region {
width: 170rpx;
color: #666666;
font-size: 28rpx;
}
}
}
.fixed {
position: fixed;
top: 300rpx;
left: 125rpx;
}
.no-fixed {
position: absolute;
top: 0rpx;
left: 125rpx;
}
.tabs {
margin-top: 80rpx;
}
.house-list {
width: 700rpx;
margin: 20rpx auto;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.item {
margin-bottom: 40rpx;
border-radius: 20rpx;
// box-shadow: 0 3rpx 10rpx 0px #cccccc;
background-color: #ffffff;
width: 338rpx;
image {
border-radius: 20rpx 20rpx 0 0;
height: 420rpx;
width: 338rpx;
}
.info {
padding: 20rpx 20rpx;
display: flex;
flex-direction: column;
.title {
font-size: 30rpx;
text-overflow: -o-ellipsis-lastline;
overflow: hidden; //溢出内容隐藏
text-overflow: ellipsis; //文本溢出部分用省略号表示
display: -webkit-box; //特别显示模式
-webkit-line-clamp: 2; //行数
line-clamp: 2;
-webkit-box-orient: vertical; //盒子中内容竖直排列
}
.desc {
color: #999999;
font-size: 28rpx;
}
.price {
color: #ff0000;
font-size: 30rpx;
}
}
}
}
}
</style>

456
pages/login/components/main.vue Executable file
View File

@@ -0,0 +1,456 @@
<template>
<view class="container">
<!-- 页面头部 -->
<view class="header">
<!-- <view class="title">
<text>账号登录</text>
</view> -->
<view class="logo">
<image src="https://file.wsdns.cn/20230801/84480e0c65b044ebb869f8f2754bc0b1.png" mode="widthFix"></image>
</view>
<!-- <view class="sub-title">
<text>未注册的手机号登录后将自动注册</text>
</view> -->
</view>
<!-- 表单 -->
<!-- #ifdef H5 -->
<view class="login-form">
<!-- 手机号 -->
<view class="form-item">
<input class="form-item--input" type="text" v-model="mobile" maxlength="20"
placeholder="请输入登录账号|手机号码|邮箱" />
</view>
<view class="form-item">
<input class="form-item--input" type="password" v-model="password" maxlength="30"
placeholder="请输入登录密码" />
</view>
<!-- 图形验证码 -->
<view class="form-item" style="display: none;">
<input class="form-item--input" type="text" v-model="captchaCode" maxlength="5"
placeholder="请输入图形验证码" />
<view class="form-item--parts">
<view class="captcha" @click="getCaptcha()">
<image class="image" :src="captcha.base64"></image>
</view>
</view>
</view>
<!-- 短信验证码 -->
<view class="form-item" style="display: none;">
<input class="form-item--input" type="number" v-model="smsCode" maxlength="6" placeholder="请输入短信验证码" />
<view class="form-item--parts">
<view class="captcha-sms" @click="handelSmsCaptcha()">
<text v-if="!smsState" class="activate">获取验证码</text>
<text v-else class="un-activate">重新发送({{ times }})</text>
</view>
</view>
</view>
<!-- 登录按钮 -->
<view class="login-button" @click="handleLogin">
<text>立即登录 找对象</text>
</view>
<view class="agree">
<view class="item">
<radio value="index" :checked="disabled" @click="onRadio" />已阅读并同意以下协议
<view class="xieyi" @click="$push('pages/article/detail/detail?id=114')">服务协议</view>
<view class="xieyi" @click="$push('pages/article/detail/detail?id=115')">隐私政策</view>
</view>
</view>
<!-- 企业微信授权登录 -->
<!-- <view class="login-button-ww" @click="onWWLogin">
<image src="@/static/login-wx-work.png"></image>
</view> -->
</view>
<!-- #endif -->
<!-- 微信授权手机号一键登录 -->
<!-- #ifdef MP-WEIXIN -->
<MpWeixinMobile :isParty="isParty" :partyData="partyData" />
<!-- #endif -->
<!-- <div id="ww_login" style="width: 100%; height: 100%"></div> -->
</view>
</template>
<script>
import store from '@/store'
import storage from '@/utils/storage'
import {
ACCESS_TOKEN,
USER_ID,
} from '@/store/mutation-types'
import {
appId,
tenantId
} from '@/config.js'
import {
getCaptcha,
login,
sendSmsCaptcha
} from '@/api/login.js'
import * as Verify from '@/utils/verify'
import http from '@/api'
import MpWeixinMobile from './mp-weixin-mobile'
// 倒计时时长(秒)
const times = 60
// 表单验证场景
const GET_CAPTCHA = 10
const SUBMIT_LOGIN = 20
export default {
components: {
MpWeixinMobile
},
props: {
// 是否存在第三方用户信息
isParty: {
type: Boolean,
default: () => false
},
// 第三方用户信息数据
partyData: {
type: Object
}
},
data() {
return {
// 正在加载
isLoading: false,
// 图形验证码信息
captcha: {},
// 短信验证码发送状态
smsState: false,
// 倒计时
times,
// 手机号
mobile: '',
password: '',
// 图形验证码
captchaCode: '',
// 短信验证码
smsCode: '',
disabled: false
}
},
/**
* 生命周期函数--监听页面加载
*/
created() {
// 获取图形验证码
this.getCaptcha()
},
methods: {
openXieyi(url){
console.log("url: ",url);
this.$navTo(url)
},
// 获取图形验证码
getCaptcha() {
const app = this
getCaptcha()
.then(result => app.captcha = result.data)
},
// 点击发送短信验证码
handelSmsCaptcha() {
const app = this
if (!app.isLoading && !app.smsState && app.formValidation(GET_CAPTCHA)) {
app.sendSmsCaptcha()
}
},
// 表单验证
formValidation(scene = GET_CAPTCHA) {
const app = this
// 验证获取短信验证码
if (scene === GET_CAPTCHA) {
if (!app.validteMobile(app.mobile) || !app.validteCaptchaCode(app.captchaCode)) {
return false
}
}
// 验证提交登录
if (scene === SUBMIT_LOGIN) {
if (!app.validteMobile(app.mobile) || !app.validteSmsCode(app.smsCode)) {
return false
}
}
return true
},
// 验证手机号
validteMobile(str) {
if (Verify.isEmpty(str)) {
this.$toast('请先输入手机号')
return false
}
if (!Verify.isMobile(str)) {
// this.$toast('请输入正确格式的手机号')
// return false
}
return true
},
// 验证图形验证码
validteCaptchaCode(str) {
if (Verify.isEmpty(str)) {
this.$toast('请先输入图形验证码')
return false
}
return true
},
// 验证短信验证码
validteSmsCode(str) {
if (Verify.isEmpty(str)) {
// this.$toast('请先输入短信验证码')
// return false
}
return true
},
onRadio(){
this.disabled = !this.disabled
},
// 请求发送短信验证码接口
sendSmsCaptcha() {
const app = this
app.isLoading = true
sendSmsCaptcha({
phone: app.mobile
})
.then(result => {
// 显示发送成功
app.$toast(result.message)
// 执行定时器
app.timer()
})
.catch(() => app.getCaptcha())
.finally(() => app.isLoading = false)
},
// 执行定时器
timer() {
const app = this
app.smsState = true
const inter = setInterval(() => {
app.times = app.times - 1
if (app.times <= 0) {
app.smsState = false
app.times = times
clearInterval(inter)
}
}, 1000)
},
// 点击登录
handleLogin() {
const app = this
if (!app.isLoading && app.formValidation(SUBMIT_LOGIN)) {
app.submitLogin()
}
},
// 确认登录
submitLogin() {
const app = this
app.isLoading = true
console.log("登录: ", '登录');
store.dispatch('Login', {
username: app.mobile,
password: app.password
})
.then(result => {
// 一键登录成功
app.$toast(result.message)
// 跳转回原页面
setTimeout(() => {
uni.reLaunch({
url: '/pages/index/index',
complete(res) {
console.log(res)
}
})
}, 1000)
// // 显示登录成功
// app.$toast(result.message)
// // 跳转回原页面
// uni.redirectTo({
// url: 'pages/user/user'
// })
// setTimeout(() => {
// app.onNavigateBack(1)
// }, 2000)
})
.catch(err => {
// 跳转回原页面
if (err.result.data.isBack) {
setTimeout(() => app.onNavigateBack(1), 2000)
}
})
.finally(() => app.isLoading = false)
},
/**
* 登录成功-跳转回原页面
*/
onNavigateBack(delta = 1) {
const pages = getCurrentPages()
if (pages.length > 1) {
uni.navigateBack({
delta: Number(delta || 1)
})
} else {
this.$navTo('pages/index/index')
}
},
onWWLogin() {
}
}
}
</script>
<style lang="scss" scoped>
.container {
min-height: 80vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
// 页面头部
.header {
margin-bottom: 5rpx;
.title {
color: #191919;
font-size: 54rpx;
}
.sub-title {
margin-top: 20rpx;
color: #b3b3b3;
font-size: 28rpx;
}
}
// 输入框元素
.form-item {
display: flex;
padding: 18rpx;
border-bottom: 1rpx solid #f3f1f2;
margin-bottom: 30rpx;
height: 96rpx;
&--input {
font-size: 28rpx;
letter-spacing: 1rpx;
flex: 1;
height: 100%;
}
&--parts {
min-width: 100rpx;
height: 100%;
}
// 图形验证码
.captcha {
height: 100%;
.image {
display: block;
width: 192rpx;
height: 100%;
}
}
// 短信验证码
.captcha-sms {
font-size: 28rpx;
line-height: 50rpx;
padding-right: 20rpx;
.activate {
color: $main-bg;
}
.un-activate {
color: #9e9e9e;
}
}
}
.logo {
display: flex;
justify-content: center;
width: 180rpx;
height: 180rpx;
overflow: hidden;
border-radius: 20rpx;
margin: auto;
image {
width: 180rpx;
}
}
// 登录按钮
.login-button {
width: 100%;
height: 86rpx;
margin-top: 80rpx;
background: linear-gradient(#ff0077, #4d0d68);
// background: url('data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%221%22%20x1%3D%220%22%20x2%3D%221%22%20y1%3D%220%22%20y2%3D%220%22%20gradientTransform%3D%22matrix(6.123233995736766e-17%2C%201%2C%20-0.024693877551020406%2C%206.123233995736766e-17%2C%200.5%2C%200)%22%3E%3Cstop%20stop-color%3D%22%230a060d%22%20stop-opacity%3D%221%22%20offset%3D%220%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23660061%22%20stop-opacity%3D%221%22%20offset%3D%220.95%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22url(%231)%22%3E%3C%2Frect%3E%3C%2Fsvg%3E');
color: $main-text;
border-radius: 80rpx;
box-shadow: 0px 10px 20px 0px rgba(0, 0, 0, 0.1);
letter-spacing: 5rpx;
display: flex;
justify-content: center;
align-items: center;
}
.login-button-ww {
margin-top: 80rpx;
display: flex;
justify-content: center;
image {
height: 96rpx;
}
}
.agree{
text-align: center;
width: 750rpx;
color: rgba(75,13,99,1);
.item{
display: flex;
align-items: center;
justify-content: center;
image{
width: 30rpx;
height: 30rpx;
margin-right: 10rpx;
}
.xieyi{
text-decoration:underline;
}
}
}
</style>

View File

@@ -0,0 +1,312 @@
<template>
<view class="weixin-login">
<!-- 微信授权手机号一键登录 -->
<view class="wechat-auth agree">
<button class="btn-normal" v-if="!disabled" @click="onAgree">
<view class="wechat-auth-container">
<!-- <image class="icon" src="../../../static/channel/wechat.png"></image> -->
<text class="title">手机号快捷登录</text>
</view>
</button>
<button v-else class="btn-normal" open-type="getPhoneNumber"
@getphonenumber="handelMpWeixinMobileLogin($event)" @click="clickPhoneNumber">
<view class="wechat-auth-container">
<!-- <image class="icon" src="../../../static/channel/wechat.png"></image> -->
<text class="title">手机号快捷登录</text>
</view>
</button>
</view>
<view class="agree-text" @click="onRadio">
<view class="item">
<!-- <image src="../../../static/icon/g.svg"></image> -->
<label>
<radio value="index" :checked="disabled" />已阅读并同意
</label>
<view class="xieyi" @click.stop="$push('pages/article/detail/detail?id=114')">服务协议</view>
<view class="xieyi" @click.stop="$push('pages/article/detail/detail?id=115')">隐私政策</view>
</view>
</view>
<u-popup :show="showAgree" mode="center" :round="10" :closeable="true" @close="showAgree = false">
<view class="offline">
<view class="head">
<view class="info">
<text class="title">请阅读并同意用户协议隐私政策</text>
</view>
</view>
</view>
</u-popup>
</view>
</template>
<script>
import store from '@/store'
import storage from '@/utils/storage'
import {
isEmpty,
inArray
} from '@/utils/util'
export default {
props: {
// 是否存在第三方用户信息
isParty: {
type: Boolean,
default: () => false
},
// 第三方用户信息数据
partyData: {
type: Object
}
},
data() {
return {
// 微信小程序登录凭证 (code)
// 提交到后端用于换取openid
code: '',
disabled: false,
showAgree: false
}
},
methods: {
// 按钮点击事件: 获取微信手机号按钮
// 实现目的: 在getphonenumber事件触发之前获取微信登录code
// 因为如果在getphonenumber事件中获取code的话,提交到后端的encryptedData会存在解密不了的情况
async clickPhoneNumber() {
this.code = await this.getCode()
},
// 微信授权获取手机号一键登录
// getphonenumber事件的回调方法
async handelMpWeixinMobileLogin(e) {
const {
detail
} = e;
const app = this
if (detail.errMsg != 'getPhoneNumber:ok') {
console.log('微信授权获取手机号失败', detail.errMsg)
// app.$error(detail.errMsg)
return
}
if (detail.errMsg == 'getPhoneNumber:ok') {
app.isLoading = true
store.dispatch('LoginMpWxMobile', {
code: detail.code,
encryptedData: detail.encryptedData,
iv: detail.iv,
isParty: app.isParty,
partyData: app.partyData,
refereeId: Number(storage.get('refereeId'))
})
.then(result => {
console.log("result: ", result);
// 显示登录成功
app.$toast(result.message)
// 跳转回原页面
setTimeout(() => {
uni.reLaunch({
url: '/pages/index/index',
complete(res) {
console.log(res)
}
})
}, 1000)
})
.catch(err => {
console.log("err: ", err);
// const resultData = err.result.data
// 显示错误信息
app.$error(err.message)
// if (isEmpty(resultData)) {
// app.$toast(err.result.message)
// }
// 跳转回原页面
// if (resultData.isBack) {
// setTimeout(() => app.onNavigateBack(1), 2000)
// }
})
.finally(() => app.isLoading = false)
}
},
onRadio() {
this.disabled = !this.disabled
},
// 获取微信登录的code
// https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html
getCode() {
return new Promise((resolve, reject) => {
uni.login({
provider: 'weixin',
success: res => {
console.log('code', res.code)
resolve(res.code)
},
fail: reject
})
})
},
iAgree() {
this.disabled = !this.disabled
this.showAgree = false
},
onAgree() {
this.$error('请阅读并同意(勾选)《用户协议》《隐私政策》')
},
/**
* 登录成功-跳转回原页面
*/
onNavigateBack(delta = 1) {
const pages = getCurrentPages()
if (pages.length > 1) {
uni.navigateBack({
delta: Number(delta || 1)
})
} else {
this.$navTo('pages/index/index')
}
}
}
}
</script>
<style lang="scss" scoped>
.agree {
background: linear-gradient(#27b0fd, #3f72f4);
// background: url('data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%221%22%20x1%3D%220%22%20x2%3D%221%22%20y1%3D%220%22%20y2%3D%220%22%20gradientTransform%3D%22matrix(6.123233995736766e-17%2C%201%2C%20-0.024693877551020406%2C%206.123233995736766e-17%2C%200.5%2C%200)%22%3E%3Cstop%20stop-color%3D%22%230a060d%22%20stop-opacity%3D%221%22%20offset%3D%220%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23660061%22%20stop-opacity%3D%221%22%20offset%3D%220.95%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22url(%231)%22%3E%3C%2Frect%3E%3C%2Fsvg%3E');
}
// 微信授权登录
.wechat-auth {
width: 600rpx;
height: 86rpx;
margin: 100rpx auto 50rpx auto;
color: $main-text;
border-radius: 12rpx;
box-shadow: 0px 10px 20px 0px rgba(0, 0, 0, 0.1);
letter-spacing: 5rpx;
display: flex;
justify-content: center;
align-items: center;
.btn-normal {
width: 580rpx;
}
.btn-normal-no {
width: 580rpx;
}
button {
background: none !important;
}
.wechat-auth-container {
display: flex;
justify-content: center;
display: flex;
align-items: center;
color: $main-text;
background: none !important;
.title {
color: #f3f3f3;
}
}
// 登录按钮
.login-button {
width: 100%;
height: 86rpx;
margin-top: 80rpx;
background: linear-gradient(#ff0077, #4d0d68);
// background: url('data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%221%22%20x1%3D%220%22%20x2%3D%221%22%20y1%3D%220%22%20y2%3D%220%22%20gradientTransform%3D%22matrix(6.123233995736766e-17%2C%201%2C%20-0.024693877551020406%2C%206.123233995736766e-17%2C%200.5%2C%200)%22%3E%3Cstop%20stop-color%3D%22%230a060d%22%20stop-opacity%3D%221%22%20offset%3D%220%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23660061%22%20stop-opacity%3D%221%22%20offset%3D%220.95%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22url(%231)%22%3E%3C%2Frect%3E%3C%2Fsvg%3E');
color: $main-text;
border-radius: 80rpx;
box-shadow: 0px 10px 20px 0px rgba(0, 0, 0, 0.1);
letter-spacing: 5rpx;
display: flex;
justify-content: center;
align-items: center;
}
.icon {
width: 38rpx;
height: 38rpx;
margin-right: 15rpx;
}
.title {
font-size: 28rpx;
color: #666666;
}
}
.offline {
border-radius: 20rpx;
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
height: 120rpx;
line-height: 120rpx;
padding: 30rpx;
.head {
padding-top: 10rpx;
width: 600rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
.title {
font-size: 28rpx;
font-weight: 600;
}
.sub-title {
padding-top: 8rpx;
padding-left: 40rpx;
color: #3f72f4;
font-size: 26rpx;
}
}
.desc {
color: #3f72f4;
display: flex;
font-size: 26rpx;
line-height: 3rem;
}
}
.agree-text {
text-align: center;
width: 750rpx;
font-size: 26rpx;
.item {
display: flex;
align-items: center;
justify-content: center;
image {
width: 30rpx;
height: 30rpx;
margin-right: 10rpx;
}
.xieyi {
color: #3f72f4;
// text-decoration:underline;
}
}
}
</style>

View File

@@ -0,0 +1,243 @@
<template>
<view class="container">
<view class="wechatapp">
<view class="header">
<!-- <open-data class="avatar" type="userAvatarUrl"></open-data> -->
<image class="image"
:src="storeInfo && storeInfo.image_url ? storeInfo.image_url : '/static/default-avatar.png'"></image>
</view>
</view>
<view class="auth-title">申请获取以下权限</view>
<view class="auth-subtitle">获得你的公开信息昵称头像等</view>
<view class="login-btn">
<!-- 获取微信用户信息 -->
<button class="button btn-normal" @click.stop="getUserProfile">授权登录</button>
</view>
<view class="no-login-btn">
<button class="button btn-normal" @click="handleCancel">暂不登录</button>
</view>
</view>
</template>
<script>
import store from '@/store'
import { isEmpty } from '@/utils/util'
import SettingModel from '@/common/model/Setting'
export default {
data() {
return {
// 商城基本信息
storeInfo: undefined,
// 微信小程序登录凭证 (code)
// 提交到后端用于换取openid
code: ''
}
},
created() {
// 获取商城基本信息
this.getStoreInfo()
},
methods: {
// 获取商城基本信息
getStoreInfo() {
SettingModel.item('store').then(store => this.storeInfo = store)
// SettingModel.h5Url(true)
},
// 获取code
// https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html
getCode() {
return new Promise((resolve, reject) => {
uni.login({
provider: 'weixin',
success: res => {
console.log('code', res.code)
resolve(res.code)
},
fail: reject
})
})
},
// 获取微信用户信息(新版)
getUserProfile() {
const app = this
wx.canIUse('getUserProfile') && wx.getUserProfile({
lang: 'zh_CN',
desc: '获取用户相关信息',
success({ userInfo }) {
console.log('用户同意了授权')
console.log('userInfo', userInfo)
// 授权成功事件
app.onAuthSuccess(userInfo)
},
fail() {
console.log('用户拒绝了授权')
}
})
},
// 授权成功事件
// 这里分为两个逻辑:
// 1.将code和userInfo提交到后端如果存在该用户 则实现自动登录,无需再填写手机号
// 2.如果不存在该用户, 则显示注册页面, 需填写手机号
// 3.如果后端报错了, 则显示错误信息
async onAuthSuccess(userInfo) {
const app = this
// 提交到后端
store.dispatch('LoginMpWx', {
partyData: {
code: await app.getCode(),
oauth: 'MP-WEIXIN',
userInfo
},
refereeId: store.getters.refereeId
})
.then(result => {
// 一键登录成功
app.$toast(result.message)
// 跳转回原页面
setTimeout(() => {
uni.reLaunch({
url: 'pages/index/index'
})
}, 1000)
// setTimeout(() => {
// app.$navTo('pages/user/user')
// }, 2000)
})
.catch(err => {
const resultData = err.result.data
// 显示错误信息
if (isEmpty(resultData)) {
app.$toast(err.result.message)
}
// 跳转回原页面
if (resultData.isBack) {
setTimeout(() => app.onNavigateBack(1), 2000)
}
// 判断还需绑定手机号
if (resultData.isBindMobile) {
app.onEmitSuccess(userInfo)
}
})
},
// 将oauth提交给父级
// 这里要重新获取code, 因为上一次获取的code不能复用(会报错)
async onEmitSuccess(userInfo) {
const app = this
app.$emit('success', {
oauth: 'MP-WEIXIN', // 第三方登录类型: MP-WEIXIN
code: await app.getCode(), // 微信登录的code, 用于换取openid
userInfo // 微信用户信息
})
},
/**
* 暂不登录
*/
handleCancel() {
// 跳转回原页面
this.onNavigateBack()
},
/**
* 登录成功-跳转回原页面
*/
onNavigateBack(delta = 1) {
const pages = getCurrentPages()
if (pages.length > 1) {
uni.navigateBack({
delta: Number(delta || 1)
})
} else {
this.$navTo('pages/index/index')
}
}
}
}
</script>
<style lang="scss" scoped>
.container {
padding: 0 60rpx;
font-size: 32rpx;
background: #fff;
min-height: 100vh;
}
.wechatapp {
padding: 80rpx 0 48rpx;
border-bottom: 1rpx solid #e3e3e3;
margin-bottom: 72rpx;
text-align: center;
.header {
width: 190rpx;
height: 190rpx;
border: 4rpx solid #fff;
margin: 0 auto 0;
border-radius: 50%;
overflow: hidden;
box-shadow: 2rpx 0 10rpx rgba(50, 50, 50, 0.3);
.image {
display: block;
width: 100%;
height: 100%;
}
}
}
.auth-title {
color: #585858;
font-size: 34rpx;
margin-bottom: 40rpx;
}
.auth-subtitle {
color: #888;
margin-bottom: 88rpx;
font-size: 28rpx;
}
.login-btn {
padding: 0 20rpx;
.button {
height: 88rpx;
background: #04be01;
color: #fff;
font-size: 30rpx;
border-radius: 999rpx;
display: flex;
justify-content: center;
align-items: center;
}
}
.no-login-btn {
margin-top: 20rpx;
padding: 0 20rpx;
.button {
height: 88rpx;
background: #dfdfdf;
color: #fff;
font-size: 30rpx;
border-radius: 999rpx;
display: flex;
justify-content: center;
align-items: center;
}
}
</style>

View File

@@ -0,0 +1,124 @@
<template>
<!-- 跳转到微信授权地址 -->
</template>
<script>
import queryStringify from '@/js_sdk/queryStringify'
import store from '@/store'
import { isEmpty, urlEncode } from '@/utils/util'
import * as Api from '@/api/wxofficial'
export default {
data() {
return {
// 页面来源是否为微信回调
isCallback: false
}
},
created() {
// 处理微信回调
this.onCallback()
// 跳转到微信授权
this.redirectUrl()
},
methods: {
// 处理微信回调
onCallback() {
// 接收微信传来的参数
const wxParam = queryStringify.parse(window.location.search)
if (!isEmpty(wxParam)) {
const url = window.location.href.replace(window.location.search, '')
window.location.href = url + '?' + urlEncode(wxParam)
return
}
// 获取code参数
const query = this.$route.query
if (isEmpty(query) || !query.code) {
return
}
// 请求后端获取微信用户信息
this.isCallback = true
Api.oauthUserInfo(query.code)
.then(({ data }) => {
console.log('用户同意了授权')
console.log('userInfo', data)
// 授权成功事件
this.onAuthSuccess(data)
})
},
// 授权成功事件
// 这里分为两个逻辑:
// 1.将openid和userInfo提交到后端如果存在该用户 则实现自动登录,无需再填写手机号
// 2.如果不存在该用户, 则显示注册页面, 需填写手机号
// 3.如果后端报错了, 则显示错误信息
async onAuthSuccess({ userInfo, encryptedData, iv }) {
const app = this
// 提交到后端
store.dispatch('LoginWxOfficial', {
partyData: { oauth: 'H5-WEIXIN', userInfo, encryptedData, iv },
refereeId: store.getters.refereeId
})
.then(result => {
// 一键登录成功
app.$toast(result.message)
// 跳转回原页面
setTimeout(() => app.onNavigateBack(), 2000)
})
.catch(err => {
const resultData = err.result.data
// 显示错误信息
if (isEmpty(resultData)) {
app.$toast(err.result.message)
}
// 判断还需绑定手机号
if (resultData.isBindMobile) {
app.onEmitSuccess({ userInfo, encryptedData, iv })
}
})
},
// 跳转到微信授权
redirectUrl() {
if (this.isCallback) {
return
}
const callbackUrl = window.location.href
Api.oauthUrl(callbackUrl)
.then(result => {
const url = result.data.redirectUrl
window.location.href = url
})
},
// 将oauth提交给父级
async onEmitSuccess({ userInfo, encryptedData, iv }) {
this.$emit('success', {
oauth: 'H5-WEIXIN', // 第三方登录类型: H5-WEIXIN
userInfo,
encryptedData,
iv
})
},
/**
* 登录成功-跳转回原页面
*/
onNavigateBack(delta = 1) {
const pages = getCurrentPages()
if (pages.length > 1) {
uni.navigateBack({
delta: Number(delta || 1)
})
} else {
this.$navTo('pages/index/index')
}
}
}
}
</script>

102
pages/login/index.vue Executable file
View File

@@ -0,0 +1,102 @@
<template>
<view v-if="isLoad" class="login" :style="appThemeStyle">
<MpWeixin v-if="isMpWeixinAuth" @success="onGetUserInfoSuccess" />
<!-- <WxOfficial v-else-if="isWxOfficialAuth" @success="onGetUserInfoSuccess" /> -->
<Main v-else :isParty="isParty" :partyData="partyData" />
</view>
</template>
<script>
import Main from './components/main'
import MpWeixin from './components/mp-weixin'
import WxOfficial from './components/wx-official'
import SettingKeyEnum from '@/common/enum/setting/Key'
import SettingModel from '@/common/model/Setting'
export default {
components: {
Main,
MpWeixin,
WxOfficial
},
data() {
return {
// 数据加载完成 [防止在微信小程序端onLoad和view渲染同步进行]
isLoad: false,
// 注册设置 (后台设置)
setting: {},
// 是否显示微信小程序授权登录
isMpWeixinAuth: false,
// 是否显示微信公众号授权登录
isWxOfficialAuth: false,
// 是否存在第三方用户信息
isParty: false,
// 第三方用户信息数据
partyData: {}
}
},
/**
* 生命周期函数--监听页面加载
*/
async onLoad(options) {
// 获取注册设置
// await this.getRegisterSetting()
// 设置当前是否显示第三方授权登录
await this.setShowUserInfo()
// 数据加载完成
this.isLoad = true
},
methods: {
// 获取注册设置 [后台-客户端-注册设置]
async getRegisterSetting() {
await SettingModel.item(SettingKeyEnum.REGISTER.value, false)
.then(setting => this.setting = setting)
},
/**
* 设置当前是否显示第三方授权登录
* - 条件1: 只有对应的客户端显示获取用户信息按钮, 例如微信小程序、微信公众号
* - 条件2: 注册设置是否已开启该选项
*/
async setShowUserInfo() {
const app = this
// 判断当前客户端是微信小程序, 并且支持getUserProfile接口
const isMpWeixin = app.platform === 'MP-WEIXIN' && wx.canIUse('getUserProfile')
const isWxOfficial = app.platform === 'H5-WEIXIN'
// 判断是否显示第三方授权登录
app.isMpWeixinAuth = isMpWeixin && app.setting.isOauthMpweixin
app.isWxOfficialAuth = isWxOfficial && app.setting.isOauthWxofficial
},
// 获取到用户信息的回调函数
onGetUserInfoSuccess(result) {
// 记录第三方用户信息数据
this.partyData = result
// 显示注册页面
this.onShowRegister()
},
// 显示注册页面
onShowRegister() {
// 是否显示微信小程序授权登录
if (this.partyData.oauth === 'MP-WEIXIN') {
this.isMpWeixinAuth = false
}
// 是否显示微信小程序授权登录
if (this.partyData.oauth === 'H5-WEIXIN') {
this.isWxOfficialAuth = false
}
// 已获取到了第三方用户信息
this.isParty = true
}
}
}
</script>
<style lang="scss" scoped>
</style>

1039
pages/love/category.vue Normal file

File diff suppressed because it is too large Load Diff

711
pages/love/love copy.vue Normal file
View File

@@ -0,0 +1,711 @@
<template>
<view class="container">
<view class="page-bg"></view>
<view class="release" @click="navTo('sub_pages/love/release/release')">
<image src="../../static/icon/add5.png" mode="widthFix"></image>
</view>
<view :style="'margin-top: ' + statusBarHeight + 'px'"></view>
<view class="header" :style="'margin-top: ' + statusBarHeight + 'px'">
<view class="pair">
<view class="search" @click="navTo('pages/search/index')">
<image src="../../static/icon/search2.png" mode="widthFix"></image>
</view>
<view class="pair-btn" @click="navTo('pages/search/index')">
<image src="../../static/icon/screen.png" mode="widthFix"></image>
</view>
</view>
<view class="menu">
<u-tabs
:list="menu"
lineColor="#AD1384"
:activeStyle="{
color: '#ffffff',
fontWeight: 'bold',
transform: 'scale(1.05)'
}"
@click="onTabs"
>
</u-tabs>
</view>
</view>
<view class="header-box"></view>
<view class="comment-box">
<view class="comment">
<view class="item" v-for="(item,index) in list" :key="index">
<view class="avatar" @click="$push('sub_pages/member/detail/detail',{userId:item.userId})">
<view class="icon">
<image :src="item.userAvatar" mode="widthFix"></image>
</view>
</view>
<view class="info">
<view class="head">
<view class="title">
<view class="nickname">{{ item.nickname }}</view>
<view class="date-time">{{ new Date(item.createTime).getTime() | timeFrom }}</view>
</view>
<view v-if="item.follow" class="unfollow-btn">
<text>已关注</text>
</view>
<view v-else class="follow-btn" @click="onFollow(item.userId,index)">
<!-- <image src="../../static/icon/follow.png" mode="widthFix"></image> -->
<u-icon name="heart" color="#ffffff" :size="15"></u-icon>
<text>关注</text>
</view>
</view>
<view class="desc">
<mp-html :content="item.content" />
<!-- <text>有没有小姐姐想今年结婚的呀我们可以私聊希望有人可以与我共黄昏有人问我粥可温...</text> -->
</view>
<view v-if="item.video" class="video">
<video id="myVideo" :src="item.video" @error="videoErrorCallback"></video>
</view>
<view v-else class="image">
<u-album :urls="item.files" keyName="thumb" multipleMode="widthFix"></u-album>
</view>
<view class="comment-btn">
<view class="zan" v-if="item.liked == 0" @click="onLikes(item,index)">
<u-icon name="thumb-up" :size="20"></u-icon>
<text>{{ item.likes }}</text>
</view>
<view class="zan" v-else @click="onLikes(item,index)">
<u-icon name="thumb-up" color="#8b004c" :size="20"></u-icon>
<text class="active">{{ item.likes }}</text>
</view>
<view class="comment2" @click="openComment(item,index)" >
<u-icon name="chat" :size="20"></u-icon>
<!-- <image src="../../static/icon/comment2.png" mode="widthFix"></image> -->
<text>{{ item.commentNumbers }}</text>
</view>
</view>
</view>
</view>
<u-empty
v-if="!list && list.length == 0"
mode="list"
icon="http://cdn.uviewui.com/uview/empty/list.png"
>
</u-empty>
</view>
</view>
<u-loadmore :status="loading" />
<u-gap height="5"></u-gap>
<u-popup :show="showComment" mode="bottom" :round="10" :closeable="true" @close="closeComment">
<view class="comment-popup">
<view class="head">
<text class="title">{{ countComment }}条评论</text>
</view>
<view class="user-list">
<u-list :height="300" @scrolltolower="scrolltolower">
<view class="list">
<u-list-item v-for="(item, index) in comment" :key="index">
<u-cell>
<view slot="title" class="nickname">
{{ item.nickname }}
</view>
<view slot="icon" :iconStyle="iconStyle" class="avatar2">
<u-avatar size="50" :src="item.avatar"
customStyle="margin: -3px 5px -3px 0"
@click="$push('sub_pages/member/detail/detail',{userId: item.userId})"></u-avatar>
</view>
<view slot="label">
<rich-text class="content" :nodes="item.content"></rich-text>
<view class="fans">{{ new Date(item.createTime).getTime() | timeFrom }}</view>
</view>
<view slot="right-icon">
</view>
</u-cell>
</u-list-item>
<u-empty
v-if="comment.length == 0"
mode="message"
icon="http://cdn.uviewui.com/uview/empty/message.png"
>
</u-empty>
</view>
</u-list>
</view>
<view class="footer">
<u-search :showAction="true" placeholder="发表评论" searchIcon="chat" actionText="发表" v-model="form.content" :actionStyle="actionStyle" @custom="onSend()"></u-search>
<!-- <view class="btn-wrapper">
<u-button text="发送" color="linear-gradient(to bottom, #010002, #681752)" :disabled="disabled"
shape="circle" @click="$push('pages/checkout/checkout')"></u-button>
</view> -->
</view>
</view>
</u-popup>
</view>
</template>
<script>
import store from '@/store/index.js'
import * as UserApi from '@/api/user.js'
import * as ArticleApi from '@/api/article.js'
import * as ArticleLikeApi from '@/api/article-like.js'
import * as ArticleCommentApi from '@/api/article-comment.js'
import * as UserFollowApi from '@/api/user-follow.js'
import * as Config from '@/config.js';
const pageSize = 10
const userId = uni.getStorageSync('userId')
const menu = [{
name: '最新'
},
{
name: '同城'
},
{
name: '关注'
}
]
import mixin from '@/core/mixins/tabbar'
export default {
mixins: [mixin],
data() {
return {
options: null,
list: [], // 文章列表
comment: [], // 文章评论列表
menu,
curTab: 0,
danmuList: [{
text: '好可爱嗷~~',
color: '#ff0000',
time: 1
},
{
text: 'かわゆい',
color: '#ff00ff',
time: 3
}
],
actionStyle: {
background: '#8b004c',
color: '#ffffff',
padding: '12rpx 16rpx',
borderRadius: '50rpx'
},
iconStyle: {
background: '#8b004c',
},
statusBarHeight: 25,
latitude: 22.766777,
longitude: 108.375152,
scale: 10,
page: 0,
// 控制onShow事件是否刷新订单列表
canReset: false,
showComment: false,
countComment: 0,
where: {
platform: 'MP-WEIXIN'
},
form: {
articleId: 0,
content: '',
},
articleIndex: 0, // 当前评论的文章
isLogin: false,
loading: 'loading'
}
},
onLoad(options) {
const app = this
console.log("options: ",options);
app.checkLogin()
app.onRefreshList()
app.getLocation(res => {
if (res.latitude && res.longitude) {
app.latitude = res.latitude
app.longitude = res.longitude
app.scale = 16
}
})
uni.getSystemInfo({
success(data) {
if (data) {
app.statusBarHeight = data.statusBarHeight
}
}
})
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
const pages = getCurrentPages()
console.log("this.options: ",this.options);
},
// 触底函数
onReachBottom() {
const app = this
if (app.canReset) {
console.log("触底函数1: ");
app.page = ++app.page;
app.onRefreshList()
}
},
onPullDownRefresh(){
this.page = 1
this.list = []
this.onRefreshList()
uni.stopPullDownRefresh();
},
methods: {
onTabs(e){
const index = e.index
this.curTab = index
console.log("index: ",index);
},
// 刷新订单列表
onRefreshList() {
const app = this
app.where.page = app.page
app.where.loginUserId = userId
app.where.categoryId = 0
app.where.showFollow = true
return new Promise((resolve, reject) => {
ArticleApi.pageArticle(app.where)
.then(result => {
const list = result.data.list
// 图片反序列化
const newList = list.map((d, i) => {
const imgs = JSON.parse(d.files)
if (imgs) {
var files = []
imgs.map(pic => {
files.push({
thumb: pic.thumb ? pic.thumb : pic.url,
url: pic.url
})
})
}
d.files = files
return d
})
// 合并新数据
app.list = app.list.concat(newList)
if(result.data.count > app.list.length){
app.canReset = true
}else{
app.loading = 'nomore'
app.canReset = false
}
resolve(newList)
})
})
},
videoErrorCallback: function(e) {
uni.showModal({
content: e.target.errMsg,
showCancel: false
})
},
// 检查是否登录
checkLogin() {
if (!!store.getters.userId && store.getters.userId != Config.userId) {
this.isLogin = true
}
},
// 获取用户坐标
// 参考文档https://uniapp.dcloud.io/api/location/location?id=getlocation
getLocation(callback) {
const app = this
uni.getLocation({
success: callback,
fail() {
app.$toast('获取定位失败,请点击右下角按钮重新尝试定位')
app.isAuthor = false
}
})
},
// 跳转页面
navTo(url) {
if(!store.getters.userId || store.getters.userId == 1101) {
this.$navTo('pages/login/index')
return false
}
this.$navTo(url)
},
onFollow(shopId,index){
const app = this
if(!app.isLogin){
app.$push('pages/login/index')
return false
}
const status = !app.list[index].follow
app.list[index].follow = status
app.list.map((d,i) => {
if(shopId == d.userId){
app.list[i].follow = status
}
})
UserFollowApi.addFollow({shopId}).then(res => {
app.$success(res.message)
})
},
onLikes(item,index){
const app = this
const { articleId, likes, liked } = item
if(!app.isLogin){
app.$push('pages/login/index')
return false
}
ArticleLikeApi.addArticleLike({
articleId,
likes,
liked
}).then(res => {
app.list[index].liked = res.data.liked
app.list[index].likes = res.data.likes
}).catch(err => {
app.$error(err.message)
})
},
openComment(item,index){
if(!this.isLogin){
this.$push('pages/login/index')
return false
}
uni.hideTabBar()
this.comment = []
this.getComment(item.articleId)
this.form.articleId = item.articleId
this.articleIndex = index
this.showComment = true
},
closeComment(){
uni.showTabBar()
this.showComment = false
},
getComment(articleId){
const app = this
ArticleCommentApi.pageArticleComment({articleId}).then(res => {
app.countComment = res.data.count
app.comment = res.data.list
})
},
// 发表评论
onSend(){
const app = this
const { form } = this
form.countComment = app.countComment
ArticleCommentApi.addArticleComment(form).then(res => {
app.form.content = ''
app.getComment(form.articleId)
app.list[app.articleIndex].commentNumbers = res.data.commentNumbers
// app.$success(res.message)
}).catch(err => {
app.$error(err.message)
})
},
}
}
</script>
<style lang="scss" scoped>
page{
background-color: #ffffff !important;
}
.page-bg {
width: 750rpx;
/* #ifdef MP-WEIXIN */
height: calc(100rpx + var(--status-bar-height));
/* #endif */
display: block;
background-color: #0d0119;
position: fixed;
left: 0;
top: 0;
z-index: 8888;
}
.release {
position: fixed;
bottom: 120rpx;
right: 30rpx;
z-index: 9999;
overflow: hidden;
image {
width: 72rpx;
height: 72rpx;
border-radius: 100%;
background-color: #ffffff;
}
}
.header {
width: 750rpx;
position: fixed;
z-index: 9999;
top: 0;
display: flex;
justify-content: space-around;
align-items: center;
height: 88rpx;
background-color: #0d0119;
.pair {
position: absolute;
left: 30rpx;
position: absolute;
right: 30rpx;
display: flex;
.search {
image {
padding-top: 15rpx;
width: 40rpx;
height: 40rpx;
}
}
.pair-btn {
image {
margin-left: 30rpx;
padding-top: 16rpx;
width: 36rpx;
height: 36rpx;
}
}
// .pair-btn{
// margin-left: 22rpx;
// height: 50rpx;
// line-height: 50rpx;
// margin-top: 15rpx;
// padding: 6rpx 12rpx;
// color: #ffffff;
// border-radius: 10rpx;
// background: url('data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%221%22%20x1%3D%220%22%20x2%3D%221%22%20y1%3D%220%22%20y2%3D%220%22%20gradientTransform%3D%22matrix(6.123233995736766e-17%2C%201%2C%20-0.024693877551020406%2C%206.123233995736766e-17%2C%200.5%2C%200)%22%3E%3Cstop%20stop-color%3D%22%230a060d%22%20stop-opacity%3D%221%22%20offset%3D%220%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23660061%22%20stop-opacity%3D%221%22%20offset%3D%220.95%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22url(%231)%22%3E%3C%2Frect%3E%3C%2Fsvg%3E');
// }
}
.menu {
display: flex;
justify-content: center;
// font-size: 32rpx;
// font-weight: 600;
z-index: 9999;
.link {
color: #cfd1d7;
}
.curr {
color: #ffffff;
border-bottom: 5rpx solid #ffffff;
}
}
// .search{
// position: absolute;
// right: 30rpx;
// image{
// padding-top: 20rpx;
// width: 50rpx;
// height: 50rpx;
// }
// }
}
.header-box{
height: 100rpx;
}
.comment-box {
width: 750rpx;
margin: 0 auto;
.comment {
width: 700rpx;
padding: 30rpx;
background-color: #ffffff;
.item {
display: flex;
padding-bottom: 30rpx;
margin-bottom: 30rpx;
border-bottom: 2rpx solid #f3f3f3;
.avatar {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
.icon {
image {
width: 90rpx !important;
height: 90rpx !important;
border-radius: 100%;
overflow: hidden;
border: 5rpx solid #ffffff;
}
}
.add {
position: absolute;
bottom: -7rpx;
width: 40rpx;
height: 40rpx;
border-radius: 100%;
overflow: hidden;
}
}
.info {
width: 660rpx;
margin-left: 10rpx;
.head {
height: 90rpx;
display: flex;
align-items: center;
justify-content: space-between;
.title {
.nickname {
font-size: 30rpx;
font-weight: 700;
}
.date-time {
color: #9a9a9a;
font-size: 26rpx;
}
}
.follow-btn {
padding: 4rpx 20rpx;
color: #ffffff;
font-size: 26rpx;
border-radius: 50rpx;
display: flex;
margin-right: 10rpx;
background: linear-gradient(#47076b, #8d1a50);
image {
width: 24rpx;
height: 66rpx;
margin-right: 6rpx;
}
}
.unfollow-btn {
padding: 4rpx 20rpx;
color: #ffffff;
font-size: 26rpx;
border-radius: 50rpx;
margin-right: 10rpx;
background: linear-gradient(#b3b3b3, #cccccc);
image {
width: 24rpx;
height: 66rpx;
margin-right: 6rpx;
}
}
}
.image {
padding: 20rpx 0;
image {
width: 160rpx;
height: 160rpx;
margin-right: 8rpx;
}
}
.video {
padding: 20rpx 0;
max-width: 400rpx;
video {
max-width: 400rpx;
}
}
.comment-btn {
display: flex;
justify-content: flex-end;
.zan {
display: flex;
image {
width: 36rpx;
height: 36rpx;
margin-right: 10rpx;
}
}
.comment2 {
margin-left: 50rpx;
display: flex;
image {
width: 36rpx;
margin-right: 10rpx;
}
text{
padding: 0 5rpx;
}
}
.active{
color: #681752;
}
}
}
}
}
}
.comment-popup {
border-radius: 20rpx;
position: relative;
display: flex;
flex-direction: column;
width: 750rpx;
height: 780rpx;
.head{
padding: 30rpx;
text-align: center;
}
.user-list{
.list{
display: flex;
flex-direction: column;
}
.nickname{
color: #999999;
}
.avatar2{
display: flex;
height: auto;
}
.content{
padding: 20rpx 0;
}
}
.footer {
width: 700rpx;
margin: auto;
position: fixed;
left: 25rpx;
bottom: 10rpx;
padding: 20rpx 0;
}
.fans{
font-size: 26rpx;
color: #999999;
}
}
</style>

1160
pages/love/love.vue Normal file

File diff suppressed because it is too large Load Diff

393
pages/notice/notice.vue Normal file
View File

@@ -0,0 +1,393 @@
<template>
<view class="notice">
<view class="user-list">
<view class="head">
<view class="search-wrapper">
<!-- <block v-for="(item,index) in menus" :key="index">
<view class="box" @click="$push(item.path,item)">
<view class="btn">
<image :src="item.icon" mode="widthFix"></image>
</view>
<text>{{ item.title }}</text>
<u-badge max="99" absolute :offset="[-2,-5]" :value="item.value"></u-badge>
</view>
</block> -->
<view class="box" @click="$push(menus[0].path,menus[0])">
<view class="btn">
<image src="@/static/icon/notice-01.png" mode="widthFix"></image>
</view>
<text>喜欢我</text>
<u-badge max="99" absolute :offset="[-2,-5]" :value="unReadLikeMeNumber"></u-badge>
</view>
<view class="box" @click="$push(menus[1].path,menus[1])">
<view class="btn">
<image src="@/static/icon/notice-02.png" mode="widthFix"></image>
</view>
<text>我喜欢</text>
</view>
<view class="box" @click="$push(menus[2].path,menus[2])">
<view class="btn">
<image src="@/static/icon/notice-03.png" mode="widthFix"></image>
</view>
<text>评论</text>
<u-badge max="99" absolute :offset="[-2,-5]" :value="unReadCommentNumber"></u-badge>
</view>
<view class="box" @click="$push(menus[3].path,menus[3])">
<view class="btn">
<image src="@/static/icon/notice-04.png" mode="widthFix"></image>
</view>
<text>看过我</text>
<u-badge max="99" absolute :offset="[-2,-5]" :value="unReadLookNumber"></u-badge>
</view>
</view>
</view>
<u-list height="88vh" v-if="isLogin">
<view class="list">
<u-swipe-action auto-close>
<u-list-item v-for="(item, index) in conversationArr" :key="item.id">
<u-swipe-action-item
closeAfterClick
:index="item.id"
:options="options"
@click="RemoveFriend(item.friendId)"
:key="item.id"
autoClose
>
<u-cell isLink @click="onUserDetail(item)">
<view slot="title" class="nickname">
{{ item.friendInfo.nickname }}
</view>
<view slot="icon" :iconStyle="iconStyle" class="head avatar2">
<u-avatar size="50" :src="item.friendInfo.avatar" shape="square" mode="aspectFill"
customStyle="margin: -3px 5px -3px 0"></u-avatar>
<view>
<u-badge type="error" max="99" shape="circle" :absolute="true" :offset="[-8,-2]" :value="item.unRead"></u-badge>
</view>
</view>
<view slot="label">
<rich-text class="content" :nodes="item.content"></rich-text>
</view>
<view slot="right-icon">
<view class="fans">{{ new Date(item.updateTime).getTime() | timeFrom }}</view>
</view>
</u-cell>
</u-swipe-action-item>
</u-list-item>
</u-swipe-action>
<u-empty v-if="conversationArr.length == 0" mode="message" text="暂无消息"
icon="http://cdn.uviewui.com/uview/empty/message.png">
</u-empty>
</view>
</u-list>
<u-empty :marginTop="180" v-if="!isLogin" mode="permission" text="暂时还没有人和你打招呼哦!"
icon="https://file.wsdns.cn/empty/data.png">
</u-empty>
</view>
<!-- <view class="wechat-auth agree" v-if="!isLogin" >
<button class="btn-normal" @click="$push('pages/login/index')">
<view class="wechat-auth-container">
<image class="icon" src="@/static/channel/wechat.png"></image>
<text class="title">立即登录</text>
</view>
</button>
</view> -->
<u-modal showCancelButton @cancel="showIdCardModal = false" @confirm="doAuth" :show="showIdCardModal" title="完成认证我们才能开始配对聊天哦" cancelText="稍后认证" confirm-text="立即认证"></u-modal>
</view>
</template>
<script>
import store from '@/store/index.js'
import storage from '../../utils/storage'
import mixin from '@/core/mixins/tabbar'
import {
ACCESS_TOKEN,
USER_ID
} from '@/store/mutation-types'
import {
navTo
} from '@/core/app.js'
import {
mapGetters,
mapMutations,
mapActions
} from 'vuex'
const menus = [
{
index: 0,
title: '喜欢我',
icon: '../../static/icon/notice-01.png',
path: 'sub_pages/notice/fans',
value: 41,
show: false
},
{
index: 1,
title: '我喜欢',
icon: '../../static/icon/notice-02.png',
path: 'sub_pages/notice/like',
value: 0,
show: false
},
{
index: 2,
title: '评论',
icon: '../../static/icon/notice-03.png',
path: 'sub_pages/notice/comment',
value: 12,
show: false
},
{
index: 3,
title: '看过我',
icon: '../../static/icon/notice-04.png',
path: 'sub_pages/notice/look',
value: 8,
show: false
}
]
export default {
mixins: [mixin],
data() {
return {
menus,
title: '国内馆',
// 正在加载中
isLoading: false,
// 是否授权了定位权限
isAuthor: true,
// 当前选择的门店ID
selectedId: null,
// 订单列表数据
list: [],
navTo,
isLogin: true,
options: [{text: '删除',style: {backgroundColor: '#fa3534'}}],
showIdCardModal: false
}
},
onLoad() {
},
onShow() {
const userId = uni.getStorageSync('userId')
if (userId == 1101) {
this.$push('pages/login/index')
return false
}
},
methods: {
...mapMutations(['ADD_FRIEND']),
...mapActions(['RemoveFriend', 'GetUserInfo']),
onUserDetail(item) {
if(this.$store.getters.userInfo.certification != 1){
this.showIdCardModal = true
return false
}
this.ADD_FRIEND(item.friendInfo)
uni.navigateTo({
url: '/pages/chat/chat?friendId=' + item.friendInfo.userId
})
},
changeCity() {
this.$toast('切换区域')
},
doAuth(){
uni.navigateTo({
url: '/sub_pages/certification/id-card/id-card',
events: {
reload: () => {
this.GetUserInfo()
this.showIdCardModal = false
}
}
})
}
},
filters: {
formatTime(val) {
const date = new Date(val);
let today = new Date().setHours(0, 0, 0, 0);
let d = new Date(val).setHours(0, 0, 0, 0);
if (d === today) {
return uni.$u.timeFormat(date, 'hh:MM')
} else {
return uni.$u.timeFormat(date)
}
}
},
}
</script>
<style>
page{
background-color: #ffffff !important;
}
</style>
<style lang="scss" scoped>
.notice {
}
.head{
display: flex;
align-items: center;
.search-wrapper {
display: flex;
justify-content: space-around;
width: 750rpx;
padding: 25rpx 0;
border-bottom: 1rpx solid #e9ebf1;
.box {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 24rpx;
color: #666666;
text-align: center;
line-height: 30rpx;
position: relative;
.btn {
width: 70rpx;
height: 70rpx;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
image {
width: 60rpx;
}
}
}
}
}
.user-list {
.list {
display: flex;
flex-direction: column;
}
.nickname {
color: #999999;
}
.avatar2 {
display: flex;
height: auto;
position: relative;
}
.unread {
position: absolute;
min-width: 35rpx;
min-height: 35rpx;
border-radius: 35rpx;
background-color: #f56c6c;
display: flex;
justify-content: center;
align-items: center;
top: -14rpx;
right: 0;
}
.content {
padding: 20rpx 0;
font-size: 26rpx;
}
.fans {
color: #999999;
font-size: 24rpx;
font-weight: normal;
}
}
// 搜索按钮
.search-button {
width: 25%;
box-sizing: border-box;
.button {
height: 64rpx;
font-size: 28rpx;
border-radius: 0 5px 5px 0;
background: #2C71C7
}
}
.u-body-item {
align-items: stretch !important
}
.agree {
background: url('data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%221%22%20x1%3D%220%22%20x2%3D%221%22%20y1%3D%220%22%20y2%3D%220%22%20gradientTransform%3D%22matrix(6.123233995736766e-17%2C%201%2C%20-0.024693877551020406%2C%206.123233995736766e-17%2C%200.5%2C%200)%22%3E%3Cstop%20stop-color%3D%22%230a060d%22%20stop-opacity%3D%221%22%20offset%3D%220%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23660061%22%20stop-opacity%3D%221%22%20offset%3D%220.95%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22url(%231)%22%3E%3C%2Frect%3E%3C%2Fsvg%3E');
}
// 微信授权登录
.wechat-auth {
width: 600rpx;
height: 86rpx;
margin: 100rpx auto 50rpx auto;
color: $main-text;
border-radius: 80rpx;
box-shadow: 0px 10px 20px 0px rgba(0, 0, 0, 0.1);
letter-spacing: 5rpx;
display: flex;
justify-content: center;
align-items: center;
.btn-normal {
width: 580rpx;
}
.btn-normal-no {
width: 580rpx;
}
button {
background: none !important;
}
.wechat-auth-container {
display: flex;
justify-content: center;
display: flex;
align-items: center;
color: $main-text;
background: none !important;
.title {
color: #f3f3f3;
}
}
// 登录按钮
.login-button {
width: 100%;
height: 86rpx;
margin-top: 80rpx;
background: url('data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%221%22%20x1%3D%220%22%20x2%3D%221%22%20y1%3D%220%22%20y2%3D%220%22%20gradientTransform%3D%22matrix(6.123233995736766e-17%2C%201%2C%20-0.024693877551020406%2C%206.123233995736766e-17%2C%200.5%2C%200)%22%3E%3Cstop%20stop-color%3D%22%230a060d%22%20stop-opacity%3D%221%22%20offset%3D%220%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23660061%22%20stop-opacity%3D%221%22%20offset%3D%220.95%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22url(%231)%22%3E%3C%2Frect%3E%3C%2Fsvg%3E');
color: $main-text;
border-radius: 80rpx;
box-shadow: 0px 10px 20px 0px rgba(0, 0, 0, 0.1);
letter-spacing: 5rpx;
display: flex;
justify-content: center;
align-items: center;
}
.icon {
width: 38rpx;
height: 38rpx;
margin-right: 15rpx;
}
.title {
font-size: 28rpx;
color: #666666;
}
}
</style>

477
pages/order/index.vue Executable file
View File

@@ -0,0 +1,477 @@
<template>
<view class="container">
<view class="tabs">
<u-tabs :list="tabs" @click="onChangeTab" lineColor="#ff0000"></u-tabs>
</view>
<!-- 订单列表 -->
<view class="order-list" v-if="list">
<view class="order-item" v-for="(item, index) in list" :key="index">
<view class="item-top">
<view class="item-top-left">
<text class="order-time">
{{ item.planName }}
</text>
</view>
<view class="item-top-right">
<u-tag text="待支付" plain size="mini" type="warning" v-if="item.payStatus == 10"></u-tag>
<u-tag text="已支付" plain size="mini" type="success"
v-else="item.payStatus == 20 && item.receiptStatus == 10"></u-tag>
</view>
</view>
<u-divider></u-divider>
<!-- 商品列表 -->
<view class="goods-list">
<block>
<view class="goods-item">
<view class="icon">
<image :src="item.planIcon" mode="widthFix"></image>
</view>
<view class="goods-content">
<text class="goods-title">订单号{{ item.logId }}</text>
<text class="goods-title">描述{{ item.priceName }}</text>
<text class="goods-title">价格{{ item.money }}</text>
<text class="goods-title">时间{{ item.createTime }}</text>
<text class="goods-title">状态{{ item.isSettled == 1 && item.status == 0 ? '已生效' : '处理中' }}</text>
<block v-if="item.planId == 17 || item.planId == 18">
<text class="goods-title">服务门店{{ item.merchantName }}</text>
<text class="goods-title">有效期至{{ item.expirationTime }}</text>
<text class="goods-title">门店地址{{ item.address }}</text>
</block>
</view>
</view>
</block>
</view>
<u-divider></u-divider>
<!-- 订单合计 -->
<view class="order-total">
<view class="pay-btn">
<view class="btn" v-if="item.payStatus == 10">
<u-button text="立即支付" plain type="error" size="small" @click="onPay(item.logId)"></u-button>
</view>
<!-- <view class="btn" v-if="item.payStatus == 10">
<u-button text="取消订单" size="small" @click="onRemove(item.logId)"></u-button>
</view> -->
</view>
<view class="total-price">
<text>合计</text>
<text class="unit" style="color: #ff0000;"></text>
<text class="money">{{ item.money }}</text>
</view>
</view>
</view>
</view>
<u-loadmore v-if="list.length > 0" :status="status" />
<u-empty mode="order" icon="http://cdn.uviewui.com/uview/empty/car.png" v-if="list.length == 0">
</u-empty>
<u-gap height="20"></u-gap>
</view>
</template>
<script>
import store from '@/store/index.js'
import * as UserPlanLogApi from '@/api/love-user-plan-log.js'
import {
dateFormat,
getWeek
} from '@/utils/util.js'
// 每页记录数量
const pageSize = 10
// tab栏数据
const tabs = [{
name: `我的订单`,
value: 'delivery'
}]
export default {
data() {
return {
// 当前页面参数
options: {
dataType: 'all'
},
// tab栏数据
tabs,
// 当前标签索引
curTab: 0,
// 订单列表数据
list: [],
total: 0,
loadMore: true,
status: '加载更多',
page: 1,
where: {
userId: 0
},
// 选择的设备
getWeek,
dateFormat
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.onRefreshList()
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
// 触底函数
onReachBottom() {
const app = this
if (app.loadMore) {
app.page = ++app.page;
app.onRefreshList()
}
},
onPullDownRefresh() {
const app = this
app.page = 1
app.list = []
app.onRefreshList();
uni.stopPullDownRefresh();
},
methods: {
// 切换标签项
onChangeTab(e) {
const app = this
// 设置当前选中的标签
app.curTab = e.index
app.page = 1
app.list = []
// 刷新订单列表
app.onRefreshList()
},
// 刷新订单列表
onRefreshList() {
const app = this
const {
curTab
} = this
app.where.showGoodsList = true
app.where.page = app.page
app.where.payStatus = 20;
app.where.receiptStatus = 10;
app.where.agent = undefined
console.log("curTab: ",curTab);
if (curTab == 0) {
// app.where.agent = undefined
// app.where.payStatus = 20;
// app.where.receiptStatus = 10;
}
if (curTab == 1) {
app.where.agent = true
// app.where.payStatus = 20;
// app.where.receiptStatus = 10;
}
const userId = uni.getStorageSync('userId')
if(userId && userId > 0){
app.where.userId = userId
// 只查询已支付订单
UserPlanLogApi.pageUserPlanLog(app.where).then(res => {
const newList = res.data.list
if (newList.length > 0) {
app.list = app.list.concat(newList)
} else {
app.status = '没有更多了'
app.loadMore = false
}
})
}
// if (curTab == 2) {
// app.where.agent = undefined
// app.where.payStatus = 20;
// app.where.receiptStatus = 10;
// }
},
// 取消订单
onCancel(orderId) {
const app = this
uni.showModal({
title: '友情提示',
content: '确认要取消该订单吗?',
success(o) {
if (o.confirm) {
OrderApi.removeOrder(orderId)
.then(result => {
// 显示成功信息
app.$toast(result.message)
// 刷新订单列表
app.list = []
app.onRefreshList()
})
}
}
});
},
onCancelOne(item) {
const app = this
// 报餐截止时间
let date = new Date();
if (date.getHours() > 20 && date.getMinutes() > 30) {
return app.$toast('报餐截止时间')
}
OrderGoodsApi.cancelfood(item).then(res => {
app.$toast(res.message)
// 刷新订单列表
app.list = []
app.onRefreshList()
})
},
// 点击去支付
onPay(orderIds) {
this.$navTo('pages/checkout/cashier/index', {
orderIds
})
},
// 跳转到订单详情页
handleTargetDetail(orderId) {
this.$navTo('pages/order/detail', {
orderId
})
},
// 跳转到订单评价页
handleTargetComment(orderId) {
this.$navTo('pages/order/comment/index', {
orderId
})
},
getDeliveryTime(time) {
return dateFormat('YYYY-mm-dd', new Date(new Date(time).toLocaleDateString()));
}
},
}
</script>
<style lang="scss" scoped>
page{
background-color: #f3f3f3 !important;
}
.container {
width: 750rpx;
background-color: #f3f3f3;
}
.order-list {}
// 项目内容
.order-item {
padding: 30rpx;
margin: 20rpx auto 10rpx auto;
width: 660rpx;
box-shadow: 0 1rpx 5rpx 0px rgba(0, 0, 0, 0.1);
border-radius: 15rpx;
background: #fff;
}
// 项目顶部
.item-top {
display: flex;
justify-content: space-between;
font-size: 26rpx;
margin-bottom: 20rpx;
.order-time {
color: #333333;
font-size: 26rpx;
font-weight: 600;
}
.state-text {
color: $main-bg;
}
}
// 商品列表
.goods-list {
// 商品项
.goods-item {
display: flex;
margin-bottom: 20rpx;
.cancel {
width: 70rpx;
position: absolute;
top: 4rpx;
right: 0;
}
.icon {
width: 100rpx;
height: 100rpx;
border-radius: 100rpx;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
background: url('data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%221%22%20x1%3D%220%22%20x2%3D%221%22%20y1%3D%220%22%20y2%3D%220%22%20gradientTransform%3D%22matrix(6.123233995736766e-17%2C%201%2C%20-0.024693877551020406%2C%206.123233995736766e-17%2C%200.5%2C%200)%22%3E%3Cstop%20stop-color%3D%22%230a060d%22%20stop-opacity%3D%221%22%20offset%3D%220%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23660061%22%20stop-opacity%3D%221%22%20offset%3D%220.95%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22url(%231)%22%3E%3C%2Frect%3E%3C%2Fsvg%3E');
// background: linear-gradient(to bottom, #010002, #681752);
image {
width: 50rpx;
height: 50rpx;
}
}
// 商品图片
.goods-image {
width: 120rpx;
height: 90rpx;
.image {
display: block;
width: 120rpx;
height: 90rpx;
border-radius: 8rpx;
}
}
// 商品内容
.goods-content {
width: 500rpx;
padding-left: 16rpx;
padding-top: 0;
display: flex;
color: #666666;
flex-direction: column;
position: relative;
.goods-title {
font-size: 26rpx;
max-height: 76rpx;
line-height: 36rpx;
}
.goods-props {
margin-top: 14rpx;
height: 40rpx;
color: #ababab;
font-size: 24rpx;
overflow: hidden;
.goods-props-item {
display: inline-block;
margin-right: 14rpx;
padding: 4rpx 16rpx;
border-radius: 12rpx;
background-color: #F5F5F5;
width: auto;
}
}
}
// 交易信息
.goods-trade {
padding-top: 16rpx;
width: 200rpx !important;
text-align: right;
color: $uni-text-color-grey;
font-size: 26rpx;
.goods-price {
vertical-align: bottom;
margin-bottom: 16rpx;
.unit {
margin-right: -2rpx;
font-size: 24rpx;
}
}
}
}
}
// 订单合计
.order-total {
font-size: 26rpx;
vertical-align: bottom;
text-align: right;
height: 50rpx;
padding-top: 10rpx;
display: flex;
justify-content: space-between;
.pay-btn{
display: flex;
.btn{
margin-right: 16rpx;
}
}
.total-price{
display: flex;
align-items: center;
}
.unit {
margin-left: 8rpx;
margin-right: -2rpx;
font-size: 26rpx;
}
.money {
font-size: 28rpx;
color: #ff0000;
}
}
// 订单操作
.order-handle {
.btn-group {
.btn-item {
border-radius: 10rpx;
padding: 8rpx 20rpx;
margin-left: 15rpx;
font-size: 26rpx;
float: right;
color: #383838;
border: 1rpx solid #a8a8a8;
&:last-child {
margin-left: 0;
}
&.active {
color: $main-bg;
border: 1rpx solid $main-bg;
}
}
}
}
.tabs {
width: 600rpx;
margin: auto;
display: flex;
justify-content: center;
}
.yuqi-text {
color: #ff0000;
}
</style>

135
pages/pair/pair.vue Normal file
View File

@@ -0,0 +1,135 @@
<template>
<view class="pair">
<image src="https://file.wsdns.cn/20230611/de68e7b6238941ea99a9ba4869b8e7c5.jpeg" class="bg" mode="widthFix">
</image>
<view class="project">
<view class="title">精心挑选与你最匹配的异性</view>
<view class="content">
<view class="item">
<u-avatar src="https://file.wsdns.cn/20230610/6e1ad1d1947144e4968e5b9aba4647ab." mode="aspectFill" :size="60"></u-avatar>
<view class="age">27</view>
</view>
<view class="item">
<u-avatar src="https://file.wsdns.cn/20230611/cdf768b22a0543b98666daa223b51746.jpeg" mode="aspectFill" :size="60"></u-avatar>
<view class="age">27</view>
</view>
<view class="item">
<u-avatar src="https://file.wsdns.cn/20230611/cdf768b22a0543b98666daa223b51746.jpeg" mode="aspectFill" :size="60"></u-avatar>
<view class="age">27</view>
</view>
<view class="item">
<u-avatar src="https://file.wsdns.cn/20230611/cdf768b22a0543b98666daa223b51746.jpeg" mode="aspectFill" :size="60"></u-avatar>
<view class="age">27</view>
</view>
<view class="item">
<u-avatar src="https://file.wsdns.cn/20230611/cdf768b22a0543b98666daa223b51746.jpeg" mode="aspectFill" :size="60"></u-avatar>
<view class="age">27</view>
</view>
<view class="item">
<u-avatar src="https://file.wsdns.cn/20230611/cdf768b22a0543b98666daa223b51746.jpeg" mode="aspectFill" :size="60"></u-avatar>
<view class="age">27</view>
</view>
<view class="item">
<u-avatar src="https://file.wsdns.cn/20230611/cdf768b22a0543b98666daa223b51746.jpeg" mode="aspectFill" :size="60"></u-avatar>
<view class="age">27</view>
</view>
<view class="item">
<u-avatar src="https://file.wsdns.cn/20230611/cdf768b22a0543b98666daa223b51746.jpeg" mode="aspectFill" :size="60"></u-avatar>
<view class="age">27</view>
</view>
</view>
<view class="btn-wrapper">
<u-button text="换一批" color="linear-gradient(to bottom, #010002, #681752)" :disabled="disabled"
shape="circle" @click="handleSubmit()"></u-button>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
}
},
methods: {
}
}
</script>
<style lang="scss" scoped>
.pair {
.bg {
width: 750rpx;
position: fixed;
top: 0;
}
.project {
position: absolute;
left: 45rpx;
width: 660rpx;
margin: 100rpx auto;
min-height: 500rpx;
background-color: #ffffff;
border-radius: 20rpx;
.title {
text-align: center;
font-family: SourceHanSansSC;
font-weight: 700;
font-size: 38rpx;
color: rgb(0, 0, 0);
font-style: normal;
letter-spacing: 0px;
height: 50rpx;
line-height: 50rpx;
text-decoration: none;
padding: 40rpx 0;
}
}
.content{
width: 600rpx;
margin: auto;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
.item{
margin: 18rpx;
border: 5rpx solid #681752;
border-radius: 100%;
position: relative;
display: flex;
justify-content: center;
.age{
position: absolute;
bottom: -12rpx;
font-size: 22rpx;
padding: 1rpx 10rpx;
color: #ffffff;
border-radius: 10rpx;
margin-right: 10rpx;
background: linear-gradient(#47076b, #8d1a50);
}
.btn {
font-size: 26rpx;
padding: 1rpx 10rpx;
color: #ffffff;
border-radius: 10rpx;
margin-right: 10rpx;
background: linear-gradient(#47076b, #8d1a50);
}
}
}
.btn-wrapper {
width: 360rpx;
margin: 50rpx auto;
// display: flex;
// align-items: center;
padding: 0 20rpx;
}
}
</style>

434
pages/refund/apply.vue Executable file
View File

@@ -0,0 +1,434 @@
<template>
<view v-if="!isLoading" class="container" :style="appThemeStyle">
<!-- 商品详情 -->
<view class="goods-detail b-f dis-flex flex-dir-row">
<view class="left">
<image class="goods-image" :src="goods.goods_image"></image>
</view>
<view class="right dis-flex flex-box flex-dir-column flex-x-around">
<view class="goods-name">
<text class="twoline-hide">{{ goods.goods_name }}</text>
</view>
<view class="dis-flex col-9 f-24">
<view class="flex-box">
<view class="goods-props clearfix">
<view class="goods-props-item" v-for="(props, idx) in goods.goods_props" :key="idx">
<text>{{ props.value.name }}</text>
</view>
</view>
</view>
<text class="t-r">×{{ goods.total_num }}</text>
</view>
</view>
</view>
<!-- 服务类型 -->
<view class="row-service b-f m-top20">
<view class="row-title">服务类型</view>
<view class="service-switch dis-flex">
<view class="switch-item" v-for="(item, index) in RefundTypeEnum.data" :key="index" :class="{ active: formData.type == item.value }"
@click="onSwitchService(item.value)">{{ item.name }}</view>
</view>
</view>
<!-- 申请原因 -->
<view class="row-textarea b-f m-top20">
<view class="row-title">申请原因</view>
<view class="content">
<textarea class="textarea" v-model="formData.content" maxlength="2000" placeholder="请详细填写申请原因,注意保持商品的完好,建议您先与卖家沟通"
placeholderStyle="color:#ccc"></textarea>
</view>
</view>
<!-- 退款金额 -->
<view v-if="formData.type == RefundTypeEnum.RETURN.value" class="row-money b-f m-top20 dis-flex">
<view class="row-title">退款金额</view>
<view class="money col-m">{{ goods.total_pay_price }}</view>
</view>
<!-- 上传凭证 -->
<view class="row-voucher b-f m-top20">
<view class="row-title">上传凭证 (最多6张)</view>
<view class="image-list">
<!-- 图片列表 -->
<view class="image-preview" v-for="(image, imageIndex) in imageList" :key="imageIndex">
<text class="image-delete iconfont icon-shanchu" @click="deleteImage(imageIndex)"></text>
<image class="image" mode="aspectFill" :src="image.path"></image>
</view>
<!-- 上传图片 -->
<view v-if="imageList.length < maxImageLength" class="image-picker" @click="chooseImage()">
<text class="choose-icon iconfont icon-camera"></text>
<text class="choose-text">上传图片</text>
</view>
</view>
</view>
<!-- 底部操作按钮 -->
<view class="footer-fixed">
<view class="btn-wrapper">
<view class="btn-item btn-item-main" :class="{ disabled }" @click="handleSubmit()">确认提交</view>
</view>
</view>
</view>
</template>
<script>
import { RefundTypeEnum } from '@/common/enum/order/refund'
import * as UploadApi from '@/api/upload'
import * as RefundApi from '@/api/refund'
const maxImageLength = 6
export default {
data() {
return {
// 枚举类
RefundTypeEnum,
// 正在加载
isLoading: true,
// 订单商品id
orderGoodsId: null,
// 订单商品详情
goods: {},
// 表单数据
formData: {
// 图片上传成功的文件ID集
images: [],
// 服务类型
type: 10,
// 申请原因
content: ''
},
// 用户选择的图片列表
imageList: [],
// 最大图片数量
maxImageLength,
// 按钮禁用
disabled: false
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad({ orderGoodsId }) {
this.orderGoodsId = orderGoodsId
// 获取订单商品详情
this.getGoodsDetail()
},
methods: {
// 获取订单商品详情
getGoodsDetail() {
const app = this
app.isLoading = true
RefundApi.goods(app.orderGoodsId)
.then(result => {
app.goods = result.data.goods
app.isLoading = false
})
},
// 切换类型
onSwitchService(value) {
this.formData.type = value
},
// 选择图片
chooseImage() {
const app = this
const oldImageList = app.imageList
// 选择图片
uni.chooseImage({
count: maxImageLength - oldImageList.length,
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success({ tempFiles }) {
// tempFiles = [{path:'xxx', size:100}]
app.imageList = oldImageList.concat(tempFiles)
}
});
},
// 删除图片
deleteImage(imageIndex) {
this.imageList.splice(imageIndex, 1)
},
// 表单提交
handleSubmit() {
const app = this
const { imageList } = app
// 判断是否重复提交
if (app.disabled === true) return false
// 表单验证
if (!app.formData.content.trim().length) {
app.$toast('请填写申请原因')
return false
}
// 按钮禁用
app.disabled = true
// 判断是否需要上传图片
if (imageList.length > 0) {
app.uploadFile()
.then(() => app.onSubmit())
.catch(err => {
app.disabled = false
if (err.statusCode !== 0) {
app.$toast(err.errMsg)
}
console.log('err', err)
})
} else {
app.onSubmit()
}
},
// 提交到后端
onSubmit() {
const app = this
RefundApi.apply(app.orderGoodsId, app.formData)
.then(result => {
app.$toast(result.message)
setTimeout(() => {
app.disabled = false
uni.navigateBack()
}, 1500)
})
.catch(err => app.disabled = false)
},
// 上传图片
uploadFile() {
const app = this
const { imageList } = app
// 批量上传
return new Promise((resolve, reject) => {
if (imageList.length > 0) {
UploadApi.image(imageList)
.then(fileIds => {
app.formData.images = fileIds
resolve(fileIds)
})
.catch(reject)
} else {
resolve()
}
})
}
}
}
</script>
<style lang="scss" scoped>
.container {
// 设置ios刘海屏底部横线安全区域
padding-bottom: calc(constant(safe-area-inset-bottom) + 140rpx);
padding-bottom: calc(env(safe-area-inset-bottom) + 140rpx);
}
.row-title {
color: #888;
margin-bottom: 20rpx;
}
// 商品信息
.goods-detail {
padding: 24rpx 20rpx;
.left {
.goods-image {
display: block;
width: 150rpx;
height: 150rpx;
}
}
.right {
padding-left: 20rpx;
}
.goods-props {
margin-top: 14rpx;
height: 40rpx;
color: #ababab;
font-size: 24rpx;
overflow: hidden;
.goods-props-item {
display: inline-block;
margin-right: 14rpx;
padding: 4rpx 16rpx;
border-radius: 12rpx;
background-color: #F5F5F5;
width: auto;
}
}
}
/* 服务类型 */
.row-service {
padding: 24rpx 20rpx;
}
.service-switch {
.switch-item {
padding: 6rpx 30rpx;
margin-right: 25rpx;
border-radius: 10rpx;
border: 1px solid rgb(177, 177, 177);
color: #888888;
&.active {
color: $main-bg;
border: 1px solid $main-bg;
}
}
}
/* 申请原因 */
.row-textarea {
padding: 24rpx 20rpx;
.textarea {
width: 100%;
height: 220rpx;
padding: 12rpx;
border: 1rpx solid #e8e8e8;
border-radius: 5rpx;
box-sizing: border-box;
font-size: 26rpx;
}
}
/* 退款金额 */
.row-money {
padding: 24rpx 20rpx;
.row-title {
margin-bottom: 0;
margin-right: 30rpx;
}
}
// 上传凭证
.row-voucher {
padding: 24rpx 20rpx;
.image-list {
padding: 0 20rpx;
margin-top: 20rpx;
margin-bottom: -20rpx;
&:after {
clear: both;
content: " ";
display: table;
}
.image {
display: block;
width: 100%;
height: 100%;
}
.image-picker,
.image-preview {
width: 184rpx;
height: 184rpx;
margin-right: 30rpx;
margin-bottom: 30rpx;
float: left;
&:nth-child(3n+0) {
margin-right: 0;
}
}
.image-picker {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
border: 1rpx dashed #ccc;
color: #ccc;
.choose-icon {
font-size: 48rpx;
margin-bottom: 6rpx;
}
.choose-text {
font-size: 24rpx;
}
}
.image-preview {
position: relative;
.image-delete {
position: absolute;
top: -15rpx;
right: -15rpx;
height: 42rpx;
width: 42rpx;
background: rgba(0, 0, 0, 0.64);
border-radius: 50%;
color: #fff;
font-weight: bolder;
font-size: 22rpx;
z-index: 10;
display: flex;
justify-content: center;
align-items: center;
}
}
}
}
// 底部操作栏
.footer-fixed {
position: fixed;
bottom: var(--window-bottom);
left: 0;
right: 0;
z-index: 11;
// 设置ios刘海屏底部横线安全区域
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
.btn-wrapper {
height: 140rpx;
display: flex;
align-items: center;
padding: 0 20rpx;
}
.btn-item {
flex: 1;
font-size: 28rpx;
height: 80rpx;
color: #fff;
border-radius: 50rpx;
display: flex;
justify-content: center;
align-items: center;
}
.btn-item-main {
background: linear-gradient(to right, $main-bg, $main-bg2);
color: $main-text;
// 禁用按钮
&.disabled {
opacity: 0.6;
}
}
}
</style>

481
pages/refund/detail.vue Executable file
View File

@@ -0,0 +1,481 @@
<template>
<view v-if="!isLoading" class="container p-bottom" :style="appThemeStyle">
<!-- 顶部状态栏 -->
<view class="detail-header dis-flex flex-y-center">
<view class="header-backdrop">
<image class="image" src="/static/order/refund-bg.png"></image>
</view>
<view class="header-state">
<text class="f-32 col-f">{{ detail.state_text }}</text>
</view>
</view>
<!-- 商品详情 -->
<view class="detail-goods b-f m-top20 dis-flex flex-dir-row" @click="onGoodsDetail(detail.orderGoods.goods_id)">
<view class="left">
<image class="goods-image" :src="detail.orderGoods.goods_image"></image>
</view>
<view class="right dis-flex flex-box flex-dir-column flex-x-around">
<view class="goods-name">
<text class="twoline-hide">{{ detail.orderGoods.goods_name }}</text>
</view>
<view class="dis-flex col-9 f-24">
<view class="flex-box">
<view class="goods-props clearfix">
<view class="goods-props-item" v-for="(props, idx) in detail.orderGoods.goods_props" :key="idx">
<text>{{ props.value.name }}</text>
</view>
</view>
</view>
<text class="t-r">×{{ detail.orderGoods.total_num }}</text>
</view>
</view>
</view>
<!-- 商品金额 -->
<view class="detail-order b-f row-block">
<view class="item dis-flex flex-x-end flex-y-center">
<text class="">商品金额</text>
<text class="col-m">{{ detail.orderGoods.total_pay_price }}</text>
</view>
</view>
<!-- 已退款金额 -->
<view v-if="detail.status == RefundStatusEnum.COMPLETED.value && detail.type == 10"
class="detail-order b-f row-block dis-flex flex-x-end flex-y-center">
<text class="">已退款金额</text>
<text class="col-m">{{ detail.refund_money }}</text>
</view>
<!-- 售后信息 -->
<view v-if="detail.status == RefundStatusEnum.REJECTED.value" class="detail-refund b-f m-top20">
<view class="detail-refund__row dis-flex">
<view class="text">
<text>售后类型</text>
</view>
<view class="flex-box">
<text>{{ RefundTypeEnum[detail.type].name }}</text>
</view>
</view>
<view class="detail-refund__row dis-flex">
<view class="text">
<text>申请原因</text>
</view>
<view class="flex-box">
<text>{{ detail.apply_desc }}</text>
</view>
</view>
<view v-if="detail.images.length > 0" class="detail-refund__row dis-flex">
<view class="text">
<text>申请凭证</text>
</view>
<view class="image-list flex-box">
<view class="image-preview" v-for="(item, index) in detail.images" :key="index">
<image class="image" mode="aspectFill" :src="item.image_url" @click="handlePreviewImages(index)"></image>
</view>
</view>
</view>
</view>
<!-- 售后信息 -->
<view v-if="detail.status.value == 10" class="detail-refund b-f m-top20">
<view class="detail-refund__row dis-flex">
<view class="text">
<text class="col-m">拒绝原因</text>
</view>
<view class="flex-box">
<text>{{ detail.refuse_desc }}</text>
</view>
</view>
</view>
<!-- 退货物流信息 -->
<view v-if="detail.audit_status == AuditStatusEnum.REVIEWED.value && detail.is_user_send" class="detail-address b-f m-top20">
<view class="detail-address__row address-title">
<text class="col-m">退货物流信息</text>
</view>
<view class="detail-address__row address-details">
<view class="address-details__row">
<text>物流公司{{ detail.express.express_name }}</text>
</view>
<view class="address-details__row">
<text>物流单号{{ detail.express_no }}</text>
</view>
<!-- <view class="address-details__row">
<text>发货状态{{ detail.is_user_send ? '已发货' : '未发货' }}</text>
</view> -->
<view class="address-details__row">
<text>发货时间{{ detail.send_time }}</text>
</view>
</view>
</view>
<!-- 商家收货地址 -->
<view v-if="detail.audit_status == AuditStatusEnum.REVIEWED.value" class="detail-address b-f m-top20">
<view class="detail-address__row address-title">
<text class="col-m">商家退货地址</text>
</view>
<view class="detail-address__row address-details">
<view class="address-details__row">
<text>收货人{{ detail.address.name }}</text>
</view>
<view class="address-details__row">
<text>联系电话{{ detail.address.phone }}</text>
</view>
<view class="address-details__row dis-flex">
<view class="text">
<text>详细地址</text>
</view>
<view class="address flex-box">
<text class="region" v-for="(region, idx) in detail.address.region" :key="idx">{{ region }}</text>
<text class="detail">{{ detail.address.detail }}</text>
</view>
</view>
</view>
<view class="detail-address__row address-tips">
<view class="f-26 col-9">
<text>· 未与卖家协商一致情况下请勿寄到付或平邮</text>
</view>
<view class="f-26 col-9">
<text>· 请填写真实有效物流信息</text>
</view>
</view>
</view>
<!-- 填写物流信息 -->
<form v-if="detail.type == RefundTypeEnum.RETURN.value && detail.audit_status == AuditStatusEnum.REVIEWED.value && !detail.is_user_send"
@submit="onSubmit()">
<view class="detail-express b-f m-top20">
<view class="form-group dis-flex flex-y-center">
<view class="field">物流公司</view>
<view class="flex-box">
<picker mode="selector" :range="expressList" range-key="express_name" :value="expressIndex" @change="onChangeExpress">
<text v-if="expressIndex > -1">{{ expressList[expressIndex].express_name }}</text>
<text v-else class="col-80">请选择物流公司</text>
</picker>
</view>
</view>
<view class="form-group dis-flex flex-y-center">
<view class="field">物流单号</view>
<view class="flex-box">
<input class="input" v-model="formData.expressNo" placeholder="请填写物流单号"></input>
</view>
</view>
</view>
<!-- 操作按钮 -->
<view class="footer">
<view class="btn-wrapper">
<button class="btn-item btn-item-main btn-normal" :class="{ disabled }" formType="submit">确认发货</button>
</view>
</view>
</form>
</view>
</template>
<script>
import { AuditStatusEnum, RefundStatusEnum, RefundTypeEnum } from '@/common/enum/order/refund'
import * as RefundApi from '@/api/refund'
import * as ExpressApi from '@/api/express'
export default {
data() {
return {
// 枚举类
AuditStatusEnum,
RefundStatusEnum,
RefundTypeEnum,
// 正在加载
isLoading: true,
// 售后单ID
orderRefundId: null,
// 售后单详情
detail: {},
// 物流公司列表
expressList: [],
// 表单数据
formData: {
// 物流公司ID
expressId: null,
// 物流单号
expressNo: ''
},
// 选择的物流公司索引
expressIndex: -1,
// 按钮禁用
disabled: false
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad({ orderRefundId }) {
// 售后单ID
this.orderRefundId = orderRefundId
// 获取页面数据
this.getPageData()
},
methods: {
// 获取页面数据
getPageData() {
const app = this
app.isLoading = true
Promise.all([app.getRefundDetail(), app.getExpressList()])
.then(result => {
app.isLoading = false
})
},
// 获取售后单详情
getRefundDetail() {
const app = this
return new Promise((resolve, reject) => {
RefundApi.detail(app.orderRefundId)
.then(result => {
app.detail = result.data.detail
resolve()
})
.catch(reject)
})
},
// 获取物流公司列表
getExpressList() {
const app = this
return new Promise((resolve, reject) => {
ExpressApi.list()
.then(result => {
app.expressList = result.data.list
resolve()
})
.catch(reject)
})
},
// 跳转商品详情页
onGoodsDetail(goodsId) {
this.$navTo('pages/goods/detail', { goodsId })
},
// 凭证图片预览
handlePreviewImages(index) {
const { detail: { images } } = this
const imageUrls = images.map(item => item.image_url)
uni.previewImage({
current: imageUrls[index],
urls: imageUrls
})
},
// 选择物流公司
onChangeExpress(e) {
const expressIndex = e.detail.value
const { expressList } = this
this.expressIndex = expressIndex
this.formData.expressId = expressList[expressIndex].express_id
},
// 表单提交
onSubmit() {
const app = this
// 判断是否重复提交
if (app.disabled === true) return false
// 按钮禁用
app.disabled = true
// 提交到后端
RefundApi.delivery(app.orderRefundId, app.formData)
.then(result => {
app.$toast(result.message)
setTimeout(() => {
app.disabled = false
uni.navigateBack()
}, 1500)
})
.catch(err => app.disabled = false)
}
}
}
</script>
<style lang="scss" scoped>
// 顶部状态栏
.detail-header {
position: relative;
width: 100%;
height: 140rpx;
.header-backdrop {
width: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 0;
.image {
display: block;
width: 100%;
height: 140rpx;
}
}
}
.header-state {
z-index: 1;
padding: 0 50rpx;
}
/* 商品详情 */
.detail-goods {
padding: 24rpx 20rpx;
.left {
.goods-image {
display: block;
width: 150rpx;
height: 150rpx;
}
}
.right {
padding-left: 20rpx;
}
.goods-props {
margin-top: 14rpx;
height: 40rpx;
color: #ababab;
font-size: 24rpx;
overflow: hidden;
.goods-props-item {
display: inline-block;
margin-right: 14rpx;
padding: 4rpx 16rpx;
border-radius: 12rpx;
background-color: #F5F5F5;
width: auto;
}
}
}
.detail-order {
padding: 15rpx 20rpx;
font-size: 26rpx;
.item {
margin-bottom: 10rpx;
&:last-child {
margin-bottom: 0;
}
}
}
/* 售后详情 */
.detail-refund {
padding: 15rpx 20rpx;
}
.detail-refund__row {
margin: 20rpx 0;
}
/* 申请凭证 */
.image-list {
margin-bottom: -15rpx;
.image-preview {
margin: 0 15rpx 15rpx 0;
float: left;
.image {
display: block;
width: 180rpx;
height: 180rpx;
}
&:nth-child(3n+0) {
margin-right: 0;
}
}
}
/* 商家收货地址 */
.detail-address {
padding: 20rpx 34rpx;
}
.address-details {
padding: 8rpx 0;
border-bottom: 1px solid #eee;
.address-details__row {
margin: 14rpx 0;
}
}
.address-tips {
margin-top: 16rpx;
line-height: 46rpx;
}
.detail-address__row {
// margin: 18rpx 0;
}
/* 填写物流信息 */
.detail-express {
padding: 10rpx 30rpx;
}
.form-group {
height: 60rpx;
margin: 14rpx 0;
.input {
height: 100%;
font-size: 28rpx;
}
}
/* 底部操作栏 */
.footer {
margin-top: 60rpx;
.btn-wrapper {
height: 100%;
display: flex;
align-items: center;
padding: 0 20rpx;
}
.btn-item {
flex: 1;
font-size: 28rpx;
height: 80rpx;
color: #fff;
border-radius: 50rpx;
display: flex;
justify-content: center;
align-items: center;
}
.btn-item-main {
background: linear-gradient(to right, $main-bg, $main-bg2);
color: $main-text;
// 禁用按钮
&.disabled {
opacity: 0.6;
}
}
}
</style>

263
pages/refund/index.vue Executable file
View File

@@ -0,0 +1,263 @@
<template>
<view class="container" :style="appThemeStyle">
<mescroll-body ref="mescrollRef" :sticky="true" @init="mescrollInit" :down="{ native: true }" @down="downCallback" :up="upOption"
@up="upCallback">
<!-- tab栏 -->
<u-tabs :list="tabs" :is-scroll="false" :current="curTab" :active-color="appTheme.mainBg" :duration="0.2" @change="onChangeTab" />
<!-- 退款/售后单 -->
<view class="widget-list">
<view class="widget-detail" v-for="(item, index) in list.data" :key="index">
<view class="row-block dis-flex flex-y-center">
<view class="flex-box">{{ item.create_time }}</view>
<view class="flex-box t-r">
<text class="col-m">{{ item.state_text }}</text>
</view>
</view>
<view class="detail-goods row-block dis-flex" @click.stop="handleTargetDetail(item.order_refund_id)">
<view class="goods-image">
<image class="image" :src="item.orderGoods.goods_image" mode="aspectFit"></image>
</view>
<view class="goods-right flex-box">
<view class="goods-name">
<text class="twoline-hide">{{ item.orderGoods.goods_name }}</text>
</view>
<view class="goods-props clearfix">
<view class="goods-props-item" v-for="(props, idx) in item.orderGoods.goods_props" :key="idx">
<text>{{ props.value.name }}</text>
</view>
</view>
<view class="goods-num t-r">
<text class="f-26 col-8">×{{ item.orderGoods.total_num }}</text>
</view>
</view>
</view>
<view class="detail-order row-block">
<view class="item dis-flex flex-x-end flex-y-center">
<text class="">付款金额</text>
<text class="col-m">{{ item.orderGoods.total_pay_price }}</text>
</view>
</view>
<view class="detail-operate row-block dis-flex flex-x-end flex-y-center">
<view class="detail-btn btn-detail" @click.stop="handleTargetDetail(item.order_refund_id)">查看详情</view>
</view>
</view>
</view>
</mescroll-body>
</view>
</template>
<script>
import MescrollBody from '@/components/mescroll-uni/mescroll-body.vue'
import MescrollMixin from '@/components/mescroll-uni/mescroll-mixins'
import { getEmptyPaginateObj, getMoreListData } from '@/core/app'
import * as RefundApi from '@/api/refund'
// 每页记录数量
const pageSize = 15
// tab栏数据
const tabs = [{
name: '全部',
value: -1
}, {
name: '待处理',
value: 0
}]
export default {
components: {
MescrollBody
},
mixins: [MescrollMixin],
data() {
return {
// 订单列表数据
list: getEmptyPaginateObj(),
// tabs栏数据
tabs,
// 当前标签索引
curTab: 0,
// 上拉加载配置
upOption: {
// 首次自动执行
auto: true,
// 每页数据的数量; 默认10
page: { size: pageSize },
// 数量要大于2条才显示无更多数据
noMoreSize: 2,
// 空布局
empty: {
tip: '亲,暂无售后单记录'
}
},
// 控制首次触发onShow事件时不刷新列表
canReset: false,
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
this.canReset && this.onRefreshList()
this.canReset = true
},
methods: {
/**
* 上拉加载的回调 (页面初始化时也会执行一次)
* 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10
* @param {Object} page
*/
upCallback(page) {
const app = this
// 设置列表数据
app.getRefundList(page.num)
.then(list => {
const curPageLen = list.data.length
const totalSize = list.data.total
app.mescroll.endBySize(curPageLen, totalSize)
})
.catch(() => app.mescroll.endErr())
},
// 获取退款/售后单列表
getRefundList(pageNo = 1) {
const app = this
return new Promise((resolve, reject) => {
RefundApi.list({ state: app.getTabValue(), page: pageNo }, { load: false })
.then(result => {
// 合并新数据
const newList = result.data.list
app.list.data = getMoreListData(newList, app.list, pageNo)
resolve(newList)
})
})
},
// 切换标签项
onChangeTab(index) {
const app = this
// 设置当前选中的标签
app.curTab = index
// 刷新售后单列表
app.onRefreshList()
},
// 刷新订单列表
onRefreshList() {
this.list = getEmptyPaginateObj()
setTimeout(() => {
this.mescroll.resetUpScroll()
}, 120)
},
// 获取当前标签项的值
getTabValue() {
return this.tabs[this.curTab].value
},
// 跳转到售后单详情页
handleTargetDetail(orderRefundId) {
this.$navTo('pages/refund/detail', { orderRefundId })
},
}
}
</script>
<style lang="scss" scoped>
.widget-detail {
box-sizing: border-box;
background: #fff;
margin-bottom: 20rpx;
.row-block {
padding: 0 20rpx;
min-height: 70rpx;
}
.detail-goods {
padding: 20rpx;
background: #f9f9f9;
.goods-image {
margin-right: 20rpx;
.image {
display: block;
width: 200rpx;
height: 200rpx;
}
}
.goods-right {
padding: 15rpx 0;
}
.goods-name {
margin-bottom: 10rpx;
}
.goods-props {
margin-top: 14rpx;
height: 40rpx;
color: #ababab;
font-size: 24rpx;
overflow: hidden;
.goods-props-item {
display: inline-block;
margin-right: 14rpx;
padding: 4rpx 16rpx;
border-radius: 12rpx;
background-color: #F5F5F5;
width: auto;
}
}
}
.detail-operate {
padding-bottom: 20rpx;
.detail-btn {
border-radius: 4px;
border: 1rpx solid #ccc;
padding: 8rpx 20rpx;
font-size: 28rpx;
color: #555;
margin-left: 10rpx;
}
}
.detail-order {
padding: 10rpx 20rpx;
font-size: 28rpx;
height: 50rpx;
display: flex;
align-items: center;
.item {
margin-bottom: 10rpx;
&:last-child {
margin-bottom: 0;
}
}
}
}
</style>

601
pages/search/index.vue Executable file
View File

@@ -0,0 +1,601 @@
<template>
<view class="search">
<u-sticky>
<view class="search-wrapper">
<u-search color="#333333" border-color="#E8E8E8" :showAction="true" actionText="搜索" :animation="false" v-model="where.keywords"
@search="onSearch" @custom="onSearch" :actionStyle="actionStyle"></u-search>
</view>
</u-sticky>
<view class="container">
<!-- <u-picker :show="showRegion" ref="uPicker" :columns="columns" :columnData="columnData" @confirm="confirm"
@change="changeHandler" @cancel="showRegion = false"></u-picker> -->
<view class="history">
<view class="his-head">
<view class="line"></view>
<text class="title">基本条件</text>
</view>
<u-cell-group :border="false">
<u-cell title="年龄" isLink :value="where.ageMate" @click="showAgeMate = true"></u-cell>
<u-cell title="注册地址" isLink :value="regionMate" @click="onArea"></u-cell>
<u-cell title="身高" isLink :value="where.heightMate" @click="showHeightMate = true"></u-cell>
<u-cell title="体型" isLink :value="where.shapeMate" @click="showShapeMate = true"></u-cell>
<u-cell title="学历" isLink :value="where.educationMate" @click="showEducationMate = true"></u-cell>
<u-cell title="年收入" isLink :value="where.monthlyPayMate"
@click="showMonthlyPayMate = true"></u-cell>
</u-cell-group>
</view>
<view class="history">
<view class="his-head">
<view class="line"></view>
<text class="title">高级搜索</text>
</view>
<u-cell-group :border="false">
<u-cell title="职员" isLink :value="where.vocationMate" @click="showVocationMate = true"></u-cell>
<u-cell title="是否有房" isLink :value="where.hasHouseMate" @click="showHasHouseMate = true"></u-cell>
<u-cell title="是否有车" isLink :value="where.hasCarMate" @click="showHasCarMate = true"></u-cell>
<u-cell title="婚姻状况" isLink :value="where.maritalStatusMate"
@click="showMaritalStatusMate = true"></u-cell>
<u-cell title="有无小孩" isLink :value="where.hasChildrenMate"
@click="showHasChildrenMate = true"></u-cell>
<u-cell title="星座" isLink :value="where.constellation" @click="showConstellation = true"></u-cell>
</u-cell-group>
</view>
<u-picker :show="showAgeMate" :columns="dict.ageMate" @confirm="confirmAgeMate"
@cancel="showAgeMate = false"></u-picker>
<u-picker :show="showRegionMate" :columns="regionsData" keyName="label" @confirm="confirmRegionMate"
@cancel="showRegionMate = false"></u-picker>
<u-picker :show="showHeightMate" :columns="dict.heightMate" @confirm="confirmHeightMate"
@cancel="showHeightMate = false"></u-picker>
<u-picker :show="showShapeMate" :columns="dict.shapeMate" @confirm="confirmShapeMate"
@cancel="showShapeMate = false"></u-picker>
<u-picker :show="showEducationMate" :columns="dict.educationMate" @confirm="confirmEducationMate"
@cancel="showEducationMate = false"></u-picker>
<u-picker :show="showMonthlyPayMate" :columns="dict.yearlyPayMate" @confirm="confirmMonthlyPayMate"
@cancel="showMonthlyPayMate = false"></u-picker>
<u-picker :show="showVocationMate" :columns="dict.positionMate" @confirm="confirmVocationMate"
@cancel="showVocationMate = false"></u-picker>
<u-picker :show="showHasHouseMate" :columns="dict.hasHouseMate" @confirm="confirmHasHouseMate"
@cancel="showHasHouseMate = false"></u-picker>
<u-picker :show="showHasCarMate" :columns="dict.hasCarMate" @confirm="confirmHasCarMate"
@cancel="showHasCarMate = false"></u-picker>
<u-picker :show="showMaritalStatusMate" :columns="dict.maritalStatusMate"
@confirm="confirmMaritalStatusMate" @cancel="showMaritalStatusMate = false"></u-picker>
<u-picker :show="showHasChildrenMate" :columns="dict.hasChildrenMate" @confirm="confirmHasChildrenMate"
@cancel="showHasChildrenMate = false"></u-picker>
<u-picker :show="showConstellation" :columns="dict.constellation" @confirm="confirmConstellation"
@cancel="showConstellation = false"></u-picker>
<view class="" style="height: 300rpx;">
</view>
<!-- 操作按钮 -->
<view class="footer">
<view class="btn-wrapper">
<u-button text="开始搜索" color="linear-gradient(to bottom, #010002, #681752)" shape="circle"
@click="onSearch"></u-button>
</view>
</view>
</view>
<!-- 地址选择器 -->
<liu-customize-sel ref="area" @change="chooseSuccess"> </liu-customize-sel>
</view>
</template>
<script>
import * as UserProfileApi from '@/api/love-user-profile.js'
import * as DictApi from '@/api/dict.js'
export default {
data() {
return {
list: [],
dict: [],
page: 0,
regionMate: '不限',
where: {
ageMate: '不限',
regionMate: '不限',
heightMate: '不限',
shapeMate: '不限',
educationMate: '不限',
monthlyPayMate: '不限',
vocationMate: '不限',
hasHouseMate: '不限',
hasCarMate: '不限',
maritalStatusMate: '不限',
hasChildrenMate: '不限',
constellation: '不限',
random: true
},
showRegion: false,
showAgeMate: false,
showRegionMate: false,
showHeightMate: false,
showShapeMate: false,
showEducationMate: false,
showMonthlyPayMate: false,
showVocationMate: false,
showHasHouseMate: false,
showHasCarMate: false,
showMaritalStatusMate: false,
showHasChildrenMate: false,
showConstellation: false,
// regionsData: [
// ['广西壮族自治区'],
// ['南宁市', '北海市', '贵港市']
// ],
// defaultIndex: ['广西壮族自治区','南宁市'],
// 控制onShow事件是否刷新订单列表
canReset: false,
disabled: false,
// citys: [],
// columns: [],
// columnData: []
actionStyle: {
background: '#8b004c',
color: '#ffffff',
padding: '12rpx 16rpx',
borderRadius: '50rpx'
},
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
if(!uni.getStorageSync("userId") ||uni.getStorageSync("userId") == 1101){
uni.redirectTo({
url: "/pages/login/index"
})
}
this.getDict()
// this.getCitysData()
// 获取历史搜索
// this.historySearch = this.getHistorySearch()
},
// 必须要在onReady生命周期因为onLoad生命周期组件可能尚未创建完毕
onReady() {
this.$refs.uForm.setRules(this.rules)
// 微信小程序需要用此写法
this.$refs.datetimePicker.setFormatter(this.formatter)
},
methods: {
getDict() {
DictApi.listDictionary().then(res => {
this.dict = res.data;
// this.dict.ageMate[0].unshift('不限')
// this.dict.heightMate[0].unshift('不限')
// this.dict.shapeMate[0].unshift('不限')
// this.dict.positionMate[0].unshift('不限')
// this.dict.monthlyPayMate[0].unshift('不限')
// this.dict.hasCarMate[0].unshift('不限')
// this.dict.hasChildrenMate[0].unshift('不限')
// this.dict.hasHouseMate[0].unshift('不限')
// this.dict.educationMate[0].unshift('不限')
// this.dict.maritalStatusMate[0].unshift('不限')
// this.dict.constellation[0].unshift('不限')
})
},
// 读取城市数据
// getCitysData() {
// const app = this
// const { defaultIndex } = this
// var province = []
// var city = []
// var region = []
// uni.request({
// url: 'https://file.wsdns.cn/json/city.js',
// success(result) {
// console.log("result: ", result);
// const list = result.data
// app.citys = list
// // 默认选中
// list.map((d, i) => {
// // 收集省份
// province.push(d.label)
// if (i == 0) {
// console.log(d);
// // 收集城市
// d.children.map((d1,i1) => {
// console.log("d1: ", d1);
// console.log("i1: ",i1);
// city.push(d1.label)
// // 收集地区
// if (i1 == 0) {
// d1.children.map(d2 => {
// console.log("d2: ",d2);
// region.push(d2.label)
// })
// }
// })
// }
// })
// app.columns = [province,city,region]
// }
// })
// },
// changeHandler(e) {
// const app = this
// const {
// columnIndex,
// value,
// values, // values为当前变化列的数组内容
// index,
// // 微信小程序无法将picker实例传出来只能通过ref操作
// picker = this.$refs.uPicker
// } = e
// // 当第一列值发生变化时,变化第二列(后一列)对应的选项
// console.log("columnIndex: ",columnIndex);
// console.log("e: ",e);
// var city = []
// if (columnIndex === 0) {
// console.log("this.citys[index]: ",app.citys[index].children);
// app.citys[index].children.map(d => {
// city.push(d.label)
// })
// console.log("city: ",city);
// // picker为选择器this实例变化第二列对应的选项
// picker.setColumnValues(1, city)
// }
// },
// //地址选择成功
// confirm(e) {
// const data = e.value
// this.regionMate = `${data[0].label} ${data[1].label} ${data[2].label}`
// this.where.cityMate = data[1].label
// this.showRegion = false
// },
/**
* 获取历史搜索
*/
getHistorySearch() {
return uni.getStorageSync(HISTORY_SEARCH) || []
},
onSearch() {
if (this.where.ageMate == '不限') {
this.where.ageMate = undefined
}
if (this.where.regionMate == '不限') {
this.where.regionMate = undefined
}
if (this.where.heightMate == '不限') {
this.where.heightMate = undefined
}
if (this.where.shapeMate == '不限') {
this.where.shapeMate = undefined
}
if (this.where.educationMate == '不限') {
this.where.educationMate = undefined
}
if (this.where.monthlyPayMate == '不限') {
this.where.monthlyPayMate = undefined
}
if (this.where.hasHouseMate == '不限') {
this.where.hasHouseMate = undefined
}
if (this.where.vocationMate == '不限') {
this.where.vocationMate = undefined
}
if (this.where.constellation == '不限') {
this.where.constellation = undefined
}
if (this.where.hasChildrenMate == '不限') {
this.where.hasChildrenMate = undefined
}
if (this.where.maritalStatusMate == '不限') {
this.where.maritalStatusMate = undefined
}
if (this.where.hasCarMate == '不限') {
this.where.hasCarMate = undefined
}
this.where.recommend = true
this.$push('/sub_pages/member/member', this.where)
},
onArea() {
this.$refs.area.open()
},
//地址选择成功
chooseSuccess(e) {
const data = e.value
this.regionMate = `${data[0].label} ${data[1].label}`
this.where.cityMate = data[1].label
},
/**
* 记录历史搜索
*/
setHistory(searchValue) {
const data = this.getHistorySearch()
const index = data.indexOf(searchValue)
index > -1 && data.splice(index, 1)
data.unshift(searchValue)
this.historySearch = data
this.onUpdateStorage()
},
/**
* 清空最近搜索记录
*/
clearSearch() {
this.historySearch = []
this.onUpdateStorage()
},
/**
* 更新历史搜索缓存
* @param {Object} data
*/
onUpdateStorage(data) {
uni.setStorageSync(HISTORY_SEARCH, this.historySearch)
},
// 选择年龄
confirmAgeMate(e) {
this.where.ageMate = e.value[0]
this.showAgeMate = false
},
confirmRegionMate(e) {
this.where.regionMate = e.value[0] + ' ' + e.value[1]
this.showRegionMate = false
},
confirmHeightMate(e) {
this.where.heightMate = e.value[0]
this.showHeightMate = false
},
confirmShapeMate(e) {
this.where.shapeMate = e.value[0]
this.showShapeMate = false
},
confirmEducationMate(e) {
this.where.educationMate = e.value[0]
this.showEducationMate = false
},
confirmMonthlyPayMate(e) {
this.where.monthlyPayMate = e.value[0]
this.showMonthlyPayMate = false
},
confirmVocationMate(e) {
this.where.vocationMate = e.value[0]
this.showVocationMate = false
},
confirmHasHouseMate(e) {
this.where.hasHouseMate = e.value[0]
this.showHasHouseMate = false
},
confirmMaritalStatusMate(e) {
this.where.maritalStatusMate = e.value[0]
this.showMaritalStatusMate = false
},
confirmHasCarMate(e) {
this.where.hasCarMate = e.value[0]
this.showHasCarMate = false
},
confirmHasChildrenMate(e) {
this.where.hasChildrenMate = e.value[0]
this.showHasChildrenMate = false
},
confirmConstellation(e) {
this.where.constellation = e.value[0]
this.showConstellation = false
},
/**
* 跳转到最近搜索
*/
handleQuick(search) {
this.$navTo('pages/goods/list', {
search
})
}
}
}
</script>
<style lang="scss" scoped>
page {
background: #f7f7f7;
}
.container {
// padding: 40rpx;
width: 700rpx;
margin: 20rpx auto;
height: 90vh;
}
.search-wrapper {
display: flex;
height: 64rpx;
padding: 20rpx;
background-color: #FFFFFF;
}
.base {
margin-top: 40rpx;
background-color: #ffffff;
}
.senior {
margin-top: 40rpx;
background-color: #ffffff;
}
// 搜索输入框
.search-input {
width: 80%;
background: #fff;
height: 72rpx;
line-height: 72rpx;
border-radius: 10rpx 0 0 10rpx;
box-sizing: border-box;
overflow: hidden;
.search-input-wrapper {
display: flex;
.left {
display: flex;
width: 60rpx;
justify-content: center;
align-items: center;
.search-icon {
display: block;
color: #b4b4b4;
font-size: 28rpx;
}
}
.right {
flex: 1;
input {
font-size: 28rpx;
height: 72rpx;
line-height: 72rpx;
display: flex;
align-items: center;
.input-placeholder {
color: #aba9a9;
}
}
}
}
}
// 搜索按钮
.search-button {
width: 20%;
box-sizing: border-box;
.button {
height: 64rpx;
font-size: 28rpx;
border-radius: 0 10rpx 10rpx 0;
background: $main-bg;
color: $main-text;
display: flex;
justify-content: center;
align-items: center;
}
}
// 最近搜索
.history {
.title {
font-weight: bold;
}
.his-head {
display: flex;
justify-content: flex-start;
align-items: center;
font-size: 30rpx;
padding: 50rpx 0 20rpx 0;
color: #681752;
.line {
background-color: #681752;
width: 8rpx;
height: 30rpx;
margin-right: 12rpx;
}
.icon {
float: right;
}
}
.his-list {
padding: 20rpx 0;
overflow: hidden;
.his-item {
width: 33.3%;
float: left;
padding: 10rpx;
box-sizing: border-box;
.history-button {
text-align: center;
padding: 14rpx;
line-height: 30rpx;
border-radius: 100rpx;
background: #fff;
font-size: 26rpx;
border: 1rpx solid #efefef;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
/deep/.u-cell__body{
padding: 10px 0 10px 10px !important;
}
}
/* 底部操作栏 */
.footer {
margin-top: 50rpx;
padding-bottom: 50rpx;
position: fixed;
left: 0;
right: 0;
bottom: 0;
background-color: #f3f3f3;
padding-top: 20rpx;
.btn-wrapper {
width: 360rpx;
margin: auto;
// display: flex;
// align-items: center;
padding: 0 20rpx;
}
.btn-item {
flex: 1;
font-size: 28rpx;
height: 86rpx;
color: #fff;
border-radius: 50rpx;
display: flex;
justify-content: center;
align-items: center;
}
.btn-item-wechat {
background: #0ba90b;
margin-bottom: 26rpx;
}
.btn-item-main {
background: linear-gradient(to right, $main-bg, $main-bg2);
color: $main-text;
// 禁用按钮
&.disabled {
opacity: 0.6;
}
}
}
</style>

198
pages/shop/detail.vue Executable file
View File

@@ -0,0 +1,198 @@
<template>
<view v-if="!isLoading" class="container">
<view class="header">
<view class="shop-logo">
<image class="image" :src="detail.logo_url"></image>
</view>
<view class="shop-name">
<text>{{ detail.shop_name }}</text>
</view>
<view v-if="detail.summary" class="shop-summary dis-flex">
<text>门店简介{{ detail.summary }}</text>
</view>
</view>
<view class="content">
<view class="content-item dis-flex flex-y-center">
<view class="content-item__icon dis-flex">
<text class="iconfont icon-shijian"></text>
</view>
<view class="content-item__text flex-box dis-flex">
<text class="f-26">{{ detail.shop_hours }}</text>
</view>
</view>
<view class="content-item dis-flex flex-y-center" @click="onOpenLocation()">
<view class="content-item__icon dis-flex">
<text class="iconfont icon-dingwei"></text>
</view>
<view class="content-item__text flex-box dis-flex">
<text
class="f-26">{{ detail.region.province }}{{ detail.region.city }}{{ detail.region.region }}{{ detail.address }}</text>
</view>
<view class="content-item__arrow dis-flex">
<text class="iconfont icon-arrow-right"></text>
</view>
</view>
<view class="content-item dis-flex flex-y-center" @click="onMakePhoneCall()">
<view class="content-item__icon dis-flex">
<text class="iconfont icon-dianhua"></text>
</view>
<view class="content-item__text flex-box dis-flex">
<text class="f-26">{{ detail.phone }}</text>
</view>
<view class="content-item__arrow dis-flex">
<text class="iconfont icon-arrow-right"></text>
</view>
</view>
</view>
</view>
</template>
<script>
// import * as ShopApi from '@/api/shop'
export default {
data() {
return {
// 正在加载中
isLoading: true,
// 当前门店ID
shopId: undefined,
// 门店详情
detail: null
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
// 记录当前门店ID
this.shopId = options.shopId
// 获取门店详情
// this.getShopDetail()
},
methods: {
// 获取门店详情
getShopDetail() {
const app = this
app.isLoading = true
ShopApi.detail(app.shopId)
.then(result => app.detail = result.data.detail)
.finally(() => app.isLoading = false)
},
// 拨打电话
onMakePhoneCall() {
const app = this
uni.makePhoneCall({
phoneNumber: app.detail.phone
})
},
// 查看位置
onOpenLocation() {
const app = this
const { detail } = app
uni.openLocation({
name: detail.shop_name,
address: detail.region.province + detail.region.city + detail.region.region + detail.address,
longitude: Number(detail.longitude),
latitude: Number(detail.latitude),
scale: 15
})
},
},
/**
* 分享当前页面
*/
onShareAppMessage() {
const app = this
// 构建页面参数
const params = app.$getShareUrlParams({ shopId: app.shopId })
return {
title: app.detail.shop_name,
path: "/pages/shop/detail?" + params
}
},
/**
* 分享到朋友圈
* 本接口为 Beta 版本,暂只在 Android 平台支持,详见分享到朋友圈 (Beta)
* https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share-timeline.html
*/
onShareTimeline() {
const app = this
// 构建页面参数
const params = app.$getShareUrlParams({ shopId: app.shopId })
return {
title: app.detail.shop_name,
path: "/pages/shop/detail?" + params
}
},
}
</script>
<style lang="scss">
page {
background: #f3f3f3;
}
</style>
<style lang="scss" scoped>
.container {
background: #fff;
padding: 0 30rpx;
}
.header {
padding: 30rpx 0;
border-bottom: 1rpx solid #f1f1f1;
.shop-logo,
.shop-name {
text-align: center;
}
.shop-logo {
.image {
width: 130rpx;
height: 130rpx;
border-radius: 50%;
box-shadow: 0 0 30rpx rgba(0, 0, 0, 0.1);
}
}
.shop-name {
margin-top: 16rpx;
font-size: 32rpx;
}
.shop-summary {
padding: 20rpx;
margin-top: 30rpx;
font-size: 26rpx;
line-height: 1.6;
background: #f9f9f9;
border-radius: 6rpx;
}
}
.content {
margin-top: 30rpx;
.content-item {
padding: 12rpx 0;
.content-item__text {
padding: 0 20rpx;
}
}
}
</style>

198
pages/shop/extract.vue Executable file
View File

@@ -0,0 +1,198 @@
<template>
<view class="container b-f">
<!-- 门店列表 -->
<view class="shop-list">
<view v-for="(item, index) in shopList" :key="index" @click="onSelectedShop(item.shop_id)" class="shop-item dis-flex flex-y-center">
<view class="shop-item__content flex-box">
<view class="shop-item__title">
<text>{{ item.shop_name }}</text>
</view>
<view class="shop-item__address">
<text>地址{{ item.region.province }}{{ item.region.city }}{{ item.region.region }}{{ item.address }}</text>
</view>
<view class="shop-item__phone">
<text>联系电话{{ item.phone }}</text>
</view>
<view v-if="item.distance" class="shop-item__distance">
<text class="iconfont icon-dingwei"></text>
<text class="f-24">{{ item.distance_unit }}</text>
</view>
</view>
<!-- 选中状态 -->
<view v-if="item.shop_id == selectedId" class="shop-item__right">
<text class="iconfont icon-check1"></text>
</view>
</view>
</view>
<!-- 定位按钮 -->
<view v-if="!isAuthor" class="widget-location dis-flex flex-x-center flex-y-center" @click="onAuthorize()">
<text class="iconfont icon-locate"></text>
</view>
<empty v-if="!shopList.length" :isLoading="isLoading" tips="亲,暂无自提门店哦" />
</view>
</template>
<script>
// import * as ShopApi from '@/api/shop'
import Empty from '@/components/empty'
export default {
components: {
Empty
},
data() {
return {
// 正在加载中
isLoading: true,
// 是否授权了定位权限
isAuthor: true,
// 当前选择的门店ID
selectedId: null,
// 门店列表
shopList: []
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad({ selectedId }) {
const app = this
// 记录当前选择的门店ID
app.selectedId = selectedId ? selectedId : null
// 获取默认门店列表
// app.getShopList()
// 获取用户坐标
// app.getLocation(res => {
// app.getShopList(res.longitude, res.latitude)
// })
},
methods: {
// 获取门店列表
getShopList(longitude, latitude) {
const app = this
app.isLoading = true
ShopApi.list({
isCheck: 1,
longitude: longitude ? longitude : '',
latitude: latitude ? latitude : ''
})
.then(result => app.shopList = result.data.list)
.finally(() => app.isLoading = false)
},
// 获取用户坐标
// 参考文档https://uniapp.dcloud.io/api/location/location?id=getlocation
getLocation(callback) {
const app = this
uni.getLocation({
type: 'wgs84',
success: callback,
fail() {
app.$toast('获取定位失败,请点击右下角按钮重新尝试定位')
app.isAuthor = false
}
})
},
// 授权启用定位权限
onAuthorize() {
const app = this
// #ifdef MP
uni.openSetting({
success(res) {
if (res.authSetting['scope.userLocation']) {
console.log('定位权限授权成功')
app.isAuthor = true
setTimeout(() => {
// 获取用户坐标
app.getLocation(res => {
app.getShopList(res.longitude, res.latitude)
})
}, 1000)
}
}
})
// #endif
// #ifdef H5
// 获取用户坐标
app.getLocation(res => {
app.getShopList(res.longitude, res.latitude)
})
// #endif
},
/**
* 选择门店
*/
onSelectedShop(selectedId) {
const app = this
// 设置选中的id
app.selectedId = selectedId
// 相应全局事件订阅: 选择自提门店
uni.$emit('syncSelectedId', selectedId)
// 返回上级页面
uni.navigateBack({
delta: 1
})
},
}
}
</script>
<style lang="scss" scoped>
.shop-list .shop-item {
padding: 20rpx 30rpx;
min-height: 180rpx;
font-size: 26rpx;
line-height: 1.5;
border-bottom: 1px solid #eee;
}
.shop-item__title {
font-size: 30rpx;
color: #535353;
margin-bottom: 10rpx;
}
.shop-item__address,
.shop-item__phone {
color: #919396;
}
.shop-item__distance {
margin-top: 10rpx;
color: #c1c1c1;
height: 40rpx;
}
.shop-item__distance .iconfont {
color: #81838e;
margin-right: 5rpx;
}
// 选中图标
.shop-item__right {
margin-left: 20rpx;
color: #535353;
font-size: 38rpx;
}
// 定位图标
.widget-location {
position: fixed;
right: calc(var(--window-right) + 40rpx);
bottom: calc(var(--window-bottom) + 70rpx);
width: 72rpx;
height: 72rpx;
z-index: 200;
border-radius: 50%;
background: #fff;
box-shadow: 0 0 10rpx rgba(0, 0, 0, 0.2);
color: #555;
font-size: 40rpx;
}
</style>

View File

@@ -0,0 +1,264 @@
<template>
<view class="container" :style="appThemeStyle">
<!-- 标题 -->
<view class="page-title">修改密码</view>
<!-- 表单组件 -->
<view class="form-wrapper">
<u--form :model="form" ref="uForm" :rules="rules" label-width="140rpx">
<u-form-item label="旧密码" prop="oldPassword">
<u--input v-model="form.oldPassword" type="text" maxlength="20" placeholder="请输入旧密码" />
</u-form-item>
<u-form-item label="新密码" prop="password">
<u--input v-model="form.password" type="text" maxlength="20" placeholder="请输入新密码" />
</u-form-item>
<u-form-item label="确认密码" prop="password2">
<u--input v-model="form.password2" type="text" maxlength="20" placeholder="请输入确认密码" />
</u-form-item>
</u--form>
</view>
<!-- 操作按钮 -->
<view class="footer">
<view class="btn-wrapper">
<view class="btn-item btn-item-main" :class="{ disabled }" @click="handleSubmit()">保存</view>
</view>
</view>
</view>
</template>
<script>
import store from '@/store'
import { fileUrl } from '@/config.js'
import AvatarImage from '@/components/avatar-image'
import * as UserApi from '@/api/user'
import * as UploadApi from '@/api/upload'
// 表单验证规则
const rules = {
nickname: [{
required: true,
message: '请输入用户昵称',
trigger: ['blur', 'change']
}]
}
export default {
components: {
AvatarImage
},
data() {
return {
// 按钮禁用
disabled: false,
// 头像路径 (用于显示)
avatarUrl: '',
// 临时图片 (用于上传)
tempFile: null,
// 表单数据
form: {
avatarId: '',
nickname: ''
},
// 验证规则
rules,
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad() {
// 获取当前用户信息
// this.getUserInfo()
},
// 必须要在onReady生命周期因为onLoad生命周期组件可能尚未创建完毕
onReady() {
this.$refs.uForm.setRules(this.rules)
},
methods: {
getUserInfo() {
const { form } = this
const app = this
UserApi.getUser().then(res => {
if( res.code == 0 && res.data.username != 'www') {
console.log("获取用户信息: ",res.data);
app.form = res.data
app.userInfo = res.data
store.dispatch('setUserInfo',res.data)
app.isLogin = true
res.data.roles.map(d => {
if(d.roleCode == 'superAdmin'){
app.superAdmin = true
}
if(d.roleCode == 'agent'){
app.agent = true
}
if(d.roleCode == 'admin'){
app.isAdmin = true
}
})
}else{
app.isLogin = false
app.handleLogout()
}
})
},
// 点击头像按钮事件
onClickAvatar() {
// #ifdef MP-WEIXIN
return
// #endif
this.chooseImage()
},
// 选择头像事件 - 仅限微信小程序
// #ifdef MP-WEIXIN
onChooseAvatar({ detail }) {
const app = this
app.avatarUrl = detail.avatarUrl
app.tempFile = { path: app.avatarUrl }
},
// #endif
// 选择图片
chooseImage() {
const app = this
// 选择图片
uni.chooseImage({
count: 1,
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success(chooseImageRes) {
const tempFilePaths = chooseImageRes.tempFilePaths;
UploadApi.uploadFile({
filePath: tempFilePaths[0],
fileType: 'image',
name: 'file'
}).then(res => {
console.log("res: ", res);
app.form.avatar = fileUrl + res.data.path
console.log("form: ",app.form);
})
}
});
},
// 上传图片
uploadFile() {
const app = this
return UploadApi.image([app.tempFile])
.then(fileIds => {
app.form.avatarId = fileIds[0]
app.tempFile = null
})
},
// 确认修改
async handleSubmit() {
const app = this
// 判断是否重复提交
if (app.disabled === true) return
app.$refs.uForm.validate(async valid => {
if (valid) {
// 按钮禁用
app.disabled = true
// 先上传头像图片
if (app.tempFile) {
await app.uploadFile()
}
// 提交保存个人信息
UserApi.updatePassword(app.form)
.then(result => {
app.$toast(result.message)
setTimeout(() => {
app.disabled = false
uni.navigateBack()
}, 1500)
})
.catch(err => app.disabled = false)
}
})
},
// 绑定昵称输入框 (用于微信小程序端快速填写昵称能力)
onInputNickName(val) {
if (val) {
this.form.nickname = val
}
}
}
}
</script>
<style>
page {
background: #f7f8fa;
}
</style>
<style lang="scss" scoped>
.container {}
.page-title {
width: 94%;
margin: 0 auto;
padding-top: 40rpx;
font-size: 28rpx;
color: rgba(69, 90, 100, 0.6);
}
.form-wrapper {
margin: 20rpx auto 20rpx auto;
padding: 0 40rpx;
width: 90%;
box-shadow: 0 1rpx 5rpx 0px rgba(0, 0, 0, 0.05);
border-radius: 16rpx;
background: #fff;
}
/* 底部操作栏 */
.footer {
margin-top: 80rpx;
.btn-wrapper {
height: 100%;
// display: flex;
// align-items: center;
padding: 0 20rpx;
}
.btn-item {
flex: 1;
font-size: 28rpx;
height: 86rpx;
color: #fff;
border-radius: 50rpx;
display: flex;
justify-content: center;
align-items: center;
}
.btn-item-wechat {
background: #0ba90b;
margin-bottom: 26rpx;
}
.btn-item-main {
width: 400rpx;
margin: auto;
background: linear-gradient(to bottom, $main-bg, $main-bg2);
color: $main-text;
// 禁用按钮
&.disabled {
opacity: 0.6;
}
}
}
</style>

1621
pages/user/user.vue Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,251 @@
<template>
<view class="container">
<view class="user-list">
<block v-for="(item,index) in list" :key="index">
<view class="item" v-if="item.userInfo" @click="$push('sub_pages/member/detail/detail',{userId: item.userId})">
<view class="has-house-num">
南宁1套
</view>
<view class="content">
喜欢极限运动摩托健身旅游看书等事业单位正式工作收入稳定想找个聊得...
</view>
<view class="user-info">
<view class="left">
<view class="avatar">
<u-avatar size="25" :src="item.userInfo.avatar"
customStyle="margin-right:5px; border: 4rpx solid #ffffff;"></u-avatar>
<view class="nickname">{{ item.userInfo.nickname }}</view>
</view>
<view class="desc">
南宁 31 20w-30w
</view>
</view>
<view class="follow-btn" @click.stop="onFollow">
<image src="@/static/icon/follow.png" mode="widthFix"></image>
<text>关注</text>
</view>
</view>
<view class="bg-color"></view>
<image class="bg" :src="item.userBgImg" mode="aspectFill"></image>
</view>
</block>
<!-- <u-list @scrolltolower="scrolltolower">
<view class="list">
<u-list-item v-for="(item, index) in list" :key="index">
<u-cell :title="`${item.userInfo.nickname}`" :label="`粉丝:${ item.id }`" isLink
@click="navTo('/pages/member/detail/detail',{userId: item.userId})">
<u-avatar slot="icon" size="50" :src="item.userInfo.avatar"
customStyle="margin: -3px 5px -3px 0"></u-avatar>
<view slot="right-icon" class="follow-btn" @click.stop="onFollow">
<image src="@/static/icon/follow.png" mode="widthFix"></image>
<text>关注</text>
</view>
</u-cell>
</u-list-item>
<u-empty
v-if="list.length == 0"
mode="search"
icon="http://cdn.uviewui.com/uview/empty/car.png"
>
</u-empty>
</view>
</u-list> -->
</view>
</view>
</template>
<script>
import * as UserProfileApi from '@/api/love-user-profile.js'
export default {
data() {
return {
list: [],
page: 0,
where: {},
// 控制onShow事件是否刷新订单列表
canReset: false,
disabled: false
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.where = options
this.onRefreshList()
uni.setNavigationBarTitle({
title: options.name
})
},
onPullDownRefresh(){
const app = this
setTimeout(function() {
uni.stopPullDownRefresh();
app.onRefreshList()
}, 500);
},
methods: {
// 刷新会员列表
onRefreshList() {
const app = this
app.where.page = app.page
return new Promise((resolve, reject) => {
UserProfileApi.pageUserProfile(app.where)
.then(result => {
const list = result.data.list
// 合并新数据
app.list = app.list.concat(list)
if(result.data.count > app.list.length){
app.canReset = true
}else{
app.canReset = false
}
// 获取第一张图片作为背景图片
list.map((d, i) => {
if(!app.list[i].userBgImg){
const imgs = JSON.parse(d.images)
console.log("imgs: ",imgs);
imgs.map(pic => {
console.log("pic: ",pic);
if (pic.type == 'image') {
app.list[i].userBgImg = pic.url
}
})
}
})
resolve(list)
})
})
},
scrolltolower(e){
console.log("e: ",e);
},
navTo(url,userId){
this.$push(url,userId)
},
onFollow(e){
console.log("e11: ",e);
},
onSearch(){
this.list = []
this.where.page = 1
this.onRefreshList()
}
}
}
</script>
<style lang="scss" scoped>
.container {
padding: 0 20rpx;
background-color: #ffffff;
}
.search-wrapper {
display: flex;
height: 64rpx;
}
.user-list{
.item{
margin: 40rpx auto;
width: 660rpx;
min-height: 500rpx;
background-color: #f3f3f3;
border-radius: 15rpx;
position: relative;
z-index: 0;
overflow: hidden;
/* 背景叠加 */
.bg-color {
position: absolute;
top: 0;
z-index: 1;
width: 660rpx;
height: 365rpx;
background-color: #000000;
opacity: .2;
filter: Alpha(opacity=20);
}
.bg{
position: absolute;
top: 0;
z-index: 0;
width: 660rpx;
}
.has-house-num{
position: absolute;
top: 20rpx;
left: 20rpx;
z-index: 3;
height: 43rpx;
line-height: 43rpx;
padding: 4rpx 20rpx;
color: #ffffff;
font-size: 26rpx;
border-radius: 10rpx;
margin-right: 40rpx;
background: linear-gradient(#47076b, #8d1a50);
}
.content{
width: 640rpx;
position: absolute;
top: 250rpx;
color: #ffffff;
font-size: 28rpx;
padding: 20rpx;
z-index: 2;
}
.user-info{
width: 660rpx;
height: 100rpx;
padding: 20rpx;
position: absolute;
bottom: 0;
z-index: 1;
background-color: #1b0121;
color: #ffffff;
display: flex;
justify-content: space-between;
align-items: center;
.left{
display: flex;
flex-direction: column;
justify-content: space-between;
.avatar{
display: flex;
align-items: center;
.nickname{
font-size: 26rpx;
}
}
.desc{
color: #999999;
font-size: 26rpx;
}
}
.follow-btn {
width: 85rpx;
height: 43rpx;
padding: 4rpx 20rpx;
color: #ffffff;
font-size: 26rpx;
border-radius: 10rpx;
margin-right: 40rpx;
background: linear-gradient(#47076b, #8d1a50);
image {
width: 24rpx;
height: 36rpx;
margin-right: 6rpx;
}
}
}
}
}
</style>

171
pages/zone/zone.vue Normal file
View File

@@ -0,0 +1,171 @@
<template>
<view class="container">
<view class="category" @click="$push('pages/zone/member/member',{name: '有车有房',desc: '0.9w人'})">
<view class="item">
<image src="https://file.wsdns.cn/thumbnail/20230604/0036e686027d4994ab03de5cbd0caf34.png" mode="widthFix"></image>
</view>
<view class="item">
<image src="https://file.wsdns.cn/thumbnail/20230604/03a95e32bc094c09bf56c3ac3ff78f0d.jpeg" mode="widthFix"></image>
</view>
<view class="item">
<image src="https://file.wsdns.cn/thumbnail/20230604/b37e315c128241f69d3a7fa5a54fea23.jpeg" mode="widthFix"></image>
</view>
<view class="item">
<image src="https://file.wsdns.cn/thumbnail/20230604/26f0ed191b174478b10a510991d18262.jpeg" mode="widthFix"></image>
</view>
<view class="item">
<image src="https://file.wsdns.cn/thumbnail/20230604/60b27769b8bb4a0d822a6219ed8767bc.jpeg" mode="widthFix"></image>
</view>
<view class="item">
<image src="https://file.wsdns.cn/thumbnail/20230604/03a95e32bc094c09bf56c3ac3ff78f0d.jpeg" mode="widthFix"></image>
</view>
</view>
<view class="category" @click="$push('pages/zone/member/member',{name: '精选人类90后',desc: '1w+人'})">
<view class="item">
<image src="https://file.wsdns.cn/thumbnail/20230604/0036e686027d4994ab03de5cbd0caf34.png" mode="widthFix"></image>
</view>
<view class="item">
<image src="https://file.wsdns.cn/thumbnail/20230604/03a95e32bc094c09bf56c3ac3ff78f0d.jpeg" mode="widthFix"></image>
</view>
<view class="item">
<image src="https://file.wsdns.cn/thumbnail/20230604/b37e315c128241f69d3a7fa5a54fea23.jpeg" mode="widthFix"></image>
</view>
<view class="item">
<image src="https://file.wsdns.cn/thumbnail/20230604/26f0ed191b174478b10a510991d18262.jpeg" mode="widthFix"></image>
</view>
<view class="item">
<image src="https://file.wsdns.cn/thumbnail/20230604/60b27769b8bb4a0d822a6219ed8767bc.jpeg" mode="widthFix"></image>
</view>
<view class="item">
<image src="https://file.wsdns.cn/thumbnail/20230604/03a95e32bc094c09bf56c3ac3ff78f0d.jpeg" mode="widthFix"></image>
</view>
</view>
</view>
</template>
<script>
import store from '@/store/index.js'
import * as DictApi from '@/api/dict.js'
import * as UserProfileApi from '@/api/love-user-profile.js'
import mixin from '@/core/mixins/tabbar'
export default {
mixins: [mixin],
data() {
return {
list: [
{
name: '有房有车'
},
{
name: '人类精选90后'
}
],
user: {},
avatar: '/static/logo.png',
nickName: 'Hello',
latitude: 22.766777,
longitude: 108.375152,
scale: 10,
isLogin: false,
// #ifdef MP-ALIPAY
canIUseAuthButton: my.canIUse('button.open-type.getAuthorize'),
// #endif
}
},
onLoad() {
this.getLocation(res => {
if (res.latitude && res.longitude) {
app.latitude = res.latitude
app.longitude = res.longitude
app.scale = 16
}
})
this.getDict()
},
onShow() {
// this.getUserInfo()
},
methods: {
getDict() {
DictApi.getDictionaryOptions({dictCode: 'zone'}).then(res => {
this.dict = res.data;
})
},
getUserInfo() {
const {
form
} = this
const app = this
getUser().then(res => {
console.log(res);
if (res.code == 0 && res.data) {
app.isLogin = true
} else {
app.$error('请先登录', function() {
app.$navTo('pages/login/index');
});
return false;
}
})
},
// 检查是否登录
checkLogin() {
if (!!store.getters.userId && store.getters.userId != userId) {
this.isLogin = true
}
},
// 获取用户坐标
// 参考文档https://uniapp.dcloud.io/api/location/location?id=getlocation
getLocation(callback) {
const app = this
uni.getLocation({
success: callback,
fail() {
app.$toast('获取定位失败,请点击右下角按钮重新尝试定位')
app.isAuthor = false
}
})
},
// 跳转页面
navTo(url) {
this.$navTo(url)
},
scan() {
const app = this
this.$navTo('pages/order/get-food/get-food')
// 只允许从相机扫码
// uni.scanCode({
// success (res) {
// console.log("res: ",res);
// }
// })
}
}
}
</script>
<style lang="scss" scoped>
.category{
width: 681rpx;
margin: 30rpx auto;
background-color: #ffffff;
border-radius: 12rpx;
overflow: hidden;
display: flex;
flex-wrap: wrap;
.item{
width: 220rpx;
height: 240rpx;
overflow: hidden;
image{
width: 100%;
}
}
}
</style>