项目初始化
This commit is contained in:
305
pages/user/address/edit.vue
Normal file
305
pages/user/address/edit.vue
Normal file
@@ -0,0 +1,305 @@
|
||||
<!-- 收货地址的新增/编辑 -->
|
||||
<template>
|
||||
<s-layout :title="state.model.id ? '编辑地址' : '新增地址'">
|
||||
<uni-forms
|
||||
ref="addressFormRef"
|
||||
v-model="state.model"
|
||||
:rules="rules"
|
||||
validateTrigger="bind"
|
||||
labelWidth="160"
|
||||
labelAlign="left"
|
||||
border
|
||||
:labelStyle="{ fontWeight: 'bold' }"
|
||||
>
|
||||
<view class="bg-white form-box ss-p-x-30">
|
||||
<uni-forms-item name="name" label="收货人" class="form-item">
|
||||
<uni-easyinput
|
||||
v-model="state.model.name"
|
||||
placeholder="请填写收货人姓名"
|
||||
:inputBorder="false"
|
||||
placeholderStyle="color:#BBBBBB;font-size:30rpx;font-weight:400;line-height:normal"
|
||||
/>
|
||||
</uni-forms-item>
|
||||
|
||||
<uni-forms-item name="mobile" label="手机号" class="form-item">
|
||||
<uni-easyinput
|
||||
v-model="state.model.mobile"
|
||||
type="number"
|
||||
placeholder="请输入手机号"
|
||||
:inputBorder="false"
|
||||
placeholderStyle="color:#BBBBBB;font-size:30rpx;font-weight:400;line-height:normal"
|
||||
>
|
||||
</uni-easyinput>
|
||||
</uni-forms-item>
|
||||
<uni-forms-item
|
||||
name="areaName"
|
||||
label="省市区"
|
||||
@tap="state.showRegion = true"
|
||||
class="form-item"
|
||||
>
|
||||
<uni-easyinput
|
||||
v-model="state.model.areaName"
|
||||
disabled
|
||||
:inputBorder="false"
|
||||
:styles="{ disableColor: '#fff', color: '#333' }"
|
||||
placeholderStyle="color:#BBBBBB;font-size:30rpx;font-weight:400;line-height:normal"
|
||||
placeholder="请选择省市区"
|
||||
>
|
||||
<template v-slot:right>
|
||||
<uni-icons type="right" />
|
||||
</template>
|
||||
</uni-easyinput>
|
||||
</uni-forms-item>
|
||||
<uni-forms-item
|
||||
name="detailAddress"
|
||||
label="详细地址"
|
||||
:formItemStyle="{ alignItems: 'flex-start' }"
|
||||
:labelStyle="{ lineHeight: '5em' }"
|
||||
class="textarea-item"
|
||||
>
|
||||
<uni-easyinput
|
||||
:inputBorder="false"
|
||||
type="textarea"
|
||||
v-model="state.model.detailAddress"
|
||||
placeholderStyle="color:#BBBBBB;font-size:30rpx;font-weight:400;line-height:normal"
|
||||
placeholder="请输入详细地址"
|
||||
clearable
|
||||
/>
|
||||
</uni-forms-item>
|
||||
</view>
|
||||
<view class="ss-m-y-20 bg-white ss-p-x-30 ss-flex ss-row-between ss-col-center default-box">
|
||||
<view class="default-box-title"> 设为默认地址 </view>
|
||||
<su-switch style="transform: scale(0.8)" v-model="state.model.defaultStatus" />
|
||||
</view>
|
||||
</uni-forms>
|
||||
<su-fixed bottom :opacity="false" bg="" placeholder :noFixed="false" :index="10">
|
||||
<view class="footer-box ss-flex-col ss-row-between ss-p-20">
|
||||
<view class="ss-m-b-20">
|
||||
<button class="ss-reset-button save-btn ui-Shadow-Main" @tap="onSave">保存</button>
|
||||
</view>
|
||||
<button v-if="state.model.id" class="ss-reset-button cancel-btn" @tap="onDelete">
|
||||
删除
|
||||
</button>
|
||||
</view>
|
||||
</su-fixed>
|
||||
|
||||
<!-- 省市区弹窗 -->
|
||||
<su-region-picker
|
||||
:show="state.showRegion"
|
||||
@cancel="state.showRegion = false"
|
||||
@confirm="onRegionConfirm"
|
||||
/>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, unref } from 'vue';
|
||||
import sheep from '@/sheep';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import _ from 'lodash-es';
|
||||
import { mobile } from '@/sheep/validate/form';
|
||||
import AreaApi from '@/sheep/api/system/area';
|
||||
import AddressApi from '@/sheep/api/member/address';
|
||||
|
||||
const addressFormRef = ref(null);
|
||||
const state = reactive({
|
||||
showRegion: false,
|
||||
model: {
|
||||
name: '',
|
||||
mobile: '',
|
||||
detailAddress: '',
|
||||
defaultStatus: false,
|
||||
areaName: '',
|
||||
},
|
||||
rules: {},
|
||||
});
|
||||
|
||||
const rules = {
|
||||
name: {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
errorMessage: '请输入收货人姓名',
|
||||
},
|
||||
],
|
||||
},
|
||||
mobile,
|
||||
detailAddress: {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
errorMessage: '请输入详细地址',
|
||||
},
|
||||
],
|
||||
},
|
||||
areaName: {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
errorMessage: '请选择您的位置',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
// 确认选择地区
|
||||
const onRegionConfirm = (e) => {
|
||||
state.model.areaName = `${e.province_name} ${e.city_name} ${e.district_name}`;
|
||||
state.model.areaId = e.district_id;
|
||||
state.showRegion = false;
|
||||
};
|
||||
|
||||
// 获得地区数据
|
||||
const getAreaData = () => {
|
||||
if (_.isEmpty(uni.getStorageSync('areaData'))) {
|
||||
AreaApi.getAreaTree().then((res) => {
|
||||
if (res.code === 0) {
|
||||
uni.setStorageSync('areaData', res.data);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 保存收货地址
|
||||
const onSave = async () => {
|
||||
// 参数校验
|
||||
const validate = await unref(addressFormRef)
|
||||
.validate()
|
||||
.catch((error) => {
|
||||
console.log('error: ', error);
|
||||
});
|
||||
if (!validate) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 提交请求
|
||||
const formData = {
|
||||
...state.model,
|
||||
};
|
||||
const { code } =
|
||||
state.model.id > 0
|
||||
? await AddressApi.updateAddress(formData)
|
||||
: await AddressApi.createAddress(formData);
|
||||
if (code === 0) {
|
||||
sheep.$router.back();
|
||||
}
|
||||
};
|
||||
|
||||
// 删除收货地址
|
||||
const onDelete = () => {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确认删除此收货地址吗?',
|
||||
success: async function (res) {
|
||||
if (!res.confirm) {
|
||||
return;
|
||||
}
|
||||
const { code } = await AddressApi.deleteAddress(state.model.id);
|
||||
if (code === 0) {
|
||||
sheep.$router.back();
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
onLoad(async (options) => {
|
||||
// 获得地区数据
|
||||
getAreaData();
|
||||
// 情况一:基于 id 获得收件地址
|
||||
if (options.id) {
|
||||
let { code, data } = await AddressApi.getAddress(options.id);
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
state.model = data;
|
||||
}
|
||||
// 情况二:微信导入
|
||||
if (options.data) {
|
||||
let data = JSON.parse(options.data);
|
||||
const areaData = uni.getStorageSync('areaData');
|
||||
const findAreaByName = (areas, name) => areas.find((item) => item.name === name);
|
||||
|
||||
let provinceObj = findAreaByName(areaData, data.province_name);
|
||||
let cityObj = provinceObj ? findAreaByName(provinceObj.children, data.city_name) : undefined;
|
||||
let districtObj = cityObj ? findAreaByName(cityObj.children, data.district_name) : undefined;
|
||||
let areaId = (districtObj || cityObj || provinceObj).id;
|
||||
|
||||
state.model = {
|
||||
...state.model,
|
||||
areaId,
|
||||
areaName: [data.province_name, data.city_name, data.district_name]
|
||||
.filter(Boolean)
|
||||
.join(' '),
|
||||
defaultStatus: false,
|
||||
detailAddress: data.address,
|
||||
mobile: data.mobile,
|
||||
name: data.consignee,
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep() {
|
||||
.uni-forms-item__label .label-text {
|
||||
font-size: 28rpx !important;
|
||||
color: #333333 !important;
|
||||
line-height: normal !important;
|
||||
}
|
||||
|
||||
.uni-easyinput__content-input {
|
||||
font-size: 28rpx !important;
|
||||
color: #333333 !important;
|
||||
line-height: normal !important;
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
|
||||
.uni-easyinput__content-textarea {
|
||||
font-size: 28rpx !important;
|
||||
color: #333333 !important;
|
||||
line-height: normal !important;
|
||||
margin-top: 8rpx !important;
|
||||
}
|
||||
|
||||
.uni-icons {
|
||||
font-size: 40rpx !important;
|
||||
}
|
||||
|
||||
.is-textarea-icon {
|
||||
margin-top: 22rpx;
|
||||
}
|
||||
|
||||
.is-disabled {
|
||||
color: #333333;
|
||||
}
|
||||
}
|
||||
|
||||
.default-box {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
height: 100rpx;
|
||||
|
||||
.default-box-title {
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
line-height: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-box {
|
||||
.save-btn {
|
||||
width: 710rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
width: 710rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
background: var(--ui-BG);
|
||||
}
|
||||
}
|
||||
</style>
|
165
pages/user/address/list.vue
Normal file
165
pages/user/address/list.vue
Normal file
@@ -0,0 +1,165 @@
|
||||
<!-- 收件地址列表 -->
|
||||
<template>
|
||||
<s-layout title="收货地址" :bgStyle="{ color: '#FFF' }">
|
||||
<view v-if="state.list.length">
|
||||
<s-address-item
|
||||
hasBorderBottom
|
||||
v-for="item in state.list"
|
||||
:key="item.id"
|
||||
:item="item"
|
||||
@tap="onSelect(item)"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<su-fixed bottom placeholder>
|
||||
<view class="footer-box ss-flex ss-row-between ss-p-20">
|
||||
<!-- 微信小程序和微信H5 -->
|
||||
<button
|
||||
v-if="['WechatMiniProgram', 'WechatOfficialAccount'].includes(sheep.$platform.name)"
|
||||
@tap="importWechatAddress"
|
||||
class="border ss-reset-button sync-wxaddress ss-m-20 ss-flex ss-row-center ss-col-center"
|
||||
>
|
||||
<text class="cicon-weixin ss-p-r-10" style="color: #09bb07; font-size: 40rpx"></text>
|
||||
导入微信地址
|
||||
</button>
|
||||
<button
|
||||
class="add-btn ss-reset-button ui-Shadow-Main"
|
||||
@tap="sheep.$router.go('/pages/user/address/edit')"
|
||||
>
|
||||
新增收货地址
|
||||
</button>
|
||||
</view>
|
||||
</su-fixed>
|
||||
<s-empty
|
||||
v-if="state.list.length === 0 && !state.loading"
|
||||
text="暂无收货地址"
|
||||
icon="/static/data-empty.png"
|
||||
/>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onBeforeMount, reactive } from 'vue';
|
||||
import { onShow, onLoad } from '@dcloudio/uni-app';
|
||||
import sheep from '@/sheep';
|
||||
import { isEmpty } from 'lodash-es';
|
||||
import AreaApi from '@/sheep/api/system/area';
|
||||
import AddressApi from '@/sheep/api/member/address';
|
||||
|
||||
const state = reactive({
|
||||
list: [], // 地址列表
|
||||
loading: true,
|
||||
openType: '', // 页面打开类型
|
||||
});
|
||||
|
||||
// 选择收货地址
|
||||
const onSelect = (addressInfo) => {
|
||||
if (state.openType !== 'select'){ // 不作为选择组件时阻断操作
|
||||
return
|
||||
}
|
||||
uni.$emit('SELECT_ADDRESS', {
|
||||
addressInfo,
|
||||
});
|
||||
sheep.$router.back();
|
||||
};
|
||||
|
||||
// 导入微信地址
|
||||
function importWechatAddress() {
|
||||
let wechatAddress = {};
|
||||
// #ifdef MP
|
||||
uni.chooseAddress({
|
||||
success: (res) => {
|
||||
wechatAddress = {
|
||||
consignee: res.userName,
|
||||
mobile: res.telNumber,
|
||||
province_name: res.provinceName,
|
||||
city_name: res.cityName,
|
||||
district_name: res.countyName,
|
||||
address: res.detailInfo,
|
||||
region: '',
|
||||
is_default: false,
|
||||
};
|
||||
if (!isEmpty(wechatAddress)) {
|
||||
sheep.$router.go('/pages/user/address/edit', {
|
||||
data: JSON.stringify(wechatAddress),
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.log('%cuni.chooseAddress,调用失败', 'color:green;background:yellow');
|
||||
},
|
||||
});
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
sheep.$platform.useProvider('wechat').jssdk.openAddress({
|
||||
success: (res) => {
|
||||
wechatAddress = {
|
||||
consignee: res.userName,
|
||||
mobile: res.telNumber,
|
||||
province_name: res.provinceName,
|
||||
city_name: res.cityName,
|
||||
district_name: res.countryName,
|
||||
address: res.detailInfo,
|
||||
region: '',
|
||||
is_default: false,
|
||||
};
|
||||
if (!isEmpty(wechatAddress)) {
|
||||
sheep.$router.go('/pages/user/address/edit', {
|
||||
data: JSON.stringify(wechatAddress),
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
// #endif
|
||||
}
|
||||
|
||||
onLoad((option) => {
|
||||
if (option.type) {
|
||||
state.openType = option.type;
|
||||
}
|
||||
});
|
||||
|
||||
onShow(async () => {
|
||||
state.list = (await AddressApi.getAddressList()).data;
|
||||
state.loading = false;
|
||||
});
|
||||
|
||||
onBeforeMount(() => {
|
||||
if (!!uni.getStorageSync('areaData')) {
|
||||
return;
|
||||
}
|
||||
// 提前加载省市区数据
|
||||
AreaApi.getAreaTree().then((res) => {
|
||||
if (res.code === 0) {
|
||||
uni.setStorageSync('areaData', res.data);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.footer-box {
|
||||
.add-btn {
|
||||
flex: 1;
|
||||
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
|
||||
border-radius: 80rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
line-height: 80rpx;
|
||||
color: $white;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.sync-wxaddress {
|
||||
flex: 1;
|
||||
line-height: 80rpx;
|
||||
background: $white;
|
||||
border-radius: 80rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: $dark-6;
|
||||
margin-right: 18rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
221
pages/user/detail/components/detail-navbar.vue
Normal file
221
pages/user/detail/components/detail-navbar.vue
Normal file
@@ -0,0 +1,221 @@
|
||||
<template>
|
||||
<su-fixed alway :bgStyles="{ background: '#fff' }" :val="0" noNav opacity :placeholder="false">
|
||||
<su-status-bar />
|
||||
<view
|
||||
class="ui-bar ss-flex ss-col-center ss-row-between ss-p-x-20"
|
||||
:style="[{ height: sys_navBar - sys_statusBar + 'px' }]"
|
||||
>
|
||||
<!-- 左 -->
|
||||
<view class="icon-box ss-flex">
|
||||
<view class="icon-button icon-button-left ss-flex ss-row-center" @tap="onClickLeft">
|
||||
<text :class="tabOpacityVal > 0.4 ? 'black' : ''" class="sicon-back" v-if="hasHistory" />
|
||||
<text :class="tabOpacityVal > 0.4 ? 'black' : ''" class="sicon-home" v-else />
|
||||
</view>
|
||||
<view class="line"></view>
|
||||
<view class="icon-button icon-button-right ss-flex ss-row-center" @tap="onClickRight">
|
||||
<text :class="tabOpacityVal > 0.4 ? 'black' : ''" class="sicon-more" />
|
||||
</view>
|
||||
</view>
|
||||
<!-- 中 -->
|
||||
<view class="detail-tab-card ss-flex-1" :style="[{ opacity: tabOpacityVal }]">
|
||||
<view class="tab-box ss-flex ss-col-center ss-row-around">
|
||||
<view
|
||||
class="tab-item ss-flex-1 ss-flex ss-row-center ss-col-center"
|
||||
v-for="item in tabList"
|
||||
:key="item.value"
|
||||
@tap="onTab(item)"
|
||||
>
|
||||
<view class="tab-title" :class="currentTab === item.value ? 'cur-tab-title' : ''">
|
||||
{{ item.label }}
|
||||
</view>
|
||||
<view v-show="currentTab === item.value" class="tab-line"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- #ifdef MP -->
|
||||
<view :style="[capsuleStyle]"></view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</su-fixed>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import sheep from '@/sheep';
|
||||
import { showMenuTools, closeMenuTools } from '@/sheep/hooks/useModal';
|
||||
export default {
|
||||
components: {
|
||||
|
||||
},
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
//滚动条滚动距离
|
||||
scrollTop: {
|
||||
type: [Number, String],
|
||||
default: 0
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
sys_navBar: sheep.$platform.navbar,
|
||||
sys_statusBar: sheep.$platform.device.statusBarHeight,
|
||||
hasHistory: sheep.$router.hasHistory(),
|
||||
tabList: [
|
||||
{
|
||||
label: '礼物墙',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '动态',
|
||||
value: 1,
|
||||
},
|
||||
],
|
||||
capsuleStyle: {
|
||||
width: sheep.$platform.capsule.width + 'px',
|
||||
height: sheep.$platform.capsule.height + 'px',
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
tabOpacityVal() {
|
||||
return this.scrollTop > sheep.$platform.navbar ? 1 : this.scrollTop * 0.01;;
|
||||
},
|
||||
currentTab() {
|
||||
return sheep.$store('sys').userTabIndex;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onClickLeft() {
|
||||
if (this.hasHistory) {
|
||||
sheep.$router.back();
|
||||
} else {
|
||||
sheep.$router.go('/pages/tabbar/index');
|
||||
}
|
||||
},
|
||||
onClickRight() {
|
||||
showMenuTools();
|
||||
},
|
||||
onTab(e) {
|
||||
this.$emit('onTab', e.value);
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.icon-box {
|
||||
box-shadow: 0px 0px 4rpx rgba(51, 51, 51, 0.08), 0px 4rpx 6rpx 2rpx rgba(102, 102, 102, 0.12);
|
||||
border-radius: 30rpx;
|
||||
width: 134rpx;
|
||||
height: 56rpx;
|
||||
margin-left: 8rpx;
|
||||
border: 1px solid rgba(#fff, 0.4);
|
||||
.line {
|
||||
width: 2rpx;
|
||||
height: 24rpx;
|
||||
background: #e5e5e7;
|
||||
}
|
||||
.sicon-back {
|
||||
font-size: 32rpx;
|
||||
color: #fff;
|
||||
}
|
||||
.sicon-home {
|
||||
font-size: 32rpx;
|
||||
color: #fff;
|
||||
}
|
||||
.sicon-more {
|
||||
font-size: 32rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.black {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.icon-button {
|
||||
width: 67rpx;
|
||||
height: 56rpx;
|
||||
&-left:hover {
|
||||
background: rgba(0, 0, 0, 0.16);
|
||||
border-radius: 30rpx 0px 0px 30rpx;
|
||||
}
|
||||
&-right:hover {
|
||||
background: rgba(0, 0, 0, 0.16);
|
||||
border-radius: 0px 30rpx 30rpx 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.left-box {
|
||||
position: relative;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.circle {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
background: rgba(#fff, 0.6);
|
||||
border: 1rpx solid #ebebeb;
|
||||
border-radius: 50%;
|
||||
box-sizing: border-box;
|
||||
z-index: -1;
|
||||
}
|
||||
}
|
||||
.right {
|
||||
position: relative;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.circle {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
background: rgba(#ffffff, 0.6);
|
||||
border: 1rpx solid #ebebeb;
|
||||
box-sizing: border-box;
|
||||
border-radius: 50%;
|
||||
z-index: -1;
|
||||
}
|
||||
}
|
||||
.detail-tab-card {
|
||||
width: 50%;
|
||||
.tab-item {
|
||||
height: 80rpx;
|
||||
position: relative;
|
||||
z-index: 11;
|
||||
|
||||
.tab-title {
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.cur-tab-title {
|
||||
font-weight: $font-weight-bold;
|
||||
}
|
||||
|
||||
.tab-line {
|
||||
width: 60rpx;
|
||||
height: 6rpx;
|
||||
border-radius: 6rpx;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
bottom: 10rpx;
|
||||
background-color: var(--ui-BG-Main);
|
||||
z-index: 12;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</style>
|
316
pages/user/detail/components/giftList.vue
Normal file
316
pages/user/detail/components/giftList.vue
Normal file
@@ -0,0 +1,316 @@
|
||||
<template>
|
||||
<view v-show="showPop" class="gift-box">
|
||||
<scroll-view style="height: 100%;" scroll-y>
|
||||
<view class="top-box">
|
||||
<view class="title">选择礼物</view>
|
||||
<view class="btn-box" @click="close">
|
||||
<u-icon name="close"></u-icon>
|
||||
<view class="text">取消</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="list-box">
|
||||
<view v-for="(item,index) in dataList" class="gift" @click="sendGift(item)">
|
||||
<view class="img-box">
|
||||
<img class="img" :src="item.img"></img>
|
||||
<view class="tag" v-if="item.giftType == 1">
|
||||
<text>特效</text>
|
||||
<text v-if="item.tag">·{{item.tag}}</text>
|
||||
</view>
|
||||
<view class="tag" v-if="item.giftType == 0 && item.tag">
|
||||
<text>{{item.tag}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="name">{{item.name}}</view>
|
||||
<view class="price">{{ fen2yuan(item.money) }} 钻石</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
</view>
|
||||
|
||||
<view class="svga-box" :class="giftFlag ? 'svga-show': 'svga-hide'">
|
||||
<c-svga ref="cSvgaRef" :canvasId='canvasId' :src="src" :loops='0' :auto-play="false" @frame='onFrame' @finished='onFinished' @percentage='onPercentage' @loaded='onLoaded'></c-svga>
|
||||
<view class="close-btn">
|
||||
<view class="bottom-box">
|
||||
<view class="title">{{gift.name}}</view>
|
||||
<view class="price">{{ fen2yuan(gift.money) }} 钻石</view>
|
||||
<view class="btn-box">
|
||||
<view class="btn" @click="cannel">取消</view>
|
||||
<view class="btn active" @click="ok">确定</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import sheep from '@/sheep';
|
||||
export default {
|
||||
components: {
|
||||
|
||||
},
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
showPop: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
dataList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
},
|
||||
emits: ["close", "update:modelValue"],
|
||||
data() {
|
||||
return {
|
||||
giftFlag: false,
|
||||
src: '',
|
||||
canvasId: 'myCanvas2',
|
||||
|
||||
gift: {},
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.$emit('close');
|
||||
},
|
||||
sendGift(e) {
|
||||
this.gift = e;
|
||||
|
||||
if(e.giftType == 0){
|
||||
// 普通礼物不播放
|
||||
this.close();
|
||||
this.$emit('update:modelValue', this.gift);
|
||||
return;
|
||||
}
|
||||
|
||||
this.src = e.pic;
|
||||
this.giftFlag = true;
|
||||
},
|
||||
onFinished() {
|
||||
this.giftFlag = false;
|
||||
console.log('动画停止播放时回调');
|
||||
},
|
||||
onFrame(frame) {//动画播放至某帧后回调
|
||||
// console.log(frame);
|
||||
},
|
||||
onPercentage(percentage) { //动画播放至某进度后回调
|
||||
// console.log(percentage);
|
||||
},
|
||||
onLoaded() {
|
||||
this.$refs.cSvgaRef.call('setContentMode', 'AspectFill');
|
||||
console.log('加载完成');
|
||||
this.$refs.cSvgaRef.call('startAnimation');
|
||||
},
|
||||
closeSvga() {
|
||||
this.src = "";
|
||||
this.$refs.cSvgaRef.call('stopAnimation');
|
||||
this.giftFlag = false;
|
||||
},
|
||||
fen2yuan(price) {
|
||||
var f = 0;
|
||||
var p = (price / 100.0).toFixed(0);
|
||||
var p1 = (price / 100.0).toFixed(1);
|
||||
var p2 = (price / 100.0).toFixed(2);
|
||||
if(p*100 == price){
|
||||
f = 0;
|
||||
}else if(p1*100 == price){
|
||||
f = 1;
|
||||
}else if(p2*100 == price){
|
||||
f = 2;
|
||||
}
|
||||
return (price / 100.0).toFixed(f)
|
||||
},
|
||||
cannel() {
|
||||
this.closeSvga();
|
||||
},
|
||||
ok() {
|
||||
this.closeSvga();
|
||||
this.close();
|
||||
this.$emit('update:modelValue', this.gift);
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.gift-box {
|
||||
background-color: #fff;
|
||||
position: absolute;
|
||||
top: 200rpx;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 9999;
|
||||
padding: 15px;
|
||||
border-top-right-radius: 20rpx;
|
||||
border-top-left-radius: 20rpx;
|
||||
padding-bottom: 0;
|
||||
|
||||
.top-box {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: #fff;
|
||||
top: 200rpx;
|
||||
padding: 0 15px;
|
||||
border-top-right-radius: 20rpx;
|
||||
border-top-left-radius: 20rpx;
|
||||
height: 110rpx;
|
||||
z-index: 1;
|
||||
|
||||
.title {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.btn-box {
|
||||
background-color: var(--ui-BG-Main);
|
||||
padding: 7px 15px;
|
||||
font-size: 24rpx;
|
||||
border-radius: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
|
||||
.text {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list-box {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding-top: 60rpx;
|
||||
|
||||
.gift {
|
||||
width: 25%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 20rpx 0px;
|
||||
|
||||
.img-box {
|
||||
position: relative;
|
||||
|
||||
.img{
|
||||
max-width: 160rpx;
|
||||
height: 160rpx;
|
||||
}
|
||||
|
||||
.tag {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
font-size: 16rpx;
|
||||
color: #fff;
|
||||
background-color: var(--ui-BG-Main);
|
||||
border-radius: 40px;
|
||||
padding: 2rpx 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: 24rpx;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
max-width: 160rpx;
|
||||
margin-top: 2px;
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
.price {
|
||||
font-size: 20rpx;
|
||||
color: var(--ui-BG-Main);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.svga-box {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 999999999;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: black;
|
||||
|
||||
.close-btn {
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
z-index: 999999999;
|
||||
padding: 5px 10px;
|
||||
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 100rpx;
|
||||
|
||||
.bottom-box {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.title {
|
||||
font-size: 28rpx;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.price {
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.btn-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 10px;
|
||||
|
||||
.btn {
|
||||
border: 1px solid #fff;
|
||||
font-size: 28rpx;
|
||||
padding: 20rpx 110rpx;
|
||||
border-radius: 40px;
|
||||
margin: 15px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.active {
|
||||
border: 1px solid var(--ui-BG-Main);
|
||||
background-color: var(--ui-BG-Main);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.svga-hide {
|
||||
/* #ifdef MP */
|
||||
transform: translate(-100%, 0);
|
||||
/* #endif */
|
||||
|
||||
/* #ifndef MP */
|
||||
display: none;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.svga-show {
|
||||
/* #ifdef MP */
|
||||
transform: translate(0, 0);
|
||||
/* #endif */
|
||||
|
||||
/* #ifndef MP */
|
||||
display: block;
|
||||
/* #endif */
|
||||
}
|
||||
</style>
|
445
pages/user/detail/components/giftPopup.vue
Normal file
445
pages/user/detail/components/giftPopup.vue
Normal file
@@ -0,0 +1,445 @@
|
||||
<template>
|
||||
<tui-bottom-popup :zIndex="1002" :maskZIndex="1001" :show="popupShow" @close="hiddenPopup">
|
||||
<view class="order-box">
|
||||
<view class="avatar-box">
|
||||
<u-image width="140" height="140" border-radius="20" :src="clerk.avatar"></u-image>
|
||||
<view class="close-span" @click="hiddenPopup">
|
||||
<u-icon name="close-circle" color="#98a2a1" size="50"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
<scroll-view style="height: 700rpx;" scroll-y>
|
||||
<view class="page-box">
|
||||
|
||||
<view class="form-box">
|
||||
|
||||
<view class="input-box">
|
||||
<view class="tag-box">
|
||||
<view class="name">赠送类型</view>
|
||||
</view>
|
||||
<view class="tab-span">
|
||||
<!-- <view @click="changeTab(0)" class="btn" :class="form.rewardType == 0 ? 'active' : ''">赠送</view> -->
|
||||
<view @click="changeTab(1)" class="btn" :class="form.rewardType == 1 ? 'active' : ''">赠礼</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<view class="input-box" v-if="form.rewardType == 0">
|
||||
<view class="tag-box">
|
||||
<view class="name">打赏金额</view>
|
||||
</view>
|
||||
<view class="input-span">
|
||||
<u-input v-model="payMoney" type="number" :placeholder-style="`fontSize: 24rpx; color: #cbced5;`" placeholder="请输入赠送金额"></u-input>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="input-box" v-if="form.rewardType == 1">
|
||||
<view class="tag-box">
|
||||
<view class="name">赠送礼物</view>
|
||||
</view>
|
||||
<view class="select-span" @click="openGift">
|
||||
<view v-if="gift.id > 0">已选【{{gift.name}}】</view>
|
||||
<view v-else>点击选择礼物</view>
|
||||
<u-icon name="arrow-right"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="input-box" v-if="gift.id > 0">
|
||||
<view class="tag-box">
|
||||
<view class="name">礼物数量</view>
|
||||
</view>
|
||||
<view class="step-span">
|
||||
<img class="img" :src="gift.img"></img>
|
||||
<tui-numberbox iconBgColor="var(--ui-BG-Main)" iconColor="#fff" backgroundColor="#fff" :min="1" :value="form.count" @change="change"></tui-numberbox>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="input-box">
|
||||
<view class="textarea-box">
|
||||
<view class="name">心动留言</view>
|
||||
</view>
|
||||
<view class="textarea-span">
|
||||
<u-input v-model="form.msg" type="textarea" :placeholder-style="`fontSize: 24rpx; color: #cbced5;`" placeholder="请输入心动留言"></u-input>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="input-box" v-if="isPass">
|
||||
<view class="tag-box">
|
||||
<view class="name">您的微信号</view>
|
||||
</view>
|
||||
<view class="input-span">
|
||||
<u-input v-model="form.weixin" :placeholder-style="`fontSize: 24rpx; color: #cbced5;`" placeholder="请输入正确的微信号"></u-input>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="bottom-box2" v-if="form.rewardType == 0">
|
||||
<view class="btn-box">
|
||||
<view class="pay-btn" @click="confirm">立即赠送</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="bottom-box" v-if="form.rewardType == 1">
|
||||
<view class="price-box">
|
||||
<text>总价:</text>
|
||||
<text class="price">{{ fen2yuan(gift.money*form.count) }}</text>
|
||||
<text>钻石</text>
|
||||
</view>
|
||||
<view class="btn-box">
|
||||
<view class="pay-btn" @click="confirm">立即赠送</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</tui-bottom-popup>
|
||||
|
||||
<gift-list :showPop="giftFlag" :dataList="giftList" v-model="gift" @close="closeGift"></gift-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import tuiBottomPopup from "@/components/thorui/tui-bottom-popup/tui-bottom-popup.vue"
|
||||
import tuiNumberbox from "@/components/thorui/tui-numberbox/tui-numberbox.vue"
|
||||
import GiftList from '@/pages/user/detail/components/giftList.vue';
|
||||
import RewardApi from '@/sheep/api/worker/reward';
|
||||
import sheep from '@/sheep';
|
||||
export default {
|
||||
components: {
|
||||
tuiBottomPopup,
|
||||
tuiNumberbox,
|
||||
GiftList,
|
||||
},
|
||||
props: {
|
||||
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
popupShow: false,
|
||||
|
||||
gift: {
|
||||
id: -1,
|
||||
money: 0,
|
||||
},
|
||||
|
||||
giftFlag: false,
|
||||
|
||||
giftList: [],
|
||||
|
||||
payMoney: '',
|
||||
|
||||
form: {
|
||||
rewardType: 1,
|
||||
count: 1,
|
||||
giftId: -1,
|
||||
money: '',
|
||||
weixin: '',
|
||||
msg: '',
|
||||
workerUserId: 0,
|
||||
payMoney: '',
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
clerk() {
|
||||
return sheep.$store('sys').user;
|
||||
},
|
||||
userInfo() {
|
||||
return sheep.$store('user').userInfo;
|
||||
},
|
||||
isPass() {
|
||||
return sheep.$store('user').tradeConfig.weixinEnabled;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
//调用此方法显示弹层
|
||||
showPopup() {
|
||||
this.form.weixin = this.userInfo.weixin;
|
||||
RewardApi.getGiftList().then(res => {
|
||||
this.giftList = res.data;
|
||||
this.popupShow = true
|
||||
});
|
||||
},
|
||||
showGiftPopup(e) {
|
||||
this.gift = e;
|
||||
this.form.rewardType = 1;
|
||||
this.form.weixin = this.userInfo.weixin;
|
||||
RewardApi.getGiftList().then(res => {
|
||||
this.giftList = res.data;
|
||||
this.popupShow = true
|
||||
});
|
||||
},
|
||||
hiddenPopup() {
|
||||
this.popupShow = false
|
||||
},
|
||||
change(e) {
|
||||
this.form.count = e.value
|
||||
},
|
||||
changeTab(e) {
|
||||
this.form.rewardType = e;
|
||||
this.gift = {
|
||||
id: -1,
|
||||
money: 0,
|
||||
};
|
||||
},
|
||||
fen2yuan(price) {
|
||||
var f = 0;
|
||||
var p = (price / 100.0).toFixed(0);
|
||||
var p1 = (price / 100.0).toFixed(1);
|
||||
var p2 = (price / 100.0).toFixed(2);
|
||||
if(p*100 == price){
|
||||
f = 0;
|
||||
}else if(p1*100 == price){
|
||||
f = 1;
|
||||
}else if(p2*100 == price){
|
||||
f = 2;
|
||||
}
|
||||
return (price / 100.0).toFixed(f)
|
||||
},
|
||||
yuan2fen(price) {
|
||||
return (price * 100.0).toFixed(0)
|
||||
},
|
||||
openGift() {
|
||||
this.giftFlag = true;
|
||||
},
|
||||
closeGift() {
|
||||
this.form.count = 1;
|
||||
this.giftFlag = false;
|
||||
},
|
||||
confirm() {
|
||||
if(this.isPass && !this.form.weixin){
|
||||
sheep.$helper.toast('请输入正确的微信');
|
||||
return;
|
||||
}
|
||||
if(this.form.rewardType == 0){
|
||||
this.form.payMoney = this.yuan2fen(this.payMoney);
|
||||
if(this.form.payMoney < 1){
|
||||
sheep.$helper.toast('请输入打赏金额');
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
this.form.giftId = this.gift.id;
|
||||
if(this.form.giftId < 1){
|
||||
sheep.$helper.toast('请选择打赏礼物');
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.form.workerUserId = this.clerk.id;
|
||||
RewardApi.createRewardOrder(this.form).then(res => {
|
||||
// 跳转到支付页面
|
||||
this.$u.route({
|
||||
url: 'pages/pay/reward/index',
|
||||
params: {
|
||||
id: res.data.payOrderId,
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.avatar-box {
|
||||
padding: 10px 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.close-span {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
width: 70rpx;
|
||||
height: 70rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.page-box {
|
||||
padding: 15px;
|
||||
padding-bottom: 10px;
|
||||
|
||||
.form-box {
|
||||
margin-bottom: 10px;
|
||||
|
||||
.tag-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 180rpx;
|
||||
|
||||
.name {
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.textarea-box {
|
||||
height: 20px;
|
||||
display: flex;
|
||||
width: 180rpx;
|
||||
|
||||
.name {
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.input-box {
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
align-items: center;
|
||||
|
||||
.input-span {
|
||||
background-color: #f6f6f6;
|
||||
margin-left: 15px;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
padding: 0 12px;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
.select-span {
|
||||
font-size: 24rpx;
|
||||
background-color: #f6f6f6;
|
||||
margin-left: 15px;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
padding: 12px 12px;
|
||||
border-radius: 10rpx;
|
||||
color: #aaaaaa;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.tab-span {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
padding: 0 12px;
|
||||
align-items: center;
|
||||
|
||||
.btn {
|
||||
background-color: #f6f6f6;
|
||||
font-size: 24rpx;
|
||||
padding: 7px 0;
|
||||
border-radius: 40px;
|
||||
min-width: 120rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.active {
|
||||
color: #fff;
|
||||
background-color: var(--ui-BG-Main);
|
||||
}
|
||||
}
|
||||
|
||||
.textarea-span {
|
||||
background-color: #f6f6f6;
|
||||
margin-left: 15px;
|
||||
flex: 1;
|
||||
padding: 2px 12px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.step-span {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex: 1;
|
||||
padding-left: 12px;
|
||||
align-items: center;
|
||||
|
||||
.img {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 100%;
|
||||
box-shadow: 0 0 8px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-box {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15px;
|
||||
box-shadow: 0 0 6px 0 #ccc;
|
||||
|
||||
.price-box {
|
||||
color: #fb932c;
|
||||
font-size: 28rpx;
|
||||
width: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.price {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-box {
|
||||
width: 50%;
|
||||
padding-left: 15px;
|
||||
|
||||
.pay-btn {
|
||||
background-color: var(--ui-BG-Main);
|
||||
color: #fff;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 40px;
|
||||
font-size: 28rpx;
|
||||
height: 70rpx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.bottom-box2 {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 15px;
|
||||
box-shadow: 0 0 6px 0 #ccc;
|
||||
|
||||
.price-box {
|
||||
color: #fb932c;
|
||||
font-size: 28rpx;
|
||||
width: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.price {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-box {
|
||||
width: 50%;
|
||||
|
||||
.pay-btn {
|
||||
background-color: var(--ui-BG-Main);
|
||||
color: #fff;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 40px;
|
||||
font-size: 28rpx;
|
||||
height: 70rpx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
</style>
|
286
pages/user/detail/components/layout.vue
Normal file
286
pages/user/detail/components/layout.vue
Normal file
@@ -0,0 +1,286 @@
|
||||
<!-- 虚拟列表演示(不使用内置列表)(vue) -->
|
||||
<!-- 写法较简单,在页面中对当前需要渲染的虚拟列表数据进行for循环,在vue3中兼容性良好 -->
|
||||
<!-- 在各平台兼容性请查阅https://z-paging.zxlee.cn/module/virtual-list.html -->
|
||||
<template>
|
||||
<view class="content">
|
||||
<!-- 如果页面中的cell高度是固定不变的,则不需要设置cell-height-mode,如果页面中高度是动态改变的,则设置cell-height-mode="dynamic" -->
|
||||
<!-- 原先的v-model修改为@virtualListChange="virtualListChange"并赋值处理后的虚拟列表 -->
|
||||
<z-paging ref="paging" :auto="false" :show-loading-more-no-more-view="showLoad" :show-default-loading-more-text="showLoad" use-virtual-list :force-close-inner-list="true" :paging-style="{ paddingTop: 0 + 'px', paddingBottom: paddingBottom + 'rpx' }" cell-height-mode="dynamic" @scroll="scroll" @virtualListChange="virtualListChange" @query="queryList">
|
||||
<!-- 需要固定在顶部不滚动的view放在slot="top"的view中,如果需要跟着滚动,则不要设置slot="top" -->
|
||||
<template #top>
|
||||
<nav-bar :title="title" :scrollTop="scrollTop" @onTab="change" @initNav="initNav"></nav-bar>
|
||||
</template>
|
||||
|
||||
<view>
|
||||
<user-box :clerk="user" :paddingTop="paddingTop"></user-box>
|
||||
<sticky-box :trendNum="total" @change="change"></sticky-box>
|
||||
</view>
|
||||
|
||||
<!-- :id="`zp-id-${item.zp_index}`"和:key="item.zp_index" 必须写,必须写!!!! -->
|
||||
<!-- 这里for循环的index不是数组中真实的index了,请使用item.zp_index获取真实的index -->
|
||||
<view class="data-box">
|
||||
<star-list v-if="currentTab == 0" @openGift="openGift" :virtualList="giftList"></star-list>
|
||||
<post-list v-if="currentTab == 1" :virtualList="virtualList"></post-list>
|
||||
</view>
|
||||
|
||||
<template #bottom>
|
||||
<view v-if="isGift" class="bottom-box">
|
||||
<view class="order" @click="doGift">赠礼</view>
|
||||
<view class="gift" @click="chat">密聊</view>
|
||||
</view>
|
||||
<view v-else class="bottom-box">
|
||||
<view class="order-btn" @click="chat">密聊</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
</z-paging>
|
||||
|
||||
<gift-popup ref="giftPopup"></gift-popup>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import UserBox from '@/pages/user/detail/components/userBox.vue';
|
||||
import StickyBox from '@/pages/user/detail/components/stickyBox.vue';
|
||||
import StarList from '@/pages/user/detail/components/starList.vue';
|
||||
import PostList from '@/pages/user/detail/components/postList.vue';
|
||||
import NavBar from '@/pages/user/detail/components/navBar.vue';
|
||||
import GiftPopup from '@/pages/user/detail/components/giftPopup.vue';
|
||||
import UserApi from '@/sheep/api/member/user';
|
||||
import TrendApi from '@/sheep/api/worker/trend';
|
||||
import RewardApi from '@/sheep/api/worker/reward';
|
||||
import ImConversationApi from '@/sheep/api/im/memberConversation';
|
||||
import { WxaSubscribeTemplate } from '@/sheep/util/const';
|
||||
import { showAuthModal } from '@/sheep/hooks/useModal';
|
||||
import dayjs from 'dayjs';
|
||||
import relativeTime from "dayjs/plugin/relativeTime";
|
||||
dayjs.extend(relativeTime);
|
||||
import sheep from '@/sheep';
|
||||
export default {
|
||||
components: {
|
||||
UserBox,
|
||||
StickyBox,
|
||||
StarList,
|
||||
PostList,
|
||||
NavBar,
|
||||
GiftPopup,
|
||||
},
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 虚拟列表数组,通过@virtualListChange监听获得最新数组
|
||||
virtualList: [],
|
||||
scrollTop: 0,
|
||||
paddingTop: 0,
|
||||
paddingBottom: 0,
|
||||
height: 0,
|
||||
|
||||
user: {},
|
||||
userId: 0,
|
||||
giftList: [],
|
||||
|
||||
total: 0,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentTab() {
|
||||
return sheep.$store('sys').userTabIndex;
|
||||
},
|
||||
showLoad() {
|
||||
return sheep.$store('sys').userTabIndex > 1;
|
||||
},
|
||||
isLogin: {
|
||||
get() {
|
||||
return sheep.$store('user').isLogin;
|
||||
},
|
||||
},
|
||||
userInfo: {
|
||||
get() {
|
||||
return sheep.$store('user').userInfo;
|
||||
},
|
||||
},
|
||||
isGift() {
|
||||
return sheep.$store('user').tradeConfig.giftEnabled;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
initNav(e) {
|
||||
this.height = e.height;
|
||||
this.paddingTop = this.height;
|
||||
},
|
||||
initData(options) {
|
||||
this.userId = options.id;
|
||||
this.getUserInfo();
|
||||
|
||||
RewardApi.getRewardGiftList({
|
||||
workerUserId: options.id,
|
||||
}).then(res => {
|
||||
this.giftList = res.data;
|
||||
});
|
||||
},
|
||||
getUserInfo() {
|
||||
UserApi.getUserInfoById(this.userId).then(res => {
|
||||
this.user = res.data;
|
||||
this.user.time = this.showDayTime(this.user.updateTime);
|
||||
sheep.$store('sys').setUser(this.user);
|
||||
|
||||
this.$refs.paging.reload();
|
||||
});
|
||||
},
|
||||
showDayTime(datetime) {
|
||||
if (!datetime) return "";
|
||||
return dayjs(datetime).fromNow();
|
||||
},
|
||||
scroll(e) {
|
||||
this.scrollTop = e.detail.scrollTop;
|
||||
},
|
||||
// 监听虚拟列表数组改变并赋值给virtualList进行重新渲染
|
||||
virtualListChange(vList) {
|
||||
this.virtualList = vList;
|
||||
},
|
||||
queryList(pageNo, pageSize) {
|
||||
// 组件加载时会自动触发此方法,因此默认页面加载时会自动触发,无需手动调用
|
||||
// 这里的pageNo和pageSize会自动计算好,直接传给服务器即可
|
||||
// 模拟请求服务器获取分页数据,请替换成自己的网络请求
|
||||
const params = {
|
||||
pageNo: pageNo,
|
||||
pageSize: pageSize,
|
||||
queryType: '2',
|
||||
workerUserId: this.userId,
|
||||
}
|
||||
|
||||
TrendApi.getTrendPage(params).then(res => {
|
||||
this.total = res.data.total;
|
||||
// 将请求的结果数组传递给z-paging
|
||||
this.$refs.paging.complete(res.data.list);
|
||||
}).catch(res => {
|
||||
// 如果请求失败写this.$refs.paging.complete(false);
|
||||
// 注意,每次都需要在catch中写这句话很麻烦,z-paging提供了方案可以全局统一处理
|
||||
// 在底层的网络请求抛出异常时,写uni.$emit('z-paging-error-emit');即可
|
||||
this.$refs.paging.complete(false);
|
||||
})
|
||||
},
|
||||
change(e) {
|
||||
sheep.$store('sys').setUserTabIndex(e);
|
||||
this.scrollTop = 0;
|
||||
this.$refs.paging.reload();
|
||||
},
|
||||
chat() {
|
||||
const isLogin = sheep.$store('user').isLogin;
|
||||
if(!isLogin) {
|
||||
showAuthModal();
|
||||
return;
|
||||
}
|
||||
|
||||
const userInfo = sheep.$store('user').userInfo;
|
||||
// 如果用户已经有头像和昵称,不要每次登录都要重新上传头像。
|
||||
if(userInfo.visible) {
|
||||
// #ifdef MP-WEIXIN
|
||||
this.subscribeMessage();
|
||||
// #endif
|
||||
|
||||
ImConversationApi.createMemberConversation({
|
||||
userId: this.userId,
|
||||
groupType: 1,
|
||||
lastMessageContentType: 1,
|
||||
}).then(res => {
|
||||
if(res.data){
|
||||
sheep.$router.go('/pages/im/index',{groupId: res.data, receiveUserId: this.userId});
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 触发小程序授权信息弹框
|
||||
// #ifdef MP-WEIXIN
|
||||
showAuthModal('mpAuthorization');
|
||||
// #endif
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
showAuthModal('h5Authorization');
|
||||
// #endif
|
||||
},
|
||||
subscribeMessage() {
|
||||
const event = [WxaSubscribeTemplate.UNREAD_MESSAGE];
|
||||
sheep.$platform.useProvider('wechat').subscribeMessage(event, () => {
|
||||
// 订阅后记录一下订阅状态
|
||||
uni.removeStorageSync(WxaSubscribeTemplate.UNREAD_MESSAGE);
|
||||
uni.setStorageSync(WxaSubscribeTemplate.UNREAD_MESSAGE, '已订阅');
|
||||
});
|
||||
},
|
||||
doGift() {
|
||||
if(this.isLogin){
|
||||
this.$refs.giftPopup.showPopup();
|
||||
}else{
|
||||
showAuthModal();
|
||||
}
|
||||
},
|
||||
openGift(e) {
|
||||
if(this.isLogin){
|
||||
this.$refs.giftPopup.showGiftPopup(e);
|
||||
}else{
|
||||
showAuthModal();
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.data-box {
|
||||
padding: 0 15px;
|
||||
}
|
||||
.bottom-box {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 10px 30px;
|
||||
box-shadow: 0 0 6px 0 #ccc;
|
||||
|
||||
.order {
|
||||
background-color: var(--ui-BG-Main);
|
||||
padding: 10px;
|
||||
border-top-left-radius: 40px;
|
||||
border-bottom-left-radius: 40px;
|
||||
color: #fff;
|
||||
width: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 88rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.order-btn {
|
||||
background-color: var(--ui-BG-Main);
|
||||
padding: 10px;
|
||||
border-radius: 40px;
|
||||
color: #fff;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 88rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.gift {
|
||||
background-color: #eef3f2;
|
||||
padding: 10px;
|
||||
border-top-right-radius: 40px;
|
||||
border-bottom-right-radius: 40px;
|
||||
width: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 88rpx;
|
||||
color: #aaa;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
89
pages/user/detail/components/navBar.vue
Normal file
89
pages/user/detail/components/navBar.vue
Normal file
@@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<view>
|
||||
<tui-navigation-bar @init="initNavigation" @change="opacityChange" :scrollTop="scrollTop" backgroundColor="#fff" color="#333">
|
||||
<detailNavbar @onTab="onTab" :scrollTop="scrollTop" />
|
||||
</tui-navigation-bar>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import tuiNavigationBar from "@/components/thorui/tui-navigation-bar/tui-navigation-bar.vue";
|
||||
import detailNavbar from '@/pages/user/detail/components/detail-navbar.vue';
|
||||
export default {
|
||||
components: {
|
||||
tuiNavigationBar,
|
||||
detailNavbar,
|
||||
},
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
//滚动条滚动距离
|
||||
scrollTop: {
|
||||
type: [Number, String],
|
||||
default: 0
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
top: 0, //标题图标距离顶部距离
|
||||
opacity: 0,
|
||||
height: 0,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initNavigation(e) {
|
||||
this.height = e.height;
|
||||
this.opacity = e.opacity;
|
||||
this.top = e.top;
|
||||
this.$emit('initNav', e);
|
||||
},
|
||||
opacityChange(e) {
|
||||
this.opacity = e.opacity;
|
||||
},
|
||||
onTab(e) {
|
||||
this.$emit('onTab', e);
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content-bpx {
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 44px;
|
||||
justify-content: center;
|
||||
|
||||
.left-box {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.nickname {
|
||||
position: absolute;
|
||||
width: 100px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 44px;
|
||||
font-size: 15px;
|
||||
font-weight: bolder;
|
||||
color: #1f2122;
|
||||
}
|
||||
|
||||
.set-btn {
|
||||
padding: 0 15px;
|
||||
height: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
</style>
|
50
pages/user/detail/components/photoBox.vue
Normal file
50
pages/user/detail/components/photoBox.vue
Normal file
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<view class="photo-box">
|
||||
<scroll-view scroll-x>
|
||||
<view class="scroll-box">
|
||||
<view class="img-box" @click="showImage(item)" v-for="(item,index) in dataList">
|
||||
<u-image border-radius="20" width="170rpx" height="170rpx" :src="item"></u-image>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
components: {
|
||||
|
||||
},
|
||||
props: {
|
||||
dataList: {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showImage(src) {
|
||||
uni.previewImage({
|
||||
indicator: "none",
|
||||
current: src,
|
||||
urls: this.dataList,
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.photo-box {
|
||||
.scroll-box {
|
||||
display: flex;
|
||||
}
|
||||
.img-box {
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
362
pages/user/detail/components/postList.vue
Normal file
362
pages/user/detail/components/postList.vue
Normal file
@@ -0,0 +1,362 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class="item" :id="`zp-id-${item.zp_index}`" :key="item.zp_index" v-for="(item,index) in orderList">
|
||||
<view class="card">
|
||||
<view class="right">
|
||||
<view class="card-header">
|
||||
<view class="box3">
|
||||
<view class="box1">
|
||||
<view class="tag-list">
|
||||
<!-- <view class="tag">Ta爱玩王者荣耀</view> -->
|
||||
<view class="tag">发布于 {{item.createTimeStr}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-content">
|
||||
<view class="text-box">
|
||||
<rich-text :nodes="item.content"></rich-text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="image-box" v-if="item.fileType == 0">
|
||||
<img-box @preAd="preAd" :ad="item.adStatus" :file="item.file"></img-box>
|
||||
</view>
|
||||
<view class="voice-box" v-if="item.fileType == 1">
|
||||
<voice-play :sec="item.seconds" @tap.stop="playAudio(item)" :isPlay="item.id == playId"></voice-play>
|
||||
</view>
|
||||
<view class="video-box" v-if="item.fileType == 2">
|
||||
<video-box :file="item.file"></video-box>
|
||||
</view>
|
||||
<view class="topic-list">
|
||||
<view class="topic">
|
||||
<u-icon name="map-fill" size="40" color="#3cc9a4"></u-icon>
|
||||
<view class="tag-text">{{item.city}}</view>
|
||||
<u-icon name="arrow-right" size="24" color="#3cc9a4"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-footer">
|
||||
<!-- <view class="toolbar">
|
||||
<u-icon color="#f880ab" name="presentfill" size="38" custom-prefix="iconfont"></u-icon>
|
||||
<view class="toolbar-text">3</view>
|
||||
</view> -->
|
||||
<!-- <view class="toolbar">
|
||||
<u-icon name="pinglun" size="38" custom-prefix="iconfont"></u-icon>
|
||||
<view class="toolbar-text">22</view>
|
||||
</view> -->
|
||||
<view class="toolbar" @click="thumb(item)">
|
||||
<u-icon v-if="item.like" name="thumb-up-fill" color="var(--ui-BG-Main)" size="40"></u-icon>
|
||||
<u-icon v-else name="thumb-up" size="40"></u-icon>
|
||||
<view class="toolbar-text" v-if="item.likeNum > 0">{{item.likeNum}}</view>
|
||||
<view class="text" v-else>点赞</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ImgBox from '@/pages/tabbar/components/trend/imgBox.vue';
|
||||
import VideoBox from '@/pages/tabbar/components/trend/videoBox.vue';
|
||||
import VoicePlay from '@/pages/tabbar/components/trend/voicePlay.vue';
|
||||
import adVideoUtils from '@/sheep/util/adVideoUtils';
|
||||
import sheep from '@/sheep';
|
||||
import TrendApi from '@/sheep/api/worker/trend';
|
||||
const audio = uni.createInnerAudioContext();
|
||||
export default {
|
||||
components: {
|
||||
ImgBox,
|
||||
VideoBox,
|
||||
VoicePlay,
|
||||
},
|
||||
props: {
|
||||
virtualList: {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
playId: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
orderList() {
|
||||
this.virtualList.forEach((order) => order.createTimeStr = sheep.$helper.timeFormat(order.createTime, 'yyyy-mm-dd hh:MM'));
|
||||
return this.virtualList;
|
||||
},
|
||||
tradeConfig() {
|
||||
return sheep.$store('user').tradeConfig;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
playAudio(e) {
|
||||
if(this.playId == e.id){
|
||||
this.playId = null;
|
||||
audio.stop();
|
||||
return;
|
||||
}
|
||||
this.playId = e.id;
|
||||
//语音自然播放结束
|
||||
audio.onEnded((res) => {
|
||||
this.playId = null;
|
||||
});
|
||||
audio.src = e.file;
|
||||
audio.play();
|
||||
},
|
||||
thumb(e) {
|
||||
TrendApi.createTrendLike({
|
||||
trendId: e.id,
|
||||
}).then((res) => {
|
||||
if(res) {
|
||||
if(e.like){
|
||||
e.like = false;
|
||||
e.likeNum = e.likeNum-1;
|
||||
sheep.$helper.toast('取消点赞');
|
||||
}else{
|
||||
e.like = true;
|
||||
e.likeNum = e.likeNum+1;
|
||||
sheep.$helper.toast('点赞成功');
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
preAd(run) {
|
||||
adVideoUtils.videoAdInit(this.tradeConfig.adUnitId);
|
||||
adVideoUtils.videoAdShow()
|
||||
.then((res) => {
|
||||
if (res) {
|
||||
run(true);
|
||||
} else {
|
||||
console.log('广告提前退出')
|
||||
run(false);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log('广告加载失败')
|
||||
run(false);
|
||||
});
|
||||
},
|
||||
fans(e) {
|
||||
TrendApi.createClerkFans({
|
||||
workerClerkId: e.workerClerkId,
|
||||
}).then((res) => {
|
||||
if(res){
|
||||
if(e.fans){
|
||||
sheep.$helper.toast('取消收藏');
|
||||
e.fans = false;
|
||||
}else{
|
||||
sheep.$helper.toast('收藏成功');
|
||||
e.fans = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
detail(e) {
|
||||
this.$u.route({
|
||||
url: 'pages/clerk/detail/index',
|
||||
params: {
|
||||
id: e.workerClerkId,
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 30rpx 20rpx;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
display: flex;
|
||||
|
||||
.right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-img{
|
||||
margin-right: 5px;
|
||||
width: 110rpx;
|
||||
height: 110rpx;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 8rpx;
|
||||
|
||||
.img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar{
|
||||
margin-right: 5px;
|
||||
width: 110rpx;
|
||||
height: 110rpx;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.img {
|
||||
width: 75%;
|
||||
height: 75%;
|
||||
border-radius: 100%;
|
||||
}
|
||||
.gif {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.box1 {
|
||||
.tag-list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 22rpx;
|
||||
margin-top: 4rpx;
|
||||
|
||||
.tag::after {
|
||||
content: '·';
|
||||
padding: 0 10rpx; /* 添加一些间隔 */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.tag-list .tag:last-child::after {
|
||||
content: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.box2 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 40rpx;
|
||||
|
||||
.nickname {
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.sex-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #d06b8d1f;
|
||||
border-radius: 20px;
|
||||
font-size: 20rpx;
|
||||
padding: 4rpx 10rpx;
|
||||
color: #d06b8d;
|
||||
line-height: 24rpx;
|
||||
margin: 0 5px;
|
||||
|
||||
.age {
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.nan {
|
||||
background-color: #007aff1a;
|
||||
color: #007aff;
|
||||
}
|
||||
}
|
||||
|
||||
.box3 {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.fans {
|
||||
width: 60rpx;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
height: 60rpx;
|
||||
align-items: center;
|
||||
color: var(--ui-BG-Main);
|
||||
font-size: 24rpx;
|
||||
padding-right: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-content {
|
||||
margin-top: 20rpx;
|
||||
margin-bottom: 10rpx;
|
||||
|
||||
.text-box {
|
||||
font-size: 26rpx;
|
||||
line-height: 180%;
|
||||
white-space: pre-wrap;
|
||||
letter-spacing: 2rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.topic-list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 10px;
|
||||
|
||||
.topic {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 28rpx;
|
||||
margin-right: 20rpx;
|
||||
color: var(--ui-BG-Main);
|
||||
font-weight: bold;
|
||||
|
||||
.tag-text {
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 30rpx;
|
||||
|
||||
.toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
color: #666666;
|
||||
width: 80rpx;
|
||||
height: 40rpx;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.toolbar-text {
|
||||
font-size: 26rpx;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-size: 24rpx;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
</style>
|
310
pages/user/detail/components/starList.vue
Normal file
310
pages/user/detail/components/starList.vue
Normal file
@@ -0,0 +1,310 @@
|
||||
<template>
|
||||
<view>
|
||||
<view v-if="isGift" class="star-box">
|
||||
<view class="title-box">
|
||||
<view class="title">礼物墙</view>
|
||||
<view class="num">(已点亮:{{starNum}}/{{total}})</view>
|
||||
</view>
|
||||
|
||||
<view class="list-box">
|
||||
<view @click="sendGift(item)" v-for="(item,index) in virtualList" :key="item.id" class="gift">
|
||||
<view class="img-box">
|
||||
<img class="img" :class="item.playStatus == 0 ? 'hui' : ''" :src="item.img"></img>
|
||||
<view class="tag" v-if="item.giftType == 1">
|
||||
<text>特效</text>
|
||||
<text v-if="item.tag">·{{item.tag}}</text>
|
||||
</view>
|
||||
<view class="tag" v-if="item.giftType == 0 && item.tag">
|
||||
<text>{{item.tag}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="name">{{item.name}}</view>
|
||||
<view class="price">x {{item.playNum}}</view>
|
||||
<view class="btn" @tap.stop="openGift(item)" v-if="item.playStatus == 0">点亮</view>
|
||||
<view class="btn" @tap.stop="openGift(item)" v-if="item.playStatus == 1">赠送</view>
|
||||
<view class="btn" v-if="item.playStatus == 2">已下架</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
|
||||
<view class="svga-box" :class="giftFlag ? 'svga-show': 'svga-hide'">
|
||||
<c-svga ref="cSvgaRef" :canvasId='canvasId' :src="src" :loops='0' :auto-play="false" @frame='onFrame' @finished='onFinished' @percentage='onPercentage' @loaded='onLoaded'></c-svga>
|
||||
<view class="close-btn" @click="closeSvga">
|
||||
<view class="bottom-box">
|
||||
<view class="title">{{gift.name}}</view>
|
||||
<view class="price">{{ fen2yuan(gift.money) }} 钻石</view>
|
||||
<view class="btn-box">
|
||||
<view class="btn" @click="cannel">取消</view>
|
||||
<view v-if="gift.playStatus == 0" class="btn active" @click="ok">点亮</view>
|
||||
<view v-if="gift.playStatus == 1" class="btn active" @click="ok">赠送</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import sheep from '@/sheep';
|
||||
export default {
|
||||
components: {
|
||||
|
||||
},
|
||||
props: {
|
||||
virtualList: {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
giftFlag: false,
|
||||
src: '',
|
||||
canvasId: 'myCanvas',
|
||||
|
||||
gift: {},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
starNum() {
|
||||
var count = 0;
|
||||
this.virtualList.forEach(e => {
|
||||
if(e.playStatus > 0){
|
||||
count ++;
|
||||
}
|
||||
});
|
||||
return count;
|
||||
},
|
||||
total() {
|
||||
return this.virtualList.length;
|
||||
},
|
||||
isGift() {
|
||||
return sheep.$store('user').tradeConfig.giftEnabled;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
sendGift(e) {
|
||||
this.gift = e;
|
||||
|
||||
if(e.giftType == 0){
|
||||
// 普通礼物不播放
|
||||
this.$emit('openGift', this.gift);
|
||||
return;
|
||||
}
|
||||
|
||||
this.src = e.pic;
|
||||
this.giftFlag = true;
|
||||
},
|
||||
onFinished() {
|
||||
this.giftFlag = false;
|
||||
console.log('动画停止播放时回调');
|
||||
},
|
||||
onFrame(frame) {//动画播放至某帧后回调
|
||||
// console.log(frame);
|
||||
},
|
||||
onPercentage(percentage) { //动画播放至某进度后回调
|
||||
// console.log(percentage);
|
||||
},
|
||||
onLoaded() {
|
||||
this.$refs.cSvgaRef.call('setContentMode', 'AspectFill');
|
||||
console.log('加载完成');
|
||||
this.$refs.cSvgaRef.call('startAnimation');
|
||||
},
|
||||
closeSvga() {
|
||||
this.src = "";
|
||||
this.$refs.cSvgaRef.call('stopAnimation');
|
||||
this.giftFlag = false;
|
||||
},
|
||||
fen2yuan(price) {
|
||||
var f = 0;
|
||||
var p = (price / 100.0).toFixed(0);
|
||||
var p1 = (price / 100.0).toFixed(1);
|
||||
var p2 = (price / 100.0).toFixed(2);
|
||||
if(p*100 == price){
|
||||
f = 0;
|
||||
}else if(p1*100 == price){
|
||||
f = 1;
|
||||
}else if(p2*100 == price){
|
||||
f = 2;
|
||||
}
|
||||
return (price / 100.0).toFixed(f)
|
||||
},
|
||||
cannel() {
|
||||
this.closeSvga();
|
||||
},
|
||||
ok() {
|
||||
this.closeSvga();
|
||||
this.$emit('openGift', this.gift);
|
||||
},
|
||||
openGift(e) {
|
||||
this.$emit('openGift', e);
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.star-box {
|
||||
padding: 30rpx 20rpx;
|
||||
|
||||
.title-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.title {
|
||||
font-size: 28rpx;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.num {
|
||||
font-size: 24rpx;
|
||||
color: var(--ui-BG-Main);
|
||||
}
|
||||
}
|
||||
|
||||
.list-box {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding-top: 30rpx;
|
||||
|
||||
.gift {
|
||||
width: 25%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 20rpx 0px;
|
||||
|
||||
.img-box {
|
||||
position: relative;
|
||||
|
||||
.img{
|
||||
max-width: 150rpx;
|
||||
height: 150rpx;
|
||||
}
|
||||
|
||||
.hui {
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
|
||||
.tag {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
font-size: 16rpx;
|
||||
color: #fff;
|
||||
background-color: var(--ui-BG-Main);
|
||||
border-radius: 40px;
|
||||
padding: 2rpx 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: 24rpx;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
max-width: 150rpx;
|
||||
margin-top: 2px;
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
.price {
|
||||
font-size: 20rpx;
|
||||
color: var(--ui-BG-Main);
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
border: 1px solid var(--ui-BG-Main);
|
||||
border-radius: 40px;
|
||||
color: var(--ui-BG-Main);
|
||||
padding: 8rpx 20rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
.svga-box {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 999999999;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: black;
|
||||
|
||||
.close-btn {
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
z-index: 999999999;
|
||||
padding: 5px 10px;
|
||||
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 100rpx;
|
||||
|
||||
.bottom-box {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.title {
|
||||
font-size: 28rpx;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.price {
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.btn-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 10px;
|
||||
|
||||
.btn {
|
||||
border: 1px solid #fff;
|
||||
font-size: 28rpx;
|
||||
padding: 20rpx 110rpx;
|
||||
border-radius: 40px;
|
||||
margin: 15px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.active {
|
||||
border: 1px solid var(--ui-BG-Main);
|
||||
background-color: var(--ui-BG-Main);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.svga-hide {
|
||||
/* #ifdef MP */
|
||||
transform: translate(-100%, 0);
|
||||
/* #endif */
|
||||
|
||||
/* #ifndef MP */
|
||||
display: none;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.svga-show {
|
||||
/* #ifdef MP */
|
||||
transform: translate(0, 0);
|
||||
/* #endif */
|
||||
|
||||
/* #ifndef MP */
|
||||
display: block;
|
||||
/* #endif */
|
||||
}
|
||||
</style>
|
59
pages/user/detail/components/stickyBox.vue
Normal file
59
pages/user/detail/components/stickyBox.vue
Normal file
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class="sticky-box">
|
||||
<view>
|
||||
<tui-tabs :tabs="tabList" badgeBgColor="var(--ui-BG-Main)" selectedColor="var(--ui-BG-Main)" sliderBgColor="var(--ui-BG-Main)" :currentTab="currentTab" @change="change"></tui-tabs>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import tuiTabs from "@/components/thorui/tui-tabs/tui-tabs.vue"
|
||||
import sheep from '@/sheep';
|
||||
export default {
|
||||
components: {
|
||||
tuiTabs,
|
||||
},
|
||||
props: {
|
||||
trendNum: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
tabList() {
|
||||
var tabs = [{
|
||||
name: '礼物墙'
|
||||
},{
|
||||
name: '动态',
|
||||
num: this.trendNum,
|
||||
}];
|
||||
return tabs;
|
||||
},
|
||||
currentTab() {
|
||||
return sheep.$store('sys').userTabIndex;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
change(e) {
|
||||
this.$emit('change', e.index);
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.sticky-box {
|
||||
background-color: #fff;
|
||||
padding: 5px 0;
|
||||
}
|
||||
</style>
|
308
pages/user/detail/components/userBox.vue
Normal file
308
pages/user/detail/components/userBox.vue
Normal file
@@ -0,0 +1,308 @@
|
||||
<template>
|
||||
<view class="user-box" :style="`background-size: contain;background-image: url(${clerk.avatar});`">
|
||||
<view class="info-box" :style="{ paddingTop: paddingTop + 20 + 'px'}">
|
||||
<view class="avatar-box">
|
||||
<view class="avatar-span">
|
||||
<u-image width="100%" height="100%" shape="circle" :src="clerk.avatar"></u-image>
|
||||
<!-- <view class="fans-btn" @click="fans(clerk)">
|
||||
<u-icon v-if="clerk.isFans" color="var(--ui-BG-Main)" name="checkmark-circle-fill" size="46"></u-icon>
|
||||
<u-icon v-else color="var(--ui-BG-Main)" name="plus-circle-fill" size="46"></u-icon>
|
||||
</view> -->
|
||||
</view>
|
||||
<view class="right-box">
|
||||
<view class="nickname-box">
|
||||
<view class="nickname">{{clerk.nickname}}</view>
|
||||
<view class="icon">
|
||||
<u-icon name="wode_duanwei" size="36" custom-prefix="iconfont"></u-icon>
|
||||
<text>L1</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="badge-box">
|
||||
<view v-if="clerk.hasQrcode" class="weixin-btn" @click="getWeixin(clerk)">
|
||||
<u-icon name="weixin-fill" size="28" color="#fff"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="sex-box">
|
||||
<view class="span" v-if="clerk.sex == 2">
|
||||
<u-icon name="ziyuan2" color="#f898c5" size="34" custom-prefix="iconfont"></u-icon>
|
||||
</view>
|
||||
<view class="span" v-if="clerk.sex == 1">
|
||||
<u-icon name="ziyuan3" color="#0081ff" size="34" custom-prefix="iconfont"></u-icon>
|
||||
</view>
|
||||
<view class="span">{{clerk.age}}</view>
|
||||
<view class="span">{{clerk.city}}</view>
|
||||
</view>
|
||||
<view class="sign-box">{{clerk.intro}}</view>
|
||||
<view class="voice-box">
|
||||
<!-- <view class="voice-span">
|
||||
<voice-play :sec="clerk.soundTime" :src="clerk.sound"></voice-play>
|
||||
</view> -->
|
||||
<view class="span">已注册{{clerk.day}}天</view>
|
||||
<span class="span" v-if="clerk.hasQrcode">可交换名片</span>
|
||||
</view>
|
||||
<view class="tag-list">
|
||||
<view class="tag-box">
|
||||
<span class="tag" v-for="(categoryName,index) in clerk.categoryNameList">{{categoryName}}</span>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- <view class="tags-box">
|
||||
<view class="span">搞笑</view>
|
||||
<view class="span">风骚走位</view>
|
||||
<view class="span">乖巧懂事🍑 极致体验</view>
|
||||
</view> -->
|
||||
|
||||
<photo-box v-if="clerk.photo" :dataList="clerk.photo.split(',')"></photo-box>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PhotoBox from '@/pages/user/detail/components/photoBox.vue';
|
||||
import sheep from '@/sheep';
|
||||
import UserApi from '@/sheep/api/member/user';
|
||||
import TrendApi from '@/sheep/api/worker/trend';
|
||||
export default {
|
||||
components: {
|
||||
PhotoBox,
|
||||
},
|
||||
props: {
|
||||
paddingTop: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
clerk: {
|
||||
type: Object,
|
||||
default: {},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
photo: 'http://cos.duopei.feiniaowangluo.com/34/clerk/1707236152609pJKyvtedS9.jpg,http://cos.duopei.feiniaowangluo.com/34/clerk/1720278125689P34fP9MU1c.jpg?imageView2/1/w/200/h/200',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fans(e) {
|
||||
TrendApi.createClerkFans({
|
||||
workerClerkId: e.id,
|
||||
}).then((res) => {
|
||||
if(res){
|
||||
if(e.isFans){
|
||||
sheep.$helper.toast('取消关注');
|
||||
e.isFans = false;
|
||||
}else{
|
||||
sheep.$helper.toast('关注成功');
|
||||
e.isFans = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
getWeixin(e) {
|
||||
var that = this;
|
||||
uni.showModal({
|
||||
title: '交换名片',
|
||||
content: '确认交换名片吗?',
|
||||
success: function (res) {
|
||||
if (res.confirm) {
|
||||
that.queryWeixin(e);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
},
|
||||
queryWeixin(e) {
|
||||
UserApi.getQrcodeByUserId(e.id).then(res => {
|
||||
if(res.data){
|
||||
uni.previewImage({
|
||||
current: 0, //预览图片的下标
|
||||
urls: [res.data], //预览图片的地址,必须要数组形式,如果不是数组形式就转换成数组形式就可以
|
||||
indicator: 'number',
|
||||
loop: true
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.info-box {
|
||||
backdrop-filter: blur(10px);
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
padding: 15px;
|
||||
|
||||
.avatar-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.avatar-span {
|
||||
border-radius: 100%;
|
||||
width: 140rpx;
|
||||
height: 140rpx;
|
||||
border: 2px solid #fff;
|
||||
position: relative;
|
||||
|
||||
.fans-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.right-box {
|
||||
color: #fff;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
margin-left: 10px;
|
||||
|
||||
.nickname {
|
||||
font-size: 34rpx;
|
||||
font-weight: bold;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
max-width: 320rpx;
|
||||
}
|
||||
|
||||
.icon {
|
||||
background-color: #ff5ebd;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 40px;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
font-size: 22rpx;
|
||||
line-height: 22rpx;
|
||||
padding: 5px 5px;
|
||||
margin-top: 10px;
|
||||
width: 110rpx;
|
||||
}
|
||||
|
||||
.online {
|
||||
border-bottom: 1px solid #fff;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sex-box {
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 30px;
|
||||
|
||||
.span {
|
||||
margin-right: 5px;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.sign-box {
|
||||
color: #cfcfcf;
|
||||
font-size: 28rpx;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.voice-box {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
|
||||
.voice-span {
|
||||
margin-bottom: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.span {
|
||||
padding: 10rpx 20rpx;
|
||||
background-color: rgba(132, 167, 164, .81);
|
||||
border-radius: 20px;
|
||||
font-size: 24rpx;
|
||||
margin-bottom: 10px;
|
||||
margin-right: 10px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.tags-box {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
margin: 5px 0;
|
||||
|
||||
.span {
|
||||
font-size: 20rpx;
|
||||
color: #fff;
|
||||
background-color: #000000;
|
||||
border-radius: 999px;
|
||||
padding: 3px 10px;
|
||||
margin: 0 10px 10px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.tag-list {
|
||||
display: flex;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.tag-box {
|
||||
display: inline-block;
|
||||
align-items: center;
|
||||
margin-bottom: 5px;
|
||||
background-color: #eef2f26e;
|
||||
border-radius: 3px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
max-width: 100%;
|
||||
padding: 5px 0;
|
||||
|
||||
.tag {
|
||||
white-space: nowrap;
|
||||
padding: 5px 5px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tag:after {
|
||||
content: ' ';
|
||||
border-left: 1px solid #fff;
|
||||
display: inline-block;
|
||||
height: 10px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.tag:last-child:after{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.weixin-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #19be6b;
|
||||
justify-content: center;
|
||||
border-radius: 40px;
|
||||
color: #fff;
|
||||
font-size: 22rpx;
|
||||
padding: 5px;
|
||||
|
||||
.text {
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
</style>
|
61
pages/user/detail/index.vue
Normal file
61
pages/user/detail/index.vue
Normal file
@@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<view class="container page-app theme-light main-green font-1">
|
||||
<layout ref="skill" title="选人下单">
|
||||
|
||||
</layout>
|
||||
|
||||
<s-auth-modal />
|
||||
<s-menu-tools />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import layout from '@/pages/user/detail/components/layout.vue';
|
||||
import sheep from '@/sheep';
|
||||
export default {
|
||||
components: {
|
||||
layout,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
// 分享小程序
|
||||
onShareAppMessage(res) {
|
||||
return {
|
||||
title: this.shareInfo.title,
|
||||
imageUrl: this.shareInfo.image,
|
||||
};
|
||||
},
|
||||
onShareTimeline() {
|
||||
return {
|
||||
title: this.shareInfo.title,
|
||||
imageUrl: this.shareInfo.image,
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.skill.initData(options);
|
||||
});
|
||||
},
|
||||
computed: {
|
||||
shareInfo() {
|
||||
return sheep.$platform.share.getShareInfo();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
background-color: #fff;
|
||||
height: calc(100vh);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
|
||||
</style>
|
233
pages/user/goods-collect.vue
Normal file
233
pages/user/goods-collect.vue
Normal file
@@ -0,0 +1,233 @@
|
||||
<!-- 我的商品收藏 -->
|
||||
<template>
|
||||
<s-layout title="商品收藏">
|
||||
<view class="cart-box ss-flex ss-flex-col ss-row-between">
|
||||
<!-- 头部 -->
|
||||
<view class="cart-header ss-flex ss-col-center ss-row-between ss-p-x-30">
|
||||
<view class="header-left ss-flex ss-col-center ss-font-26">
|
||||
共
|
||||
<text class="goods-number ui-TC-Main ss-flex">{{ state.pagination.total }}</text> 件商品
|
||||
</view>
|
||||
<view class="header-right">
|
||||
<button
|
||||
v-if="state.editMode && state.pagination.total"
|
||||
class="ss-reset-button"
|
||||
@tap="state.editMode = false"
|
||||
>
|
||||
取消
|
||||
</button>
|
||||
<button
|
||||
v-if="!state.editMode && state.pagination.total"
|
||||
class="ss-reset-button ui-TC-Main"
|
||||
@tap="state.editMode = true"
|
||||
>
|
||||
编辑
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 内容 -->
|
||||
<view class="cart-content">
|
||||
<view
|
||||
class="goods-box ss-r-10 ss-m-b-14"
|
||||
v-for="item in state.pagination.list"
|
||||
:key="item.id"
|
||||
>
|
||||
<view class="ss-flex ss-col-center">
|
||||
<label
|
||||
class="check-box ss-flex ss-col-center ss-p-l-10"
|
||||
v-if="state.editMode"
|
||||
@tap="onSelect(item.spuId)"
|
||||
>
|
||||
<radio
|
||||
:checked="state.selectedCollectList.includes(item.spuId)"
|
||||
color="var(--ui-BG-Main)"
|
||||
style="transform: scale(0.8)"
|
||||
@tap.stop="onSelect(item.spuId)"
|
||||
/>
|
||||
</label>
|
||||
<s-goods-item
|
||||
:title="item.spuName"
|
||||
:img="item.picUrl"
|
||||
:price="item.price"
|
||||
priceColor="#FF3000"
|
||||
:titleWidth="400"
|
||||
@tap="
|
||||
sheep.$router.go('/pages/goods/index', {
|
||||
id: item.spuId,
|
||||
})
|
||||
"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部 -->
|
||||
<su-fixed bottom :val="0" placeholder v-show="state.editMode">
|
||||
<view class="cart-footer ss-flex ss-col-center ss-row-between ss-p-x-30 border-bottom">
|
||||
<view class="footer-left ss-flex ss-col-center">
|
||||
<label class="check-box ss-flex ss-col-center ss-p-r-30" @tap="onSelectAll">
|
||||
<radio
|
||||
:checked="state.selectAll"
|
||||
color="var(--ui-BG-Main)"
|
||||
style="transform: scale(0.7)"
|
||||
@tap.stop="onSelectAll"
|
||||
/>
|
||||
<view> 全选 </view>
|
||||
</label>
|
||||
</view>
|
||||
<view class="footer-right">
|
||||
<button
|
||||
class="ss-reset-button ui-BG-Main-Gradient pay-btn ss-font-28 ui-Shadow-Main"
|
||||
@tap="onCancel"
|
||||
>
|
||||
取消收藏
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</su-fixed>
|
||||
</view>
|
||||
<uni-load-more
|
||||
v-if="state.pagination.total > 0"
|
||||
:status="state.loadStatus"
|
||||
:content-text="{
|
||||
contentdown: '上拉加载更多',
|
||||
}"
|
||||
@tap="loadMore"
|
||||
/>
|
||||
<s-empty v-if="state.pagination.total === 0" text="暂无收藏" icon="/static/collect-empty.png" />
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import sheep from '@/sheep';
|
||||
import { reactive } from 'vue';
|
||||
import { onLoad, onReachBottom } from '@dcloudio/uni-app';
|
||||
import _ from 'lodash-es';
|
||||
import FavoriteApi from '@/sheep/api/product/favorite';
|
||||
import { resetPagination } from '@/sheep/util';
|
||||
|
||||
const sys_navBar = sheep.$platform.navbar;
|
||||
|
||||
const state = reactive({
|
||||
pagination: {
|
||||
list: [],
|
||||
total: 0,
|
||||
pageNo: 1,
|
||||
pageSize: 6,
|
||||
},
|
||||
loadStatus: '',
|
||||
|
||||
editMode: false,
|
||||
selectedCollectList: [], // 选中的 SPU 数组
|
||||
selectAll: false,
|
||||
});
|
||||
|
||||
async function getData() {
|
||||
state.loadStatus = 'loading';
|
||||
const { code, data } = await FavoriteApi.getFavoritePage({
|
||||
pageNo: state.pagination.pageNo,
|
||||
pageSize: state.pagination.pageSize,
|
||||
});
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
state.pagination.list = _.concat(state.pagination.list, data.list);
|
||||
state.pagination.total = data.total;
|
||||
state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
|
||||
}
|
||||
|
||||
// 单选选中
|
||||
const onSelect = (spuId) => {
|
||||
if (!state.selectedCollectList.includes(spuId)) {
|
||||
state.selectedCollectList.push(spuId);
|
||||
} else {
|
||||
state.selectedCollectList.splice(state.selectedCollectList.indexOf(spuId), 1);
|
||||
}
|
||||
state.selectAll = state.selectedCollectList.length === state.pagination.list.length;
|
||||
};
|
||||
|
||||
// 全选
|
||||
const onSelectAll = () => {
|
||||
state.selectAll = !state.selectAll;
|
||||
if (!state.selectAll) {
|
||||
state.selectedCollectList = [];
|
||||
} else {
|
||||
state.selectedCollectList = state.pagination.list.map((item) => item.spuId);
|
||||
}
|
||||
};
|
||||
|
||||
async function onCancel() {
|
||||
if (!state.selectedCollectList) {
|
||||
return;
|
||||
}
|
||||
// 取消收藏
|
||||
for (const spuId of state.selectedCollectList) {
|
||||
await FavoriteApi.deleteFavorite(spuId);
|
||||
}
|
||||
|
||||
// 清空选择 + 重新加载
|
||||
state.editMode = false;
|
||||
state.selectedCollectList = [];
|
||||
state.selectAll = false;
|
||||
resetPagination(state.pagination);
|
||||
await getData();
|
||||
}
|
||||
|
||||
// 加载更多
|
||||
function loadMore() {
|
||||
if (state.loadStatus === 'noMore') {
|
||||
return;
|
||||
}
|
||||
state.pagination.pageNo++;
|
||||
getData();
|
||||
}
|
||||
|
||||
onReachBottom(() => {
|
||||
loadMore();
|
||||
});
|
||||
|
||||
onLoad(() => {
|
||||
getData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cart-box {
|
||||
.cart-header {
|
||||
height: 70rpx;
|
||||
background-color: #f6f6f6;
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: v-bind('sys_navBar') rpx;
|
||||
z-index: 1000;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.cart-footer {
|
||||
height: 100rpx;
|
||||
background-color: #fff;
|
||||
|
||||
.pay-btn {
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
padding: 0 40rpx;
|
||||
min-width: 200rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.cart-content {
|
||||
width: 100%;
|
||||
margin-top: 70rpx;
|
||||
padding: 0 20rpx;
|
||||
box-sizing: border-box;
|
||||
.goods-box {
|
||||
background-color: #fff;
|
||||
&:last-child {
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
308
pages/user/goods-log.vue
Normal file
308
pages/user/goods-log.vue
Normal file
@@ -0,0 +1,308 @@
|
||||
<!-- 商品浏览记录 -->
|
||||
<template>
|
||||
<s-layout title="我的足迹" :bgStyle="{ color: '#f2f2f2' }">
|
||||
<view class="cart-box ss-flex ss-flex-col ss-row-between">
|
||||
<!-- 头部 -->
|
||||
<view class="cart-header ss-flex ss-col-center ss-row-between ss-p-x-30">
|
||||
<view class="header-left ss-flex ss-col-center ss-font-26">
|
||||
共
|
||||
<text class="goods-number ui-TC-Main ss-flex">
|
||||
{{ state.pagination.total }}
|
||||
</text>
|
||||
件商品
|
||||
</view>
|
||||
<view class="header-right">
|
||||
<button
|
||||
v-if="state.editMode && state.pagination.total"
|
||||
class="ss-reset-button"
|
||||
@tap="state.editMode = false"
|
||||
>
|
||||
取消
|
||||
</button>
|
||||
<button
|
||||
v-if="!state.editMode && state.pagination.total"
|
||||
class="ss-reset-button ui-TC-Main"
|
||||
@tap="state.editMode = true"
|
||||
>
|
||||
编辑
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 内容 -->
|
||||
<view class="cart-content">
|
||||
<view
|
||||
class="goods-box ss-r-10 ss-m-b-14"
|
||||
v-for="item in state.pagination.list"
|
||||
:key="item.id"
|
||||
>
|
||||
<view class="ss-flex ss-col-center">
|
||||
<label
|
||||
class="check-box ss-flex ss-col-center ss-p-l-10"
|
||||
v-if="state.editMode"
|
||||
@tap="onSelect(item.spuId)"
|
||||
>
|
||||
<radio
|
||||
:checked="state.selectedSpuIdList.includes(item.spuId)"
|
||||
color="var(--ui-BG-Main)"
|
||||
style="transform: scale(0.8)"
|
||||
@tap.stop="onSelect(item.spuId)"
|
||||
/>
|
||||
</label>
|
||||
<s-goods-item
|
||||
:title="item.spuName"
|
||||
:img="item.picUrl"
|
||||
:price="item.price"
|
||||
:skuText="item.introduction"
|
||||
priceColor="#FF3000"
|
||||
:titleWidth="400"
|
||||
@tap="
|
||||
sheep.$router.go('/pages/goods/index', {
|
||||
id: item.spuId,
|
||||
})
|
||||
"
|
||||
>
|
||||
</s-goods-item>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 底部 -->
|
||||
<su-fixed bottom :val="0" placeholder v-show="state.editMode">
|
||||
<view class="cart-footer ss-flex ss-col-center ss-row-between ss-p-x-30 border-bottom">
|
||||
<view class="footer-left ss-flex ss-col-center">
|
||||
<label class="check-box ss-flex ss-col-center ss-p-r-30" @tap="onSelectAll">
|
||||
<radio
|
||||
:checked="state.selectAll"
|
||||
color="var(--ui-BG-Main)"
|
||||
style="transform: scale(0.7)"
|
||||
@tap.stop="onSelectAll"
|
||||
/>
|
||||
<view>全选</view>
|
||||
</label>
|
||||
</view>
|
||||
<view class="footer-right ss-flex">
|
||||
<button
|
||||
:class="[
|
||||
'ss-reset-button pay-btn ss-font-28 ',
|
||||
{
|
||||
'ui-BG-Main-Gradient': state.selectedSpuIdList.length > 0,
|
||||
'ui-Shadow-Main': state.selectedSpuIdList.length > 0,
|
||||
},
|
||||
]"
|
||||
@tap="onDelete"
|
||||
>
|
||||
删除足迹
|
||||
</button>
|
||||
<button
|
||||
class="ss-reset-button ui-BG-Main-Gradient pay-btn ss-font-28 ui-Shadow-Main ml-2"
|
||||
@tap="onClean"
|
||||
>
|
||||
清空
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</su-fixed>
|
||||
</view>
|
||||
<uni-load-more
|
||||
v-if="state.pagination.total > 0"
|
||||
:status="state.loadStatus"
|
||||
:content-text="{
|
||||
contentdown: '上拉加载更多',
|
||||
}"
|
||||
@tap="loadMore"
|
||||
/>
|
||||
<s-empty
|
||||
v-if="state.pagination.total === 0"
|
||||
text="暂无浏览记录"
|
||||
icon="/static/collect-empty.png"
|
||||
/>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import sheep from '@/sheep';
|
||||
import { reactive } from 'vue';
|
||||
import { onLoad, onReachBottom } from '@dcloudio/uni-app';
|
||||
import _ from 'lodash-es';
|
||||
import SpuHistoryApi from '@/sheep/api/product/history';
|
||||
import { cloneDeep } from '@/sheep/helper/utils';
|
||||
|
||||
const sys_navBar = sheep.$platform.navbar;
|
||||
const pagination = {
|
||||
list: [],
|
||||
pageNo: 1,
|
||||
total: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
const state = reactive({
|
||||
pagination: cloneDeep(pagination),
|
||||
loadStatus: '',
|
||||
editMode: false,
|
||||
selectedSpuIdList: [],
|
||||
selectAll: false,
|
||||
});
|
||||
|
||||
async function getList() {
|
||||
state.loadStatus = 'loading';
|
||||
const { code, data } = await SpuHistoryApi.getBrowseHistoryPage({
|
||||
pageNo: state.pagination.pageNo,
|
||||
pageSize: state.pagination.pageSize,
|
||||
});
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
state.pagination.list = _.concat(state.pagination.list, data.list);
|
||||
state.pagination.total = data.total;
|
||||
state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
|
||||
}
|
||||
|
||||
// 单选选中
|
||||
const onSelect = (id) => {
|
||||
if (!state.selectedSpuIdList.includes(id)) {
|
||||
state.selectedSpuIdList.push(id);
|
||||
} else {
|
||||
state.selectedSpuIdList.splice(state.selectedSpuIdList.indexOf(id), 1);
|
||||
}
|
||||
state.selectAll = state.selectedSpuIdList.length === state.pagination.list.length;
|
||||
};
|
||||
|
||||
// 全选
|
||||
const onSelectAll = () => {
|
||||
state.selectAll = !state.selectAll;
|
||||
if (!state.selectAll) {
|
||||
state.selectedSpuIdList = [];
|
||||
} else {
|
||||
state.pagination.list.forEach((item) => {
|
||||
if (state.selectedSpuIdList.includes(item.spuId)) {
|
||||
state.selectedSpuIdList.splice(state.selectedSpuIdList.indexOf(item.spuId), 1);
|
||||
}
|
||||
state.selectedSpuIdList.push(item.spuId);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 删除足迹
|
||||
async function onDelete() {
|
||||
if (state.selectedSpuIdList.length <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { code } = await SpuHistoryApi.deleteBrowseHistory(state.selectedSpuIdList);
|
||||
if (code === 0) {
|
||||
reload();
|
||||
}
|
||||
}
|
||||
|
||||
// 清空
|
||||
async function onClean() {
|
||||
const { code } = await SpuHistoryApi.cleanBrowseHistory();
|
||||
if (code === 0) {
|
||||
reload();
|
||||
}
|
||||
}
|
||||
|
||||
function reload() {
|
||||
state.editMode = false;
|
||||
state.selectedSpuIdList = [];
|
||||
state.selectAll = false;
|
||||
state.pagination = pagination;
|
||||
getList();
|
||||
}
|
||||
|
||||
// 加载更多
|
||||
function loadMore() {
|
||||
if (state.loadStatus !== 'noMore') {
|
||||
state.pagination.pageNo += 1;
|
||||
getList();
|
||||
}
|
||||
}
|
||||
|
||||
onReachBottom(() => {
|
||||
loadMore();
|
||||
});
|
||||
|
||||
onLoad(() => {
|
||||
getList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cart-box {
|
||||
.cart-header {
|
||||
height: 70rpx;
|
||||
background-color: #f6f6f6;
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: v-bind('sys_navBar') rpx;
|
||||
z-index: 1000;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.cart-footer {
|
||||
height: 100rpx;
|
||||
background-color: #fff;
|
||||
|
||||
.pay-btn {
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
padding: 0 40rpx;
|
||||
min-width: 200rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.cart-content {
|
||||
width: 100%;
|
||||
padding: 0 20rpx;
|
||||
box-sizing: border-box;
|
||||
margin-top: 70rpx;
|
||||
.goods-box {
|
||||
background-color: #fff;
|
||||
&:last-child {
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.title-card {
|
||||
padding: 36rpx 0 46rpx 20rpx;
|
||||
|
||||
.img-box {
|
||||
width: 164rpx;
|
||||
height: 164rpx;
|
||||
|
||||
.order-img {
|
||||
width: 164rpx;
|
||||
height: 164rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.check-box {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.title-text {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.params-box {
|
||||
.params-title {
|
||||
height: 38rpx;
|
||||
background: #f4f4f4;
|
||||
border-radius: 2rpx;
|
||||
font-size: 24rpx;
|
||||
font-weight: 400;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
|
||||
.price-text {
|
||||
color: $red;
|
||||
font-family: OPPOSANS;
|
||||
}
|
||||
}
|
||||
</style>
|
275
pages/user/goods_details_store/index.vue
Normal file
275
pages/user/goods_details_store/index.vue
Normal file
@@ -0,0 +1,275 @@
|
||||
<template>
|
||||
<s-layout title="选择自提门店" :bgStyle="{ color: '#FFF' }">
|
||||
<view class="storeBox" ref="container">
|
||||
<view class="storeBox-box" v-for="(item, index) in state.storeList" :key="index" @tap="checked(item)">
|
||||
<view class="store-img">
|
||||
<image :src="item.logo" class="img" />
|
||||
</view>
|
||||
<view class="store-cent-left">
|
||||
<view class="store-name">{{ item.name }}</view>
|
||||
<view class="store-address line1">
|
||||
{{ item.areaName }}{{ ', ' + item.detailAddress }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="row-right ss-flex-col ss-col-center">
|
||||
<view>
|
||||
<!-- #ifdef H5 -->
|
||||
<a class="store-phone" :href="'tel:' + item.phone">
|
||||
<view class="iconfont">
|
||||
<view class="ss-rest-button">
|
||||
<text class="_icon-forward" />
|
||||
</view>
|
||||
</view>
|
||||
</a>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef MP -->
|
||||
<view class="store-phone" @click="call(item.phone)">
|
||||
<view class="iconfont">
|
||||
<view class="ss-rest-button">
|
||||
<text class="_icon-forward" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
<view class="store-distance ss-flex ss-row-center" @tap.stop="showMaoLocation(item)">
|
||||
<text class="addressTxt" v-if="item.distance">距离{{ item.distance.toFixed(2) }}千米</text>
|
||||
<text class="addressTxt" v-else>查看地图</text>
|
||||
<view class="iconfont">
|
||||
<view class="ss-rest-button">
|
||||
<text class="_icon-forward" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import DeliveryApi from '@/sheep/api/trade/delivery';
|
||||
import { onMounted, reactive } from 'vue';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import sheep from '@/sheep';
|
||||
|
||||
const LONGITUDE = 'user_longitude';
|
||||
const LATITUDE = 'user_latitude';
|
||||
const state = reactive({
|
||||
loaded: false,
|
||||
loading: false,
|
||||
storeList: [],
|
||||
system_store: {},
|
||||
locationShow: false,
|
||||
user_latitude: 0,
|
||||
user_longitude: 0,
|
||||
});
|
||||
|
||||
const call = (phone) => {
|
||||
uni.makePhoneCall({
|
||||
phoneNumber: phone,
|
||||
});
|
||||
};
|
||||
const selfLocation = () => {
|
||||
// #ifdef H5
|
||||
const jsWxSdk = sheep.$platform.useProvider('wechat').jsWxSdk;
|
||||
if (jsWxSdk.isWechat()) {
|
||||
jsWxSdk.getLocation((res) => {
|
||||
console.log(res);
|
||||
state.user_latitude = res.latitude;
|
||||
state.user_longitude = res.longitude;
|
||||
uni.setStorageSync(LATITUDE, res.latitude);
|
||||
uni.setStorageSync(LONGITUDE, res.longitude);
|
||||
getList();
|
||||
});
|
||||
} else {
|
||||
// #endif
|
||||
uni.getLocation({
|
||||
type: 'gcj02',
|
||||
success: (res) => {
|
||||
try {
|
||||
state.user_latitude = res.latitude;
|
||||
state.user_longitude = res.longitude;
|
||||
uni.setStorageSync(LATITUDE, res.latitude);
|
||||
uni.setStorageSync(LONGITUDE, res.longitude);
|
||||
} catch {
|
||||
}
|
||||
getList();
|
||||
},
|
||||
complete: () => {
|
||||
getList();
|
||||
},
|
||||
});
|
||||
// #ifdef H5
|
||||
}
|
||||
// #endif
|
||||
};
|
||||
const showMaoLocation = (e) => {
|
||||
// #ifdef H5
|
||||
const jsWxSdk = sheep.$platform.useProvider('wechat').jsWxSdk;
|
||||
if (jsWxSdk.isWechat()) {
|
||||
jsWxSdk.openLocation({
|
||||
latitude: Number(e.latitude),
|
||||
longitude: Number(e.longitude),
|
||||
name: e.name,
|
||||
address: `${e.areaName}-${e.detailAddress}`
|
||||
});
|
||||
} else {
|
||||
// #endif
|
||||
uni.openLocation({
|
||||
latitude: Number(e.latitude),
|
||||
longitude: Number(e.longitude),
|
||||
name: e.name,
|
||||
address: `${e.areaName}-${e.detailAddress}`,
|
||||
success: function() {
|
||||
console.log('success');
|
||||
},
|
||||
});
|
||||
// #ifdef H5
|
||||
}
|
||||
// #endif
|
||||
};
|
||||
|
||||
/**
|
||||
* 选中门店
|
||||
*/
|
||||
const checked = (addressInfo) => {
|
||||
uni.$emit('SELECT_PICK_UP_INFO', {
|
||||
addressInfo,
|
||||
});
|
||||
sheep.$router.back();
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取门店列表数据
|
||||
*/
|
||||
const getList = async () => {
|
||||
if (state.loading || state.loaded) {
|
||||
return;
|
||||
}
|
||||
state.loading = true;
|
||||
const { data, code } = await DeliveryApi.getDeliveryPickUpStoreList({
|
||||
latitude: state.user_latitude,
|
||||
longitude: state.user_longitude,
|
||||
});
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
state.loading = false;
|
||||
state.storeList = data;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (state.user_latitude && state.user_longitude) {
|
||||
getList();
|
||||
} else {
|
||||
selfLocation();
|
||||
getList();
|
||||
}
|
||||
});
|
||||
onLoad(() => {
|
||||
try {
|
||||
state.user_latitude = uni.getStorageSync(LATITUDE);
|
||||
state.user_longitude = uni.getStorageSync(LONGITUDE);
|
||||
} catch (e) {
|
||||
// error
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.line1 {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap
|
||||
}
|
||||
|
||||
.geoPage {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
.storeBox {
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
padding: 0 30rpx;
|
||||
}
|
||||
|
||||
.storeBox-box {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 23rpx 0;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.store-cent {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.store-cent-left {
|
||||
//width: 45%;
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
.store-img {
|
||||
flex: 1;
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 6rpx;
|
||||
margin-right: 22rpx;
|
||||
}
|
||||
|
||||
.store-img .img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.store-name {
|
||||
color: #282828;
|
||||
font-size: 30rpx;
|
||||
margin-bottom: 22rpx;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.store-address {
|
||||
color: #666666;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.store-phone {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
color: #fff;
|
||||
border-radius: 50%;
|
||||
display: block;
|
||||
text-align: center;
|
||||
line-height: 48rpx;
|
||||
background-color: #e83323;
|
||||
margin-bottom: 22rpx;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.store-distance {
|
||||
font-size: 22rpx;
|
||||
color: #e83323;
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-size: 20rpx;
|
||||
}
|
||||
|
||||
.row-right {
|
||||
flex: 2;
|
||||
//display: flex;
|
||||
//flex-direction: column;
|
||||
//align-items: flex-end;
|
||||
//width: 33.5%;
|
||||
}
|
||||
</style>
|
475
pages/user/info.vue
Normal file
475
pages/user/info.vue
Normal file
@@ -0,0 +1,475 @@
|
||||
<!-- 用户信息 -->
|
||||
<template>
|
||||
<s-layout title="用户信息" class="set-userinfo-wrap">
|
||||
<uni-forms
|
||||
:model="state.model"
|
||||
:rules="state.rules"
|
||||
labelPosition="left"
|
||||
border
|
||||
class="form-box"
|
||||
>
|
||||
<!-- 头像 -->
|
||||
<view class="ss-flex ss-row-center ss-col-center ss-p-t-60 ss-p-b-60 bg-white">
|
||||
<view class="header-box-content">
|
||||
<su-image
|
||||
class="content-img"
|
||||
isPreview
|
||||
:current="0"
|
||||
:src="state.model?.avatar"
|
||||
:height="160"
|
||||
:width="160"
|
||||
:radius="80"
|
||||
mode="scaleToFill"
|
||||
/>
|
||||
<view class="avatar-action">
|
||||
<button class="ss-reset-button avatar-action-btn" @tap="onChooseAvatar">修改</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="bg-white ss-p-x-30">
|
||||
<!-- <view class="form-item">
|
||||
<view class="label">昵称</view>
|
||||
<view class="input-box">
|
||||
<view>{{state.model.nickname}}</view>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<!-- 昵称 + 性别 -->
|
||||
<uni-forms-item name="nickname" label="昵称">
|
||||
<uni-easyinput
|
||||
v-model="state.model.nickname"
|
||||
placeholder="设置昵称"
|
||||
:inputBorder="false"
|
||||
:placeholderStyle="placeholderStyle"
|
||||
/>
|
||||
</uni-forms-item>
|
||||
|
||||
|
||||
<uni-forms-item name="sex" label="性别">
|
||||
<view class="ss-flex ss-col-center ss-h-100">
|
||||
<radio-group @change="onChangeGender" class="ss-flex ss-col-center">
|
||||
<label class="radio" v-for="item in sexRadioMap" :key="item.value">
|
||||
<view class="ss-flex ss-col-center ss-m-r-32">
|
||||
<radio
|
||||
:value="item.value"
|
||||
color="var(--ui-BG-Main)"
|
||||
style="transform: scale(0.8)"
|
||||
:checked="parseInt(item.value) === state.model?.sex"
|
||||
/>
|
||||
<view class="gender-name">{{ item.name }}</view>
|
||||
</view>
|
||||
</label>
|
||||
</radio-group>
|
||||
</view>
|
||||
</uni-forms-item>
|
||||
|
||||
<!-- <view class="form-item" @tap="onChangeMobile">
|
||||
<view class="label">手机号</view>
|
||||
<view class="input-box">
|
||||
<view v-if="userInfo.mobile">{{userInfo.mobile}}</view>
|
||||
<view v-else class="placeholder">请绑定手机号</view>
|
||||
<view class="ss-flex ss-col-center">
|
||||
<su-radio class="ss-flex" v-if="userInfo.mobile" :modelValue="true" />
|
||||
<button v-else class="ss-reset-button ss-flex ss-col-center ss-row-center">
|
||||
<text class="_icon-forward" style="color: #bbbbbb; font-size: 26rpx"></text>
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item" @tap="onSetPassword">
|
||||
<view class="label">登录密码</view>
|
||||
<view class="input-box">
|
||||
<view v-if="userInfo.password">{{userInfo.password}}</view>
|
||||
<view v-else class="placeholder">点击修改登录密码</view>
|
||||
<view class="ss-flex ss-col-center">
|
||||
<su-radio class="ss-flex" v-if="userInfo.password" :modelValue="true" />
|
||||
<button v-else class="ss-reset-button ss-flex ss-col-center ss-row-center">
|
||||
<text class="_icon-forward" style="color: #bbbbbb; font-size: 26rpx"></text>
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
-->
|
||||
|
||||
</view>
|
||||
|
||||
|
||||
</uni-forms>
|
||||
|
||||
<!-- 当前社交平台的绑定关系,只处理 wechat 微信场景 -->
|
||||
<!-- <view v-if="sheep.$platform.name !== 'H5'">
|
||||
<view class="title-box ss-p-l-30">第三方账号绑定</view>
|
||||
<view class="account-list ss-flex ss-row-between">
|
||||
<view v-if="'WechatOfficialAccount' === sheep.$platform.name" class="ss-flex ss-col-center">
|
||||
<image
|
||||
class="list-img"
|
||||
:src="sheep.$url.static('/static/img/shop/platform/WechatOfficialAccount.png')"
|
||||
/>
|
||||
<text class="list-name">微信公众号</text>
|
||||
</view>
|
||||
<view v-if="'WechatMiniProgram' === sheep.$platform.name" class="ss-flex ss-col-center">
|
||||
<image
|
||||
class="list-img"
|
||||
:src="sheep.$url.static('/static/img/shop/platform/WechatMiniProgram.png')"
|
||||
/>
|
||||
<text class="list-name">微信小程序</text>
|
||||
</view>
|
||||
<view v-if="'App' === sheep.$platform.name" class="ss-flex ss-col-center">
|
||||
<image
|
||||
class="list-img"
|
||||
:src="sheep.$url.static('/static/img/shop/platform/wechat.png')"
|
||||
/>
|
||||
<text class="list-name">微信开放平台</text>
|
||||
</view>
|
||||
<view class="ss-flex ss-col-center">
|
||||
<view class="info ss-flex ss-col-center" v-if="state.thirdInfo">
|
||||
<image class="avatar ss-m-r-20" :src="sheep.$url.cdn(state.thirdInfo.avatar)" />
|
||||
<text class="name">{{ state.thirdInfo.nickname }}</text>
|
||||
</view>
|
||||
<view class="bind-box ss-m-l-20">
|
||||
<button
|
||||
v-if="state.thirdInfo.openid"
|
||||
class="ss-reset-button relieve-btn"
|
||||
@tap="unBindThirdOauth"
|
||||
>
|
||||
解绑
|
||||
</button>
|
||||
<button v-else class="ss-reset-button bind-btn" @tap="bindThirdOauth">绑定</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<su-fixed bottom placeholder bg="none">
|
||||
<view class="footer-box ss-p-20">
|
||||
<button class="ss-rest-button logout-btn ui-Shadow-Main" @tap="onSubmit">保存</button>
|
||||
</view>
|
||||
</su-fixed>
|
||||
|
||||
<qrcode-modal />
|
||||
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import qrcodeModal from '@/components/qrcode-modal/qrcode-modal.vue';
|
||||
import { computed, reactive, ref, onBeforeMount } from 'vue';
|
||||
import sheep from '@/sheep';
|
||||
import { clone } from 'lodash-es';
|
||||
import { showAuthModal } from '@/sheep/hooks/useModal';
|
||||
import FileApi from '@/sheep/api/infra/file';
|
||||
import UserApi from '@/sheep/api/member/user';
|
||||
|
||||
const clerk = ref();
|
||||
|
||||
const state = reactive({
|
||||
model: {}, // 个人信息
|
||||
rules: {},
|
||||
thirdInfo: {}, // 社交用户的信息
|
||||
});
|
||||
|
||||
const placeholderStyle = 'color:#BBBBBB;font-size:28rpx;line-height:normal';
|
||||
|
||||
const sexRadioMap = [
|
||||
{
|
||||
name: '男',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
name: '女',
|
||||
value: '2',
|
||||
},
|
||||
];
|
||||
|
||||
const userInfo = computed(() => sheep.$store('user').userInfo);
|
||||
|
||||
// 选择性别
|
||||
function onChangeGender(e) {
|
||||
state.model.sex = e.detail.value;
|
||||
}
|
||||
|
||||
// 修改手机号
|
||||
const onChangeMobile = () => {
|
||||
showAuthModal('changeMobile');
|
||||
};
|
||||
|
||||
function onChooseAvatar() {
|
||||
uni.chooseImage({
|
||||
count: 1, //默认9
|
||||
sourceType: ['album', 'camera'],
|
||||
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
|
||||
success: (res) => {
|
||||
for (let i = 0; i < res.tempFilePaths.length; i++) {
|
||||
uni.getImageInfo({
|
||||
src: res.tempFilePaths[i],
|
||||
success: (image) => {
|
||||
uploadAvatar(image.path);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 上传头像文件
|
||||
async function uploadAvatar(tempUrl) {
|
||||
if (!tempUrl) {
|
||||
return;
|
||||
}
|
||||
let { data } = await FileApi.uploadFile(tempUrl);
|
||||
state.model.avatar = data;
|
||||
}
|
||||
|
||||
// 修改密码
|
||||
function onSetPassword() {
|
||||
showAuthModal('changePassword');
|
||||
}
|
||||
|
||||
// 绑定第三方账号
|
||||
async function bindThirdOauth() {
|
||||
let result = await sheep.$platform.useProvider('wechat').bind();
|
||||
if (result) {
|
||||
await getUserInfo();
|
||||
}
|
||||
}
|
||||
|
||||
// 解绑第三方账号
|
||||
function unBindThirdOauth() {
|
||||
uni.showModal({
|
||||
title: '解绑提醒',
|
||||
content: '解绑后您将无法通过微信登录此账号',
|
||||
cancelText: '再想想',
|
||||
confirmText: '确定',
|
||||
success: async function (res) {
|
||||
if (!res.confirm) {
|
||||
return;
|
||||
}
|
||||
const result = await sheep.$platform.useProvider('wechat').unbind(state.thirdInfo.openid);
|
||||
if (result) {
|
||||
await getUserInfo();
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 保存信息
|
||||
async function onSubmit() {
|
||||
const { code } = await UserApi.updateUser({
|
||||
avatar: state.model.avatar,
|
||||
nickname: state.model.nickname,
|
||||
sex: state.model.sex,
|
||||
});
|
||||
if (code === 0) {
|
||||
await getUserInfo();
|
||||
}
|
||||
}
|
||||
|
||||
// 获得用户信息
|
||||
const getUserInfo = async () => {
|
||||
// 个人信息
|
||||
const userInfo = await sheep.$store('user').getInfo();
|
||||
state.model = clone(userInfo);
|
||||
|
||||
// 获得社交用户的信息
|
||||
if (sheep.$platform.name !== 'H5') {
|
||||
const result = await sheep.$platform.useProvider('wechat').getInfo();
|
||||
state.thirdInfo = result || {};
|
||||
}
|
||||
};
|
||||
|
||||
onBeforeMount(() => {
|
||||
getUserInfo();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep() {
|
||||
.uni-file-picker {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.uni-file-picker__container {
|
||||
margin: -14rpx -12rpx;
|
||||
}
|
||||
|
||||
.file-picker__progress {
|
||||
height: 0 !important;
|
||||
}
|
||||
|
||||
.uni-list-item__content-title {
|
||||
font-size: 28rpx !important;
|
||||
color: #333333 !important;
|
||||
line-height: normal !important;
|
||||
}
|
||||
|
||||
.uni-icons {
|
||||
font-size: 40rpx !important;
|
||||
}
|
||||
|
||||
.is-disabled {
|
||||
color: #333333;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.disabled) {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.gender-name {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
line-height: normal;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.title-box {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #666666;
|
||||
line-height: 100rpx;
|
||||
}
|
||||
|
||||
.logout-btn {
|
||||
width: 710rpx;
|
||||
height: 80rpx;
|
||||
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
|
||||
border-radius: 40rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.radio-dark {
|
||||
filter: grayscale(100%);
|
||||
filter: gray;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.content-img {
|
||||
border-radius: 50%;
|
||||
}
|
||||
.header-box-content {
|
||||
position: relative;
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
overflow: hidden;
|
||||
border-radius: 50%;
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
.avatar-action {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
width: 160rpx;
|
||||
height: 46rpx;
|
||||
background: rgba(#000000, 0.3);
|
||||
|
||||
.avatar-action-btn {
|
||||
width: 160rpx;
|
||||
height: 46rpx;
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
// 绑定项
|
||||
.account-list {
|
||||
background-color: $white;
|
||||
height: 100rpx;
|
||||
padding: 0 20rpx;
|
||||
|
||||
.list-img {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
.list-name {
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.info {
|
||||
.avatar {
|
||||
width: 38rpx;
|
||||
height: 38rpx;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: 28rpx;
|
||||
font-weight: 400;
|
||||
color: $dark-9;
|
||||
}
|
||||
}
|
||||
|
||||
.bind-box {
|
||||
width: 100rpx;
|
||||
height: 50rpx;
|
||||
line-height: normal;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 24rpx;
|
||||
|
||||
.bind-btn {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 25rpx;
|
||||
background: #f4f4f4;
|
||||
color: #999999;
|
||||
}
|
||||
.relieve-btn {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 25rpx;
|
||||
background: var(--ui-BG-Main-opacity-1);
|
||||
color: var(--ui-BG-Main);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list-border {
|
||||
font-size: 28rpx;
|
||||
font-weight: 400;
|
||||
color: #333333;
|
||||
border-bottom: 2rpx solid #eeeeee;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 110rpx;
|
||||
border-top: 1px #eee solid;
|
||||
|
||||
.label {
|
||||
width: 140rpx;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.input-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex: 1;
|
||||
|
||||
.placeholder {
|
||||
color:#BBBBBB;
|
||||
font-size:28rpx;
|
||||
line-height:normal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
382
pages/user/vip.vue
Normal file
382
pages/user/vip.vue
Normal file
@@ -0,0 +1,382 @@
|
||||
<template>
|
||||
<s-layout title="我的特权">
|
||||
<view class="page" v-if="isPass">
|
||||
<view class="vip-box">
|
||||
<view class="vip-name">VIP尊享会员</view>
|
||||
<view class="vip-tip-box">
|
||||
<u-avatar size="50" :src="userInfo.avatar"></u-avatar>
|
||||
<view class="vip-tip" v-if="userInfo.isVip">VIP会员({{showDayTime(userInfo.vipEndTime)}}到期)</view>
|
||||
<view class="vip-tip" v-else>暂未激活VIP会员</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="price-tab-box">
|
||||
<view class="price-tab" v-for="(item, index) in dataList" :key="index">
|
||||
<view @click="changeTab(index)" class="price-tab-border" :class="[currentIndex==index ? 'active' : '']">
|
||||
<view class="price-texta">{{item.num}}{{item.unit}}</view>
|
||||
<view class="price-textb">¥{{item.month}}/{{item.tip}}</view>
|
||||
<view class="price-textc">¥{{item.pay}}</view>
|
||||
<view class="tab-band" v-if="item.band">新人优惠</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="vip-title">
|
||||
VIP特权
|
||||
</view>
|
||||
<!-- <view class="vip-info">
|
||||
<view class="vip-info-icon">
|
||||
<u-icon name="star-fill" color="#ffd32f" size="36"></u-icon>
|
||||
</view>
|
||||
<view>
|
||||
<view class="vip-info-title">拥有申请置顶推荐特权</view>
|
||||
<view class="vip-info-text">每天可以免费申请置顶推荐</view>
|
||||
</view>
|
||||
</view> -->
|
||||
<view class="vip-info">
|
||||
<view class="vip-info-icon">
|
||||
<u-icon name="edit-pen-fill" color="#ffd32f" size="36"></u-icon>
|
||||
</view>
|
||||
<view>
|
||||
<view class="vip-info-title">每天3次发布动态无广告</view>
|
||||
<view class="vip-info-text">每天免费发布3次无广告增加曝光</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="vip-info">
|
||||
<view class="vip-info-icon">
|
||||
<u-icon name="weixin-fill" color="#ffd32f" size="36"></u-icon>
|
||||
</view>
|
||||
<view>
|
||||
<view class="vip-info-title">每天5次交换名片</view>
|
||||
<view class="vip-info-text">每天可以免费交换5次名片</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="vip-info">
|
||||
<view class="vip-info-icon">
|
||||
<u-icon name="chat-fill" color="#ffd32f" size="36"></u-icon>
|
||||
</view>
|
||||
<view>
|
||||
<view class="vip-info-title">打招呼聊天免费</view>
|
||||
<view class="vip-info-text">打招呼聊天发送消息无限制</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="vip-info">
|
||||
<view class="vip-info-icon">
|
||||
<u-icon name="star-fill" color="#ffd32f" size="36"></u-icon>
|
||||
</view>
|
||||
<view>
|
||||
<view class="vip-info-title">每天3次首页置顶</view>
|
||||
<view class="vip-info-text">每天可以免费置顶3次</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="vip-info">
|
||||
<view class="vip-info-icon">
|
||||
<u-icon name="map-fill" color="#ffd32f" size="40"></u-icon>
|
||||
</view>
|
||||
<view>
|
||||
<view class="vip-info-title">可查看同城的用户</view>
|
||||
<view class="vip-info-text">离得近奔现的概率更高</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="platform == 'android'">
|
||||
<view class="btn-box" v-if="userInfo.isVip">
|
||||
<view class="buy-btn">已开通</view>
|
||||
</view>
|
||||
<view class="btn-box" v-else>
|
||||
<view class="btn-border" @click="payHandle">
|
||||
<view class="buy-btn">¥{{pay.pay}} 立即购买</view>
|
||||
<view class="btn-tip">每天不到¥{{pay.day}}</view>
|
||||
</view>
|
||||
|
||||
<!-- <view class="btn-border" @click="goPay">
|
||||
<view class="pay-btn">去充值趣豆</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</view>
|
||||
<view v-else>
|
||||
<view class="btn-box" v-if="userInfo.isVip">
|
||||
<view class="buy-btn">已开通</view>
|
||||
</view>
|
||||
<view class="btn-box" v-else>
|
||||
<view class="btn-border" @click="payHot">
|
||||
<view class="buy-btn">¥{{pay.pay}} 购买会员</view>
|
||||
<view class="btn-tip">每天不到¥{{pay.day}}</view>
|
||||
</view>
|
||||
|
||||
<!-- <view class="btn-border" @click="goPay">
|
||||
<view class="pay-btn">去充值趣豆</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import sheep from '@/sheep';
|
||||
import PayPointApi from '@/sheep/api/pay/point';
|
||||
import dayjs from 'dayjs';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
currentIndex: 1,
|
||||
dataList: [
|
||||
{
|
||||
band: false,
|
||||
num: 1,
|
||||
month: 5.7,
|
||||
pay: 40,
|
||||
day: 5.7,
|
||||
unit: '个周',
|
||||
tip: '天',
|
||||
},
|
||||
{
|
||||
band: true,
|
||||
num: 1,
|
||||
month: 2.5,
|
||||
pay: 80,
|
||||
day: 2.5,
|
||||
unit: '个月',
|
||||
tip: '天',
|
||||
},
|
||||
{
|
||||
band: false,
|
||||
num: 6,
|
||||
month: 40,
|
||||
pay: 240,
|
||||
day: 1.2,
|
||||
unit: '个月',
|
||||
tip: '月',
|
||||
}
|
||||
],
|
||||
pay: {
|
||||
|
||||
},
|
||||
my: 'false',
|
||||
platform: 'android',
|
||||
}
|
||||
},
|
||||
onLoad(option) {
|
||||
this.my = option.my;
|
||||
this.pay = this.dataList[this.currentIndex];
|
||||
|
||||
var that = this;
|
||||
uni.getSystemInfo({
|
||||
success: function(e) {
|
||||
that.platform = e.platform;
|
||||
}
|
||||
});
|
||||
sheep.$store('user').getInfo();
|
||||
},
|
||||
computed: {
|
||||
userInfo: {
|
||||
get() {
|
||||
return sheep.$store('user').userInfo;
|
||||
},
|
||||
},
|
||||
isPass() {
|
||||
return sheep.$store('user').tradeConfig.weixinEnabled;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
changeTab(index) {
|
||||
this.currentIndex = index;
|
||||
this.pay = this.dataList[index];
|
||||
},
|
||||
payHot() {
|
||||
uni.showModal({
|
||||
title: '温馨提示',
|
||||
content: '苹果用户请联系客服充值,客服微信:rbtnet',
|
||||
showCancel: false,
|
||||
success: function(res) {
|
||||
if (res.confirm) {
|
||||
uni.setClipboardData({
|
||||
data: 'rbtnet' ,
|
||||
success: function (res) {
|
||||
uni.showToast({
|
||||
title: '复制成功',
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
goPay() {
|
||||
this.$u.route({
|
||||
url: 'pages/me/coin/pay',
|
||||
params: {
|
||||
my: 'true',
|
||||
}
|
||||
});
|
||||
},
|
||||
payHandle() {
|
||||
var coinNum = 100*this.pay.pay;
|
||||
PayPointApi.createPointRecharge({
|
||||
payPrice: coinNum,
|
||||
}).then(res => {
|
||||
sheep.$router.go('/pages/pay/vip/index', {
|
||||
id: res.data.payOrderId,
|
||||
orderType: 'recharge',
|
||||
});
|
||||
});
|
||||
},
|
||||
showDayTime(datetime) {
|
||||
if (!datetime) return "";
|
||||
return dayjs(datetime).format('YYYY-MM-DD HH:mm:ss');
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page {
|
||||
padding: 15px;
|
||||
padding-bottom: 150px;
|
||||
background-color: #fff;
|
||||
}
|
||||
.vip-box {
|
||||
padding: 15px;
|
||||
background-image: linear-gradient(180deg, #ffd32f, #db854e);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.vip-name {
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
margin-bottom: 50rpx;
|
||||
}
|
||||
.vip-tip {
|
||||
color: #fff;
|
||||
font-size: 24rpx;
|
||||
margin-left: 5px;
|
||||
}
|
||||
.price-tab-box {
|
||||
display: flex;
|
||||
}
|
||||
.price-tab {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
padding-right: 5px;
|
||||
}
|
||||
.price-tab .active {
|
||||
border: 8rpx solid #e09049;
|
||||
color: #e09049;
|
||||
}
|
||||
.price-tab-box .price-tab:last-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
.price-tab-border {
|
||||
border: 8rpx solid #f5e8e8;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 20px 0;
|
||||
border-radius: 10px;
|
||||
color: #858585;
|
||||
position: relative;
|
||||
}
|
||||
.price-texta {
|
||||
font-size: 36rpx;
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.price-textb {
|
||||
font-size: 30rpx;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.price-textc {
|
||||
font-size: 36rpx;
|
||||
}
|
||||
.vip-title {
|
||||
font-size: 28rpx;
|
||||
color: #9e9696ed;
|
||||
padding: 15px 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
.vip-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.vip-info-icon {
|
||||
margin-right: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 3px solid #f5e8e8;
|
||||
padding: 15px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.vip-info-title {
|
||||
font-size: 30rpx;
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.vip-info-text {
|
||||
font-size: 26rpx;
|
||||
color: #858585;
|
||||
}
|
||||
.btn-box {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 15px;
|
||||
}
|
||||
.buy-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #ffd32f;
|
||||
padding: 15px;
|
||||
border-radius: 10px;
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
.pay-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #18b566;
|
||||
padding: 15px;
|
||||
border-radius: 10px;
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
.btn-border {
|
||||
position: relative;
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
.tab-band {
|
||||
position: absolute;
|
||||
background-color: #efc93c;
|
||||
top: -10px;
|
||||
border-radius: 5px;
|
||||
padding: 5px 10px;
|
||||
font-size: 22rpx;
|
||||
color: #fff;
|
||||
}
|
||||
.vip-tip-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.btn-tip {
|
||||
position: absolute;
|
||||
background-color: #efa3fa;
|
||||
top: -10px;
|
||||
right: -3px;
|
||||
border: 3px solid #fff;
|
||||
border-radius: 10px;
|
||||
padding: 3px 5px;
|
||||
font-size: 22rpx;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
379
pages/user/wallet/money.vue
Normal file
379
pages/user/wallet/money.vue
Normal file
@@ -0,0 +1,379 @@
|
||||
<!-- 我的钱包 -->
|
||||
<template>
|
||||
<s-layout class="wallet-wrap" title="我的钻石">
|
||||
<!-- 钱包卡片 -->
|
||||
<view class="header-box ss-flex ss-row-center ss-col-center">
|
||||
<view class="card-box ui-BG-Main ui-Shadow-Main">
|
||||
<view class="card-head ss-flex ss-col-center">
|
||||
<view class="card-title ss-m-r-10">钻石余额(钻)</view>
|
||||
<view
|
||||
@tap="state.showMoney = !state.showMoney"
|
||||
class="ss-eye-icon"
|
||||
:class="state.showMoney ? 'cicon-eye' : 'cicon-eye-off'"
|
||||
/>
|
||||
</view>
|
||||
<view class="ss-flex ss-row-between ss-col-center ss-m-t-64">
|
||||
<view class="money-num">{{
|
||||
state.showMoney ? fen2yuan(userWallet.balance) : '*****'
|
||||
}}</view>
|
||||
<button class="ss-reset-button topup-btn" @tap="sheep.$router.go('/pages/pay/recharge')">
|
||||
充值
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<su-sticky>
|
||||
<!-- 统计 -->
|
||||
<view class="filter-box ss-p-x-30 ss-flex ss-col-center ss-row-between">
|
||||
<uni-datetime-picker
|
||||
v-model="state.data"
|
||||
type="daterange"
|
||||
@change="onChangeTime"
|
||||
:end="state.today"
|
||||
>
|
||||
<button class="ss-reset-button date-btn">
|
||||
<text>{{ dateFilterText }}</text>
|
||||
<text class="cicon-drop-down ss-seldate-icon"></text>
|
||||
</button>
|
||||
</uni-datetime-picker>
|
||||
<view class="total-box">
|
||||
<view class="ss-m-b-10">总收入¥{{ fen2yuan(state.summary.totalIncome) }}</view>
|
||||
<view>总支出¥{{ fen2yuan(state.summary.totalExpense) }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<su-tabs
|
||||
:list="tabMaps"
|
||||
@change="onChange"
|
||||
:scrollable="false"
|
||||
:current="state.currentTab"
|
||||
></su-tabs>
|
||||
</su-sticky>
|
||||
<s-empty v-if="state.pagination.total === 0" text="暂无数据" icon="/static/data-empty.png" />
|
||||
|
||||
<!-- 钱包记录 -->
|
||||
<view v-if="state.pagination.total > 0">
|
||||
<view
|
||||
class="wallet-list ss-flex border-bottom"
|
||||
v-for="item in state.pagination.list"
|
||||
:key="item.id"
|
||||
>
|
||||
<view class="list-content">
|
||||
<view class="title-box ss-flex ss-row-between ss-m-b-20">
|
||||
<text class="title ss-line-1">
|
||||
{{ item.title }}
|
||||
</text>
|
||||
<view class="money">
|
||||
<text v-if="item.price >= 0" class="add">+{{ fen2yuan(item.price) }}</text>
|
||||
<text v-else class="minus">{{ fen2yuan(item.price) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<text class="time">
|
||||
{{ sheep.$helper.timeFormat(state.createTime, 'yyyy-mm-dd hh:MM:ss') }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<uni-load-more
|
||||
v-if="state.pagination.total > 0"
|
||||
:status="state.loadStatus"
|
||||
:content-text="{
|
||||
contentdown: '上拉加载更多',
|
||||
}"
|
||||
/>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, reactive } from 'vue';
|
||||
import { onLoad, onReachBottom } from '@dcloudio/uni-app';
|
||||
import sheep from '@/sheep';
|
||||
import dayjs from 'dayjs';
|
||||
import _ from 'lodash-es';
|
||||
import PayWalletApi from '@/sheep/api/pay/wallet';
|
||||
import { fen2yuan } from '@/sheep/hooks/useGoods';
|
||||
import { resetPagination } from '@/sheep/util';
|
||||
|
||||
const headerBg = sheep.$url.css('/static/img/shop/user/wallet_card_bg.png');
|
||||
|
||||
// 数据
|
||||
const state = reactive({
|
||||
showMoney: false,
|
||||
date: [], // 筛选的时间段
|
||||
currentTab: 0,
|
||||
pagination: {
|
||||
list: [],
|
||||
total: 0,
|
||||
pageNo: 1,
|
||||
pageSize: 8,
|
||||
},
|
||||
summary: {
|
||||
totalIncome: 0,
|
||||
totalExpense: 0,
|
||||
},
|
||||
loadStatus: '',
|
||||
today: '',
|
||||
});
|
||||
|
||||
const tabMaps = [
|
||||
{
|
||||
name: '全部',
|
||||
value: '',
|
||||
},
|
||||
{
|
||||
name: '收入',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
name: '支出',
|
||||
value: '2',
|
||||
},
|
||||
];
|
||||
|
||||
const userWallet = computed(() => sheep.$store('user').userWallet);
|
||||
|
||||
// 格式化时间段
|
||||
const dateFilterText = computed(() => {
|
||||
if (state.date[0] === state.date[1]) {
|
||||
return state.date[0];
|
||||
} else {
|
||||
return state.date.join('~');
|
||||
}
|
||||
});
|
||||
|
||||
// 获得钱包记录分页
|
||||
async function getLogList() {
|
||||
state.loadStatus = 'loading';
|
||||
const { data, code } = await PayWalletApi.getWalletTransactionPage({
|
||||
pageNo: state.pagination.pageNo,
|
||||
pageSize: state.pagination.pageSize,
|
||||
type: tabMaps[state.currentTab].value,
|
||||
'createTime[0]': state.date[0] + ' 00:00:00',
|
||||
'createTime[1]': state.date[1] + ' 23:59:59',
|
||||
});
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
state.pagination.list = _.concat(state.pagination.list, data.list);
|
||||
state.pagination.total = data.total;
|
||||
state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
|
||||
}
|
||||
|
||||
// 获得钱包统计
|
||||
async function getSummary() {
|
||||
const { data, code } = await PayWalletApi.getWalletTransactionSummary({
|
||||
createTime: [state.date[0] + ' 00:00:00', state.date[1] + ' 23:59:59'],
|
||||
});
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
state.summary = data;
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
state.today = dayjs().format('YYYY-MM-DD');
|
||||
state.date = [state.today, state.today];
|
||||
getLogList();
|
||||
getSummary();
|
||||
// 刷新钱包的缓存
|
||||
sheep.$store('user').getWallet();
|
||||
});
|
||||
|
||||
// 处理 tab 切换
|
||||
function onChange(e) {
|
||||
state.currentTab = e.index;
|
||||
// 重新加载列表
|
||||
resetPagination(state.pagination);
|
||||
getLogList();
|
||||
getSummary();
|
||||
}
|
||||
|
||||
// 处理时间筛选
|
||||
function onChangeTime(e) {
|
||||
state.date[0] = e[0];
|
||||
state.date[1] = e[e.length - 1];
|
||||
// 重新加载列表
|
||||
resetPagination(state.pagination);
|
||||
getLogList();
|
||||
getSummary();
|
||||
}
|
||||
|
||||
onReachBottom(() => {
|
||||
if (state.loadStatus === 'noMore') {
|
||||
return;
|
||||
}
|
||||
state.pagination.pageNo++;
|
||||
getLogList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 钱包
|
||||
.header-box {
|
||||
background-color: $white;
|
||||
padding: 30rpx;
|
||||
|
||||
.card-box {
|
||||
width: 100%;
|
||||
min-height: 300rpx;
|
||||
padding: 40rpx;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 30rpx;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
box-sizing: border-box;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 2;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: v-bind(headerBg) no-repeat;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.card-head {
|
||||
color: $white;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.ss-eye-icon {
|
||||
font-size: 40rpx;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.money-num {
|
||||
font-size: 70rpx;
|
||||
line-height: 70rpx;
|
||||
font-weight: 500;
|
||||
color: $white;
|
||||
font-family: OPPOSANS;
|
||||
}
|
||||
|
||||
.reduce-num {
|
||||
font-size: 26rpx;
|
||||
font-weight: 400;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.topup-btn {
|
||||
width: 120rpx;
|
||||
height: 60rpx;
|
||||
line-height: 60rpx;
|
||||
border-radius: 30px;
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
background-color: $white;
|
||||
color: var(--ui-BG-Main);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 筛选
|
||||
|
||||
.filter-box {
|
||||
height: 114rpx;
|
||||
background-color: $bg-page;
|
||||
|
||||
.total-box {
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
color: $dark-9;
|
||||
}
|
||||
|
||||
.date-btn {
|
||||
background-color: $white;
|
||||
line-height: 54rpx;
|
||||
border-radius: 27rpx;
|
||||
padding: 0 20rpx;
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
color: $dark-6;
|
||||
|
||||
.ss-seldate-icon {
|
||||
font-size: 50rpx;
|
||||
color: $dark-9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tabs-box {
|
||||
background: $white;
|
||||
border-bottom: 2rpx solid #eeeeee;
|
||||
}
|
||||
|
||||
// tab
|
||||
.wallet-tab-card {
|
||||
.tab-item {
|
||||
height: 80rpx;
|
||||
position: relative;
|
||||
|
||||
.tab-title {
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.cur-tab-title {
|
||||
font-weight: $font-weight-bold;
|
||||
}
|
||||
|
||||
.tab-line {
|
||||
width: 60rpx;
|
||||
height: 6rpx;
|
||||
border-radius: 6rpx;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
bottom: 2rpx;
|
||||
background-color: var(--ui-BG-Main);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 钱包记录
|
||||
.wallet-list {
|
||||
padding: 30rpx;
|
||||
background-color: #ffff;
|
||||
|
||||
.head-img {
|
||||
width: 70rpx;
|
||||
height: 70rpx;
|
||||
border-radius: 50%;
|
||||
background: $gray-c;
|
||||
}
|
||||
|
||||
.list-content {
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
flex: 1;
|
||||
|
||||
.title {
|
||||
font-size: 28rpx;
|
||||
color: $dark-3;
|
||||
width: 400rpx;
|
||||
}
|
||||
|
||||
.time {
|
||||
color: $gray-c;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.money {
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
font-family: OPPOSANS;
|
||||
.add {
|
||||
color: var(--ui-BG-Main);
|
||||
}
|
||||
|
||||
.minus {
|
||||
color: $dark-3;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
323
pages/user/wallet/score.vue
Normal file
323
pages/user/wallet/score.vue
Normal file
@@ -0,0 +1,323 @@
|
||||
<!-- 我的积分 -->
|
||||
<template>
|
||||
<s-layout class="wallet-wrap" title="我的积分">
|
||||
<!-- 钱包卡片 -->
|
||||
<view class="header-box ss-flex ss-row-center ss-col-center">
|
||||
<view class="card-box ui-BG-Main ui-Shadow-Main">
|
||||
<view class="card-head ss-flex ss-col-center">
|
||||
<view class="card-title ss-m-r-10">剩余积分(个)</view>
|
||||
<view
|
||||
@tap="state.showMoney = !state.showMoney"
|
||||
class="ss-eye-icon"
|
||||
:class="state.showMoney ? 'cicon-eye' : 'cicon-eye-off'"
|
||||
/>
|
||||
</view>
|
||||
<view class="ss-flex ss-row-between ss-col-center ss-m-t-64">
|
||||
<view class="money-num">{{
|
||||
state.showMoney ? (userInfo.point || 0) : '*****'
|
||||
}}</view>
|
||||
<button class="ss-reset-button topup-btn" @tap="sheep.$router.go('/pages/point/recharge')">
|
||||
充值
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- tab -->
|
||||
<su-sticky>
|
||||
<!-- 统计 -->
|
||||
<view class="filter-box ss-p-x-30 ss-flex ss-col-center ss-row-between">
|
||||
<uni-datetime-picker
|
||||
v-model="state.date"
|
||||
type="daterange"
|
||||
@change="onChangeTime"
|
||||
:end="state.today"
|
||||
>
|
||||
<button class="ss-reset-button date-btn">
|
||||
<text>{{ dateFilterText }}</text>
|
||||
<text class="cicon-drop-down ss-seldate-icon"></text>
|
||||
</button>
|
||||
</uni-datetime-picker>
|
||||
|
||||
<!-- TODO 芋艿:【钱包】可优化 -->
|
||||
<!-- <view class="total-box">-->
|
||||
<!-- <view class="ss-m-b-10">总收入¥{{ state.pagination.income }}</view>-->
|
||||
<!-- <view>总支出¥{{ -state.pagination.expense }}</view>-->
|
||||
<!-- </view>-->
|
||||
</view>
|
||||
<su-tabs
|
||||
:list="tabMaps"
|
||||
@change="onChange"
|
||||
:scrollable="false"
|
||||
:current="state.currentTab"
|
||||
></su-tabs>
|
||||
</su-sticky>
|
||||
|
||||
<!-- list -->
|
||||
<view class="list-box">
|
||||
<view v-if="state.pagination.total > 0">
|
||||
<view
|
||||
class="list-item ss-flex ss-col-center ss-row-between"
|
||||
v-for="item in state.pagination.list"
|
||||
:key="item.id"
|
||||
>
|
||||
<view class="ss-flex-col">
|
||||
<view class="name"
|
||||
>{{ item.title }}{{ item.description ? ' - ' + item.description : '' }}</view
|
||||
>
|
||||
<view class="time">{{
|
||||
sheep.$helper.timeFormat(item.createTime, 'yyyy-mm-dd hh:MM:ss')
|
||||
}}</view>
|
||||
</view>
|
||||
<view class="add" v-if="item.point > 0">+{{ item.point }}</view>
|
||||
<view class="minus" v-else>{{ item.point }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<s-empty v-else text="暂无数据" icon="/static/data-empty.png" />
|
||||
</view>
|
||||
|
||||
<uni-load-more
|
||||
v-if="state.pagination.total > 0"
|
||||
:status="state.loadStatus"
|
||||
:content-text="{
|
||||
contentdown: '上拉加载更多',
|
||||
}"
|
||||
@tap="onLoadMore"
|
||||
/>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import sheep from '@/sheep';
|
||||
import { onLoad, onReachBottom } from '@dcloudio/uni-app';
|
||||
import { computed, reactive } from 'vue';
|
||||
import _ from 'lodash-es';
|
||||
import dayjs from 'dayjs';
|
||||
import PointApi from '@/sheep/api/member/point';
|
||||
import { resetPagination } from '@/sheep/util';
|
||||
|
||||
const statusBarHeight = sheep.$platform.device.statusBarHeight * 2;
|
||||
const userInfo = computed(() => sheep.$store('user').userInfo);
|
||||
const sys_navBar = sheep.$platform.navbar;
|
||||
|
||||
const state = reactive({
|
||||
showMoney: true,
|
||||
currentTab: 0,
|
||||
pagination: {
|
||||
list: 0,
|
||||
total: 0,
|
||||
pageSize: 20,
|
||||
pageNo: 1,
|
||||
},
|
||||
loadStatus: '',
|
||||
date: [],
|
||||
today: '',
|
||||
});
|
||||
|
||||
const tabMaps = [
|
||||
{
|
||||
name: '全部',
|
||||
value: 'all',
|
||||
},
|
||||
{
|
||||
name: '收入',
|
||||
value: 'true',
|
||||
},
|
||||
{
|
||||
name: '支出',
|
||||
value: 'false',
|
||||
},
|
||||
];
|
||||
|
||||
const dateFilterText = computed(() => {
|
||||
if (state.date[0] === state.date[1]) {
|
||||
return state.date[0];
|
||||
} else {
|
||||
return state.date.join('~');
|
||||
}
|
||||
});
|
||||
|
||||
async function getLogList() {
|
||||
state.loadStatus = 'loading';
|
||||
let { code, data } = await PointApi.getPointRecordPage({
|
||||
pageNo: state.pagination.pageNo,
|
||||
pageSize: state.pagination.pageSize,
|
||||
addStatus: state.currentTab > 0 ? tabMaps[state.currentTab].value : undefined,
|
||||
'createTime[0]': state.date[0] + ' 00:00:00',
|
||||
'createTime[1]': state.date[1] + ' 23:59:59',
|
||||
});
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
state.pagination.list = _.concat(state.pagination.list, data.list);
|
||||
state.pagination.total = data.total;
|
||||
state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
state.today = dayjs().format('YYYY-MM-DD');
|
||||
state.date = [state.today, state.today];
|
||||
getLogList();
|
||||
// 刷新积分缓存
|
||||
sheep.$store('user').getInfo();
|
||||
});
|
||||
|
||||
function onChange(e) {
|
||||
state.currentTab = e.index;
|
||||
resetPagination(state.pagination);
|
||||
getLogList();
|
||||
}
|
||||
|
||||
function onChangeTime(e) {
|
||||
state.date[0] = e[0];
|
||||
state.date[1] = e[e.length - 1];
|
||||
resetPagination(state.pagination);
|
||||
getLogList();
|
||||
}
|
||||
|
||||
function onLoadMore() {
|
||||
if (state.loadStatus === 'noMore') {
|
||||
return;
|
||||
}
|
||||
state.pagination.pageNo++;
|
||||
getLogList();
|
||||
}
|
||||
|
||||
onReachBottom(() => {
|
||||
onLoadMore();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 钱包
|
||||
.header-box {
|
||||
background-color: $white;
|
||||
padding: 30rpx;
|
||||
|
||||
.card-box {
|
||||
width: 100%;
|
||||
min-height: 300rpx;
|
||||
padding: 40rpx;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 30rpx;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
box-sizing: border-box;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 2;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: v-bind(headerBg) no-repeat;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.card-head {
|
||||
color: $white;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.ss-eye-icon {
|
||||
font-size: 40rpx;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.money-num {
|
||||
font-size: 70rpx;
|
||||
line-height: 70rpx;
|
||||
font-weight: 500;
|
||||
color: $white;
|
||||
font-family: OPPOSANS;
|
||||
}
|
||||
|
||||
.reduce-num {
|
||||
font-size: 26rpx;
|
||||
font-weight: 400;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.topup-btn {
|
||||
width: 120rpx;
|
||||
height: 60rpx;
|
||||
line-height: 60rpx;
|
||||
border-radius: 30px;
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
background-color: $white;
|
||||
color: var(--ui-BG-Main);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 筛选
|
||||
.filter-box {
|
||||
height: 114rpx;
|
||||
background-color: $bg-page;
|
||||
|
||||
.total-box {
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
color: $dark-9;
|
||||
}
|
||||
|
||||
.date-btn {
|
||||
background-color: $white;
|
||||
line-height: 54rpx;
|
||||
border-radius: 27rpx;
|
||||
padding: 0 20rpx;
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
color: $dark-6;
|
||||
|
||||
.ss-seldate-icon {
|
||||
font-size: 50rpx;
|
||||
color: $dark-9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list-box {
|
||||
.list-item {
|
||||
background: #fff;
|
||||
border-bottom: 1rpx solid #dfdfdf;
|
||||
padding: 30rpx;
|
||||
|
||||
.name {
|
||||
font-size: 28rpx;
|
||||
|
||||
font-weight: 500;
|
||||
color: rgba(102, 102, 102, 1);
|
||||
line-height: 28rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.time {
|
||||
font-size: 24rpx;
|
||||
|
||||
font-weight: 500;
|
||||
color: rgba(196, 196, 196, 1);
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.add {
|
||||
font-size: 30rpx;
|
||||
|
||||
font-weight: 500;
|
||||
color: #e6b873;
|
||||
}
|
||||
|
||||
.minus {
|
||||
font-size: 30rpx;
|
||||
|
||||
font-weight: 500;
|
||||
color: $dark-3;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user