This commit is contained in:
全栈小学生 2024-08-06 17:56:04 +08:00
parent 4890be9b9a
commit 4aaf885ef0
85 changed files with 3171 additions and 1404 deletions

View File

@ -1,7 +1,7 @@
<script setup lang="ts">
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app'
import { launchInterceptor } from '@/utils/interceptor'
import { getToken, isWeixinBrowser } from '@/utils/common'
import { getToken, isWeixinBrowser, currRoute } from '@/utils/common'
import useMemberStore from '@/stores/member'
import useConfigStore from '@/stores/config'
import useSystemStore from '@/stores/system'
@ -48,13 +48,37 @@
wechatInit()
// #endif
// #ifdef MP
const updateManager = uni.getUpdateManager();
updateManager.onCheckForUpdate(function(res) {
//
});
updateManager.onUpdateReady(function(res) {
uni.showModal({
title: '更新提示',
content: '新版本已经准备好,是否重启应用?',
success(res) {
if (res.confirm) {
// applyUpdate
updateManager.applyUpdate();
}
}
});
});
updateManager.onUpdateFailed(function(res) {
//
});
// #endif
const configStore = useConfigStore()
await configStore.getTabbarConfig()
await configStore.getLoginConfig()
useSystemStore().getMapFn()
useSystemStore().getSiteInfoFn()
useMemberStore().getMemberLevel()
useMemberStore().getMemberLevel()
try {
// tabbar
uni.hideTabBar()
@ -62,6 +86,12 @@
}
//
let url = currRoute()
if ((url == 'app/pages/auth/login' || url == 'app/pages/auth/register') && (configStore.login.is_username || configStore.login.is_mobile || configStore.login.is_bind_mobile)) {
return false
}
//
if (getToken()) {
const memberStore = useMemberStore()
@ -70,27 +100,54 @@
setTimeout(() => {
if (!uni.getStorageSync('openid')) {
const memberInfo = useMemberStore().info
const login = useLogin()
// #ifdef MP-WEIXIN
memberInfo && memberInfo.weapp_openid && uni.setStorageSync('openid', memberInfo.weapp_openid)
if (memberInfo && memberInfo.weapp_openid) {
uni.setStorageSync('openid', memberInfo.weapp_openid)
} else {
login.getAuthCode('', true)
}
// #endif
// #ifdef H5
isWeixinBrowser() && memberInfo && memberInfo.wx_openid && uni.setStorageSync('openid', memberInfo.wx_openid)
if (isWeixinBrowser()) {
if (memberInfo && memberInfo.wx_openid) {
uni.setStorageSync('openid', memberInfo.wx_openid)
} else {
data.query.code ? login.updateOpenid(data.query.code) : login.getAuthCode('snsapi_userinfo')
}
}
// #endif
}
//
if (uni.getStorageSync('isbindmobile')) {
uni.removeStorageSync('isbindmobile');
}
if (configStore.login.is_bind_mobile && !memberStore.info.mobile) {
//
uni.setStorageSync('isbindmobile', true)
}
}, 1000)
}
if (!getToken()) {
const login = useLogin()
//
// todo 退
// #ifdef MP
login.getAuthCode()
// #endif
// #ifdef H5
if (isWeixinBrowser()) {
data.query.code ? login.authLogin(data.query.code) : login.getAuthCode('snsapi_userinfo')
if(uni.getStorageSync('autoLoginLock')){
return false
}
// #endif
//
if (configStore.login.is_auth_register) {
const login = useLogin()
//
// #ifdef MP
login.getAuthCode()
// #endif
// #ifdef H5
if (isWeixinBrowser()) {
data.query.code ? login.authLogin(data.query.code) : login.getAuthCode('snsapi_userinfo')
}
// #endif
}
}
})
@ -102,7 +159,7 @@
</script>
<style>
uni-page-head {
display: none !important;
}
uni-page-head {
display: none !important;
}
</style>

View File

@ -1,29 +1,29 @@
.draggable-element,.ignore-draggable-element {
&.decorate {
&:hover:before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border: 4rpx dotted $u-primary;
z-index: 10;
pointer-events: none;
cursor: move;
}
.draggable-element {
&.decorate {
&:hover:before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border: 4rpx dotted $u-primary;
z-index: 10;
pointer-events: none;
cursor: move;
}
&.selected:before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border: 4rpx solid $u-primary;
z-index: 10;
pointer-events: none;
cursor: move;
}
}
&.selected:before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border: 4rpx solid $u-primary;
z-index: 10;
pointer-events: none;
cursor: move;
}
}
}

View File

@ -1,11 +1,11 @@
<template>
<view class="diy-group" id="componentList">
<top-tabbar :scrollTop="topTabbarScrollBool" v-if="data.global && Object.keys(data.global).length && data.global.topStatusBar && data.global.topStatusBar.isShow" ref="topTabbarRef" :data="data.global" />
<view v-for="(component, index) in data.value" :key="component.id" @click="diyStore.changeCurrentIndex(index, component)" :class="getComponentClass(index,component)" :style="component.pageStyle">
<top-tabbar v-if="data.global && Object.keys(data.global).length && data.global.topStatusBar && data.global.topStatusBar.isShow" :scrollBool="diyGroup.componentsScrollBool.TopTabbar" ref="topTabbarRef" :data="data.global" />
<view v-for="(component, index) in data.value" :key="component.id" @click="diyStore.changeCurrentIndex(index, component)" :class="diyGroup.getComponentClass(index,component)" :style="component.pageStyle">
<view class="relative" :style="{ marginTop : component.margin.top < 0 ? (component.margin.top * 2) + 'rpx' : '0' }">
<!-- 装修模式下设置负上边距后超出的内容禁止选中设置 -->
<view v-if="isShowPlaceHolder(index,component)" class="absolute w-full z-1" :style="{ height : (component.margin.top * 2 * -1) + 'rpx' }" @click.stop="placeholderEvent"></view>
<view v-if="diyGroup.isShowPlaceHolder(index,component)" class="absolute w-full z-1" :style="{ height : (component.margin.top * 2 * -1) + 'rpx' }" @click.stop="diyGroup.placeholderEvent"></view>
<template v-if="component.componentName == 'GraphicNav'">
<diy-graphic-nav :component="component" :global="data.global" :index="index" :pullDownRefreshCount="props.pullDownRefreshCount" />
@ -47,180 +47,47 @@
<diy-float-btn :component="component" :global="data.global" :index="index" :pullDownRefreshCount="props.pullDownRefreshCount"/>
</template>
<template v-if="component.componentName == 'CarouselSearch'">
<diy-carousel-search ref="carouselSearchRef" :scrollTop="carouselSearchScrollBool" :component="component" :global="data.global" :index="index" :pullDownRefreshCount="props.pullDownRefreshCount" />
<diy-carousel-search :scrollBool="diyGroup.componentsScrollBool.CarouselSearch" :component="component" :global="data.global" :index="index" :pullDownRefreshCount="props.pullDownRefreshCount" />
</template>
</view>
</view>
<template v-if="diyStore.mode == '' && data.global.bottomTabBarSwitch">
<view class="pt-[20rpx]"></view>
<tabbar :addon="tabbarAddonName" />
<tabbar />
</template>
</view>
</template>
<script lang="ts" setup>
import topTabbar from '@/components/top-tabbar/top-tabbar.vue'
import topTabbar from '@/components/top-tabbar/top-tabbar.vue'
import useDiyStore from '@/app/stores/diy';
import { ref, onMounted, nextTick, computed, watch } from 'vue';
import { useRouter } from 'vue-router';
import { getLocation } from '@/utils/common';
import Sortable from 'sortablejs';
import { range } from 'lodash-es';
import { onPageScroll } from '@dcloudio/uni-app'
import useConfigStore from '@/stores/config'
import { useDiyGroup } from './useDiyGroup'
import useDiyStore from '@/app/stores/diy';
import { ref } from 'vue';
const props = defineProps(['data','pullDownRefreshCount']);
const diyStore = useDiyStore();
const router = useRouter();
const data = computed(()=>{
if (diyStore.mode == 'decorate') {
return diyStore;
} else {
return props.data;
}
})
let carouselSearchRef = ref(null)
let carouselSearchScrollValue = 0
let topTabbarRef = ref(null)
let topTabbarScrollValue = 0
// - - start
// #ifdef H5
watch(() => router.currentRoute.value, (newRoute) => {
if(newRoute.path != "/addon/shop/pages/index"){
diyStore.topFixedStatus = 'home'
}
});
const props = defineProps(['data', 'pullDownRefreshCount']);
// #endif
const topTabbarRef = ref(null);
const diyStore = useDiyStore();
const diyGroup = useDiyGroup({
...props,
getFormRef() {
return {
topTabbarRef: topTabbarRef.value
}
}
});
// #ifdef MP
wx.onAppRoute(function(res) {
if(res.path != "addon/shop/pages/index"){
diyStore.topFixedStatus = 'home'
}
});
// #endif
// - - end
const data = ref(diyGroup.data)
const tabbarAddonName = computed(() => {
return useConfigStore().addon;
})
//
diyGroup.onMounted()
const positionFixed = ref(['fixed', 'top_fixed','right_fixed','bottom_fixed','left_fixed']);
//
diyGroup.onPageScroll()
const getComponentClass = (index:any,component:any) => {
let obj: any = {
relative: true,
selected: diyStore.currentIndex == index,
decorate: diyStore.mode == 'decorate'
}
obj['top-fixed-' + diyStore.topFixedStatus] = true;
if (component.position && positionFixed.value.indexOf(component.position) != -1) {
//
obj['ignore-draggable-element'] = true;
} else {
obj['draggable-element'] = true;
}
return obj;
}
onMounted(() => {
// #ifdef H5
if (diyStore.mode == 'decorate') {
var el = document.getElementById('componentList');
const sortable = Sortable.create(el, {
draggable: '.draggable-element',
animation: 200,
//
onEnd: event => {
let temp = diyStore.value[event.oldIndex!];
diyStore.value.splice(event.oldIndex!, 1);
diyStore.value.splice(event.newIndex!, 0, temp);
nextTick(() => {
sortable.sort(range(diyStore.value.length).map(value => {
return value.toString();
}));
diyStore.postMessage(event.newIndex, diyStore.value[event.newIndex]);
});
}
});
}
// #endif
nextTick(() => {
setTimeout(() => {
if (data.value.global && data.value.global.topStatusBar && data.value.global.topStatusBar.style == 'style-4') {
//
getLocation()
}
//
carouselSearchScrollValue = carouselSearchRef.value ? carouselSearchRef.value[0].scrollValue : 0;
// top-tabbar
topTabbarScrollValue = topTabbarRef.value ? topTabbarRef.value.scrollValue : 0;
}, 500)
});
});
//
const isShowPlaceHolder = (index: any, component: any) => {
// #ifdef H5
if (diyStore.mode == 'decorate') {
let el: any = document.getElementById('componentList');
if (el && el.children.length && el.children[index]) {
let height = el.children[index].offsetHeight;
let top = 0;
if (component.margin.top < 0) {
top = component.margin.top * 2 * -1;
//
if (top > height) {
return false;
}
}
}
return true;
}
// #endif
return false;
}
//
const placeholderEvent = ()=>{}
// onShow
const refresh = ()=>{
nextTick(()=>{
topTabbarRef.value?.refresh();
})
}
// carouselSearchScrollBooltrue,
let carouselSearchScrollBool = ref(false)
// top-tabbartrue,
let topTabbarScrollBool = ref(false)
onPageScroll((e)=>{
//
if(e.scrollTop > carouselSearchScrollValue){
carouselSearchScrollBool.value = true
}else{
carouselSearchScrollBool.value = false
}
// top-tabbar
if(e.scrollTop > topTabbarScrollValue){
topTabbarScrollBool.value = true
}else{
topTabbarScrollBool.value = false
}
})
defineExpose({
refresh
})
defineExpose({
refresh: diyGroup.refresh
})
</script>
<style lang="scss" scoped>
@import './index.scss';

View File

@ -0,0 +1,163 @@
import { ref, reactive, onMounted, nextTick, computed } from 'vue';
import Sortable from 'sortablejs';
import { range } from 'lodash-es';
import { onPageScroll, onHide, onShow } from '@dcloudio/uni-app';
import useDiyStore from '@/app/stores/diy';
import { getLocation } from '@/utils/common';
export function useDiyGroup(params: any = {}) {
let scrollVal = ""; //组件滚动值集合
const componentsScrollBool = ref({}); //组件是否根据滚动进行相应改变
const diyStore = useDiyStore();
const positionFixed = ref(['fixed', 'top_fixed', 'right_fixed', 'bottom_fixed', 'left_fixed']);
const data = computed(() => {
if (diyStore.mode == 'decorate') {
return diyStore;
} else {
return params.data;
}
})
const getComponentClass = (index: any, component: any) => {
let obj: any = {
relative: true,
selected: diyStore.currentIndex == index,
decorate: diyStore.mode == 'decorate'
}
obj['top-fixed-' + diyStore.topFixedStatus] = true;
if (component.position && positionFixed.value.indexOf(component.position) != -1) {
// 找出置顶组件,设置禁止拖动
obj['ignore-draggable-element'] = true;
} else {
obj['draggable-element'] = true;
}
return obj;
}
// 是否显示占位区域,用于禁止选中负上边距的内容
const isShowPlaceHolder = (index: any, component: any) => {
// #ifdef H5
if (diyStore.mode == 'decorate') {
let el: any = document.getElementById('componentList');
if (el && el.children.length && el.children[index]) {
let height = el.children[index].offsetHeight;
let top = 0;
if (component.margin.top < 0) {
top = component.margin.top * 2 * -1;
// 若负上边距大于组件的高度,则允许选中进行装修
if (top > height) {
return false;
}
}
}
return true;
}
// #endif
return false;
}
// 监听页面加载完成
const onMountedLifeCycle = () => {
onMounted(() => {
// #ifdef H5
if (diyStore.mode == 'decorate') {
var el = document.getElementById('componentList');
const sortable = Sortable.create(el, {
draggable: '.draggable-element',
animation: 200,
// 结束拖拽
onEnd: event => {
let temp = diyStore.value[event.oldIndex!];
diyStore.value.splice(event.oldIndex!, 1);
diyStore.value.splice(event.newIndex!, 0, temp);
nextTick(() => {
sortable.sort(range(diyStore.value.length).map(value => {
return value.toString();
}));
diyStore.postMessage(event.newIndex, diyStore.value[event.newIndex]);
});
}
});
}
// #endif
nextTick(() => {
setTimeout(() => {
if (data.value.global && data.value.global.topStatusBar && data.value.global.topStatusBar.style == 'style-4') {
// 第一次获取经纬度
getLocation()
}
}, 500)
// 初始化组件滚动值
scrollVal = uni.getStorageSync('componentsScrollValGroup');
if (scrollVal) {
for (let key in scrollVal) {
componentsScrollBool.value[key] = -1;
}
}
});
});
}
// 页面onShow调用时也会触发改方法
const refresh = () => {
nextTick(() => {
params.getFormRef().topTabbarRef?.refresh();
})
}
// 空函数,禁止选中
const placeholderEvent = () => {
}
let isPagesHide = ref(false)
onShow(() => {
isPagesHide.value = false;
})
onHide(() => {
isPagesHide.value = true;
})
// 监听滚动事件
let scrollValStr = ref()
const onPageScrollLifeCycle = () => {
onPageScroll((e) => {
if (scrollVal && !isPagesHide.value) {
for (let key in scrollVal) {
if (e.scrollTop <= 0) {
// -1 表示页面滚动值小于零,组件随页面下拉而下来
componentsScrollBool.value[key] = -1;
} else if (e.scrollTop > scrollVal[key]) {
// 1 表示页面滚动值大于传入滚动值,组件随页面上拉背景、文字颜色等采用滚动后的变量
componentsScrollBool.value[key] = 1;
} else {
// 2 表示页面滚动值小于传入滚动值,组件随页面下拉背景、文字颜色等采用滚动前的变量
componentsScrollBool.value[key] = 2
}
}
}
})
}
return {
scrollV: scrollValStr.value,
data: data.value,
componentsScrollBool: componentsScrollBool.value,
placeholderEvent,
refresh,
isShowPlaceHolder,
getComponentClass,
onPageScroll: onPageScrollLifeCycle,
onMounted: onMountedLifeCycle
}
}

View File

@ -61,6 +61,9 @@ export function wechatUser(data : AnyObject) {
* openid
*/
export function wechatUserLogin(data : AnyObject) {
if(uni.getStorageSync('pid')){
data.pid = uni.getStorageSync('pid');
}
return request.post('wechat/userlogin', data, { showErrorMessage: true })
}
@ -68,16 +71,34 @@ export function wechatUserLogin(data : AnyObject) {
*
*/
export function wechatLogin(data : AnyObject) {
if(uni.getStorageSync('pid')){
data.pid = uni.getStorageSync('pid');
}
return request.post('wechat/login', data, { showErrorMessage: false })
}
/**
* openid
*/
export function updateWechatOpenid(data : AnyObject) {
return request.put('wechat/update_openid', data, { showErrorMessage: false })
}
/**
*
*/
export function weappLogin(data : AnyObject) {
if(uni.getStorageSync('pid')){
data.pid = uni.getStorageSync('pid');
}
return request.post('weapp/login', data, { showErrorMessage: false })
}
/**
* openid
*/
export function updateWeappOpenid(data : AnyObject) {
return request.put('weapp/update_openid', data, { showErrorMessage: false })
}
/**
*
*/

View File

@ -10,7 +10,12 @@ export function getMemberInfo() {
export function getPointList(data : AnyObject) {
return request.get('member/account/point', data)
}
/**
*
*/
export function getPointType(account_type : string) {
return request.get(`member/account/fromtype/${account_type}`)
}
/**
*
*/

View File

@ -11,7 +11,7 @@ export function getCaptcha() {
*
*/
export function getWechatAuthCode(data: AnyObject) {
return request.get('wechat/codeurl', data, {showErrorMessage: false})
return request.get('wechat/codeurl', data, {showErrorMessage: false })
}
/**
@ -116,13 +116,6 @@ export function getAddressByLatlng(params: Record<string, any>) {
return request.get(`area/address_by_latlng`, params, {showErrorMessage: true})
}
/**
*
*/
export function getWapIndexList(data: AnyObject) {
return request.get('wap_index', data)
}
/**
*
* @returns

View File

@ -3,45 +3,41 @@ import request from '@/utils/request'
/**
*
*/
export function getVerifyCode(type: string ,params: AnyObject) {
return request.get('verify', {type, data: params})
export function getVerifyCode(type: string, params: AnyObject) {
return request.get('verify', { type, data: params })
}
/**
*
*/
export function getVerifyRecords(params: Record<string, any>) {
return request.get('verify_records', params)
return request.get('verify_records', params)
}
/**
*
*/
export function getCheckVerifier() {
return request.get('check_verifier')
return request.get('check_verifier')
}
/**
*
*/
export function getVerifierInfo(code: string) {
return request.get(`get_verify_by_code/${code}`)
return request.get(`get_verify_by_code/${ code }`)
}
/**
*
*/
export function verify(code: string) {
return request.post(`verify/${code}`,{}, { showSuccessMessage: true, showErrorMessage: true })
return request.post(`verify/${ code }`, {}, { showErrorMessage: true })
}
/**
*
*/
export function getVerifyDetail(code: string) {
return request.get(`verify_detail/${code}`,{}, { showErrorMessage: true })
}
return request.get(`verify_detail/${ code }`, {}, { showErrorMessage: true })
}

View File

@ -167,7 +167,7 @@
uni.createSelectorQuery().in(instance).select('#item0'+diyComponent.value.id).boundingClientRect((data:any) => {
itemStyle3.value = `margin-right:${(res.width - data.width*4)/3}px;`
}).exec()
}).exec()
}).exec()
// #endif
// #ifdef H5
itemStyle3.value= 'margin-right:14rpx;'
@ -182,7 +182,7 @@
itemStyle4.value = `margin-right:${(res.width - data.width*4)/3}px;`
}).exec()
}).exec()
}).exec()
// #endif
// #ifdef H5
itemStyle4.value= 'margin-right:14rpx;'

View File

@ -6,14 +6,13 @@
<view v-else class="w-full h-full bg-[#ccc]"></view>
<view class="bg-img-box" :style="bgImgBoxStyle"></view>
</view>
<view class="fixed-wrap" :class="[ diyStore.mode != 'decorate' ? diyComponent.positionWay : '' ]" :style="fixedStyle">
<view class="fixed-wrap" :style="fixedStyle">
<view class="diy-search-wrap relative z-10" @click="diyStore.toRedirect(diyComponent.search.link)" :style="navbarInnerStyle">
<view class="img-wrap" v-if="diyComponent.search.logo">
<image :src="img(diyComponent.search.logo)" mode="aspectFit"/>
</view>
<view class="search-content">
<input type="text" class="uni-input" placeholder-style="color:#fff" placeholder-class="!text-[#fff] text-[24rpx] leading-[68rpx]" :placeholder="isShowSearchPlaceholder ? diyComponent.search.text : ''" disabled="true"/>
<view class="search-content" @click="diyStore.toRedirect(diyComponent.search.link)">
<text class="input-content text-[#fff] text-[24rpx] leading-[68rpx]">{{isShowSearchPlaceholder ? diyComponent.search.text : ''}}</text>
<text class="nc-iconfont nc-icon-sousuo-duanV6xx1"></text>
<swiper class="swiper-wrap" :interval="diyComponent.search.hotWord.interval * 1000" autoplay="true" vertical="true" circular="true" v-if="!isShowSearchPlaceholder">
@ -47,7 +46,7 @@
<!-- 解决fixed定位后导航栏塌陷的问题 -->
<template v-if="diyStore.mode != 'decorate'">
<view v-if="diyComponent.positionWay == 'fixed'" class="u-navbar-placeholder" :style="{ width: '100%', paddingTop: moduleHeight }"></view>
<view v-if="diyComponent.positionWay == 'fixed' && props.scrollBool != -1" class="u-navbar-placeholder" :style="{ width: '100%', paddingTop: moduleHeight }"></view>
</template>
<!-- 轮播图 -->
@ -118,8 +117,7 @@
import { getDiyInfo } from '@/app/api/diy';
const instance = getCurrentInstance();
const props = defineProps(['component', 'index', 'pullDownRefreshCount', 'global','scrollTop']);
const props = defineProps(['component', 'index', 'pullDownRefreshCount', 'global', 'scrollBool']);
const diyStore = useDiyStore();
const diyComponent = computed(() => {
@ -172,7 +170,12 @@
style += 'top:' + diyStore.topTabarHeight + 'px;';
}
// #endif
if(diyComponent.value.positionWay == 'fixed') {
if (props.scrollBool != -1) {
style += 'position: fixed;z-index: 10;left: 0;right: 0;';
}
// #ifdef MP-WEIXIN || MP-BAIDU || MP-TOUTIAO || MP-QQ
menuButtonInfo = uni.getMenuButtonBoundingClientRect();
if(props.global.topStatusBar.isShow) {
@ -181,7 +184,7 @@
// #endif
fixedStyleBg.value = false;
if (props.scrollTop) {
if (props.scrollBool == 1) {
let str = diyComponent.value.fixedBgColor;
let arr = str.split(',');
let num = diyComponent.value.fixedBgColor ? parseInt(arr[arr.length-1]) : 0;
@ -200,12 +203,12 @@
let color = '';
if(flag){
color = diyComponent.value.tab.selectColor;
if(diyComponent.value.positionWay == 'fixed' && props.scrollTop) {
if(diyComponent.value.positionWay == 'fixed' && props.scrollBool == 1) {
color = diyComponent.value.tab.fixedSelectColor;
}
}else{
color = diyComponent.value.tab.noColor;
if(diyComponent.value.positionWay == 'fixed' && props.scrollTop) {
if(diyComponent.value.positionWay == 'fixed' && props.scrollBool == 1) {
color = diyComponent.value.tab.fixedNoColor;
}
}
@ -288,9 +291,9 @@
}
}
let tabAllPopup = ref(false);
const tabAllPopup = ref(false);
let menuButtonInfo:any = {};
let navbarInnerStyle = ref('')
const navbarInnerStyle = ref('')
onMounted(() => {
refresh();
@ -397,10 +400,19 @@
isShowDots.value = false;
// #endif
// ,20,
defineExpose({
scrollValue: 20
})
/******************************* 存储滚动值-start ***********************/
//
let componentsScrollVal = uni.getStorageSync('componentsScrollValGroup')
if(componentsScrollVal && (typeof componentsScrollVal == "object")){
componentsScrollVal.CarouselSearch = 20
uni.setStorageSync('componentsScrollValGroup', componentsScrollVal);
}else{
let obj = {
CarouselSearch: 20
}
uni.setStorageSync('componentsScrollValGroup', obj);
}
/******************************* 存储滚动值-end ***********************/
</script>
@ -463,12 +475,12 @@
.search-content {
display: flex;
align-items: center;
padding: 0 40rpx;
padding: 0 32rpx;
border-radius: 50rpx;
background-color: rgba(255,255,255,.2);
flex: 1;
position: relative;
input, .uni-input {
.input-content, .uni-input {
box-sizing: border-box;
display: block;
height: 64rpx;

View File

@ -1,17 +1,34 @@
<template>
<view :style="warpCss">
<view :class="['float-btn flex flex-col z-1000 items-center px-[24rpx] fixed', diyComponent.bottomPosition, diyStore.mode == 'decorate' ? 'float-btn-border' : '']" :style="floatBtnWrapCss">
<view class="float-btn fixed z-1000" :class="[diyComponent.style,diyComponent.bottomPosition, diyStore.mode == 'decorate' ? 'float-btn-border' : '']" :style="floatBtnWrapCss">
<view v-if="diyComponent.style==='style-1'" class="flex flex-col items-center p-[24rpx]" :style="warpCss">
<view v-for="(item,index) in diyComponent.list" :key="index" @click="diyStore.toRedirect(item.link)" :class="{'flex items-center justify-center' : true, 'mb-[20rpx]': diyComponent.list.length != index+1 }" :style="floatBtnItemCss">
<image v-if="item && item.imageUrl" :style="floatBtnItemCss" :src="img(item.imageUrl)" mode="aspectFit"></image>
<image v-else :src="img('static/resource/images/diy/figure.png')" mode="aspectFit" :style="floatBtnItemCss"/>
</view>
</view>
<!-- <view v-if="diyComponent.style==='style-2'" class="relative w-[3rpx] h-[3rpx]">
<view class="py-[14rpx] overflow-hidden absolute right-[25rpx] top-[1rpx] transform -translate-y-1/2" :style="styleTwoWarpCss">
<swiper :style="{'width':diyComponent.imageSize * 2+24+'rpx','height':diyComponent.imageSize * 2+44+'rpx !important',}" circular>
<swiper-item v-for="(item,index) in diyComponent.list" :key="index">
<view @click="diyStore.toRedirect(item.link)" class="px-[12rpx] flex flex-col items-center justify-center">
<image v-if="item && item.imageUrl" :style="floatBtnItemCss" :src="img(item.imageUrl)" mode="aspectFit"></image>
<image v-else :src="img('static/resource/images/diy/figure.png')" mode="aspectFit" :style="floatBtnItemCss"/>
<view class="text-[24rpx] text-[303133] text-center mt-[20rpx]">{{ item.link.title }}</view>
</view>
</swiper-item>
</swiper>
</view>
<view class="w-[60rpx] h-[60rpx] absolute right-[-64rpx] top-[1rpx] transform -translate-y-1/2 rounded-[30rpx] flex items-center" :style="styleTwoSphere">
<text class="!text-[60rpx] iconfont iconxiaolian-1 text-[var(--primary-color)] font-400 transform rotate-90 translate-x-[-13rpx]"></text>
</view>
</view> -->
</view>
</template>
<script setup lang="ts">
//
import { computed, watch } from 'vue';
import { computed, watch,ref } from 'vue';
import { onPageScroll } from '@dcloudio/uni-app';
import useDiyStore from '@/app/stores/diy';
import { img } from '@/utils/common';
@ -37,6 +54,7 @@
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;';
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;';
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;';
return style;
})
@ -52,14 +70,49 @@
let style = '';
if(diyComponent.value.offset){
if(diyComponent.value.bottomPosition == 'lowerRight' || diyComponent.value.bottomPosition == 'lowerLeft'){
style += 'padding-bottom:'+ diyComponent.value.offset * 2 + 'rpx;';
style += 'transform: translateY('+ ((-diyComponent.value.offset) * 2) + 'rpx)';
}else if(diyComponent.value.bottomPosition == 'upperRight' || diyComponent.value.bottomPosition == 'upperLeft'){
style += 'padding-top:'+ diyComponent.value.offset * 2 + 'rpx;';
style += 'transform: translateX('+ diyComponent.value.offset * 2 + 'rpx);';
}
}
return style;
})
//
const styleTwoRepeat = ref(true)
const styleTwoRepeatTime = ref(null)
const styleTwoWarpCss = computed(() => {
var style = '';
if(diyComponent.value.componentStartBgColor) {
if (diyComponent.value.componentStartBgColor && diyComponent.value.componentEndBgColor) style += `background:linear-gradient(${diyComponent.value.componentGradientAngle},${diyComponent.value.componentStartBgColor},${diyComponent.value.componentEndBgColor});`;
else style += 'background-color:' + diyComponent.value.componentStartBgColor + ';';
}
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;';
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;';
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;';
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;';
style += 'transition: right .25s;box-shadow:0px 32rpx 96rpx 32rpx rgba(0, 0, 0, .08), 0px 24rpx 64px rgba(0, 0, 0, .12), 0px 16rpx 32rpx -16rpx rgba(0, 0, 0, .16);'
style +=styleTwoRepeat.value?'transition-delay: 0.25s;':('right:-'+(diyComponent.value.imageSize * 2+24)+'rpx !important;');
return style;
})
const styleTwoSphere = computed(()=>{
var style = 'transition: right .25s;background: rgba(0, 0, 0, 0.5);';
style +=styleTwoRepeat.value?'':'right:-32rpx !important;transition-delay: 0.25s;';
return style
})
onPageScroll(() => {
if(diyComponent.value.style==='style-2'){
if(styleTwoRepeatTime) clearTimeout(styleTwoRepeatTime.value)
styleTwoRepeat.value = false
styleTwoRepeatTime.value = setTimeout(()=>{
styleTwoRepeat.value = true
clearTimeout(styleTwoRepeatTime.value)
},200)
}
})
watch(
() => props.pullDownRefreshCount,
(newValue, oldValue) => {
@ -70,20 +123,20 @@
<style lang="scss" scoped>
.float-btn{
&.decorate-position.upperRight,&.decorate-position.lowerRight {
align-items: flex-end;
}
&.decorate-position.upperLeft,&.decorate-position.lowerLeft {
align-items: baseline;
}
&.upperLeft {
top: 100rpx;
left: 30rpx;
&.style-2{
left:0 ;
}
}
&.upperRight {
top: 100rpx;
right: 30rpx;
&.style-2{
right:0 ;
}
}
&.lowerLeft {
@ -93,6 +146,10 @@
/*兼容 IOS<11.2*/
padding-bottom: env(safe-area-inset-bottom);
/*兼容 IOS>11.2*/
&.style-2{
left:0 ;
}
}
&.lowerRight {
@ -102,6 +159,9 @@
/*兼容 IOS<11.2*/
padding-bottom: env(safe-area-inset-bottom);
/*兼容 IOS>11.2*/
&.style-2{
right:0 ;
}
}
}
.z-1000{

View File

@ -40,9 +40,9 @@
<template v-for="(item, index) in diyComponent.list">
<view class="graphic-nav-item" :class="[diyComponent.mode]" :key="item.id" v-if="swiperCondition(index,numItem)" :style="{ width: 100 / diyComponent.rowCount + '%' }">
<view :class="[diyComponent.mode]" :key="item.id" v-if="swiperCondition(index,numItem)" :style="{ width: 100 / diyComponent.rowCount + '%' }">
<view @click="diyStore.toRedirect(item.link)" class="flex flex-col items-center box-border py-2">
<view @click="diyStore.toRedirect(item.link)" class="graphic-nav-item flex flex-col items-center box-border py-2">
<view class="graphic-img relative flex items-center justify-center w-10 h-10"
v-if="diyComponent.mode != 'text'"
@ -72,6 +72,45 @@
</template>
</swiper-item>
</swiper>
<scroll-view v-else-if="diyComponent.layout == 'horizontal' && diyComponent.pageCount == 2 && diyComponent.showStyle == 'singleSlide'" :scroll-x="diyComponent.showStyle == 'singleSlide'" :class="['graphic-nav','graphic-nav-' + diyComponent.showStyle]" class="py-[10rpx]">
<!-- #ifdef MP -->
<view class="uni-scroll-view-content">
<!-- #endif -->
<view :style="horizontalSingleSlideStyle" class="flex">
<view class="graphic-nav-wrap flex flex-wrap" :style="horizontalSingleSlideBoxStyle(numIndex)" v-for="(numItem, numIndex) in Math.ceil(diyComponent.list.length / (diyComponent.pageCount * diyComponent.rowCount))">
<template v-for="(item, index) in diyComponent.list">
<view v-if="swiperCondition(index,numItem)" @click="diyStore.toRedirect(item.link)" :style="horizontalSingleSlideItemStyle(numIndex)" class="graphic-nav-item flex flex-col items-center box-border py-2">
<view class="graphic-img relative flex items-center justify-center w-10 h-10"
v-if="diyComponent.mode != 'text'"
:style="{ width: diyComponent.imageSize * 2 + 'rpx', height: diyComponent.imageSize * 2 + 'rpx' }">
<image v-if="item.imageUrl" :src="img(item.imageUrl)" mode="aspectFill"
:style="{ maxWidth: diyComponent.imageSize * 2 + 'rpx', maxHeight: diyComponent.imageSize * 2 + 'rpx', borderRadius: diyComponent.aroundRadius * 2 + 'rpx' }"/>
<image v-else :src="img('static/resource/images/diy/figure.png')" mode="aspectFill"
:style="{ maxWidth: diyComponent.imageSize * 2 + 'rpx', maxHeight: diyComponent.imageSize * 2 + 'rpx', borderRadius: diyComponent.aroundRadius * 2 + 'rpx' }"/>
<text
:class="['tag absolute -top-[10rpx] -right-[24rpx] text-white rounded-[24rpx] rounded-bl-none transform scale-80 py-1 px-2 text-xs']"
v-if="item.label.control"
:style="{ color: item.label.textColor, backgroundImage: 'linear-gradient(' + item.label.bgColorStart + ',' + item.label.bgColorEnd + ')' }">
{{ item.label.text }}
</text>
</view>
<text v-if="diyComponent.mode != 'img'"
class="graphic-text w-full text-center truncate leading-normal"
:class="{ 'pt-1.5' : diyComponent.mode != 'text' }"
:style="{ fontSize: diyComponent.font.size * 2 + 'rpx', fontWeight: diyComponent.font.weight, color: diyComponent.font.color }">
{{ item.title }}
</text>
</view>
</template>
</view>
</view>
<!-- #ifdef MP -->
</view>
<!-- #endif -->
</scroll-view>
<scroll-view v-else :scroll-x="diyComponent.showStyle == 'singleSlide'" :class="['graphic-nav','graphic-nav-' + diyComponent.showStyle]" class=" py-[10rpx]">
<!-- #ifdef MP -->
@ -170,6 +209,48 @@
return style;
});
//
const horizontalSingleSlideStyle = computed(()=>{
let style = {width: ""};
let widthStr = 100 / diyComponent.value.rowCount; //
let itemLen = (parseInt(diyComponent.value.list.length / (diyComponent.value.rowCount*2))*diyComponent.value.rowCount) + (diyComponent.value.list.length%(diyComponent.value.rowCount*2)); //
let marginLen = diyComponent.value.margin.both*4
style.width = `calc(${widthStr * itemLen}vw - ${marginLen}rpx)`;
return style;
})
const horizontalSingleSlideBoxStyle = (index: any)=>{
let style = {width: ""};
let widthStr = 100 / diyComponent.value.rowCount; //
let marginLen = diyComponent.value.margin.both * 4 / diyComponent.value.rowCount;
if(parseInt(diyComponent.value.list.length / (diyComponent.value.rowCount*2)) >= (index+1)){
style.width = `calc(${widthStr * diyComponent.value.rowCount}vw - ${marginLen*diyComponent.value.rowCount}rpx)`;
}else{
let len = diyComponent.value.list.length%(diyComponent.value.rowCount*2);
if(len > diyComponent.value.rowCount){ //
style.width = `calc(${widthStr * diyComponent.value.rowCount}vw - ${marginLen*diyComponent.value.rowCount}rpx)`;
}else{
style.width = `calc(${widthStr * len}vw - ${marginLen * len}rpx)`; //
}
}
return style;
}
const horizontalSingleSlideItemStyle = (index: any)=>{
let style = {width: ""};
if(parseInt(diyComponent.value.list.length / (diyComponent.value.rowCount*2)) >= (index+1)){
style.width = `${100 / diyComponent.value.rowCount}%`;
}else{
let len = diyComponent.value.list.length%(diyComponent.value.rowCount*2);
if(len > diyComponent.value.rowCount){ //
style.width = `${100 / diyComponent.value.rowCount}%`;
}else{
style.width = `${100 / len}%`; //
}
}
return style;
}
watch(
() => props.pullDownRefreshCount,
@ -187,14 +268,8 @@
const swiperCondition = (index, numItem) => {
let count = diyComponent.value.pageCount * diyComponent.value.rowCount;
let result = true;
// #ifdef MP-WEIXIN
result = index >= [(numItem) * (count)] && index < [(numItem + 1) * (count)];
// #endif
// #ifdef H5
result = index >= [(numItem - 1) * (count)] && index < [numItem * (count)];
// #endif
return result;
}
@ -206,7 +281,11 @@
var height = 0;
const query = uni.createSelectorQuery().in(instance);
query.select('.graphic-nav-item').boundingClientRect((data: any) => {
height = data.height * diyComponent.value.pageCount;
let len = 1;
if(diyComponent.value.pageCount == 2){
len = (diyComponent.value.list.length / diyComponent.value.rowCount) > 1 ? 2 : 1 ;
}
height = data.height * len;
swiperHeight.value = (height * 2) + 'rpx';
}).exec();
}

View File

@ -7,7 +7,7 @@
<!-- #endif -->
<view v-if="info" class="flex ml-[32rpx] mr-[52rpx] items-center relative">
<!-- 唤起获取微信 -->
<u-avatar :src="img(info.headimg)" size="55" leftIcon="none" @click="clickAvatar"></u-avatar>
<u-avatar :src="img(info.headimg)" size="55" leftIcon="none" :default-url="img('static/resource/images/default_headimg.png')" @click="clickAvatar"></u-avatar>
<view class="ml-[22rpx]">
<view class="text-[#222222] flex pr-[50rpx] flex-wrap items-center">
<view class="text-[#222222] truncate max-w-[320rpx] font-bold text-lg mr-[16rpx]" :style="{ color : diyComponent.textColor }">{{ info.nickname }}</view>
@ -21,7 +21,7 @@
</view>
</view>
<view v-else class="flex ml-[32rpx] mr-[52rpx] items-center relative" @click="toLogin">
<u-avatar src="" size="55"></u-avatar>
<u-avatar src="" size="55" :default-url="img('static/resource/images/default_headimg.png')" />
<view class="ml-[22rpx]">
<view class="text-[#222222] font-bold text-lg" :style="{ color : diyComponent.textColor }">
{{ t('login') }}/{{ t('register') }}
@ -58,6 +58,11 @@
<!-- #ifdef MP-WEIXIN -->
<information-filling ref="infoFill"></information-filling>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<!-- 小程序隐私协议 -->
<wx-privacy-popup ref="wxPrivacyPopupRef"></wx-privacy-popup>
<!-- #endif -->
</view>
</template>
@ -69,9 +74,11 @@
import { t } from '@/locale'
import { wechatSync } from '@/app/api/system'
import useDiyStore from '@/app/stores/diy'
import useConfigStore from '@/stores/config'
const props = defineProps(['component', 'index', 'pullDownRefreshCount','global']);
const configStore = useConfigStore()
const diyStore = useDiyStore();
const diyComponent = computed(() => {
@ -144,7 +151,21 @@
})
const toLogin = () => {
useLogin().setLoginBack({ url: '/app/pages/member/index' })
if(configStore.login.is_username || configStore.login.is_mobile || configStore.login.is_bind_mobile){
useLogin().setLoginBack({ url: '/app/pages/member/index' })
}else if(configStore.login.is_auth_register){ //
//
// #ifdef MP
useLogin().getAuthCode()
// #endif
// #ifdef H5
if (isWeixinBrowser()) {
useLogin().getAuthCode('snsapi_userinfo')
}
// #endif
}else{
uni.showToast({ title: '商家未开启注册方式', icon: 'none' })
}
}
const infoFill = ref(false)

View File

@ -25,22 +25,25 @@
</view>
<view v-if="diyComponent.style == 'style-3'" class="rounded-[16rpx] style-bg-3 p-[30rpx]">
<view class="flex items-center justify-between style-border-3 mb-[22rpx] pb-[22rpx]">
<view class="flex flex-col">
<view class="flex items-center">
<view class="flex justify-end leading-[30rpx] box-border text-[#fff] pr-[10rpx] text-[26rpx] w-[120rpx] h-[30rpx] bg-contain bg-no-repeat" :style="{'backgroundImage': 'url('+img('static/resource/images/diy/member/VIP.png')+')'}">
VIP.{{currIndex}}
<view class="flex flex-col flex-1">
<view class="flex items-center justify-between">
<view class="flex items-center">
<view class="flex justify-end leading-[30rpx] box-border text-[#fff] pr-[10rpx] text-[26rpx] w-[120rpx] h-[30rpx] bg-contain bg-no-repeat" :style="{'backgroundImage': 'url('+img('static/resource/images/diy/member/VIP.png')+')'}">
VIP.{{currIndex}}
</view>
<text class="text-[#733F02] ml-[8rpx] text-[30rpx] font-bold max-w-[380rpx] truncate">{{info.member_level_name}}</text>
</view>
<view class="flex items-center" @click="toLink('/app/pages/member/level')">
<view class="flex items-center">
<image :src="img('static/resource/images/diy/member/rule.png')" mode="aspectFit" class="w-[20rpx] h-[20rpx]" />
<text class="text-[18rpx] text-[#733F02] ml-[6rpx] leading-[24rpx]">规则</text>
</view>
<view class="ml-[6rpx] text-[#733F02] !text-[26rpx] nc-iconfont nc-icon-youV6xx"></view>
</view>
<text class="text-[#733F02] ml-[8rpx] text-[30rpx] font-bold max-w-[380rpx] truncate">{{info.member_level_name}}</text>
</view>
<text class="text-[28rpx] text-[#794200] mt-[16rpx]">购物或邀请好友可以提升等级</text>
</view>
<view class="flex items-center" @click="toLink('/app/pages/member/level')">
<view class="flex flex-col items-center justify-center">
<image :src="img('static/resource/images/diy/member/rule.png')" mode="aspectFit" class="w-[26rpx] h-[26rpx]" />
<text class="text-[24rpx] text-[#733F02] mt-[10rpx]">规则</text>
</view>
<view class="ml-[10rpx] text-[#733F02] !text-[26rpx] nc-iconfont nc-icon-youV6xx"></view>
</view>
</view>
<view class="flex items-center justify-between">
<view class="flex flex-col flex-1">

View File

@ -14,10 +14,10 @@
<view class="flex-1 flex overflow-hidden horizontal-body" :id="'horizontal-body-'+diyComponent.id" :class="{'items-center':diyComponent.scrollWay == 'upDown'}">
<!-- 横向滚动 -->
<view class="horizontal-wrap" :style="marqueeStyle" v-if="diyComponent.scrollWay == 'horizontal'">
<view class="marquee marquee-one" id="marquee-one" >
<view class="marquee marquee-one" id="marquee-one">
<view class="item flex-shrink-0 !leading-[40rpx] h-[40rpx]" :class="{'ml-[80rpx]':index}" v-for="(item, index) in diyComponent.list" :key="index" @click="toRedirect(item)" :style="{ color: diyComponent.textColor, fontSize: diyComponent.fontSize * 2 + 'rpx', fontWeight: diyComponent.fontWeight }">{{ item.text }}</view>
</view>
<view class="marquee">
<view class="marquee" v-if="marqueeBodyWidth < (marqueeOneWidth-30)">
<view class="item flex-shrink-0 !leading-[40rpx] h-[40rpx]" :class="{'ml-[80rpx]':index}" v-for="(item, index) in diyComponent.list" :key="index" @click="toRedirect(item)" :style="{ color: diyComponent.textColor, fontSize: diyComponent.fontSize * 2 + 'rpx', fontWeight: diyComponent.fontWeight }">{{ item.text }}</view>
</view>
</view>
@ -117,14 +117,11 @@ watch(
)
const marqueeBodyWidth = ref(0); //
const marqueeOneWidth = ref(0); //
const marqueeStyle = ref(''); //
const time = ref(0); //
const delayTime = ref(800); //
// pxrpx
const pxToRpx=(px)=> {
const screenWidth = uni.getSystemInfoSync().screenWidth
return (750 * Number.parseInt(px)) / screenWidth
}
//
const bindCrossSlipEvent = ()=> {
if (diyComponent.value.scrollWay == 'horizontal') {
@ -135,9 +132,9 @@ const bindCrossSlipEvent = ()=> {
marqueeBodyWidth.value = res.width;
const query = uni.createSelectorQuery().in(instance);
query.select('#horizontal-body-' + diyComponent.value.id + ' .marquee-one').boundingClientRect((data: any) => {
const width = data.width
time.value = Math.ceil(width * 14);
if (marqueeBodyWidth.value > width) {
marqueeOneWidth.value = data.width
time.value = Math.ceil(marqueeOneWidth.value * 14);
if (marqueeBodyWidth.value > (marqueeOneWidth.value-30)) {
marqueeStyle.value = `animation: none;`;
} else {
marqueeStyle.value = `
@ -152,9 +149,9 @@ const bindCrossSlipEvent = ()=> {
let marqueeOne = window.document.getElementById('marquee-one');
if(documentObj && marqueeOne) {
marqueeBodyWidth.value = documentObj.offsetWidth;
const width = marqueeOne.offsetWidth;
time.value = Math.ceil(width * 14);
if (marqueeBodyWidth.value > width) {
marqueeOneWidth.value = marqueeOne.offsetWidth;
time.value = Math.ceil(marqueeOneWidth.value * 14);
if (marqueeBodyWidth.value > (marqueeOneWidth.value-30)) {
marqueeStyle.value = `animation: none;`;
} else {
marqueeStyle.value = `
@ -199,12 +196,11 @@ const refresh = ()=> {
const toRedirect = (data: {}) => {
if (diyStore.mode == 'decorate') return false;
if (diyComponent.value.showType == 'popup') {
noticeShow.value = true;
noticeContent.value = data.text;
} else {
diyStore.toRedirect(data);
diyStore.toRedirect(data.link);
}
}
</script>
@ -276,8 +272,7 @@ const toRedirect = (data: {}) => {
align-items: center;
height: 100%;
white-space: nowrap;
padding-right: 60rpx;
padding-right: 30px;
// -webkit-perspective: 1000;
// -moz-perspective: 1000;

View File

@ -6,5 +6,6 @@
"pleaceAgree": "请勾选已阅读并同意",
"mobilePlaceholder": "请输入手机号",
"codePlaceholder": "请输入验证码",
"weixinUserAuth": "微信用户一键绑定"
"weixinUserAuth": "一键绑定",
"mobileQuickLogin": "手机号快捷登录"
}

View File

@ -10,5 +10,6 @@
"isAgreeTips": "请先阅读并同意协议",
"usernameLogin": "密码登录",
"mobileLogin": "验证码登录",
"mobilePlaceholder": "请输入手机号"
"mobilePlaceholder": "请输入手机号",
"oneClicklogin":"一键登录"
}

View File

@ -1,6 +1,11 @@
<template>
<view v-if="agreement" class="p-[30rpx]" :style="themeColor()">
<u-parse :content="agreement.content" :tagStyle="{img: 'vertical-align: top;'}"></u-parse>
<view :style="themeColor()">
<view v-if="agreement && agreement.content" class="p-[30rpx]">
<u-parse :content="agreement.content" :tagStyle="{img: 'vertical-align: top;'}"></u-parse>
</view>
<view v-else class="h-[100vh] w-full flex items-center justify-center">
<u-empty :icon="img('static/resource/images/empty.png')" text="暂无协议" />
</view>
</view>
</template>
@ -8,6 +13,7 @@
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { getAgreementInfo } from '@/app/api/system'
import { img} from '@/utils/common'
const agreement = ref(null)

View File

@ -10,11 +10,11 @@
<view class="px-[60rpx]">
<u-form labelPosition="left" :model="formData" errorType='toast' :rules="rules" ref="formRef">
<u-form-item label="" prop="mobile" :border-bottom="true">
<u-input v-model="formData.mobile" border="none" clearable :placeholder="t('mobilePlaceholder')" class="!bg-transparent" :disabled="real_name_input"/>
<u-input v-model="formData.mobile" border="none" clearable :placeholder="t('mobilePlaceholder')" class="!bg-transparent" :disabled="real_name_input" fontSize="26rpx" placeholderClass="!text-[#8288A2]"/>
</u-form-item>
<view class="mt-[40rpx]">
<u-form-item label="" prop="mobile_code" :border-bottom="true">
<u-input v-model="formData.mobile_code" border="none" clearable :placeholder="t('codePlaceholder')" class="!bg-transparent" :disabled="real_name_input">
<u-input v-model="formData.mobile_code" border="none" clearable :placeholder="t('codePlaceholder')" class="!bg-transparent" :disabled="real_name_input" fontSize="26rpx" placeholderClass="!text-[#8288A2]">
<template #suffix>
<sms-code :mobile="formData.mobile" type="bind_mobile" v-model="formData.mobile_key"></sms-code>
</template>
@ -36,12 +36,12 @@
</view>
</view>
<view class="mt-[60rpx]">
<u-button type="primary" :text="t('bind')" :loading="loading" :loadingText="t('binding')" @click="handleBind"></u-button>
<button hover-class="none" class="bg-[var(--primary-color)] text-[#fff] h-[80rpx] leading-[80rpx] rounded-[100rpx] text-[28rpx]" :loading="loading" :loadingText="t('binding')" @click="handleBind">{{t('bind')}}</button>
</view>
<!-- #ifdef MP-WEIXIN -->
<view class="mt-[30rpx]">
<u-button type="primary" :plain="true" :text="t('weixinUserAuth')" @click="agreeTips" v-if="!info && config.agreement_show && !isAgree"></u-button>
<u-button type="primary" :plain="true" :text="t('weixinUserAuth')" open-type="getPhoneNumber" @getphonenumber="mobileAuth" v-else></u-button>
<u-button type="primary" :plain="true" :text="t('mobileQuickLogin')" open-type="getPhoneNumber" @getphonenumber="mobileAuth" @click="checkWxPrivacy" v-else></u-button>
</view>
<!-- #endif -->
</u-form>
@ -50,7 +50,7 @@
<!-- #ifdef MP-WEIXIN -->
<!-- 小程序隐私协议 -->
<wx-privacy-popup ref="wxPrivacyPopup"></wx-privacy-popup>
<wx-privacy-popup ref="wxPrivacyPopupRef"></wx-privacy-popup>
<!-- #endif -->
</view>
</template>
@ -81,7 +81,7 @@
mobile_key: ''
})
let real_name_input = ref(true);
const real_name_input = ref(true);
onMounted(() => {
//
setTimeout(()=>{
@ -153,6 +153,13 @@
})
}
const wxPrivacyPopupRef:any = ref(null)
//
const checkWxPrivacy = ()=>{
wxPrivacyPopupRef.value.proactive();
}
const mobileAuth = (e) => {
if (!isAgree.value && !info.value && config.value.agreement_show) {
uni.showToast({

View File

@ -17,21 +17,21 @@
<u-form labelPosition="left" :model="formData" errorType='toast' :rules="rules" ref="formRef">
<view v-show="type == 'username'">
<u-form-item label="" prop="username" :border-bottom="true">
<u-input v-model="formData.username" border="none" clearable :placeholder="t('usernamePlaceholder')" autocomplete="off" class="!bg-transparent" :disabled="real_name_input"/>
<u-input v-model="formData.username" border="none" clearable :placeholder="t('usernamePlaceholder')" autocomplete="off" class="!bg-transparent" :disabled="real_name_input" fontSize="26rpx" placeholderClass="!text-[#8288A2] text-[26rpx]"/>
</u-form-item>
<view class="mt-[40rpx]">
<u-form-item label="" prop="password" :border-bottom="true">
<u-input v-model="formData.password" border="none" type="password" clearable :placeholder="t('passwordPlaceholder')" autocomplete="new-password" class="!bg-transparent" :disabled="real_name_input"/>
<u-input v-model="formData.password" border="none" type="password" clearable :placeholder="t('passwordPlaceholder')" autocomplete="new-password" class="!bg-transparent" :disabled="real_name_input" fontSize="26rpx" placeholderClass="!text-[#8288A2] text-[26rpx]"/>
</u-form-item>
</view>
</view>
<view v-show="type == 'mobile'">
<u-form-item label="" prop="mobile" :border-bottom="true">
<u-input v-model="formData.mobile" border="none" clearable :placeholder="t('mobilePlaceholder')" autocomplete="off" class="!bg-transparent" :disabled="real_name_input"/>
<u-input v-model="formData.mobile" border="none" clearable :placeholder="t('mobilePlaceholder')" autocomplete="off" class="!bg-transparent" :disabled="real_name_input" fontSize="26rpx" placeholderClass="!text-[#8288A2]"/>
</u-form-item>
<view class="mt-[40rpx]">
<u-form-item label="" prop="mobile_code" :border-bottom="true">
<u-input v-model="formData.mobile_code" border="none" clearable class="!bg-transparent" :disabled="real_name_input" :placeholder="t('codePlaceholder')">
<u-input v-model="formData.mobile_code" border="none" clearable class="!bg-transparent" fontSize="26rpx" :disabled="real_name_input" :placeholder="t('codePlaceholder')" placeholderClass="!text-[#8288A2]">
<template #suffix>
<sms-code :mobile="formData.mobile" type="login" v-model="formData.mobile_key"></sms-code>
</template>
@ -39,16 +39,24 @@
</u-form-item>
</view>
</view>
<view class="flex text-xs justify-between mt-[20rpx] text-gray-400">
<view class="flex text-xs justify-between mt-[20rpx] text-[#8288A2]">
<view @click="redirect({ url: '/app/pages/auth/register' })">{{ t('noAccount') }}
<text class="text-primary">{{ t('toRegister') }}</text>
</view>
<view @click="redirect({ url: '/app/pages/auth/resetpwd' })">{{ t('resetpwd') }}</view>
</view>
<view class="mt-[80rpx]">
<u-button type="primary" :text="t('login')" :loading="loading" :loadingText="t('logining')" @click="handleLogin">
</u-button>
<button hover-class="none" class="bg-[var(--primary-color)] text-[#fff] h-[80rpx] leading-[80rpx] rounded-[100rpx] text-[28rpx]" :loading="loading" :loadingText="t('logining')" @click="handleLogin">{{t('login')}}</button>
</view>
<!-- #ifdef MP-WEIXIN -->
<view class="mt-[20rpx]" v-if="configStore.login.is_auth_register">
<button hover-class="none" class="text-[var(--primary-color)] bg-[#fff] h-[80rpx] leading-[80rpx] rounded-[100rpx] text-[28rpx]" :loading="loginLoading" :loadingText="t('logining')" @click="oneClickLogin">{{t('oneClicklogin')}}</button>
</view>
<view class="mt-[20rpx]" v-else-if="type == 'mobile'">
<u-button :customStyle="{border:'none',color:'var(--primary-color)',fontSize:'26rpx',height:'40rpx', lineHeight:'40rpx'}" :text="t('mobileQuickLogin')" open-type="getPhoneNumber" @getphonenumber="mobileAuth" @click="checkWxPrivacy"></u-button>
</view>
<!-- #endif -->
</u-form>
</view>
</view>
@ -63,17 +71,22 @@
<text class="text-primary">{{ t('privacyAgreement') }}</text>
</view>
</view>
<!-- #ifdef MP-WEIXIN -->
<!-- 小程序隐私协议 -->
<wx-privacy-popup ref="wxPrivacyPopupRef"></wx-privacy-popup>
<!-- #endif -->
</view>
</template>
<script setup lang="ts">
import { ref, reactive, computed, onMounted } from 'vue'
import { usernameLogin, mobileLogin } from '@/app/api/auth'
import { usernameLogin, mobileLogin,bind } from '@/app/api/auth'
import useMemberStore from '@/stores/member'
import useConfigStore from '@/stores/config'
import { useLogin } from '@/hooks/useLogin'
import { t } from '@/locale'
import { redirect } from '@/utils/common'
import { redirect,getToken } from '@/utils/common'
import { onLoad,onShow } from '@dcloudio/uni-app';
const formData = reactive({
username: '',
@ -83,7 +96,7 @@
mobile_key: ''
})
let real_name_input = ref(true);
const real_name_input = ref(true);
onMounted(() => {
//
setTimeout(()=>{
@ -91,23 +104,34 @@
},800)
});
if (!uni.getStorageSync('autoLoginLock')) {
uni.getStorageSync('openid') && (Object.assign(formData, { openid: uni.getStorageSync('openid') }))
uni.getStorageSync('unionid') && (Object.assign(formData, { unionid: uni.getStorageSync('unionid') }))
}
uni.getStorageSync('pid') && (Object.assign(formData, { pid: uni.getStorageSync('pid') }))
const memberStore = useMemberStore()
const configStore = useConfigStore()
onLoad(async()=>{
await configStore.getLoginConfig()
uni.getStorageSync('openid') && (Object.assign(formData, { openid: uni.getStorageSync('openid') }))
uni.getStorageSync('unionid') && (Object.assign(formData, { unionid: uni.getStorageSync('unionid') }))
uni.getStorageSync('pid') && (Object.assign(formData, { pid: uni.getStorageSync('pid') }))
if(!getToken() && !configStore.login.is_username && !configStore.login.is_mobile && !configStore.login.is_bind_mobile){
uni.showToast({ title: '商家未开启普通账号登录注册', icon: 'none' })
setTimeout(() => {
redirect({ url: '/app/pages/index/index', mode: 'reLaunch' })
}, 100)
}
})
const loading = ref(false)
const type = ref('')
const loginType = computed(() => {
const value = []
configStore.login.is_username && (value.push({ type: 'username', title: t('usernameLogin') }))
configStore.login.is_mobile && (value.push({ type: 'mobile', title: t('mobileLogin') }))
if(configStore.login.is_username){
value.push({ type: 'username', title: t('usernameLogin') })
}
if(configStore.login.is_bind_mobile || configStore.login.is_mobile){
value.push({ type: 'mobile', title: t('mobileLogin') })
}
type.value = value[0] ? value[0].type : ''
return value
})
@ -169,12 +193,72 @@
login(formData).then((res) => {
memberStore.setToken(res.data.token)
if(configStore.login.is_bind_mobile && !res.data.mobile){
uni.setStorageSync('isbindmobile', true)
}
useLogin().handleLoginBack()
}).catch(() => {
loading.value = false
})
})
}
// todo
const loginLoading = ref(false)
const oneClickLogin = () =>{
//
if (loginLoading.value) return
loginLoading.value =true
const login = useLogin()
login.getAuthCode('',false,true)
}
const wxPrivacyPopupRef:any = ref(null)
//
const checkWxPrivacy = ()=>{
wxPrivacyPopupRef.value.proactive();
}
const mobileAuth = (e) => {
if (!isAgree.value && configStore.login.agreement_show) {
uni.showToast({
title: `${ t('pleaceAgree') }${ t('userAgreement') }》《${ t('privacyAgreement') }`,
icon: 'none'
})
return
}
const login = useLogin()
login.getAuthCode('',false,true,(data) => {
if (e.detail.errMsg == 'getPhoneNumber:ok') {
uni.showLoading({ title: '' })
bind({
openid:data.openid,
unionid:data.unionid,
mobile_code: e.detail.code
}).then((res) => {
uni.hideLoading()
memberStore.setToken(res.data.token)
useLogin().handleLoginBack()
}).catch((res) => {
setTimeout(() => {
uni.hideLoading()
}, 2000);
})
}
if (e.detail.errno == 104) {
let msg = '用户未授权隐私权限';
uni.showToast({ title: msg, icon: 'none' })
}
if (e.detail.errMsg == "getPhoneNumber:fail user deny") {
let msg = '用户拒绝获取手机号码';
uni.showToast({ title: msg, icon: 'none' })
}
})
}
</script>
<style lang="scss">

View File

@ -1,5 +1,5 @@
<template>
<view class="w-screen h-screen flex flex-col" :style="themeColor()" v-show="type">
<view class="w-screen h-screen flex flex-col" :style="themeColor()" >
<view class="flex-1">
<!-- #ifdef H5 -->
<view class="h-[100rpx]"></view>
@ -18,31 +18,31 @@
<view v-show="type == 'username'">
<view class="mt-[30rpx]">
<u-form-item label="" prop="username" :border-bottom="true">
<u-input v-model="formData.username" border="none" clearable :placeholder="t('usernamePlaceholder')" class="!bg-transparent" :disabled="real_name_input"/>
<u-input v-model="formData.username" border="none" clearable :placeholder="t('usernamePlaceholder')" class="!bg-transparent" :disabled="real_name_input" fontSize="26rpx" placeholderClass="!text-[#8288A2]"/>
</u-form-item>
</view>
<view class="mt-[30rpx]">
<u-form-item label="" prop="password" :border-bottom="true">
<u-input v-model="formData.password" border="none" type="password" clearable :placeholder="t('passwordPlaceholder')" class="!bg-transparent" :disabled="real_name_input"/>
<u-input v-model="formData.password" border="none" type="password" clearable :placeholder="t('passwordPlaceholder')" class="!bg-transparent" :disabled="real_name_input" fontSize="26rpx" placeholderClass="!text-[#8288A2]"/>
</u-form-item>
</view>
<view class="mt-[30rpx]">
<u-form-item label="" prop="confirm_password" :border-bottom="true">
<u-input v-model="formData.confirm_password" border="none" type="password" clearable :placeholder="t('confirmPasswordPlaceholder')" class="!bg-transparent" :disabled="real_name_input"/>
<u-input v-model="formData.confirm_password" border="none" type="password" clearable :placeholder="t('confirmPasswordPlaceholder')" class="!bg-transparent" :disabled="real_name_input" fontSize="26rpx" placeholderClass="!text-[#8288A2]"/>
</u-form-item>
</view>
</view>
<view v-show="type == 'mobile' || configStore.login.is_bind_mobile">
<view class="mt-[30rpx]">
<u-form-item label="" prop="mobile" :border-bottom="true">
<u-input v-model="formData.mobile" border="none" clearable :placeholder="t('mobilePlaceholder')" class="!bg-transparent" :disabled="real_name_input"/>
<u-input v-model="formData.mobile" border="none" clearable :placeholder="t('mobilePlaceholder')" class="!bg-transparent" :disabled="real_name_input" fontSize="26rpx" placeholderClass="!text-[#8288A2]"/>
</u-form-item>
</view>
<view class="mt-[30rpx]">
<u-form-item label="" prop="code" :border-bottom="true">
<u-input v-model="formData.mobile_code" border="none" clearable :placeholder="t('codePlaceholder')" class="!bg-transparent" :disabled="real_name_input">
<u-form-item label="" prop="mobile_code" :border-bottom="true">
<u-input v-model="formData.mobile_code" border="none" clearable :placeholder="t('codePlaceholder')" class="!bg-transparent" :disabled="real_name_input" fontSize="26rpx" placeholderClass="!text-[#8288A2]">
<template #suffix>
<sms-code :mobile="formData.mobile" type="register" v-model="formData.mobile_key"></sms-code>
<sms-code v-show="type" :mobile="formData.mobile" type="register" v-model="formData.mobile_key"></sms-code>
</template>
</u-input>
</u-form-item>
@ -51,7 +51,7 @@
<view v-show="type == 'username'">
<view class="mt-[30rpx]">
<u-form-item label="" prop="captcha_code" :border-bottom="true">
<u-input v-model="formData.captcha_code" border="none" clearable :placeholder="t('captchaPlaceholder')" class="!bg-transparent" :disabled="real_name_input">
<u-input v-model="formData.captcha_code" border="none" clearable :placeholder="t('captchaPlaceholder')" class="!bg-transparent" :disabled="real_name_input" fontSize="26rpx" placeholderClass="!text-[#8288A2]">
<template #suffix>
<image :src="captcha.image.value" class="h-[48rpx] w-[60rpx] ml-[20rpx]" mode="heightFix" @click="captcha.refresh()"></image>
</template>
@ -59,12 +59,11 @@
</u-form-item>
</view>
</view>
<view class="flex text-xs justify-between mt-[20rpx] text-gray-400">
<view class="flex text-xs justify-between mt-[20rpx] text-[#8288A2]">
<view @click="redirect({ url: '/app/pages/auth/login' })">{{ t('haveAccount') }}<text class="text-primary">{{ t('toLogin') }}</text></view>
</view>
<view class="mt-[80rpx]">
<u-button type="primary" :text="t('register')" :loading="loading" :loadingText="t('registering')" @click="handleRegister">
</u-button>
<button hover-class="none" class="bg-[var(--primary-color)] text-[#fff] h-[80rpx] leading-[80rpx] rounded-[100rpx] text-[28rpx]" :loading="loading" :loadingText="t('registering')" @click="handleRegister">{{t('register')}}</button>
</view>
</u-form>
</view>
@ -91,7 +90,8 @@
import { useLogin } from '@/hooks/useLogin'
import { useCaptcha } from '@/hooks/useCaptcha'
import { t } from '@/locale'
import { redirect } from '@/utils/common'
import { redirect, getToken } from '@/utils/common'
import { onLoad } from '@dcloudio/uni-app';
const formData = reactive({
username: '',
@ -104,7 +104,7 @@
captcha_code: ''
})
let real_name_input = ref(true);
const real_name_input = ref(true);
onMounted(() => {
//
setTimeout(()=>{
@ -112,18 +112,27 @@
},800)
});
if (!uni.getStorageSync('autoLoginLock')) {
uni.getStorageSync('openid') && (Object.assign(formData, {openid: uni.getStorageSync('openid')}))
uni.getStorageSync('pid') && (Object.assign(formData, {pid: uni.getStorageSync('pid')}))
}
uni.getStorageSync('unionid') && (Object.assign(formData, { unionid: uni.getStorageSync('unionid') }))
const memberStore = useMemberStore()
const configStore = useConfigStore()
onLoad(async() =>{
await configStore.getLoginConfig()
if (!uni.getStorageSync('autoLoginLock')) {
uni.getStorageSync('openid') && (Object.assign(formData, {openid: uni.getStorageSync('openid')}))
uni.getStorageSync('pid') && (Object.assign(formData, {pid: uni.getStorageSync('pid')}))
}
uni.getStorageSync('unionid') && (Object.assign(formData, { unionid: uni.getStorageSync('unionid') }))
if(!getToken() && !configStore.login.is_username && !configStore.login.is_mobile && !configStore.login.is_bind_mobile){
uni.showToast({ title: '商家未开启普通账号登录注册', icon: 'none' })
setTimeout(() => {
redirect({ url: '/app/pages/index/index', mode: 'reLaunch' })
}, 100)
}
})
const captcha = useCaptcha(formData)
captcha.refresh()
const memberStore = useMemberStore()
const configStore = useConfigStore()
const loading = ref(false)
const type = ref('')

View File

@ -12,12 +12,12 @@
<u-form labelPosition="left" :model="formData" errorType='toast' :rules="rules" ref="formRef">
<view class="mt-[30rpx]">
<u-form-item label="" prop="mobile" :border-bottom="true">
<u-input v-model="formData.mobile" border="none" clearable :placeholder="t('mobilePlaceholder')" class="!bg-transparent" :disabled="real_name_input"/>
<u-input v-model="formData.mobile" border="none" clearable :placeholder="t('mobilePlaceholder')" class="!bg-transparent" :disabled="real_name_input" fontSize="26rpx" placeholderClass="!text-[#8288A2]"/>
</u-form-item>
</view>
<view class="mt-[30rpx]">
<u-form-item label="" prop="code" :border-bottom="true">
<u-input v-model="formData.mobile_code" border="none" clearable :placeholder="t('codePlaceholder')" class="!bg-transparent" :disabled="real_name_input">
<u-input v-model="formData.mobile_code" border="none" clearable :placeholder="t('codePlaceholder')" class="!bg-transparent" :disabled="real_name_input" fontSize="26rpx" placeholderClass="!text-[#8288A2]">
<template #suffix>
<sms-code :mobile="formData.mobile" type="find_pass" v-model="formData.mobile_key"></sms-code>
</template>
@ -26,17 +26,16 @@
</view>
<view class="mt-[30rpx]">
<u-form-item label="" prop="password" :border-bottom="true">
<u-input v-model="formData.password" border="none" type="password" clearable :placeholder="t('passwordPlaceholder')" class="!bg-transparent" :disabled="real_name_input"/>
<u-input v-model="formData.password" border="none" type="password" clearable :placeholder="t('passwordPlaceholder')" class="!bg-transparent" :disabled="real_name_input" fontSize="26rpx" placeholderClass="!text-[#8288A2]"/>
</u-form-item>
</view>
<view class="mt-[30rpx]">
<u-form-item label="" prop="confirm_password" :border-bottom="true">
<u-input v-model="formData.confirm_password" border="none" type="password" clearable :placeholder="t('confirmPasswordPlaceholder')" class="!bg-transparent" :disabled="real_name_input"/>
<u-input v-model="formData.confirm_password" border="none" type="password" clearable :placeholder="t('confirmPasswordPlaceholder')" class="!bg-transparent" :disabled="real_name_input" fontSize="26rpx" placeholderClass="!text-[#8288A2]"/>
</u-form-item>
</view>
<view class="mt-[80rpx]">
<u-button type="primary" :text="t('confirm')" :loading="loading" :loadingText="t('confirm')" @click="handleConfirm">
</u-button>
<button hover-class="none" class="bg-[var(--primary-color)] text-[#fff] h-[80rpx] leading-[80rpx] rounded-[100rpx] text-[28rpx]" :loading="loading" :loadingText="t('confirm')" @click="handleConfirm">{{t('confirm')}}</button>
</view>
</u-form>
</view>
@ -58,7 +57,7 @@
confirm_password: ''
})
let real_name_input = ref(true);
const real_name_input = ref(true);
onMounted(() => {
//
setTimeout(()=>{

View File

@ -23,7 +23,7 @@
<!-- #ifdef MP-WEIXIN -->
<!-- 小程序隐私协议 -->
<wx-privacy-popup ref="wxPrivacyPopup"></wx-privacy-popup>
<wx-privacy-popup ref="wxPrivacyPopupRef"></wx-privacy-popup>
<!-- #endif -->
</view>
@ -51,6 +51,9 @@
setShare(share);
diyGroupRef.value?.refresh();
});
//
diy.onUnload();
//
diy.onPullDownRefresh()

View File

@ -23,7 +23,7 @@
<!-- #ifdef MP-WEIXIN -->
<!-- 小程序隐私协议 -->
<wx-privacy-popup ref="wxPrivacyPopup"></wx-privacy-popup>
<wx-privacy-popup ref="wxPrivacyPopupRef"></wx-privacy-popup>
<!-- #endif -->
</view>
@ -57,6 +57,9 @@
}
diyGroupRef.value?.refresh();
});
//
diy.onUnload();
//
diy.onPullDownRefresh()

View File

@ -1,8 +1,8 @@
<template>
<view class="w-screen h-screen bg-page" :style="themeColor()">
<mescroll-body ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="getCashoutAccountListFn">
<view class="h-[20rpx]"></view>
<u-swipe-action-item :options="accountOptions" @click="swipeClick(index)" v-for="(item, index) in accountList" :key="index" class="mx-[32rpx] my-[20rpx]">
<mescroll-body ref="mescrollRef" @init="mescrollInit" :down="{ use: false }" @up="getCashoutAccountListFn">
<view class="h-[10rpx]"></view>
<u-swipe-action-item :options="accountOptions" @click="swipeClick(index)" v-for="(item, index) in accountList" :key="index" class="sidebar-marign my-[20rpx]">
<view class="p-[30rpx] bg-white rounded flex justify-between" >
<view class="flex">
<view class="w-[100rpx] h-[100rpx] flex items-center justify-center mr-[10rpx]" @click="handleClick(item)">
@ -21,7 +21,7 @@
<text class="flex items-center nc-iconfont nc-icon-xiugaiV6xx shrink-0 text-[32rpx] p-[20rpx] pr-0" @click="editAccount(item)"></text>
</view>
</u-swipe-action-item>
<view class="p-[30rpx] bg-white mx-[32rpx] my-[20rpx] rounded flex" @click="redirect({ url: '/app/pages/member/account_edit', param: { type: accountType, mode } })">
<view class="p-[30rpx] bg-white sidebar-marign my-[20rpx] rounded flex" @click="redirect({ url: '/app/pages/member/account_edit', param: { type: accountType, mode } })">
<u-icon name="plus" color="#333" size="16"></u-icon>
<text class="text-sm ml-[10rpx] flex-1">{{ accountType == 'bank' ? t('addBankCard') : t('addAlipayAccount') }}</text>
<u-icon name="arrow-right" color="#333" size="14"></u-icon>
@ -46,7 +46,7 @@
const mescrollRef = ref(null)
const mode = ref('get')
onLoad((data) => {
onLoad((data: any) => {
data.type && (accountType.value = data.type)
data.mode && (mode.value = data.mode)
})

View File

@ -1,27 +1,27 @@
<template>
<view :style="themeColor()">
<scroll-view scroll-y="true" class="w-screen h-screen bg-page">
<view class="h-[30rpx]"></view>
<view class="p-[30rpx] bg-white mx-[32rpx] rounded">
<view class="h-[20rpx]"></view>
<view class="p-[30rpx] bg-white sidebar-marign rounded">
<block v-if="formData.account_type == 'bank'">
<view class="text-center text-base font-bold mt-[50rpx]">{{ t('addBankCard') }}</view>
<view class="text-center text-sm mt-[10rpx]">{{ t('addBankCardTips') }}</view>
<view class="mt-[50rpx]">
<u-form labelPosition="left" :model="formData" labelWidth="200rpx" errorType='toast' :rules="rules" ref="formRef">
<u-form labelPosition="left" :model="formData" :label-style="{'font-size':'28rpx'}" labelWidth="200rpx" errorType='toast' :rules="rules" ref="formRef">
<view class="mt-[10rpx]">
<u-form-item :label="t('bankRealname')" prop="realname" :border-bottom="true">
<u-input v-model.trim="formData.realname" maxlength="30" border="none" clearable :placeholder="t('bankRealnamePlaceholder')"/>
<u-input v-model.trim="formData.realname" fontSize="28rpx" maxlength="30" border="none" clearable :placeholder="t('bankRealnamePlaceholder')"/>
</u-form-item>
</view>
<view class="mt-[10rpx]">
<u-form-item :label="t('bankName')" prop="bank_name" :border-bottom="true">
<u-input v-model.trim="formData.bank_name" maxlength="30" border="none" clearable :placeholder="t('bankNamePlaceholder')"/>
<u-input v-model.trim="formData.bank_name" fontSize="28rpx" maxlength="30" border="none" clearable :placeholder="t('bankNamePlaceholder')"/>
</u-form-item>
</view>
<view class="mt-[10rpx]">
<u-form-item :label="t('bankAccountNo')" prop="account_no" :border-bottom="true">
<u-input v-model.trim="formData.account_no" maxlength="30" border="none" clearable :placeholder="t('bankAccountNoPlaceholder')"/>
<u-input v-model.trim="formData.account_no" fontSize="28rpx" maxlength="30" border="none" clearable :placeholder="t('bankAccountNoPlaceholder')"/>
</u-form-item>
</view>
</u-form>
@ -49,12 +49,12 @@
</block>
<view class="mt-[100rpx]">
<u-button :text="t('save')" type="primary" shape="circle" :loading="loading" @click="handleSave"></u-button>
<button :loading="loading" class="bg-[var(--primary-color)] text-[#fff] h-[80rpx] leading-[80rpx] rounded-[100rpx] text-[28rpx]" @click="handleSave">{{t('save')}}</button>
</view>
</view>
</scroll-view>
<u-modal :show="deleteConfirm" :content="t('deleteConfirm')" :confirmText="t('confirm')" :cancelText="t('cancel')" :showCancelButton="true" @confirm="handleDelete" @cancel="deleteConfirm = false"></u-modal>
<u-modal :show="deleteConfirm" :content="t('deleteConfirm')" :confirmText="t('confirm')" :cancelText="t('cancel')" :showCancelButton="true" @confirm="handleDelete" @cancel="deleteConfirm = false" confirmColor="var(--primary-color)"></u-modal>
</view>
</template>
@ -100,13 +100,13 @@
}
})
onLoad((data) => {
onLoad((data: any) => {
data.type && (formData.account_type = data.type)
data.mode && (mode.value = data.mode)
if (data.id) {
formData.account_id = data.id
getCashoutAccountInfo({ account_id: data.id }).then((res : responseResult) => {
getCashoutAccountInfo({ account_id: data.id }).then((res : any) => {
if (res.data) {
Object.keys(formData).forEach((key : string) => {
if (res.data[key] != undefined) formData[key] = res.data[key]

View File

@ -2,7 +2,7 @@
<view v-if="!loading" :style="themeColor()">
<scroll-view scroll-y="true">
<u-swipe-action>
<view class="p-[30rpx]">
<view class="py-[30rpx] sidebar-marign">
<u-swipe-action-item :options="addressOptions" @click="swipeClick(key)" v-for="(item, key) in addressList">
<view class="border-0 !border-b !border-[#f5f5f5] border-solid pb-[30rpx] flex items-center">
<view class="flex-1 line-feed" @click="selectAddress(item)">
@ -23,7 +23,7 @@
</u-swipe-action>
<u-tabbar :fixed="true" :safeAreaInsetBottom="true" :border="false" zIndex="99">
<view class="p-[24rpx] pt-0 w-full">
<u-button type="primary" shape="circle" :text="t('createAddress')" @click="addAddress"></u-button>
<button hover-class="none" class="bg-[var(--primary-color)] text-[#fff] h-[80rpx] leading-[80rpx] rounded-[100rpx] text-[28rpx]" @click="addAddress">{{t('createAddress')}}</button>
</view>
</u-tabbar>
</scroll-view>
@ -45,7 +45,7 @@
const type = ref('')
const source = ref('')
onLoad((data) => {
onLoad((data: any) => {
type.value = data.type || ''
source.value = data.source || ''
if (data.type) current.value = data.type == 'address' ? 0 : 1

View File

@ -1,29 +1,29 @@
<template>
<view class="px-[30rpx] pt-[10rpx]" :style="themeColor()">
<u-form labelPosition="left" :model="formData" labelWidth="200rpx" errorType='toast' :rules="rules" ref="formRef">
<view class="sidebar-marign pt-[10rpx]" :style="themeColor()">
<u-form labelPosition="left" :model="formData" :label-style="{'font-size':'28rpx'}" labelWidth="200rpx" errorType='toast' :rules="rules" ref="formRef">
<view class="">
<u-form-item :label="t('name')" prop="name" :border-bottom="true">
<u-input fontSize="30rpx" v-model.trim="formData.name" border="none" clearable maxlength="25" :placeholder="t('namePlaceholder')"/>
<u-input fontSize="28rpx" v-model.trim="formData.name" border="none" clearable maxlength="25" :placeholder="t('namePlaceholder')"/>
</u-form-item>
</view>
<view class="mt-[10rpx]">
<u-form-item :label="t('mobile')" prop="mobile" :border-bottom="true">
<u-input fontSize="30rpx" v-model.trim="formData.mobile" border="none" clearable :placeholder="t('mobilePlaceholder')"/>
<u-input fontSize="28rpx" v-model.trim="formData.mobile" border="none" clearable :placeholder="t('mobilePlaceholder')"/>
</u-form-item>
</view>
<view class="mt-[10rpx]">
<u-form-item :label="t('selectArea')" prop="area" :border-bottom="true" >
<view class="flex w-full items-center" v-if="addressType == 'address' && isSelectMap != 1" @click="selectArea">
<view v-if="!formData.area" class="text-gray-placeholder text-[30rpx] flex-1">{{ t('selectAreaPlaceholder') }}</view>
<view v-else class="text-[30rpx] flex-1">{{ formData.area }}</view>
<view v-if="!formData.area" class="text-gray-placeholder text-[28rpx] flex-1">{{ t('selectAreaPlaceholder') }}</view>
<view v-else class="text-[28rpx] flex-1">{{ formData.area }}</view>
<view @click.stop="chooseLocation" class="flex items-center">
<text class="nc-iconfont nc-icon-dizhiguanliV6xx mr-[4rpx] text-[32rpx] text-[#e93323]"></text>
<text class="text-[24rpx] whitespace-nowrap">定位</text>
</view>
</view>
<view v-else class="flex justify-between items-center flex-1" @click="chooseLocation">
<view class="text-[30rpx] text-[#303133]" v-if="formData.area || formData.address_name">{{formData.area || formData.address_name}}</view>
<view class="text-[#c3c4d5] text-[30rpx]" v-else>{{t('selectAddressPlaceholder')}}</view>
<view class="text-[28rpx] text-[#303133]" v-if="formData.area || formData.address_name">{{formData.area || formData.address_name}}</view>
<view class="text-[#c3c4d5] text-[28rpx]" v-else>{{t('selectAddressPlaceholder')}}</view>
<view class="flex items-center">
<text class="nc-iconfont nc-icon-dizhiguanliV6xx text-[32rpx] mr-[4rpx] text-[#e93323]"></text>
<text class="text-[24rpx] whitespace-nowrap">定位</text>
@ -33,7 +33,7 @@
</view>
<view class="mt-[10rpx]">
<u-form-item :label="t('address')" prop="address" :border-bottom="true">
<u-input fontSize="30rpx" v-model.trim="formData.address" border="none" clearable maxlength="120" :placeholder="t('addressPlaceholder')"/>
<u-input fontSize="28rpx" v-model.trim="formData.address" border="none" clearable maxlength="120" :placeholder="t('addressPlaceholder')"/>
</u-form-item>
</view>
<view class="mt-[10rpx]">
@ -42,13 +42,13 @@
</u-form-item>
</view>
<view class="mt-[40rpx]">
<u-button type="primary" shape="circle" :text="t('save')" @click="save" :disabled="btnDisabled" :loading="operateLoading"></u-button>
<button hover-class="none" class="!bg-[var(--primary-color)] !text-[#fff] h-[80rpx] leading-[80rpx] rounded-[100rpx] text-[28rpx]" :class="{'opacity-50': btnDisabled}" @click="save" :disabled="btnDisabled" :loading="operateLoading">{{t('save')}}</button>
</view>
</u-form>
<area-select ref="areaRef" @complete="areaSelectComplete" :area-id="formData.district_id"/>
<!-- #ifdef MP-WEIXIN -->
<!-- 小程序隐私协议 -->
<wx-privacy-popup ref="wxPrivacyPopup"></wx-privacy-popup>
<wx-privacy-popup ref="wxPrivacyPopupRef"></wx-privacy-popup>
<!-- #endif -->
</view>
@ -82,23 +82,21 @@
const formRef = ref(null)
const source = ref('')
const btnDisabled = ref(false)
let isSelectAddress = ref(false)
let addressType = ref('address');
let isSelectMap = ref(2) // 1
const isSelectAddress = ref(false)
const addressType = ref('address');
const isSelectMap = ref(2) // 1
onLoad((data) => {
onLoad((data: any) => {
isSelectMap.value = data.isSelectMap || '';
const selectAddress = uni.getStorageSync('selectAddressCallback')
if (data.id) {
getAddressInfo(data.id)
.then(res => {
getAddressInfo(data.id).then(res => {
res.data && Object.assign(formData.value, res.data)
//
if(selectAddress){
addressType.value = selectAddress.delivery == 'express' ? 'address' : 'locationAddress';
}
})
.catch()
}else if (data.name) {
if (uni.getStorageSync('addressInfo')) {
@ -198,8 +196,7 @@
btnDisabled.value = false
return false;
}
save(formData.value).then((res) => {
operateLoading.value = false
setTimeout(() => {
@ -273,8 +270,7 @@
window.location.href = 'https://apis.map.qq.com/tools/locpicker?search=1&type=0&backurl=' + encodeURIComponent(backurl) + '&key=' + manifestJson.h5.sdkConfigs.maps.qqmap.key + '&referer=myapp';
// #endif
}
//
const getAddress = (latlng:any)=> {
getAddressByLatlng({latlng}).then((res: any) => {
@ -310,4 +306,6 @@
}
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
</style>

View File

@ -1,18 +1,18 @@
<template>
<view :style="themeColor()">
<scroll-view scroll-y="true" class="w-screen h-screen bg-page" v-if="!pageLoading && config.is_open == 1">
<view class="px-[30rpx] pt-[20rpx]">
<view class="p-[20rpx] bg-white rounded-[16rpx]">
<scroll-view :scroll-y="true" class="w-screen h-screen bg-page" v-if="!pageLoading && config.is_open == 1">
<view class="sidebar-marign pt-[20rpx]">
<view class="card-template">
<view class="font-500 text-[32rpx] text-[#333] leading-[44rpx]">{{t('cashOutMoneyTip')}}</view>
<view class="flex pt-[30rpx] pb-[8rpx] items-center border-0 border-b-[2rpx] border-solid border-gray-200">
<text class="text-[54rpx] font-bold leading-[76rpx] ">{{ t('currency') }}</text>
<input type="digit" class="h-[76rpx] leading-[76rpx] pl-[10rpx] flex-1 font-bold text-[54rpx] bg-[#fff]" v-model="applyData.apply_money" maxlength="7" :placeholder="applyData.apply_money?'':(t('minWithdrawal') + t('currency') + moneyFormat(config.min))" placeholder-class="apply-price" :adjust-position="false"/>
<view class="flex pt-[30rpx] pb-[8rpx] items-center border-0 border-b-[2rpx] border-solid border-[#F1F2F5]">
<text class="text-[54rpx] font-500 leading-[76rpx] ">{{ t('currency') }}</text>
<input type="digit" class="h-[76rpx] leading-[76rpx] pl-[10rpx] flex-1 font-bold text-[54rpx] bg-[#fff]" v-model="applyData.apply_money" maxlength="7" :placeholder="applyData.apply_money?'':(t('minWithdrawal') + t('currency') + moneyFormat(config.min))" placeholder-class="apply-price" :adjust-position="false"/>
<image @click="clearMoney" v-if="applyData.apply_money"
:src="img('static/resource/images/member/apply_withdrawal/close.png')" class="w-[40rpx] h-[40rpx]"
mode="widthFix" />
</view>
<view class="pt-[18rpx] flex items-center justify-between mb-[20rpx]">
<view class="text-[26rpx] text-[#666] leading-[36rpx]">
<view class="pt-[20rpx] flex items-center justify-between">
<view class="text-[26rpx] text-[#626779] leading-[36rpx]">
<text>{{t('money')}}{{ t('currency') }}{{ moneyFormat(cashOutMoney) }}</text>
<text>{{t('commissionTo')}}{{ config.rate + '%' }}</text>
</view>
@ -20,10 +20,10 @@
</view>
</view>
<view class="px-[20rpx] pt-[20rpx] pb-[30rpx] bg-white mt-[20rpx] rounded-[16rpx]">
<view class="font-500 text-[32rpx] text-[#333] leading-[44rpx] mb-[20rpx]">到账方式</view>
<view class="mt-[20rpx] card-template">
<view class="font-500 text-[32rpx] text-[#333] leading-[44rpx] mb-[30rpx]">到账方式</view>
<!-- 提现到微信 -->
<view class="p-[20rpx] mb-[20rpx] flex items-center rounded-[16rpx] border-[2rpx] border-solid border-[#eee]" v-if="config.transfer_type.includes('wechatpay') && memberStore.info && (memberStore.info.wx_openid || memberStore.info.weapp_openid)" @click="applyData.transfer_type = 'wechatpay'" :class="{'border-[#089C98] bg-[#F6FFFF]': applyData.transfer_type == 'wechatpay'}">
<view class="p-[20rpx] mb-[20rpx] flex items-center rounded-[16rpx] border-[1rpx] border-solid border-[#eee]" v-if="config.transfer_type.includes('wechatpay') && memberStore.info && (memberStore.info.wx_openid || memberStore.info.weapp_openid)" @click="applyData.transfer_type = 'wechatpay'" :class="{'border-[#089C98] bg-[#F6FFFF]': applyData.transfer_type == 'wechatpay'}">
<view>
<image class="h-[60rpx] w-[60rpx]" :src="img('static/resource/images/member/apply_withdrawal/wechat.png')" mode="widthFix" />
</view>
@ -34,7 +34,7 @@
</view>
<!-- 提现到支付宝 -->
<view class="p-[20rpx] mb-[20rpx] flex items-center rounded-[16rpx] border-[2rpx] border-solid border-[#eee]" v-if="config.transfer_type.includes('alipay')" :class="{'border-[#089C98] bg-[#F6FFFF]': applyData.transfer_type == 'alipay' && alipayAccountInfo}" >
<view class="p-[20rpx] mb-[20rpx] flex items-center rounded-[16rpx] border-[1rpx] border-solid border-[#eee]" v-if="config.transfer_type.includes('alipay')" :class="{'border-[#089C98] bg-[#F6FFFF]': applyData.transfer_type == 'alipay' && alipayAccountInfo}" >
<view @click="transferAlipay" >
<image class="h-[60rpx] w-[60rpx] align-middle" :src="img('static/resource/images/member/apply_withdrawal/alipay-icon.png')" mode="widthFix" />
</view>
@ -55,7 +55,7 @@
</view>
<!-- 提现到银行卡 -->
<view class="p-[20rpx] flex items-center rounded-[16rpx] border-[2rpx] border-solid border-[#eee]" v-if="config.transfer_type.includes('bank')" :class="{'border-[#089C98] bg-[#F6FFFF]': applyData.transfer_type == 'bank' && bankAccountInfo}">
<view class="p-[20rpx] flex items-center rounded-[16rpx] border-[1rpx] border-solid border-[#eee]" v-if="config.transfer_type.includes('bank')" :class="{'border-[#089C98] bg-[#F6FFFF]': applyData.transfer_type == 'bank' && bankAccountInfo}">
<view @click="transferBank" >
<image class="h-[42rpx] w-[60rpx] align-middle" :src="img('static/resource/images/member/apply_withdrawal/bank-icon.png')" mode="widthFix" />
</view>
@ -72,23 +72,23 @@
</view>
</view>
<view class="flex items-center">
<u-button :plain="true" :text="t('toAdd')" type="primary" shape="circle" :custom-style="{height: '56rpx'}" v-if="!bankAccountInfo && !bankLoading" @click="redirect({ url: '/app/pages/member/account', param: { type: 'bank', mode: 'select' }, mode: 'redirectTo' })"></u-button>
<text v-else class="nc-iconfont nc-icon-youV6xx text-[40rpx] text-[#999] p-[10rpx]" @click.stop="redirect({ url: '/app/pages/member/account', param: { type: 'bank', mode: 'select' }, mode: 'redirectTo' })"></text>
<button hover-class="none" class="h-[54rpx] leading-[50rpx] rounded-full p-[0] w-[100rpx] text-[var(--primary-color)] bg-transparent border-[2rpx] border-solid border-[var(--primary-color)] text-[28rpx]" v-if="!bankAccountInfo && !bankLoading" @click="redirect({ url: '/app/pages/member/account', param: { type: 'bank', mode: 'select' }, mode: 'redirectTo' })">{{t('toAdd')}}</button>
<text v-else class="nc-iconfont nc-icon-youV6xx text-[40rpx] text-[#999] p-[10rpx]" @click.stop="redirect({ url: '/app/pages/member/account', param: { type: 'bank', mode: 'select' }, mode: 'redirectTo' })"></text>
</view>
</view>
</view>
<view class="mt-[100rpx]">
<u-button type="primary" shape="circle" :text="t('cashOutNow')" class="mb-[40rpx]" :disabled="applyData.apply_money == '' || applyData.apply_money == 0" :loading="loading" @click="cashOut" :customStyle="{background: 'linear-gradient( 94deg, #FB7939 0%, #FE120E 99%), #EF000C',fontSize:'32rpx'}"></u-button>
</view>
<view class="mt-[40rpx] text-center text-[26rpx] text-primary" @click.stop="redirect({ url: '/app/pages/member/cash_out'})">
{{t('cashOutList')}}
<view class="fixed bottom-[60rpx] left-0 right-0 px-[30rpx]">
<button class="mt-[100rpx] h-[80rpx] !text-[#fff] leading-[80rpx] primary-btn-bg rounded-[50rpx] text-[32rpx]" :disabled="applyData.apply_money == '' || applyData.apply_money == 0" :loading="loading" @click="cashOut">{{t('cashOutNow')}}</button>
<view class="mt-[20rpx] text-center text-[26rpx] text-primary" @click.stop="redirect({ url: '/app/pages/member/cash_out'})">
{{t('cashOutList')}}
</view>
</view>
</view>
</scroll-view>
<block v-if="config.is_open == 0 && !pageLoading">
<u-empty :text="t('isOpenApply')" :icon="img('static/resource/images/empty.png')"/>
</block>
<view class="h-[100vh] w-[100vw] flex justify-center items-center" v-if="config.is_open == 0 && !pageLoading">
<u-empty :text="t('isOpenApply')" width="320rpx" height="244rpx" :icon="img('static/resource/images/empty.png')"/>
</view>
<u-loading-page :loading="pageLoading" bg-color="#e8e8e8" loading-text=""></u-loading-page>
</view>
</template>
@ -156,7 +156,18 @@
title: t('abnormalOperation'),
icon: 'none',
success() {
setTimeout(() => { uni.navigateBack({ delta: 1}) }, 1500)
setTimeout(() => {
if(getCurrentPages().length > 1){
uni.navigateBack({
delta: 1
});
}else{
redirect({
url: '/app/pages/member/index',
mode: 'reLaunch'
});
}
}, 1500)
}
})
return
@ -301,7 +312,7 @@
<style lang="scss" scoped>
:deep(.apply-price){
color:#999;
color: #8288A2;
font-size: 26rpx;
font-weight: normal;
line-height: 76rpx;

View File

@ -3,7 +3,7 @@
<view class="fixed w-full z-2 !bg-[#F6F6F6]">
<view class="pb-[203rpx] text-[#fff] w-full" :style="headerStyle">
<!-- #ifdef MP-WEIXIN -->
<top-tabbar :data="param" titleColor="#fff" class="top-header"/>
<top-tabbar :data="param" class="top-header"/>
<!-- #endif -->
<view class="leading-[39rpx] text-[28rpx] pl-[53rpx] pt-[79rpx]">{{t('accountBalance')}}</view>
<view class="flex items-baseline pl-[53rpx]">
@ -11,7 +11,7 @@
<text class="text-[70rpx] leading-[98rpx]">{{ memberStore.info ? moneyFormat((parseFloat(memberStore.info.balance) + parseFloat(memberStore.info.money)).toString()) : '0.00' }}</text>
</view>
</view>
<view class="mx-[30rpx] py-[30rpx] bg-[#fff] rounded-[16rpx] px-[40rpx] box-border w-[calc(100% - 60rpx)] mt-[-112rpx]">
<view class="sidebar-marign py-[30rpx] bg-[#fff] rounded-[16rpx] px-[40rpx] box-border w-[calc(100% - 60rpx)] mt-[-112rpx]">
<view class="flex flex-col items-center w-full" @click="redirect({ url: '/app/pages/member/detailed_account', param: { type : 'money' } })" :class="{'pt-[12rpx]': !Object.keys(cashOutConfigObj).length || (Object.keys(cashOutConfigObj).length && !systemStore.siteAddons.includes('recharge') && cashOutConfigObj.is_open != 1)}">
<view class=" text-[#999] text-[24rpx] leading-[34rpx] font-400">{{t('money')}}</view>
<view class="flex items-baseline text-[#333]">
@ -21,22 +21,26 @@
</view>
<view class="mt-[50rpx] flex justify-between" v-if="Object.keys(cashOutConfigObj).length && (systemStore.siteAddons.includes('recharge') || cashOutConfigObj.is_open == 1)">
<button :class="{'!w-[610rpx]': cashOutConfigObj.is_open != 1}" class="w-[280rpx] h-[66rpx] rounded-[40rpx] text-[30rpx] !bg-[#fff] !text-[var(--primary-color)] leading-[64rpx] !m-0 border-[2rpx] border-[var(--primary-color)] border-solid box-border" shape="circle" v-if="systemStore.siteAddons.includes('recharge')"
<button :class="{'!w-[630rpx]': cashOutConfigObj.is_open != 1}" class="w-[280rpx] h-[66rpx] rounded-[40rpx] text-[30rpx] !bg-[#fff] !text-[var(--primary-color)] leading-[64rpx] !m-0 border-[2rpx] border-[var(--primary-color)] border-solid box-border" shape="circle" v-if="systemStore.siteAddons.includes('recharge')"
@click="redirect({url: '/addon/recharge/pages/recharge'})">充值</button>
<view v-if="cashOutConfigObj.is_open == 1" :class="{'!w-[610rpx]': !systemStore.siteAddons.includes('recharge')}" class="text-center w-[280rpx] h-[66rpx] rounded-[40rpx] text-[30rpx] !text-[#fff] leading-[66rpx] !m-0"
style="background: linear-gradient( 94deg, #FB7939 0%, #FE120E 99%), #EF000C;" shape="circle" @click="applyCashOut">{{t('cashOut')}}</view>
<view v-if="cashOutConfigObj.is_open == 1" :class="{'!w-[630rpx]': !systemStore.siteAddons.includes('recharge')}" class="text-center w-[280rpx] h-[66rpx] rounded-[40rpx] text-[30rpx] !text-[#fff] leading-[66rpx] !m-0"
style="background: linear-gradient( 94deg, #FB7939 0%, #FE120E 99%), #EF000C;" @click="applyCashOut">{{t('cashOut')}}</view>
</view>
</view>
<view class=" box-border px-[30rpx] w-full mt-[20rpx]">
<scroll-view :scroll-x="true" scroll-with-animation :scroll-into-view="'id' + (subActive>3 ? subActive - 2 : 0)" class="!h-[100%]">
<view class="px-[var(--sidebar-m)] box-border mt-[20rpx] flex justify-between items-center">
<scroll-view :scroll-x="true" scroll-with-animation :scroll-into-view="'id' + (subActive>3 ? subActive - 2 : 0)" class="!h-[100%] flex-1">
<view class="flex whitespace-nowrap">
<view :id="'id' + index" class="text-[26rpx] leading-[70rpx] text-[#666] font-400" :class="{ 'class-select': fromType === item.key,'ml-30rpx':index}" @click="fromTypeFn(item.key,index)" v-for="(item, index) in accountTypeList">{{ item.name }}</view>
</view>
</scroll-view>
<view class="flex items-center" @click="handleSelect">
<view class="text-[26rpx] text-[#333] mr-[10rpx]">日期</view>
<view class="nc-iconfont nc-icon-riliV6xx !text-[28rpx] leading-[36rpx]"></view>
</view>
</view>
</view>
<mescroll-body ref="mescrollRef" @init="mescrollInit" :down="{ use: false }" @up="getListFn" :top="mescrollTop">
<view class="px-[30rpx] pt-[20rpx] body-bottom" v-if="list.length">
<mescroll-body ref="mescrollRef" @init="mescrollInit" :down="{ use: false }" height="auto" @up="getListFn" :top="mescrollTop">
<view class="sidebar-marign pt-[20rpx] body-bottom" v-if="list.length">
<view v-for="(item,index) in list" :key="item.id" class="w-full h-[120rpx] flex justify-between items-center bg-[#fff] box-border p-[20rpx] rounded-[16rpx]" :class="{'mt-[20rpx]':index>0}">
<view class="flex items-center">
<view class="w-[80rpx] h-[80rpx] text-center rounded-[40rpx] text-[40rpx] font-bold leading-[80rpx] text-[#fff]"
@ -59,7 +63,7 @@
</view>
</view>
<view class="box-border pt-[20rpx] px-[30rpx] body-bottom" :style="{'height':'calc(100vh - '+mescrollTop +')'}" v-if="!list.length && !loading &&!listLoading">
<view class="h-full bg-[#fff] rounded-[16rpx] flex items-center justify-center">
<view class="h-full rounded-[16rpx] flex items-center justify-center">
<mescroll-empty></mescroll-empty>
</view>
</view>
@ -67,33 +71,34 @@
</mescroll-body>
<u-loading-page bg-color="rgb(248,248,248)" :loading="loading" loadingText="" fontSize="16" color="#303133"></u-loading-page>
<!-- <pay ref="payRef" @close="rechargeLoading = false"></pay> -->
<!-- 时间选择 -->
<select-date ref="selectDateRef" @confirm="confirmFn" />
</view>
</template>
<script setup lang="ts">
import { ref, reactive,computed } from 'vue'
import { t } from '@/locale'
import { moneyFormat, redirect, img } from '@/utils/common';
import { moneyFormat, redirect, img,pxToRpx } from '@/utils/common';
import { cashOutConfig,getBalanceListAll } from '@/app/api/member';
import MescrollBody from '@/components/mescroll/mescroll-body/mescroll-body.vue';
import MescrollEmpty from '@/components/mescroll/mescroll-empty/mescroll-empty.vue';
import useMescroll from '@/components/mescroll/hooks/useMescroll.js';
import { onLoad,onShow, onPageScroll, onReachBottom } from '@dcloudio/uni-app';
import { onShow, onPageScroll, onReachBottom } from '@dcloudio/uni-app';
import useMemberStore from '@/stores/member'
import useSystemStore from '@/stores/system'
import { topTabar } from '@/utils/topTabbar'
import selectDate from '@/components/select-date/select-date.vue';
const { downCallback,mescrollInit, getMescroll } = useMescroll(onPageScroll, onReachBottom);
const memberStore = useMemberStore()
const systemStore = useSystemStore()
let param = ref({
title:'我的余额',
topStatusBar: {
style: 'style-1',
isTransparent: true,
bgColor: 'transparent',
textColor: '#fff'
}
})
const systemStore = useSystemStore()
/********* 自定义头部 - start ***********/
const topTabarObj = topTabar()
let param = topTabarObj.setTopTabbarParam({title:'我的余额'})
/********* 自定义头部 - end ***********/
const cashOutConfigObj = reactive({})
onShow(() => {
cashOutConfig().then((res) => {
@ -116,20 +121,25 @@
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
backgroundPosition: 'bottom',
// paddingTop:Object.keys(menuButtonInfo).length?(Number(menuButtonInfo.height) * 2 + menuButtonInfo.top * 2 + 99)+'rpx':'99rpx',
}
})
const mescrollTop = computed(()=>{
return Object.keys(menuButtonInfo).length?(pxToRpx(Number(menuButtonInfo.height)) + pxToRpx(menuButtonInfo.top) +pxToRpx(8)+669)+'rpx':'669rpx'
if(Object.keys(cashOutConfigObj).length && (systemStore.siteAddons.includes('recharge') || cashOutConfigObj.is_open == 1)){
if(Object.keys(menuButtonInfo).length){
return (pxToRpx(Number(menuButtonInfo.height)) + pxToRpx(menuButtonInfo.top) +pxToRpx(8)+669)+'rpx'
}else{
return '669rpx'
}
}else {
if(Object.keys(menuButtonInfo).length){
return (pxToRpx(Number(menuButtonInfo.height)) + pxToRpx(menuButtonInfo.top) +pxToRpx(8)+566)+'rpx'
}else{
return '566rpx'
}
}
})
// pxrpx
const pxToRpx=(px)=> {
const screenWidth = uni.getSystemInfoSync().screenWidth
return (750 * Number.parseInt(px)) / screenWidth
}
//
const accountTypeList = ref([
{name:'全部',key:''},
@ -138,6 +148,7 @@
{name:'提现',key:'cash_out'},
])
const fromType = ref('')
const create_time = ref([])
//
const subActive = ref(0)
const fromTypeFn = (key,index)=>{
@ -168,7 +179,8 @@
let data : Object = {
page: mescroll.num,
limit: mescroll.size,
from_type:fromType.value
trade_type:fromType.value,
create_time: create_time.value
};
interface acceptingDataStructure {
@ -177,12 +189,12 @@
code : number
}
interface acceptingDataItemStructure {
data : object,
data : [],
[propName : string] : number | string | object
}
getBalanceListAll(data).then((res : acceptingDataStructure) => {
let newArr = res.data.data;-
let newArr = res.data.data;
mescroll.endSuccess(newArr.length);
//
if (mescroll.num == 1) {
@ -197,6 +209,17 @@
mescroll.endErr(); // ,
})
}
//
const selectDateRef = ref()
const handleSelect = () =>{
selectDateRef.value.show = true
}
//
const confirmFn = (data) =>{
create_time.value = data;
list.value = []
getMescroll().resetUpScroll();
}
</script>
<style lang="scss" scoped>
@ -226,4 +249,5 @@
.pl-20rpx{
padding-left: 20rpx;
}
</style>

View File

@ -1,6 +1,6 @@
<template>
<view class="member-record-list" :style="themeColor()">
<mescroll-body ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="getCashOutListFn">
<mescroll-body ref="mescrollRef" @init="mescrollInit" :down="{ use: false }" @up="getCashOutListFn">
<view v-for="(item,index) in cashOutList" :key="item.id" class="member-record-item" @click="toDetailFn(item)">
<view class="name">{{item.transfer_type_name}}</view>
<view class="desc">{{t('applyTime')}}: {{item.create_time}}</view>
@ -8,9 +8,7 @@
<view class="money" :class="item.apply_money > 0 ? 'text-active' : ''">
{{ item.apply_money > 0 ? '+' + item.apply_money : item.apply_money }}
</view>
<view class="state">
{{ item.status_name }}
</view>
<view class="state">{{ item.status_name }}</view>
</view>
<mescroll-empty v-if="!cashOutList.length && loading" :option="{tip : t('emptyTip')}"></mescroll-empty>
</mescroll-body>
@ -29,9 +27,9 @@ import { onPageScroll, onReachBottom } from '@dcloudio/uni-app';
const { mescrollInit, downCallback, getMescroll } = useMescroll(onPageScroll, onReachBottom);
let cashOutList = ref<Array<any>>([]);
let mescrollRef = ref(null);
let loading = ref<boolean>(false);
const cashOutList = ref<Array<any>>([]);
const mescrollRef = ref(null);
const loading = ref<boolean>(false);
let account_type = uni.getStorageSync('cashOutAccountType')
const currentStatusDesc = (status) =>{
switch(status){
@ -47,12 +45,12 @@ const currentStatusDesc = (status) =>{
}
const getCashOutListFn = (mescroll)=>{
let data = ref({});
let data:any = {}
loading.value = false;
data.value.page = mescroll.num;
data.value.page_size = mescroll.size;
data.value.account_type = account_type;
getCashOutList(data.value).then((res) => {
data.page = mescroll.num;
data.page_size = mescroll.size;
data.account_type = account_type;
getCashOutList(data).then((res) => {
let newArr = res.data.data;
mescroll.endSuccess(newArr.length);
//

View File

@ -56,9 +56,9 @@ import { t } from '@/locale'
import { redirect, img } from '@/utils/common';
import { getCashOutDetail } from '@/app/api/member';
let cashOutInfo = ref({});
let loading = ref<boolean>(true);
onLoad((option) => {
const cashOutInfo = ref({});
const loading = ref<boolean>(true);
onLoad((option: any) => {
let id = option.id || "";
getCashoutAccountListFn(id)
})

View File

@ -1,38 +1,32 @@
<template>
<view class="bg-[#F6F6F6] min-h-[100vh] w-full" :style="themeColor()" v-if="memberStore.info">
<view class="fixed w-full z-2 !bg-[#F6F6F6]">
<view class="pb-[174rpx]" :style="headerStyle">
<view class="fixed w-full z-2 !bg-[#F6F6F6]">
<view class="pb-[272rpx]" :style="headerStyle">
<!-- #ifdef MP-WEIXIN -->
<top-tabbar :data="param" class="top-header"/>
<top-tabbar :data="param" class="top-header"/>
<!-- #endif -->
<!-- <view class="pt-[18rpx] pb-[20rpx] pl-[30rpx] flex items-center" v-if="info">
<u-avatar :src="img(info.headimg)" :size="'60rpx'" leftIcon="none"></u-avatar>
<view class="ml-[12rpx] mr-[46rpx] text-[32rpx] font-bold text-[#333] leading-[38rpx]">{{info.nickname}}</view>
<view class="member-level pl-[30rpx] pr-[12rpx] py-[2rpx] font-400 text-[24rpx] text-[#fff] leading-[34rpx] relative">
<text>{{ info.member_level_name }}</text>
<image class="h-[40rpx] w-[36rpx] absolute top-0 left-[-20rpx] " :src="img('static/resource/images/member/commission/level_icon.png')" mode="heightFix" />
</view>
</view> -->
</view>
<view class=" mt-[-114rpx] mx-[30rpx]" :style="{ backgroundImage: 'url(' + img('static/resource/images/member/commission/account_bg.png') + ')',backgroundRepeat:'no-repeat',backgroundSize:'100% 100%'}">
<view class="pt-[40rpx] pb-[20rpx]">
<view class="mt-[-232rpx] sidebar-marign" :style="{ backgroundImage: 'url(' + img('static/resource/images/member/commission/account_bg.png') + ')',backgroundRepeat:'no-repeat',backgroundSize:'100% 100%'}">
<view class="pt-[40rpx]">
<view class="flex items-center justify-between px-[30rpx]">
<view>
<view class="text-[26rpx] font-500 text-[#fff] leading-[36rpx] mb-[8rpx]">{{t('accountCommission')}}</view>
<view class="text-[56rpx] font-bold text-[#fff] leading-[68rpx]">{{ memberStore.info ? moneyFormat(memberStore.info.commission) : 0.00 }}</view>
<view class="text-[26rpx] font-400 text-[#fff] leading-[36rpx] mb-[16rpx]">{{t('accountCommission')}}</view>
<view class="font-bold text-[#fff] flex items-baseline">
<text class="text-[56rpx] h-[72rpx] price-font">{{ memberStore.info ? (moneyFormat(memberStore.info.commission).split(".")[0]+'.') : '0.' }}</text>
<text class="text-[44rpx] h-[56rpx] price-font">{{ memberStore.info ? moneyFormat(memberStore.info.commission).split(".")[1] : '00' }}</text>
</view>
</view>
<u-button type="primary" :text="t('transferMoney')" :plain="true" shape="circle" :customStyle="{backgroundColor: '#fff',color: '#EF000C',width: '150rpx', height:'66rpx', lineHeight:'66rpx', margin:'0rpx',border:'none'}" @click="applyCashOut"></u-button>
<button @click="applyCashOut" hover-class="none" class="bg-[#fff] rounded-[100rpx] w-[150rpx] h-[66rpx] leading-[66rpx] text-[#EF000C] m-[0] border-[0] text-[32rpx]">{{t('transferMoney')}}</button>
</view>
<view class="h-[1rpx] bg-[#fff] opacity-30 mt-[80rpx] mb-[20rpx]"></view>
<view class="flex items-center px-[30rpx]">
<view class="flex items-center mt-[68rpx] px-[30rpx] border-[0] border-t-[2rpx] border-solid border-[rgba(255,255,255,.3)] h-[126rpx]">
<view class="flex-1">
<view class="font-bold text-[#fff] text-[36rpx] leading-[44rpx] mb-[6rpx]">
<view class="font-bold text-[#fff] text-[36rpx] leading-[44rpx] mb-[6rpx] price-font">
{{ moneyFormat(memberStore.info?.commission_get)|| '0.00' }}
</view>
<view class="text-[26rpx] text-[#fff] leading-[36rpx]">{{ t('commission') }}</view>
</view>
<view class="flex-1">
<view class="font-bold text-[#fff] text-[36rpx] leading-[44rpx] mb-[6rpx]">
<view class="font-bold text-[#fff] text-[36rpx] leading-[44rpx] mb-[6rpx] price-font">
{{ moneyFormat(memberStore.info?.commission_cash_outing)|| '0.00' }}
</view>
<view class="text-[26rpx] text-[#fff] leading-[36rpx]">{{ t('money') }}</view>
@ -40,41 +34,46 @@
</view>
</view>
</view>
<view class="mt-[40rpx] box-border px-[15rpx]">
<view class="flex whitespace-nowrap">
<view class="text-[26rpx] leading-[70rpx] text-[#666] font-400 px-[15rpx]" :class="{ 'class-select': fromType.from_type === item.from_type && fromType.account_data_gt === item.account_data_gt }" @click="fromTypeFn(item,index)" v-for="(item, index) in accountTypeList">{{ item.name }}</view>
<view class="mt-[40rpx] tab-style-1">
<view class="tab-left">
<view class="tab-left-item" :class="{ 'class-select': fromType.from_type === item.from_type && fromType.account_data_gt === item.account_data_gt }" @click="fromTypeFn(item,index)" v-for="(item, index) in accountTypeList">{{ item.name }}</view>
</view>
<view class="tab-right" @click="handleSelect">
<view class="tab-right-date">日期</view>
<view class="nc-iconfont nc-icon-riliV6xx tab-right-icon"></view>
</view>
</view>
</view>
<mescroll-body ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="geCommissiontListFn" :top="mescrollTop">
<view class="px-[30rpx] pt-[20rpx] body-bottom" v-if="list.length">
<view v-for="(item,index) in list" :key="item.id" class="w-full h-[120rpx] flex justify-between items-center bg-[#fff] box-border p-[20rpx] rounded-[16rpx]" :class="{'mt-[20rpx]':index}">
<mescroll-body ref="mescrollRef" @init="mescrollInit" :down="{ use: false }" @up="geCommissionListFn" :top="mescrollTop">
<view class="px-[var(--sidebar-m)] pt-[20rpx] body-bottom" v-if="list.length">
<view v-for="(item,index) in list" :key="item.id" class="w-full h-[140rpx] flex justify-between items-center card-template" :class="{'mt-[20rpx]':index}">
<view class="flex items-center">
<view class="w-[80rpx] h-[80rpx] text-center rounded-[40rpx] text-[40rpx] font-bold leading-[80rpx] text-[#fff]"
<view class="w-[80rpx] h-[80rpx] text-center rounded-[40rpx] text-[40rpx] font-500 leading-[80rpx] text-[#fff]"
:class="{'bg-[#EF000C]' :item.account_data > 0, 'bg-[#1379FF]':item.account_data <= 0 }">
{{item.account_data > 0?'收':'提'}}
</view>
<view class="flex flex-col ml-[20rpx]">
<view class="text-[#333] text-[26rpx] leading-[36rpx]">{{item.from_type_name}}</view>
<view class="text-[#999] text-[24rpx] leading-[34rpx] mt-[4rpx] font-400">{{item.create_time}}</view>
<view class="text-[#8288A2] text-[24rpx] leading-[34rpx] mt-[4rpx] font-400">{{item.create_time}}</view>
</view>
</view>
<view class="text-[36rpx] leading-[50rpx]" :class="{'text-[#EF000C]' :item.account_data > 0, 'text-[#333]':item.account_data <= 0 }">{{ item.account_data > 0 ? '+' + item.account_data : item.account_data }}</view>
</view>
</view>
<view class="box-border pt-[20rpx] px-[30rpx] body-bottom" :style="{'height':'calc(100vh - '+mescrollTop +')'}" v-if="!list.length && !loading &&!listLoading">
<view class="h-full bg-[#fff] rounded-[16rpx] flex items-center justify-center">
<view class="box-border pt-[20rpx] px-[30rpx] body-bottom" :style="{'height':'calc(100vh - '+ mescrollTop +')'}" v-if="!list.length && !loading &&!listLoading">
<view class="h-full rounded-[16rpx] flex items-center justify-center">
<mescroll-empty></mescroll-empty>
</view>
</view>
</mescroll-body>
<u-loading-page bg-color="rgb(248,248,248)" :loading="loading" loadingText="" fontSize="16" color="#303133"></u-loading-page>
<!-- 时间选择 -->
<select-date ref="selectDateRef" @confirm="confirmFn" />
</view>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import { computed, ref, reactive } from 'vue'
import { t } from '@/locale'
import { moneyFormat, redirect, img } from '@/utils/common';
import useMemberStore from '@/stores/member'
@ -82,7 +81,9 @@
import MescrollBody from '@/components/mescroll/mescroll-body/mescroll-body.vue';
import MescrollEmpty from '@/components/mescroll/mescroll-empty/mescroll-empty.vue';
import useMescroll from '@/components/mescroll/hooks/useMescroll.js';
import { onLoad, onPageScroll, onReachBottom } from '@dcloudio/uni-app';
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app';
import { topTabar } from '@/utils/topTabbar'
import selectDate from '@/components/select-date/select-date.vue';
const { downCallback,mescrollInit, getMescroll } = useMescroll(onPageScroll, onReachBottom);
const memberStore = useMemberStore();
@ -91,17 +92,13 @@
const applyCashOut = ()=> {
uni.setStorageSync('cashOutAccountType', 'commission')
redirect({ url: '/app/pages/member/apply_cash_out' })
}
}
/********* 自定义头部 - start ***********/
const topTabarObj = topTabar()
let param = topTabarObj.setTopTabbarParam({title:'我的佣金',topStatusBar:{bgColor: '#fff',textColor: '#333'}})
/********* 自定义头部 - end ***********/
let param = ref({
title:'我的佣金',
topStatusBar: {
isTransparent: true,
style: 'style-1',
bgColor: 'transparent',
textColor: '#333'
}
})
//
let menuButtonInfo:any = {};
// (API)
@ -113,12 +110,12 @@
backgroundImage: 'url(' + img('static/resource/images/member/commission/commission_bg.png') + ') ',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
backgroundPosition: 'center',
backgroundPosition: 'bottom',
}
})
// 16padding-bottom
const mescrollTop = computed(()=>{
return Object.keys(menuButtonInfo).length?(Number(menuButtonInfo.height) * 2 + menuButtonInfo.top * 2 + 530 + 16)+'rpx':'530rpx'
return Object.keys(menuButtonInfo).length? (Number(menuButtonInfo.height) * 2 + menuButtonInfo.top * 2 + 486 + 16)+'rpx':'504rpx'
})
//
@ -131,6 +128,7 @@
{name:'佣金',from_type:'',account_data_gt: 0},
{name:'提现',from_type:'cash_out',account_data_gt: ''},
])
const create_time = ref([])
const list = ref<Array<any>>([])
const loading = ref<boolean>(true)
const listLoading = ref<boolean>(true)
@ -141,13 +139,14 @@
fromType.value.account_data_gt = data.account_data_gt
getMescroll().resetUpScroll();
}
const geCommissiontListFn = (mescroll) => {
const geCommissionListFn = (mescroll) => {
listLoading.value = true;
let data : Object = {
page: mescroll.num,
limit: mescroll.size,
from_type:fromType.value.from_type,
account_data_gt: fromType.value.account_data_gt
account_data_gt: fromType.value.account_data_gt,
create_time:create_time.value
}
getMemberCommission(data).then((res:any) => {
let newArr = res.data.data;-
@ -165,6 +164,17 @@
mescroll.endErr(); // ,
})
}
//
const selectDateRef = ref()
const handleSelect = () =>{
selectDateRef.value.show = true
}
//
const confirmFn = (data) =>{
create_time.value = data;
list.value = []
getMescroll().resetUpScroll();
}
</script>
<style lang="scss">
@ -172,22 +182,6 @@
background: linear-gradient( 360deg, #F23621 11%, #FF7F71 100%), #D9D9D9;
border-radius: 0rpx 20rpx 20rpx 0rpx;
}
.class-select {
position: relative;
font-weight: 500;
color: var(--primary-color);
&::before {
content: "";
position: absolute;
bottom: 0;
height: 4rpx;
border-radius: 4rpx;
background-color: var(--primary-color);
width: 40rpx;
left: 50%;
transform: translateX(-50%);
}
}
:deep(.uni-scroll-view){
overflow: auto hidden !important;
}

View File

@ -0,0 +1,192 @@
<template>
<u-popup :show="show" @close="show = false" mode="bottom" :round="10" >
<view>
<view class="py-[30rpx] px-[40rpx] flex items-center justify-between">
<view class="text-center flex-1">选择时间</view>
<view class="nc-iconfont nc-icon-guanbiV6xx text-[36rpx] text-primary" @click="show = false"></view>
</view>
<view class="px-[30rpx] mb-[20rpx]">
<view class="flex items-center justify-between mb-[30rpx]">
<view class="w-[160rpx] h-[60rpx] leading-[60rpx] rounded-[30rpx] bg-[#F4F6FA] text-center text-[26rpx] text-[#666] border-[2rpx] border-solid border-[#F4F6FA]" v-for="(item,index) in curselectDate" :key="'a'+index" :class="{'text-primary !border-[var(--primary-color)] !bg-[rgba(239,0,12,0.04)]': currentValue.type == item.type}" @click="loadDateFn(item)">{{item.name}}</view>
</view>
<view class="flex items-center justify-between">
<view class="w-[316rpx] h-[60rpx] leading-[60rpx] rounded-[30rpx] bg-[#F4F6FA] text-center text-[26rpx] text-[#666] border-[2rpx] border-solid border-[#F4F6FA]" :class="{'text-primary !border-[var(--primary-color)] !bg-[rgba(239,0,12,0.04)]': currentValue.type == 'first'}" @click="currentValue.type = 'first'">{{dateList.nowDate[0]}}</view>
<view class="nc-iconfont nc-icon-jianV6xx"></view>
<view class="w-[316rpx] h-[60rpx] leading-[60rpx] rounded-[30rpx] bg-[#F4F6FA] text-center text-[26rpx] text-[#666] border-[2rpx] border-solid border-[#F4F6FA]" :class="{'text-primary !border-[var(--primary-color)] !bg-[rgba(239,0,12,0.04)]': currentValue.type == 'second'}" @click="currentValue.type = 'second'">{{dateList.nowDate[1]}}</view>
</view>
</view>
<view class="h-[396rpx]">
<picker-view :indicator-style="{height:'70rpx',backgroundColor:'#F4F6FA'}" :value="dateList.curIndex" @change="bindChange" class="px-[60rpx] h-full">
<picker-view-column>
<view class="text-center leading-[70rpx] !h-[70rpx] text-[28rpx]" v-for="(item,index) in dateList.years" :key="index">{{item}}</view>
</picker-view-column>
<picker-view-column>
<view class="text-center leading-[70rpx] !h-[70rpx] text-[28rpx]" v-for="(item,index) in dateList.months" :key="index">{{item}}</view>
</picker-view-column>
<picker-view-column>
<view class="text-center leading-[70rpx] !h-[70rpx] text-[28rpx]" v-for="(item,index) in dateList.days" :key="index">{{item}}</view>
</picker-view-column>
</picker-view>
</view>
<view class="px-[30rpx] pb-[30rpx] pt-[20rpx] flex justify-between">
<button class="w-[330rpx] h-[88rpx] text-[var(--primary-color)] text-[32rpx] leading-[84rpx] border-[2rpx] border-solid border-[var(--primary-color)] rounded-[100rpx] bg-transparent" @click="reset">重置</button>
<button class="w-[330rpx] h-[88rpx] text-[#fff] text-[32rpx] leading-[88rpx] border-[0] rounded-[100rpx] primary-btn-bg" shape="circle" @click="save">确定</button>
</view>
</view>
</u-popup>
</template>
<script setup lang="ts">
import { ref,reactive } from 'vue'
const emits = defineEmits(['confirm'])
//
const show = ref(false)
const create_time = ref([])
//
const init = () =>{
const date = new Date();
const years = []
const months = []
const days = []
const year = date.getFullYear()
const month = date.getMonth();
const day = date.getDate()
for (let i = 1990; i <= date.getFullYear()+2; i++) {
years.push(i)
}
for (let i = 1; i <= 12; i++) {
months.push(i)
}
let dayCount = getDaysInMonth(year, month+1)
for (let i = 1; i <= dayCount; i++) {
days.push(i)
}
let yearIndex = years.indexOf(year)
let curIndex = [yearIndex, month, day-1]
let nowDate = `${year}-${month + 1 < 10 ? '0' + (month + 1) :(month + 1) }-${day < 10 ? '0' + day :day }`
let lastMonthDate = new Date(date.getFullYear(),month - 1,date.getDate())
let lastThreeMonthDate = new Date(date.getFullYear(),month - 3,date.getDate())
let halfYear = new Date(date.getFullYear(), month - 6, date.getDate())
let lastYear =new Date(date.getFullYear() - 1, month, date.getDate())
const formatDate = (dateTime:any) => {
const yearTime = dateTime.getFullYear()
const monthTime = dateTime.getMonth() + 1
const dayTime = dateTime.getDate()
return `${yearTime}-${monthTime < 10 ? '0' + monthTime : monthTime}-${dayTime < 10 ? '0' + dayTime :dayTime }`
}
return {
years,
months,
days,
curIndex,
nowDate,
lastMonth: formatDate(lastMonthDate),
lastThreeMonth: formatDate(lastThreeMonthDate),
halfYear: formatDate(halfYear),
lastYear: formatDate(lastYear)
}
}
const getDaysInMonth = (year, month) => {
let date = new Date(year, month, 0).getDate()
return date
}
const getDaysCount = (year, month) =>{
let count = getDaysInMonth(year, month)
let days = []
for (let i = 1; i <= count; i++) {
days.push(i)
}
return days
}
const dateList = reactive({
years: init().years,
months: init().months,
days: init().days,
curIndex:init().curIndex, //
nowDate:[init().nowDate,init().nowDate] //
})
const bindChange = (e) =>{
const val = e.detail.value
let year = dateList.years[val[0]]
let month= dateList.months[val[1]]
let day = dateList.days[val[2]]
// ,
dateList.days = getDaysCount(year, month)
if(currentValue.value.type == 'first'){
dateList.nowDate[0] = `${year}-${month < 10 ? '0' + month :month }-${day < 10 ? '0' + day :day }`
}else if(currentValue.value.type == 'second'){
dateList.nowDate[1] = `${year}-${month < 10 ? '0' + month :month }-${day < 10 ? '0' + day :day }`
}
}
const curselectDate = reactive([
{
time:[init().lastMonth,init().nowDate],
type:'lastMonth',
name:'近1个月'
},
{
time:[init().lastThreeMonth,init().nowDate],
type:'lastThreeMonth',
name:'近3个月'
},
{
time:[init().halfYear,init().nowDate],
type:'halfYear',
name:'近半年'
},
{
time:[init().lastYear,init().nowDate],
type:'lastYear',
name:'近一年'
}
])
//
const currentValue = ref({
type: 'first',
time: []
})
const loadDateFn = (data) =>{
currentValue.value.type = data.type
currentValue.value.time = data.time
}
const save = () =>{
if(currentValue.value.type == 'first' ||currentValue.value.type == 'second'){
create_time.value = dateList.nowDate
let start = new Date(create_time.value[0]).getTime()
let end = new Date(create_time.value[1]).getTime()
if( start > end){
uni.showToast({ title: '开始时间不能大于结束时间', icon: 'none' })
return
}
}else{
create_time.value = currentValue.value.time
}
emits('confirm',create_time.value)
show.value = false
}
const reset = () =>{
currentValue.value.type = 'first'
dateList.curIndex = init().curIndex
dateList.nowDate = [init().nowDate,init().nowDate]
}
defineExpose({
show
})
</script>
<style scoped>
:deep(.uni-picker-view-content){
z-index: 10;
}
:deep(.uni-picker-view-indicator::before){
border: none !important;
}
:deep(.uni-picker-view-indicator::after){
border: none !important;
}
</style>

View File

@ -0,0 +1,49 @@
<template>
<view class="flex items-center justify-center min-h-[100vh]" :style="themeColor()">
<view class="contact-wrap pt-[5%]">
<image :src="img('static/resource/images/member/contact_service.png')" mode="widthFix" />
<view class="mt-[40rpx] text-[28rpx]">
欢迎您联系我们提供您宝贵的意见
</view>
<nc-contact
:send-message-title="sendMessageTitle"
:send-message-path="sendMessagePath"
:send-message-img="sendMessageImg">
<button type="primary" class="btn-wrap primary-btn-bg">{{ t('customerService') }}</button>
</nc-contact>
</view>
</view>
</template>
<script setup lang="ts">
import { t } from '@/locale'
import { img } from '@/utils/common';
import { ref } from 'vue';
const sendMessageTitle = ref('')
const sendMessagePath = ref('')
const sendMessageImg = ref('')
sendMessageImg.value = img('static/resource/images/member/contact_service.png')
</script>
<style lang="scss" scoped>
.contact-wrap {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
image {
width: 674rpx;
}
.btn-wrap {
margin-top: 120rpx;
width: 530rpx;
height: 88rpx;
font-size: 32rpx;
border-radius: 50rpx;
line-height: 88rpx;
}
}
</style>

View File

@ -1,34 +1,56 @@
<template>
<view class="member-record-list" :style="themeColor()">
<mescroll-body ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="getListFn" top="">
<view v-for="(item,index) in list" :key="item.id" class="member-record-item">
<view class="name">{{item.from_type_name}}</view>
<view class="desc" v-if="item.memo">{{item.memo}}</view>
<view class="desc">{{item.create_time}}</view>
<view class="money" :class="item.account_data > 0 ? 'text-active' : ''">
{{ item.account_data > 0 ? '+' + item.account_data : item.account_data }}
<view class="min-h-[100vh] bg-[#F6F6F6] overflow-hidden" :style="themeColor()">
<view class="fixed left-0 right-0 top-0 z-99">
<view class="bg-[#fff] px-[var(--sidebar-m)] h-[88rpx] flex items-center">
<view class="flex-1 flex items-center h-[60rpx] bg-[#F8F9FD] rounded-[30rpx] px-[20rpx]">
<u-input class="flex-1" maxlength="50" v-model="keyword" @confirm="searchTypeFn()" placeholder="请输入搜索关键词" placeholderClass="text-[#999] text-[24rpx]" fontSize="26rpx" clearable border="none"></u-input>
<text class="nc-iconfont nc-icon-sousuo-duanV6xx1 text-[28rpx] ml-[32rpx] !text-[#999]" @click="searchTypeFn()"></text>
</view>
</view>
<view class="tab-style-1 pt-[14rpx] bg-[#fff]">
<view class="tab-left">
<view class="tab-left-item" :class="{'!text-primary class-select':fromType.from_type === item.from_type && fromType.account_data_gt === item.account_data_gt}" v-for="(item,index) in accountTypeList" :key="index" @click="fromTypeFn(item,index)">{{ item.name }}</view>
</view>
<view class="tab-right" @click="handleSelect">
<view class="tab-right-date">日期</view>
<view class="nc-iconfont nc-icon-riliV6xx tab-right-icon"></view>
</view>
</view>
</view>
<mescroll-body ref="mescrollRef" @init="mescrollInit" :down="{ use: false }" @up="getListFn" top="196rpx">
<view v-for="(item,index) in list" :key="item.id" class="sidebar-marign mb-[20rpx] card-template relative">
<view class="flex items-center justify-between mb-[10rpx]">
<view class="text-[28rpx] font-500 text-[#333] leading-[40rpx]">{{item.from_type_name}}</view>
<view class="absolute right-[30rpx] top-[30rpx] text-[36rpx] font-500 text-[#03B521] leading-[50rpx]" :class="{'!text-[var(--price-text-color)]':item.account_data > 0}">{{ item.account_data > 0 ? '+' + item.account_data : item.account_data }}</view>
</view>
<view class="text-[24rpx] leading-[34rpx] text-[#8288A2] mb-[10rpx]" v-if="item.memo">{{item.memo}}</view>
<view class="text-[24rpx] leading-[34rpx] text-[#8288A2]">{{item.create_time}}</view>
</view>
<view class="mx-[30rpx] rounded-[16rpx] noData flex items-center justify-center" v-if="!list.length && loading">
<mescroll-empty :option="{tip : tip}"></mescroll-empty>
</view>
<mescroll-empty v-if="!list.length && loading" :option="{tip : tip}"></mescroll-empty>
</mescroll-body>
<!-- 时间选择 -->
<select-date ref="selectDateRef" @confirm="confirmFn" />
</view>
</template>
<script setup lang="ts">
import { ref,nextTick } from 'vue'
import { ref,nextTick, reactive } from 'vue'
import { t } from '@/locale'
import MescrollBody from '@/components/mescroll/mescroll-body/mescroll-body.vue';
import MescrollEmpty from '@/components/mescroll/mescroll-empty/mescroll-empty.vue';
import useMescroll from '@/components/mescroll/hooks/useMescroll.js';
import { getBalanceList, getMoneyList, getCommissionList} from '@/app/api/member';
import { onPageScroll, onReachBottom, onLoad, onShow } from '@dcloudio/uni-app';
import selectDate from '@/components/select-date/select-date.vue';
const { mescrollInit, downCallback, getMescroll } = useMescroll(onPageScroll, onReachBottom);
const type = ref('')
const tip = ref('')
onLoad((options) => {
onLoad((options: any) => {
type.value = options.type || 'balance';
nextTick(()=>{
setTimeout(()=>{
@ -43,6 +65,18 @@
})
});
const keyword = ref<string>('')
const create_time = ref([])
//
const fromType = ref({
from_type:'',
account_data_gt:''
})
const accountTypeList = ref([
{name:'全部',from_type:'',account_data_gt: ''},
{name:'佣金',from_type:'',account_data_gt: 0},
{name:'提现',from_type:'cash_out',account_data_gt: ''},
])
const list = ref<Array<any>>([]),
loading = ref<boolean>(false),
mescrollRef = ref(null);
@ -58,7 +92,11 @@
loading.value = false;
let data : Object = {
page: mescroll.num,
page_size: mescroll.size
page_size: mescroll.size,
keyword:keyword.value,
create_time:create_time.value,
from_type:fromType.value.from_type,
account_data_gt: fromType.value.account_data_gt
};
interface acceptingDataStructure {
data : acceptingDataItemStructure,
@ -89,8 +127,36 @@
mescroll.endErr(); // ,
})
}
//
const searchTypeFn = () =>{
list.value = [];
getMescroll().resetUpScroll();
}
//
const fromTypeFn = (data : any ,index : number)=>{
fromType.value.from_type = data.from_type
fromType.value.account_data_gt = data.account_data_gt
list.value = []
getMescroll().resetUpScroll();
}
//
const selectDateRef = ref()
const handleSelect = () =>{
selectDateRef.value.show = true
}
//
const confirmFn = (data) =>{
create_time.value = data;
list.value = []
getMescroll().resetUpScroll();
}
</script>
<style lang="scss">
@import '@/styles/member_record_list.scss';
.noData{
height: calc(100vh - 210rpx - constant(safe-area-inset-bottom));
height: calc(100vh - 210rpx - env(safe-area-inset-bottom));
}
</style>

View File

@ -23,7 +23,7 @@
<!-- #ifdef MP-WEIXIN -->
<!-- 小程序隐私协议 -->
<wx-privacy-popup ref="wxPrivacyPopup"></wx-privacy-popup>
<wx-privacy-popup ref="wxPrivacyPopupRef"></wx-privacy-popup>
<!-- #endif -->
</view>
@ -65,6 +65,9 @@
useMemberStore().getMemberInfo()
}
});
//
diy.onUnload();
//
diy.onPullDownRefresh()

View File

@ -3,22 +3,18 @@
<u-loading-page :loading="loading && memberInfo" loadingText="" bg-color="#f7f7f7"></u-loading-page>
<view v-if="!loading && memberInfo && list && list.length" class=" min-h-[100vh] overflow-hidden flex flex-col" :style="{backgroundColor: currLevelInfo.level_style.bg_color }">
<!-- #ifdef MP -->
<top-tabbar :data="topTabbarData" titleColor="#fff"/>
<top-tabbar :data="topTabbarData" :scrollBool="topTabarObj.getScrollBool()"/>
<!-- #endif -->
<view>
<view class="pt-[40rpx] mb-[20rpx]">
<!-- 轮播图 -->
<view class="relative">
<swiper class="swiper ns-indicator-dots relative" :style="{ height: '300rpx' }" @change="swiperChange" :current = "swiperIndex"
previous-margin="48rpx" next-margin="48rpx">
<swiper class="swiper ns-indicator-dots relative" :style="{ height: '300rpx' }" @change="swiperChange" :current = "swiperIndex" previous-margin="48rpx" next-margin="48rpx">
<swiper-item class="swiper-item" v-for="(item,index) in list" :key="item.id">
<view class="h-[300rpx] relative">
<view v-if="memberInfo.member_level == item.level_id && swiperIndex == index" class="text-[24rpx] absolute top-0 left-0 z-10 h-[66rpx] !bg-contain w-[150rpx] flex pt-[12rpx] pl-[16rpx] leadinig-[34rpx] box-border" :style="{ background: 'url(' + img(currLevelInfo.level_tag) + ') no-repeat',color: currLevelInfo.level_style.level_color}">
<view v-if="memberInfo.member_level == item.level_id && swiperIndex == index" class="text-[24rpx] absolute top-0 left-0 z-10 h-[66rpx] !bg-contain w-[150rpx] flex pt-[12rpx] pl-[16rpx] box-border" :style="{ background: 'url(' + img(currLevelInfo.level_tag) + ') no-repeat',color: currLevelInfo.level_style.level_color}">
当前等级
</view>
<view v-else-if="Number(memberInfo.growth) < Number(currLevelInfo.growth) && swiperIndex == index" class="text-[24rpx] absolute top-0 left-0 z-10 h-[66rpx] !bg-contain w-[150rpx] text-[#999] flex pt-[12rpx] pl-[16rpx] leadinig-[34rpx] box-border" :style="{ background: 'url(' + img('static/resource/images/member/level/not_reach.png') + ') no-repeat'}" >
未达标
</view>
<view class="absolute top-0 left-0 right-0 bottom-0 z-20 px-[30rpx] pt-[76rpx] box-border" :class="{'px-[50rpx]': swiperIndex != index}">
<view class="flex items-center leading-[50rpx] mb-[70rpx]">
<image class="h-[32rpx] w-[34rpx] align-middle" :src="img(item.level_icon ? item.level_icon : '')" mode="aspectFill" />
@ -26,7 +22,7 @@
</view>
<view class="flex items-center" :style="{color: currLevelInfo.level_style.level_color}">
<view class="text-[28rpx] font-bold leading-[38rpx]">{{ memberInfo.growth }}</view>
<view class="text-[24rpx] leading-[34rpx]">/{{list[index].growth}}成长值</view>
<view class="text-[24rpx] leading-[34rpx] font-500">/{{list[index].growth}}成长值</view>
</view>
<view class="flex justify-between items-center mt-[10rpx]">
<view class="flex flex-col flex-1">
@ -60,14 +56,14 @@
</scroll-view>
</view>
</view>
<view class="flex mx-[30rpx] px-[38rpx] pt-[30rpx] pb-[46rpx] items-center flex-col level_benefits" v-if="currLevelInfo.benefits_arr && currLevelInfo.benefits_arr.length" :style="{ backgroundImage: 'url(' + img(currLevelInfo.member_bg) + ')'}">
<view class="flex mx-[30rpx] pt-[30rpx] pb-[46rpx] items-center flex-col level_benefits" v-if="currLevelInfo.benefits_arr && currLevelInfo.benefits_arr.length" :style="{ backgroundImage: 'url(' + img(currLevelInfo.member_bg) + ')'}">
<view class="flex items-center justify-center">
<text class="text-[#fff] text-[32rpx] font-bold leading-[44rpx]">会员权益</text>
</view>
<view class="flex flex-wrap w-[690rpx] mt-[40rpx] justify-between">
<view class="flex flex-col w-[25%] items-center" v-for="(item,index) in currLevelInfo.benefits_arr" :key="index">
<image class="h-[100rpx] w-[100rpx]" :src="img(item.icon)" mode="heightFix" />
<text class="text-[rgba(255,255,255,0.9)] mt-[10rpx] text-[24rpx]">{{item.title}}</text>
<text class="text-[rgba(255,255,255,0.9)] mt-[10rpx] text-[24rpx] leading-[34rpx]">{{item.title}}</text>
</view>
</view>
</view>
@ -77,7 +73,7 @@
<!-- 升级礼包 -->
<view v-if="currLevelInfo.gifts_arr && currLevelInfo.gifts_arr.length">
<view class="pt-[10rpx] pb-[30rpx] flex items-center">
<text class="text-[32rpx] text-[#3A3945] font-bold leading-[44rpx]">升级礼包</text>
<text class="text-[32rpx] text-[#333] font-bold leading-[44rpx]">升级礼包</text>
</view>
<view class="flex flex-wrap">
<view v-for="(item,index) in currLevelInfo.gifts_arr" :key="index" class="mb-[20rpx]" :class="{'mr-[20rpx]': (index+1) % 3 != 0}">
@ -106,34 +102,33 @@
</view>
</view>
</view>
<u-empty v-if="!loading && (!list || !list.length)" :icon="img('static/resource/images/empty.png')" text="暂无会员等级" />
<view v-if="!loading && (!list || !list.length)" class="h-[100vh] w-full flex items-center justify-center">
<u-empty :icon="img('static/resource/images/empty.png')" text="暂无会员等级" />
</view>
</view>
</template>
<script setup lang="ts">
import { ref, reactive, computed } from 'vue'
import { onLoad, onShow } from '@dcloudio/uni-app'
import { onShow } from '@dcloudio/uni-app'
import { getMemberLevel, getTaskGrowth } from '@/app/api/member';
import { img,redirect, deepClone, getToken } from '@/utils/common';
import useMemberStore from '@/stores/member'
import { topTabar } from '@/utils/topTabbar'
const memberStore = useMemberStore()
let loading = ref(false)
let list = ref([]) //
let upgradeSkills = ref([]) //
const loading = ref(false)
const list = ref([]) //
const upgradeSkills = ref([]) //
const swiperIndex = ref(0); //
const levelIndex = ref(0); //
//
let topTabbarData = ref({
title: '会员等级',
topStatusBar: {
isTransparent: true,
style: 'style-1',
bgColor: 'transparent',
textColor: '#fff'
}
})
/********* 自定义头部 - start ***********/
const topTabarObj = topTabar()
let topTabbarData = topTabarObj.setTopTabbarParam({title:'会员等级'})
/********* 自定义头部 - end ***********/
onShow(() => {
//
@ -149,7 +144,7 @@
})
//
let progress = (index:any) => {
const progress = (index:any) => {
let indent = index;
let num = 100
if(list.value[indent] && list.value[indent].growth) {
@ -159,7 +154,7 @@
}
//
let upgradeGrowth = (index:any) => {
const upgradeGrowth = (index:any) => {
let indent = index;
let num = 0;
if(list.value[indent] && list.value[indent].growth) {
@ -228,8 +223,8 @@
};
//
let currLevelInfo = ref<any>({});
let infoStructureFn = (index:number)=>{
const currLevelInfo = ref<any>({});
const infoStructureFn = (index:number)=>{
let data:any = deepClone(list.value[index]);
//
if(data && data.level_benefits){

View File

@ -36,7 +36,7 @@
</u-form-item>
</view>
<view class="mt-[40rpx]">
<u-button type="primary" shape="circle" :text="t('save')" @click="save" :disabled="btnDisabled" :loading="operateLoading"></u-button>
<button class="!bg-[var(--primary-color)] !text-[#fff] h-[80rpx] leading-[80rpx] rounded-[100rpx] text-[28rpx]" :class="{'opacity-50': btnDisabled}" @click="save" :disabled="btnDisabled" :loading="operateLoading">{{t('save')}}</button>
</view>
</u-form>
</view>
@ -44,7 +44,7 @@
<!-- #ifdef MP-WEIXIN -->
<!-- 小程序隐私协议 -->
<wx-privacy-popup ref="wxPrivacyPopup"></wx-privacy-popup>
<wx-privacy-popup ref="wxPrivacyPopupRef"></wx-privacy-popup>
<!-- #endif -->
</view>
</template>
@ -79,15 +79,15 @@
type: 'location_address'
})
onLoad((option) => {
onLoad((option:any) => {
if (option.id) {
getAddressInfo(option.id).then(({data}) => {
getAddressInfo(option.id).then(({ data }) => {
if (data) {
Object.assign(formData.value, data)
formData.value.area = formData.value.full_address.replace(formData.value.address, '').replace(formData.value.address_name, '')
}
}).catch()
}else if (option.name) {
} else if (option.name) {
if (uni.getStorageSync('addressInfo')) {
Object.assign(formData.value, uni.getStorageSync('addressInfo'))
}

View File

@ -2,14 +2,14 @@
<view class="w-full h-screen bg-page personal-wrap" v-if="info" :style="themeColor()">
<view class="flex flex-col items-center pt-[30rpx]">
<!-- #ifdef MP-WEIXIN -->
<button open-type="chooseAvatar" @chooseavatar="onChooseAvatar" :plain="true" class="border-0">
<u-avatar :src="img(info.headimg)" size="60" leftIcon="none"></u-avatar>
<button open-type="chooseAvatar" @chooseavatar="onChooseAvatar" :plain="true" class="border-0" @click="checkWxPrivacy">
<u-avatar :src="img(info.headimg)" :default-url="img('static/resource/images/default_headimg.png')" size="60" leftIcon="none"></u-avatar>
<view class="text-primary text-sm mt-[10rpx]">{{ t('updateHeadimg') }}</view>
</button>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<u-upload @afterRead="afterRead" :maxCount="1">
<u-avatar :src="img(info.headimg)" size="60" leftIcon="none"></u-avatar>
<u-avatar :src="img(info.headimg)" :default-url="img('static/resource/images/default_headimg.png')" size="60" leftIcon="none"></u-avatar>
<view class="text-primary text-sm mt-[10rpx]">{{ t('updateHeadimg') }}</view>
</u-upload>
<!-- #endif -->
@ -23,23 +23,23 @@
<template #value>
<view v-if="info.mobile" class="mr-[10rpx]">{{ mobileConceal(info.mobile) }}</view>
<view v-else @click="redirect({ url: '/app/pages/auth/bind' })">
<u-button type="primary" :plain="true" :text="t('bindMobile')" shape="circle" size="mini"></u-button>
<button class="bg-transparent w-[132rpx] p-[0] rounded-[100rpx] text-[var(--primary-color)] !border-[2rpx] !border-solid border-[var(--primary-color)] text-[20rpx] h-[44rpx] leading-[40rpx]">{{t('bindMobile')}}</button>
</view>
</template>
</u-cell>
<u-cell :title="t('birthday')" :is-link="true" :value="info.birthday || t('unknown')" @click="birthdayPicker = true"></u-cell>
<u-cell :title="t('birthday')" :is-link="true" :value="formatDate(info.birthday) || t('unknown')" @click="birthdayPicker = true"></u-cell>
</u-cell-group>
</view>
<u-modal :show="updateNickname.modal" :closeOnClickOverlay="true" @close="updateNickname.modal = false"
:show-cancel-button="true"
@cancel="updateNickname.modal = false" :title="t('updateNickname')">
@cancel="updateNickname.modal = false" :title="t('updateNickname')" confirmColor="var(--primary-color)">
<view class="w-full mt-[20rpx] border-0 border-b border-gray-300 border-solid py-[20rpx]">
<input type="nickname" v-model="updateNickname.value" :placeholder="t('nicknamePlaceholder')" @blur="bindNickname">
</view>
<template #confirmButton>
<view class="mt-[10rpx]">
<u-button type="primary" :text="t('confirm')" shape="circle" @click="updateNicknameConfirm"></u-button>
<button class="bg-[var(--primary-color)] text-[#fff] h-[80rpx] leading-[80rpx] rounded-[100rpx] text-[28rpx]" @click="updateNicknameConfirm">{{t('confirm')}}</button>
</view>
</template>
</u-modal>
@ -52,11 +52,15 @@
:maxDate="new Date().valueOf()" :minDate="0"
:cancel-text="t('cancel')" @cancel="birthdayPicker = false" @confirm="updateBirthday"></u-datetime-picker>
<!-- #ifdef MP-WEIXIN -->
<!-- 小程序隐私协议 -->
<wx-privacy-popup ref="wxPrivacyPopupRef"></wx-privacy-popup>
<!-- #endif -->
</view>
</template>
<script setup lang="ts">
import { ref, computed, reactive, watch } from 'vue'
import { ref, computed, reactive } from 'vue'
import { t } from '@/locale'
import useMemberStore from '@/stores/member'
import { img, redirect,mobileConceal } from '@/utils/common'
@ -66,6 +70,14 @@
const memberStore = useMemberStore()
const info = computed(() => memberStore.info)
const wxPrivacyPopupRef:any = ref(null)
//
const checkWxPrivacy = ()=>{
wxPrivacyPopupRef.value.proactive();
}
/**
* 修改昵称
*/
@ -73,9 +85,11 @@
modal: false,
value: info.nickname || ''
})
const bindNickname = (e) => {
updateNickname.value = e.detail.value
}
const updateNicknameConfirm = () => {
if (uni.$u.test.isEmpty(updateNickname.value)) { uni.showToast({ title: t('nicknamePlaceholder'), icon: 'none' }); return }
@ -155,13 +169,22 @@
birthdayPicker.value = false
})
}
const formatDate=(date:any)=>{
return date ? uni.$u.date(new Date(date), 'yyyy-mm-dd') : ''
}
</script>
<style lang="scss" scoped>
page {
background: var(--page-bg-color);
}
:deep(.u-upload__wrap ){
>view{
justify-content: center;
align-items: center;
}
}
:deep(.u-cell-group__wrapper) {
.u-cell__body {
padding-left: 0;

View File

@ -4,7 +4,7 @@
<view class="w-full bg-[#F6F6F6]">
<view class="pb-[210rpx] relative" :style="headerStyle">
<!-- #ifdef MP-WEIXIN -->
<top-tabbar :data="param" titleColor="#fff" class="top-header"/>
<top-tabbar :data="param" :scrollBool="topTabarObj.getScrollBool()" class="top-header"/>
<!-- #endif -->
<view class="text-[70rpx] leading-[98rpx] text-[#fff] pl-[60rpx] font-600 pt-[77rpx]">{{pointInfo.point||0}}</view>
<view class="flex items-center pl-[60rpx]">
@ -12,16 +12,16 @@
<view class="text-[26rpx] leading-[36rpx] text-[#fff] ml-[10rpx]">我的积分</view>
</view>
<view class="flex items-center absolute right-0 px-[14rpx] bg-color rounded-l-[35rpx] text-[#fff] text-[24rpx] h-[50rpx] z-10" :style="{top: topStyle}" @click="toLink('/app/pages/member/point_detail')">
<text class="nc-iconfont nc-icon-meiriqiandaoV6xx text-[28rpx] text-[#fff] mr-[4rpx]"></text>
<text class="nc-iconfont nc-icon-jifenduihuanV6xx1 text-[28rpx] text-[#fff] mr-[10rpx]"></text>
<text class="text-[24rpx]">积分明细</text>
</view>
</view>
<view class="mx-[30rpx] flex flex-col mt-[-178rpx] relative">
<view class="sidebar-marign flex flex-col mt-[-178rpx] relative">
<view class="w-[322rpx] h-[80rpx] leading-[80rpx] text-[26rpx] text-[#333] font-bold box-border pl-[30rpx]"
:style="{backgroundImage: 'url(' + img('static/resource/images/member/point/top_bg.png') + ') ',backgroundSize: '100% 100%',backgroundRepeat: 'no-repeat'}">
积分详情
</view>
<view class="flex items-center w-[690rpx] px-[30rpx] rounded-[16rpx] !rounded-tl-none bg-[#fff] h-[173rpx] box-border">
<view class="flex items-center px-[30rpx] rounded-[16rpx] !rounded-tl-none bg-[#fff] h-[173rpx] box-border">
<view class="w-[196rpx] flex-shrink-0 text-center">
<view class="text-[#333] text-[42rpx] leading-[59rpx] font-bold">{{pointInfo.point_get||0}}</view>
<view class="mt-[8rpx] text-[#666] text-[26rpx] leading-[36rpx] font-400">累计积分</view>
@ -39,7 +39,7 @@
</view>
</view>
</view>
<view class="mt-[20rpx] mx-[30rpx] p-[30rpx] pb-[70rpx] box-border rounded-[16rpx] bg-[#fff]">
<view class="mt-[20rpx] sidebar-marign p-[30rpx] pb-[70rpx] box-border rounded-[16rpx] bg-[#fff]">
<view class="text-[32rpx] leading-[45rpx] font-bold">热门活动</view>
<view class="mt-[50rpx] flex justify-between">
<view class="w-[200rpx] h-[253rpx] box-border pt-[69rpx] relative text-center"
@ -116,18 +116,15 @@
import { computed, ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { t } from '@/locale'
import { redirect, img } from '@/utils/common';
import { redirect, img,pxToRpx } from '@/utils/common';
import { getMemberAccountPointcount,getTaskPoint } from '@/app/api/member';
import { topTabar } from '@/utils/topTabbar'
/********* 自定义头部 - start ***********/
const topTabarObj = topTabar()
let param = topTabarObj.setTopTabbarParam({title:'我的积分'})
/********* 自定义头部 - end ***********/
let param = ref({
title:'我的积分',
topStatusBar: {
style: 'style-1',
isTransparent: true,
bgColor: 'transparent',
textColor: '#fff'
}
})
//
let menuButtonInfo:any = {};
// (API)
@ -148,11 +145,7 @@ const topStyle = computed(() => {
style = Object.keys(menuButtonInfo).length?(pxToRpx(Number(menuButtonInfo.height)) + pxToRpx(menuButtonInfo.top) + 38) + 'rpx;':'38rpx'
return style
})
// pxrpx
const pxToRpx=(px)=> {
const screenWidth = uni.getSystemInfoSync().screenWidth
return (750 * Number.parseInt(px)) / screenWidth
}
//
const pointInfo = ref({});
//

View File

@ -1,37 +1,101 @@
<template>
<view class="bg-gray-100 min-h-[100vh]" :class="{'bg-[#fff]':!pointList.length}" :style="themeColor()">
<mescroll-body ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="getPointListFn">
<view v-for="(item,index) in pointList" :key="item.id" :class="['bg-white relative p-[10px]',{'border-solid border-t-0 border-l-0 border-r-0 border-b-[1px] border-gray-200': pointList.length-1 != index}] ">
<view class="text-[14px]">{{item.from_type_name}}</view>
<view class="text-[12px] text-gray-400 mt-[10px]">{{item.create_time}}</view>
<view class="text-[14px] absolute top-[50%] transform -translate-y-[50%] right-[10px]" :class="{ 'text-primary' : item.account_data > 0 }">{{item.account_data > 0 ? '+' + item.account_data : item.account_data}}</view>
<view class="bg-[#F6F6F6] min-h-[100vh]" :style="themeColor()">
<view class="fixed left-0 right-0 top-0 z-10085">
<view class="bg-[#fff] px-[var(--sidebar-m)] py-[14rpx] relative z-10084">
<view class="flex items-center h-[60rpx] bg-[#F8F9FD] rounded-[30rpx] px-[20rpx]">
<view class="flex-1 text-[26rpx] leading-[60rpx] text-[#8288A2]" :class="{'!text-[#333]':from_type}" @click="typePopup = true">{{from_type_name || '请选择来源用途'}}</view>
<text class="nc-iconfont nc-icon-shangV6xx-1 text-[32rpx] ml-[18rpx] !text-[#626779]" v-if="typePopup" @click="typePopup = false"></text>
<text class="nc-iconfont nc-icon-xiaV6xx text-[32rpx] ml-[18rpx] !text-[#626779]" v-else @click="typePopup = true"></text>
</view>
</view>
<u-popup :show="typePopup" mode="top" @close="typePopup = false" class="type-class">
<view @touchmove.prevent.stop class="py-[22rpx]">
<view class="leading-[80rpx] text-[26rpx] text-[#333] px-[50rpx]" :class="{'bg-[#FDF8F8] !text-primary font-500' : from_type == ''}" @click="searchTypeFn()">全部</view>
<view class="leading-[80rpx] text-[26rpx] text-[#333] px-[50rpx]" :class="{'bg-[#FDF8F8] !text-primary font-500' : from_type == index}" v-for="(item,index) in pointType" @click="searchTypeFn(index,item)">{{ item.name }}</view>
</view>
</u-popup>
<view class="px-[var(--sidebar-m)] pt-[30rpx] pb-[20rpx] flex items-center justify-between bg-[#F6F6F6]">
<view class="flex items-center">
<view class="px-[20rpx] py-[6rpx] bg-[#fff] rounded-[30rpx] text-[26rpx] leading-[36rpx] mr-[20rpx] text-[#333]" :class="{'!text-[var(--primary-color)] font-500':amount_type == item.status}" v-for="(item,index) in typeList" :key="index" @click="loadTypeFn(item.status)">{{ item.name }}</view>
</view>
<view class="flex items-center" @click="handleSelect">
<view class="text-[26rpx] text-[#333] mr-[10rpx]">日期</view>
<view class="nc-iconfont nc-icon-riliV6xx !text-[28rpx] leading-[36rpx]"></view>
</view>
</view>
</view>
<mescroll-body ref="mescrollRef" @init="mescrollInit" :down="{ use: false }" @up="getPointListFn" top="186rpx">
<view v-for="(item,index) in pointList" :key="index" class="bg-white sidebar-marign rounded-[16rpx] px-[30rpx] mb-[20rpx] py-[12rpx]">
<view class="flex justify-between items-center">
<view class="text-[20rpx] text-[#333] font-500">
<text>{{item.month_info.year}}</text>
<text class="text-[36rpx] font-bold ml-[10rpx] mr-[4rpx]">{{item.month_info.month}}</text>
<text></text>
</view>
<view>
<text class="nc-iconfont nc-icon-xiaV6xx !text-[32rpx] text-[#626779]" v-if="item.flag" @click="item.flag = false"></text>
<text class="nc-iconfont nc-icon-shangV6xx-1 !text-[32rpx] text-[#626779]" v-else @click="item.flag = true"></text>
</view>
</view>
<view v-show="item.flag">
<block v-for="(subItem,subIndex) in item.month_data" :key="subItem.id">
<view class="flex items-center ">
<view class="w-[60rpx] h-[60rpx]">
<image v-if="subItem.account_data > 0" :src="img('static/resource/images/member/point/detail/point_add.png')" class="w-[60rpx] h-[60rpx]"></image>
<image v-else :src="img('static/resource/images/member/point/detail/point_min.png')" class="w-[60rpx] h-[60rpx]"></image>
</view>
<view class="flex-1 flex items-center ml-[20rpx] box-border py-[20rpx] border-0" :class="{'border-solid border-t-[2rpx] border-[#F0F2F8]' : subIndex}">
<view class="flex-1">
<view class="text-[26rpx] font-500 leading-[36rpx] text-[#333]">{{subItem.from_type_name}}</view>
<view class="text-[24rpx] text-[#8288A2] leading-[34rpx] mt-[4rpx]">{{subItem.create_time}}</view>
</view>
<view class="text-[36rpx] font-500 text-[#03B521]" :class="{ '!text-primary' : subItem.account_data > 0 }">{{subItem.account_data > 0 ? '+' + subItem.account_data : subItem.account_data}}</view>
</view>
</view>
</block>
</view>
</view>
<view class="mx-[30rpx] rounded-[16rpx] noData flex items-center justify-center" v-if="!pointList.length && loading">
<mescroll-empty :option="{tip : '暂无积分明细'}"></mescroll-empty>
</view>
<mescroll-empty v-if="!pointList.length && loading" :option="{tip : '暂无积分明细'}"></mescroll-empty>
</mescroll-body>
<!-- 时间选择 -->
<select-date ref="selectDateRef" @confirm="confirmFn" />
</view>
</template>
<script setup lang="ts">
import { reactive, ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { t } from '@/locale'
import { redirect, img } from '@/utils/common';
import { getPointList } from '@/app/api/member';
import { getPointList, getPointType } from '@/app/api/member';
import MescrollBody from '@/components/mescroll/mescroll-body/mescroll-body.vue';
import MescrollEmpty from '@/components/mescroll/mescroll-empty/mescroll-empty.vue';
import useMescroll from '@/components/mescroll/hooks/useMescroll.js';
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app';
import selectDate from '@/components/select-date/select-date.vue';
const { mescrollInit, downCallback, getMescroll } = useMescroll(onPageScroll, onReachBottom);
let pointList = ref<Array<any>>([]);
let mescrollRef = ref(null);
let loading = ref<boolean>(false);
const from_type = ref('');
const from_type_name = ref('')
const amount_type = ref('all');
const create_time = ref([])
const pointList = ref<Array<any>>([]);
const mescrollRef = ref(null);
const loading = ref<boolean>(false);
const typeList = ref([
{name:'全部',status:'all'},
{name:'收入',status:'income'},
{name:'支出',status:'disburse'}
])
const getPointListFn = (mescroll)=> {
let data = {
page: mescroll.num,
page_size: mescroll.size
page_size: mescroll.size,
from_type:from_type.value,
amount_type:amount_type.value,
create_time: create_time.value
};
loading.value = false;
getPointList(data).then((res) => {
@ -42,12 +106,60 @@ const getPointListFn = (mescroll)=> {
pointList.value = []; //
}
pointList.value = pointList.value.concat(newArr);
pointList.value = pointList.value.map(item =>{
item.flag = true
return item
})
loading.value = true;
}).catch(() => {
loading.value = true;
mescroll.endErr(); // ,
})
}
const pointType = ref({})
const getPointTypeFn = () =>{
getPointType('point').then(res =>{
pointType.value = res.data
})
}
getPointTypeFn()
//
const typePopup = ref(false)
const searchTypeFn = (index:string = '',item:any = {}) =>{
from_type.value = index
from_type_name.value = item.name
typePopup.value = false
pointList.value = [];
getMescroll().resetUpScroll();
}
//
const loadTypeFn = (type:string) =>{
amount_type.value = type;
pointList.value = [];
getMescroll().resetUpScroll();
}
//
const selectDateRef = ref()
const handleSelect = () =>{
selectDateRef.value.show = true
}
//
const confirmFn = (data:any) =>{
create_time.value = data;
pointList.value = []
getMescroll().resetUpScroll();
}
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
:deep(.u-popup.type-class .u-transition) {
top: 88rpx !important;
box-shadow: 1rpx 1rpx 6rpx 2rpx rgba(184,201,212,0.25);
}
.noData{
height: calc(100vh - 206rpx - constant(safe-area-inset-bottom));
height: calc(100vh - 206rpx - env(safe-area-inset-bottom));
}
</style>

View File

@ -4,111 +4,115 @@
<view v-if="info.is_use">
<view class="sigin-header">
<!-- #ifdef MP-WEIXIN -->
<view class="flex items-center absolute right-0 px-[14rpx] bg-color rounded-l-[35rpx] text-[#fff] text-[24rpx] h-[50rpx] z-10" :style="{top: topStyle}" @click="signPopup = true">
<text class="nc-iconfont nc-icon-meiriqiandaoV6xx text-[28rpx] text-[#fff] mr-[4rpx]"></text>
<view class="flex items-center absolute right-0 px-[14rpx] bg-color rounded-l-[35rpx] text-[#fff] text-[24rpx] h-[40rpx] z-10" :style="{top: topStyle}" @click="signPopup = true">
<text class="nc-iconfont nc-icon-meiriqiandaoV6xx text-[28rpx] text-[#fff] mr-[6rpx]"></text>
<text class="text-[24rpx]">签到规则</text>
</view>
<view :style="{height: headStyle, backgroundImage: 'url(' + img('static/resource/images/app/sigin_uniapp.png') + ')',backgroundSize: '100% 100%', backgroundRepeat: 'no-repeat'}">
<top-tabbar :data="topTabbarData" titleColor="#fff" class="top-header" />
<top-tabbar :data="topTabbarData" :scrollBool="topTabarObj.getScrollBool()" class="top-header" />
</view>
<!-- #endif -->
<!-- #ifdef H5 -->
<view v-if="info.rule_explain" class="flex items-center absolute top-[38rpx] right-0 px-[14rpx] bg-color rounded-l-[35rpx] text-[#fff] text-[24rpx] h-[50rpx] z-10" @click="signPopup = true">
<text class="nc-iconfont nc-icon-meiriqiandaoV6xx text-[28rpx] text-[#fff] mr-[4rpx]"></text>
<view v-if="info.rule_explain" class="flex items-center absolute top-[44rpx] right-0 px-[14rpx] bg-color rounded-l-[35rpx] text-[#fff] text-[24rpx] h-[40rpx] z-10" @click="signPopup = true">
<text class="nc-iconfont nc-icon-meiriqiandaoV6xx text-[28rpx] text-[#fff] mr-[6rpx]"></text>
<text class="text-[24rpx]">签到规则</text>
</view>
<view class="h-[382rpx]" :style="{ backgroundImage: 'url(' + img('static/resource/images/app/sigin_h5.png') + ')',backgroundSize: '100%', backgroundRepeat: 'no-repeat'}">
<top-tabbar :data="topTabbarData" class="top-header" />
</view>
<!-- #endif -->
</view>
<view>
<view class="mx-[30rpx] bg-[#fff] rounded-[16rpx] -mt-[85rpx]">
<view class="px-[30rpx]">
<view class="pt-[32rpx] mb-[40rpx] flex justify-between items-center" v-if="flag" >
<view class="sidebar-marign bg-[#fff] rounded-[16rpx] -mt-[85rpx]">
<view class="card-template">
<view class=" mb-[30rpx] flex justify-between items-center" v-if="flag">
<view class="flex items-center">
<text class="iconfont iconshangyibu text-[#999] text-[24rpx]" @click="changeMonth('prev')"></text>
<view class="mx-[30rpx] font-bold text-[32rpx] text-[#333] leading-[38rpx]">{{ state.curYear }}{{ state.curMonth+1 }}</view>
<text class="iconfont iconxiayibu1 text-[#999] text-[24rpx]" @click="changeMonth('next')"></text>
<text class="iconfont iconshangyibu text-[#333] text-[24rpx]" @click="changeMonth('prev')"></text>
<view class="mx-[30rpx] font-bold text-[32rpx] text-[#333] leading-[45rpx]">{{ state.curYear }}{{ state.curMonth+1 }}</view>
<text class="iconfont iconxiayibu1 text-[#333] text-[24rpx]" @click="changeMonth('next')"></text>
</view>
<view class="flex items-center">
<text class="nc-iconfont nc-icon-shangV6xx-1 text-[#666] text-[30rpx] transform scale-80" @click="handleChange"></text>
<text class="nc-iconfont nc-icon-shangV6xx-1 text-[#626779] text-[26rpx]" @click="handleChange"></text>
</view>
</view>
<view class="pt-[32rpx] mb-[40rpx] flex justify-between items-center" v-else>
<view class="mb-[30rpx] flex justify-between items-center" v-else>
<view class="flex items-center">
<view class="font-bold text-[32rpx] text-[#333] leading-[38rpx]">已连续签到<text class="text-[#EF000C] mx-[4rpx]">{{ info.days }}</text></view>
<view class="font-500 text-[32rpx] text-[#333] leading-[45rpx]">已连续签到<text class="text-[#EF000C] mx-[4rpx]">{{ info.days }}</text></view>
</view>
<text class="nc-iconfont nc-icon-xiaV6xx text-[#666] text-[30rpx] transform scale-80" v-if="!flag" @click="flag = !flag"></text>
<text class="nc-iconfont nc-icon-xiaV6xx text-[#626779] text-[26rpx]" v-if="!flag" @click="flag = !flag"></text>
</view>
<view class="relative z-9 pb-[30rpx] bg-[#fff] rounded-[18rpx]">
<view class="relative z-9 bg-[#fff] rounded-[18rpx]">
<view>
<view class="flex items-center justify-between text-[#666] text-[26rpx] mb-[14rpx]">
<text class="w-[14.2%] leading-[30rpx] text-center">周一</text>
<text class="w-[14.2%] leading-[30rpx] text-center">周二</text>
<text class="w-[14.2%] leading-[30rpx] text-center">周三</text>
<text class="w-[14.2%] leading-[30rpx] text-center">周四</text>
<text class="w-[14.2%] leading-[30rpx] text-center">周五</text>
<text class="w-[14.2%] leading-[30rpx] text-center">周六</text>
<text class="w-[14.2%] leading-[30rpx] text-center">周日</text>
<view class="flex items-center justify-between text-[#626779] text-[24rpx] mb-[16rpx]">
<text class="w-[14.28%] leading-[36rpx] text-center">周一</text>
<text class="w-[14.28%] leading-[36rpx] text-center">周二</text>
<text class="w-[14.28%] leading-[36rpx] text-center">周三</text>
<text class="w-[14.28%] leading-[36rpx] text-center">周四</text>
<text class="w-[14.28%] leading-[36rpx] text-center">周五</text>
<text class="w-[14.28%] leading-[36rpx] text-center">周六</text>
<text class="w-[14.28%] leading-[36rpx] text-center">周日</text>
</view>
<view class="flex flex-wrap items-center justify-start" v-if="!flag">
<block v-for="(item,index) in state.weekCount" :key="index">
<view class="w-[14.2%] flex flex-col justify-center items-center">
<view v-if="filteredDate(item)" class="w-[74rpx] h-[92rpx] bg-[#F2F2F2] text-[#666] border-box py-[10rpx] rounded-[8rpx] flex flex-col items-center" :class="{'sigin-bg !text-[#fff]': isVerDate(item),'bg-[#FDFDFD] border-[1rpx] border-[#E0E0E0] border-solid !text-[#999]': !isVerDate(item) && item < state.curDate && (state.curMonth + 1) == (new Date().getMonth() + 1) ,'mb-[10rpx]':isCurrentDate(item),'mb-[20rpx]':!isCurrentDate(item) }" @click="getDayPackFn(item)">
<text class="text-[24rpx] leading-[34rpx] mb-[6rpx]">{{ filteredDate(item) }}</text>
<view v-if="filteredDate(item)">
<view class="w-[14.28%] flex flex-col justify-center items-center">
<view v-if="filteredDate(item)" class="w-[74rpx] h-[92rpx] bg-[#F1F2F5] text-[#626779] box-border py-[10rpx] rounded-[8rpx] flex flex-col items-center" :class="{'sigin-bg !text-[#fff]': isVerDate(item),'!bg-[#F6FAFF] border-[1rpx] border-[#F0F4FA] border-solid': !isVerDate(item) && item < state.curDate && (state.curMonth + 1) == (new Date().getMonth() + 1) ,'mb-[20rpx]':isCurrentDate(item),'mb-[30rpx]':!isCurrentDate(item)}" @click="getDayPackFn(item)">
<text class="text-[24rpx] leading-[28rpx] mb-[6rpx]">{{ filteredDate(item) }}</text>
<view v-if="filteredDate(item)" class="flex items-center justufy-center">
<image v-if="isPackDate(item)" :src="img('static/resource/images/app/package.png')" class="w-[40rpx] h-[40rpx]"></image>
<image v-else-if="isVerDate(item)" :src="img('static/resource/images/app/hassigin.png')" class="w-[34rpx] h-[34rpx]"></image>
<image v-else :src="img('static/resource/images/app/nosigin.png')" class="w-[34rpx] h-[34rpx]"></image>
<template v-else>
<image v-if="!isVerDate(item) && item < state.curDate && (state.curMonth + 1) == (new Date().getMonth() + 1)" :src="img('static/resource/images/app/nosigin.png')" class="w-[34rpx] h-[34rpx]"></image>
<image v-else :src="img('static/resource/images/app/nosigin1.png')" class="w-[34rpx] h-[34rpx]"></image>
</template>
</view>
</view>
<view class="w-[10rpx] h-[10rpx] rounded-[50%] bg-[#FF5527]" v-if="isCurrentDate(item)"></view>
</view>
</view>
</block>
</view>
<view class="flex flex-wrap items-center justify-start" v-else>
<block v-for="(item,index) in state.dataCount" >
<view class="w-[14.2%] flex flex-col justify-center items-center mb-[10rpx]">
<view v-if="filteredDate(item)" class="w-[74rpx] h-[92rpx] bg-[#F2F2F2] text-[#666] border-box py-[10rpx] rounded-[8rpx] flex flex-col items-center" :class="{'sigin-bg !text-[#fff]': isVerDate(item) && active ,'bg-[#FDFDFD] border-[1rpx] border-[#E0E0E0] border-solid !text-[#999]': !isVerDate(item) && item < state.curDate && (state.curMonth + 1) == (new Date().getMonth() + 1) && state.curYear == new Date().getFullYear() ,'mb-[10rpx]':isCurrentDate(item),'mb-[20rpx]':!isCurrentDate(item)}" @click="getDayPackFn(item)">
<text class="text-[24rpx] leading-[34rpx] mb-[6rpx]">{{ filteredDate(item) }}</text>
<view v-if="filteredDate(item)">
<view class="w-[14.28%] flex flex-col justify-center items-center mb-[30rpx]">
<view v-if="filteredDate(item)" class="w-[74rpx] h-[92rpx] bg-[#F6FAFF] text-[#626779] box-border py-[10rpx] rounded-[8rpx] flex flex-col items-center" :class="{'sigin-bg !text-[#fff]': isVerDate(item) && active ,'!bg-[#FDFDFD] border-[1rpx] border-[#F0F4FA] border-solid': !isVerDate(item) && item < state.curDate && (state.curMonth + 1) == (new Date().getMonth() + 1) && state.curYear == new Date().getFullYear() ,'mb-[20rpx]':isCurrentDate(item),'mb-[30rpx]':!isCurrentDate(item)}" @click="getDayPackFn(item)">
<text class="text-[24rpx] leading-[28rpx] mb-[6rpx]">{{ filteredDate(item) }}</text>
<view v-if="filteredDate(item)" class="flex items-center justufy-center">
<image v-if="isPackDate(item)" :src="img('static/resource/images/app/package.png')" class="w-[40rpx] h-[40rpx]"></image>
<image v-else-if="isVerDate(item) && active " :src="img('static/resource/images/app/hassigin.png')" class="w-[34rpx] h-[34rpx]"></image>
<image v-else :src="img('static/resource/images/app/nosigin.png')" class="w-[34rpx] h-[34rpx]"></image>
<template v-else>
<image v-if="!isVerDate(item) && item < state.curDate && (state.curMonth + 1) == (new Date().getMonth() + 1)" :src="img('static/resource/images/app/nosigin.png')" class="w-[34rpx] h-[34rpx]"></image>
<image v-else :src="img('static/resource/images/app/nosigin1.png')" class="w-[34rpx] h-[34rpx]"></image>
</template>
</view>
</view>
<view class="w-[10rpx] h-[10rpx] rounded-[50%] bg-[#FF5527]" v-if="isCurrentDate(item)"></view>
</view>
</view>
</block>
</view>
<view class="mt-[50rpx] mx-[20rpx] flex justify-center" v-if="state.curMonth + 1 == (new Date().getMonth() + 1) && state.curYear == new Date().getFullYear() ">
<button v-if="!info.is_sign" class="rounded-[40rpx] !bg-transparent" :style="{width:'470rpx',height:'80rpx',border:'none', color:'#fff', fontSize:'28rpx',lineHeight:'76rpx',backgroundImage: `url(${img('static/resource/images/app/button_bg2.png')})`,backgroundSize: '100%', backgroundRepeat: 'no-repeat'}" shape="circle" @click="setSignFn">
<text class="nc-iconfont nc-icon-meiriqiandaoV6xx text-[30rpx] text-[#fff] mr-[8rpx]"></text>
<view class="mt-[40rpx] flex justify-center" v-if="state.curMonth + 1 == (new Date().getMonth() + 1) && state.curYear == new Date().getFullYear() ">
<button v-if="!info.is_sign" class="rounded-[40rpx] !bg-transparent" :style="{width:'490rpx',height:'88rpx',border:'none', color:'#fff', fontSize:'32rpx',lineHeight:'84rpx',backgroundImage: `url(${img('static/resource/images/app/button_bg2.png')})`,backgroundSize: '100%', backgroundRepeat: 'no-repeat'}" shape="circle" @click="setSignFn">
<text class="nc-iconfont nc-icon-meiriqiandaoV6xx text-[32rpx] text-[#fff] mr-[8rpx]"></text>
<text>立即签到</text>
</button>
<button v-else class="rounded-[40rpx] !bg-transparent" :style="{width:'470rpx',height:'80rpx',border:'none',color:'#fff', fontSize:'28rpx',lineHeight:'76rpx',backgroundImage: `url(${img('static/resource/images/app/button_bg1.png')})`,backgroundSize: '100%', backgroundRepeat: 'no-repeat'}" shape="circle">
<text class="nc-iconfont nc-icon-meiriqiandaoV6xx text-[30rpx] text-[#fff] mr-[8rpx]"></text>
<button v-else class="rounded-[40rpx] !bg-transparent" :style="{width:'490rpx',height:'88rpx',border:'none',color:'#fff', fontSize:'32rpx',lineHeight:'84rpx',backgroundImage: `url(${img('static/resource/images/app/button_bg1.png')})`,backgroundSize: '100%', backgroundRepeat: 'no-repeat'}" shape="circle">
<text class="nc-iconfont nc-icon-meiriqiandaoV6xx text-[32rpx] text-[#fff] mr-[8rpx]"></text>
<text>已签到</text>
</button>
</view>
<!-- <view class="mx-[20rpx] flex items-baseline justify-between mt-[16rpx]">
<text class="text-[26rpx] text-[#FF9000] leading-[30rpx]">查看签到记录</text>
</view> -->
</view>
</view>
</view>
</view>
<view class="mt-[20rpx] mb-[30rpx] mx-[30rpx] p-[30rpx] bg-[#fff] rounded-[16rpx]">
<view class="mt-[20rpx] mb-[30rpx] sidebar-marign card-template" v-if="info && info.continue_award && Object.keys(info.continue_award).length">
<view class="mb-[30rpx] flex items-center">
<view class="font-bold text-[32rpx] text-[#333] leading-[38rpx]">签到奖励</view>
<view class="font-500 text-[32rpx] text-[#333] leading-[44rpx]">签到奖励</view>
<!-- <view class="text-[#666] text-[26rpx] leading-[30rpx]">
<text>签到记录</text>
<image :src="img('static/resource/images/app/more.png')" class="w-[12rpx] h-[18rpx] ml-[8rpx]"></image>
</view> -->
</view>
<view>
<view v-for="(item,index) in info.continue_award" :key="index" class="flex items-center mt-[40rpx] border-box">
<view v-for="(item,index) in info.continue_award" :key="index" class="flex items-center border-box" :class="{'mt-[40rpx]':index}">
<view class="w-[90rpx] h-[90rpx] rounded-[50%] bg-[#E7F6FF] flex items-center justify-center flex-shrink-0" v-if="(index + 1) % 4 == 1">
<image :src="img('static/resource/images/app/icon_02.png')" class="w-[40rpx] h-[40rpx]"></image>
</view>
@ -122,26 +126,28 @@
<image :src="img('static/resource/images/app/icon_05.png')" class="w-[40rpx] h-[40rpx]"></image>
</view>
<view class="flex-1 mx-[20rpx]">
<view class="font-500 text-[28rpx] text-[#333] leading-[33rpx] mb-[10rpx]">连续签到{{item.continue_sign}}</view>
<view class="font-400 text-[28rpx] text-[#333] leading-[38rpx] mb-[8rpx]">连续签到{{item.continue_sign}}</view>
<view class="flex flex-wrap" v-if="item.gift">
<view class="flex mb-[10rpx] ">
<view class="flex">
<image :src="img(item.gift.total.icon)" class="w-[30rpx] h-[30rpx] flex-shrink-0"></image>
<view class="text-[24rpx] ml-[6rpx] text-[#FF9000] leading-[30rpx] max-w-[330rpx]">{{item.gift.total.text}}</view>
<view class="text-[24rpx] ml-[8rpx] text-[#FF9000] leading-[34rpx] max-w-[330rpx]">{{item.gift.total.text}}</view>
</view>
</view>
</view>
<view class="flex-shrink-0">
<view v-if="Number(info.days) < Number(item.continue_sign) " class="px-[28rpx] py-[8rpx] bg-[#FFECE9] rounded-[40rpx] font-500 text-[24rpx] text-[rgba(239,0,12,.8)] leading-[34rpx]">待完成</view>
<view v-else class="px-[28rpx] py-[8rpx] rounded-[40rpx] font-500 text-[24rpx] text-[#fff] leading-[34rpx]" style="background:linear-gradient( 90deg, #FB7939 0%, #FE120E 100%) ;">已完成</view>
<view v-if="Number(info.days) < Number(item.continue_sign) " class="w-[130rpx] h-[56rpx] text-center bg-[#FFECE9] rounded-[28rpx] font-400 text-[26rpx] text-[#FF343E] leading-[56rpx]">待完成</view>
<view v-else class="w-[130rpx] h-[56rpx] text-center rounded-[28rpx] font-400 text-[26rpx] text-[#fff] leading-[56rpx]" style="background:linear-gradient( 90deg, #FB7939 0%, #FE120E 100%) ;">已完成</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<view class="min-h-screen flex flex-col justify-center bg-[#fff]" v-else>
<image class="rounded-[8rpx] overflow-hidden mx-auto w-[320rpx] h-[184rpx]" :src="img('static/resource/images/system/empty.png')" model="aspectFill" />
<view class="text-[#999] text-[26rpx] font-400 mt-[26rpx] text-center leading-[30rpx]">签到未开启</view>
<view class="h-[100vh] w-[100vw] flex justify-center items-center" v-else>
<!-- #ifdef MP-WEIXIN -->
<top-tabbar :data="topTabbarData" :scrollBool="topTabarObj.getScrollBool()" class="top-header"/>
<!-- #endif -->
<u-empty text="签到未开启" width="347rpx" height="265rpx" :icon="img('static/resource/images/system/empty.png')"/>
</view>
<!-- 签到规则-->
<u-popup :show="signPopup" :round="16" mode="bottom" :closeable="true" @close="signPopup = false">
@ -153,35 +159,35 @@
</block>
</scroll-view>
<view>
<u-button text="知道了" :customStyle="{height:'66rpx',color:'#fff', fontSize:'28rpx',lineHeight:'66rpx',background: 'linear-gradient( 90deg, #fc7035 0%, #EF000C 100%)',border:'none'}" shape="circle" @click="signPopup = false"></u-button>
<button class="primary-btn-bg h-[66rpx] text-[#fff] text-[28rpx] border-[0] leading-[66rpx] rounded-[50rpx]" shape="circle" @click="signPopup = false">知道了</button>
</view>
</view>
</view>
</u-popup>
<!-- 签到奖励 -->
<u-popup :show="awardShow" class="award-popup" :customStyle="{backgroundColor:'transparent'}" @close="awardShow = false" mode="center" :round="5" :safeAreaInsetBottom="false" >
<view class="w-[550rpx]" v-if="Object.values(signAward).length">
<view class="w-[550rpx] -mt-[124rpx]" v-if="Object.values(signAward).length">
<view class="flex justify-center">
<image :src="img('static/resource/images/app/award.png')" class="w-[484rpx] h-[480rpx]"></image>
<image :src="img('static/resource/images/app/award.png')" class="w-[484rpx] h-[480rpx] z-10" mode="aspectFill"></image>
</view>
<view class="-mt-[265rpx] bg-award rounded-[30rpx] pt-[100rpx] pb-[48rpx] mb-[50rpx] raleative z-10">
<view class="-mt-[265rpx] bg-award rounded-[30rpx] pt-[100rpx] pb-[40rpx] mb-[50rpx] relative">
<view class="px-[32rpx]">
<view class="text-[48rpx] text-[#EF000C] font-bold leading-[56rpx] mb-[4rpx] text-center">{{ signAward.title }}</view>
<view class="text-[24rpx] text-[#F05F66] leading-[28rpx] text-center mb-[60rpx]">{{ signAward.info }}</view>
<view class="px-[68rpx] mb-[54rpx]">
<view class="text-[48rpx] text-[#EF000C] font-bold leading-[68rpx] mb-[6rpx] text-center">{{ signAward.title }}</view>
<view class="text-[24rpx] text-[#F05F66] leading-[34rpx] text-center mb-[60rpx]" v-if="signAward.info">{{ signAward.info }}</view>
<view class="px-[68rpx] mb-[80rpx]">
<block v-for="(item,index) in signAward.awards">
<template v-if="item.content" v-for="(subItem,subIndex) in item.content">
<view class="flex items-center mb-[30rpx]" >
<view class="flex items-center mb-[30rpx]" >
<image :src="img(subItem.icon)" class="w-[42rpx] h-[42rpx]"></image>
<view class="ml-[20rpx] text-[28rpx] text-[#333] leading-[32rpx]">{{subItem.text }}</view>
<view class="ml-[20rpx] text-[28rpx] text-[#333] leading-[38rpx]">{{subItem.text }}</view>
</view>
</template>
</block>
</view>
<view class="flex justify-center">
<view class="w-[380rpx] h-[80rpx] bg-gradient-to-r from-[#FB7939] to-[#FE120E] rounded-[50rpx] text-[#ffffff] text-center leading-[80rpx] text-[30rpx]" @click="awardShow = false">我知道了</view>
<view class="flex justify-center relative z-30">
<view class="w-[370rpx] h-[88rpx] primary-btn-bg rounded-[50rpx] text-[#ffffff] text-center leading-[88rpx] text-[32rpx]" @click="awardShow = false">我知道了</view>
</view>
</view>
</view>
</view>
<view class="flex justify-center">
<text class="nc-iconfont nc-icon-cuohaoV6xx text-[#fff] text-[60rpx]" @click="awardShow = false"></text>
</view>
@ -189,26 +195,28 @@
</u-popup>
<!-- 查看当日或连续签到奖励 -->
<u-popup :show="packShow" class="award-popup" :customStyle="{backgroundColor:'transparent'}" @close="packShow = false" mode="center" :round="5" :safeAreaInsetBottom="false">
<view class="w-[550rpx]" v-if="Object.values(packInfo).length">
<view class="w-[550rpx] -mt-[124rpx]" v-if="Object.values(packInfo).length">
<view class="flex justify-center">
<image :src="img('static/resource/images/app/award.png')" class="w-[484rpx] h-[480rpx]"></image>
<image :src="img('static/resource/images/app/award.png')" class="w-[484rpx] h-[480rpx] z-10" mode="aspectFill"></image>
</view>
<view class="-mt-[265rpx] bg-award rounded-[30rpx] pt-[100rpx] pb-[48rpx] mb-[50rpx] raleative z-10">
<view class="-mt-[265rpx] bg-award rounded-[30rpx] pt-[100rpx] pb-[40rpx] mb-[50rpx] relative">
<view class="px-[32rpx]">
<view class="text-[48rpx] text-[#EF000C] font-bold leading-[56rpx] mb-[4rpx] text-center opacity-60">签到奖励</view>
<view class="text-[24rpx] text-[#F05F66] opacity-60 leading-[28rpx] text-center mb-[60rpx]">您将获得以下奖励</view>
<view class="px-[68rpx] mb-[54rpx]">
<block v-for="(item,index) in packInfo">
<view class="text-[48rpx] text-[#333] font-bold leading-[68rpx] mb-[6rpx] text-center relative z-20">
{{ packInfo.title }}
</view>
<view class="text-[24rpx] text-[#F05F66] leading-[34rpx] text-center mb-[60rpx]">{{ packInfo.info }}</view>
<view class="px-[68rpx] mb-[80rpx]">
<block v-for="(item,index) in packInfo.awards">
<template v-if="item.content">
<view class="flex items-center mb-[32rpx]" v-for="(subItem,subIndex) in item.content" :key="subIndex">
<view class="flex items-center mb-[32rpx]" v-for="(subItem,subIndex) in item.content" :key="subIndex">
<image :src="img(subItem.icon)" class="w-[42rpx] h-[42rpx]"></image>
<view class="ml-[20rpx] text-[28rpx] text-[#333] leading-[32rpx]">{{ subItem.text }}</view>
<view class="ml-[20rpx] text-[28rpx] text-[#333] leading-[38rpx]">{{ subItem.text }}</view>
</view>
</template>
</block>
</view>
<view class="flex justify-center">
<view class="w-[380rpx] h-[80rpx] bg-gradient-to-r from-[#FB7939] to-[#FE120E] rounded-[50rpx] text-[#ffffff] text-center leading-[80rpx] text-[30rpx]" @click="packShow = false">我知道了</view>
<view class="flex justify-center relative z-30">
<view class="w-[370rpx] h-[88rpx] border-[4rpx] border-[#EF000C] border-solid rounded-[50rpx] text-[#EF000C] text-center leading-[88rpx] text-[32rpx] font-500 box-border" @click="packShow = false">我知道了</view>
</view>
</view>
</view>
@ -224,12 +232,13 @@
<script setup lang="ts">
import { reactive, ref, toRefs, toRaw, computed } from 'vue'
import { redirect, img } from '@/utils/common'
import { redirect, img,pxToRpx } from '@/utils/common'
import { onLoad } from '@dcloudio/uni-app'
import { getSignInfo,getSignConfig, setSign,getDayPack } from '@/app/api/member'
import useMemberStore from '@/stores/member'
import { topTabar } from '@/utils/topTabbar'
let state = reactive({
const state = reactive({
dataCount:[], //
weekCount:[], //7
curYear:0, //
@ -239,21 +248,21 @@ let state = reactive({
signInList:[], //
packList:[] //
})
let week = reactive({
const week = reactive({
weekDay:0, //
week:0 //
})
const loading = ref(false)
let flag = ref(false)
let info = ref({}) //
let signPopup = ref(false)//
let signAward = ref({}) //
let awardShow = ref(false) //
let packShow = ref(false) //
let packInfo = ref({}) //
let active = ref(false)
let currentYear=null
let currentMonth=null
const flag = ref(false)
const info = ref({}) //
const signPopup = ref(false)//
const signAward = ref({}) //
const awardShow = ref(false) //
const packShow = ref(false) //
const packInfo = ref({}) //
const active = ref(false)
let currentYear: any = null
let currentMonth: any = null
onLoad(() =>{
let date=new Date()
state.curYear=date.getFullYear()
@ -277,6 +286,9 @@ const getSignConfigFn = () =>{
loading.value = true
getSignConfig().then((res:any) =>{
info.value = res.data
if(!info.value.is_use){
topTabbarData = topTabarObj.setTopTabbarParam({title:'我的签到',topStatusBar:{textColor:'#333',bgColor:'#fff'}})
}
loading.value = false
})
}
@ -287,9 +299,12 @@ const getSignInfoFn = (data:any) =>{
state.signInList = []
state.packList = []
state.packList = res.data.period
state.signInList = res.data.days.map((el:any) =>{
return Number(el)
})
if(res.data.length){
state.signInList = res.data.days.map((el:any) =>{
return Number(el)
})
}
active.value = true
})
}
@ -364,6 +379,16 @@ const setSignFn = () =>{
setSign().then(res =>{
if(Object.values(res.data).length){
signAward.value = res.data
//
let isShowInfo = 0
Object.values(signAward.value.awards).forEach((item,index)=>{
if(!item.content){
isShowInfo++;
}
})
if(isShowInfo == Object.values(signAward.value.awards).length){
signAward.value.info = "";
}
getSignInfoFn({year:state.curYear,month:state.curMonth+1})
getSignConfigFn()
memberStore.getMemberInfo()
@ -373,7 +398,7 @@ const setSignFn = () =>{
}
//
let curPickDay = ref(null)
const curPickDay = ref(null)
const getDayPackFn = (date:number) =>{
let {curYear,curMonth}=toRefs(state)
let itemDate=`${curYear.value}-${(curMonth.value+1) < 10 ? '0' + (curMonth.value+1) : (curMonth.value+1)}-${date < 10 ? '0'+date : date}`
@ -431,36 +456,19 @@ let menuButtonInfo = {};
// #ifdef MP-WEIXIN || MP-BAIDU || MP-TOUTIAO || MP-QQ
menuButtonInfo = uni.getMenuButtonBoundingClientRect();
// #endif
let topTabbarData = ref({
title:'我的签到',
topStatusBar: {
style: 'style-1',
isTransparent: true,
bgColor: 'transparent',
textColor: '#fff'
}
})
/********* 自定义头部 - start ***********/
const topTabarObj = topTabar()
let topTabbarData = topTabarObj.setTopTabbarParam({title:'我的签到'})
/********* 自定义头部 - end ***********/
const headStyle = computed(() => {
let style = ''
style = pxToRpx(Number(menuButtonInfo.height) + menuButtonInfo.top + 8)+ 382 + 'rpx;'
let style = pxToRpx(Number(menuButtonInfo.height) + menuButtonInfo.top + 8)+ 382 + 'rpx;'
return style
})
const topStyle = computed(() => {
let style = ''
style = pxToRpx(Number(menuButtonInfo.height) + menuButtonInfo.top + 8)+38 + 'rpx;'
let style = pxToRpx(Number(menuButtonInfo.height) + menuButtonInfo.top + 8)+38 + 'rpx;'
return style
})
// rpxpx
const rpxToPx=(rpx:any)=>{
const screenWidth = uni.getSystemInfoSync().screenwidth
return(screenWidth*Number.parseInt(rpx))/750
}
// pxrpx
const pxToRpx=(px:any)=>{
const screenWidth =uni.getSystemInfoSync().screenWidth
return(750*Number.parseInt(px))/screenWidth
}
</script>
<style lang="scss" scoped>

View File

@ -9,7 +9,7 @@
import { img, isWeixinBrowser } from '@/utils/common'
import { onLoad } from '@dcloudio/uni-app'
onLoad((data : AnyObject) => {
onLoad((data : any) => {
if (!isWeixinBrowser() && data.alipay) {
uni.setStorageSync('paymenting', { trade_type: data.trade_type, trade_id: data.trade_id })
location.href = data.alipay

View File

@ -13,7 +13,7 @@
<u-button type="primary" :text="payInfo.status == 2 ? t('complete') : t('close')" :plain="true" @click="complete"></u-button>
</view>
</view>
<u-modal :show="loading" :showCancelButton="true" :confirmText="t('pay.completePay')" :cancelText="t('pay.incompletePay')" @cancel="complete">
<u-modal :show="loading" :showCancelButton="true" :confirmText="t('pay.completePay')" :cancelText="t('pay.incompletePay')" @cancel="complete" confirmColor="var(--primary-color)">
<view class="py-[20rpx]">
<u-loading-icon :text="t('pay.getting')" textSize="16" mode="circle" :vertical="true"></u-loading-icon>
</view>
@ -61,8 +61,6 @@
title: payInfo.value.status == 2 ? t('pay.paySuccess') : t('pay.payFail')
})
}
}).catch(() => {
})
}

View File

@ -69,7 +69,9 @@
padding-left: 0;
padding-right: 0;
}
.u-cell__value{
line-height: 1;
}
.u-cell {
&:last-child .u-line {
display: none;

View File

@ -1,47 +1,47 @@
<template>
<view :style="themeColor()" class="bg-[#f8f8f8] min-h-[100vh] overflow-hidden">
<block v-if="!loading">
<view class="mt-[30rpx] mx-[30rpx]">
<view class="py-[10rpx] px-[20rpx] flex flex-col rounded-[16rpx] bg-white">
<view class="flex h-[180rpx]" :class="{'mb-[20rpx]': verifyInfo.value.list.length-1 != index}" v-for="(item,index) in verifyInfo.value.list" :key="index">
<image class="w-[120rpx] h-[120rpx] mt-[30rpx] rounded-[8rpx]" mode="aspectFit" v-if="item.cover" :src="img(item.cover)"></image>
<image class="w-[120rpx] h-[120rpx] mt-[30rpx] rounded-[8rpx]" mode="aspectFit" v-else :src="img('addon/tourism/tourism/member/hotel.png')"></image>
<view class="flex flex-col flex-1 ml-[20rpx] mt-36rpx">
<view class="leading-[39rpx] text-[28rpx] max-w-[432rpx] multi-hidden">{{item.name}}</view>
<view class="self-end text-[28rpx]">x1</view>
<view class="pt-[20rpx] sidebar-marign">
<view class="flex flex-col card-template">
<view class="flex" :class="{'mb-[20rpx]': verifyInfo.value.list.length-1 != index}" v-for="(item,index) in verifyInfo.value.list" :key="index">
<image class="w-[150rpx] h-[150rpx] rounded-[8rpx]" mode="aspectFill" v-if="item.cover" :src="img(item.cover)"></image>
<image class="w-[150rpx] h-[150rpx] rounded-[8rpx]" mode="aspectFill" v-else :src="img('addon/tourism/tourism/member/hotel.png')"></image>
<view class="flex flex-col flex-1 ml-[20rpx] py-[4rpx]">
<view class="leading-[1.3] text-[28rpx] multi-hidden">{{item.name}}</view>
<view class="self-end text-[#626779] text-[26rpx] mt-[20rpx]">x1</view>
</view>
</view>
</view>
<view class="flex flex-col bg-[#fff] p-[20rpx] rounded-[16rpx] mt-[20rpx]">
<view class="text-[28rpx] text-[#333333] font-bold leading-[39rpx] h-[39rpx]">核销信息</view>
<view class="flex justify-between items-center mt-[30rpx] h-[39rpx]">
<text class="text-[28rpx] text-[#333]">核销类型</text>
<view class="text-[28rpx] text-[#333]">{{verifyInfo.type_name}}</view>
<view class="flex flex-col card-template mt-[20rpx]">
<view class="text-[32rpx] text-[#333333] font-500 leading-[1.2] mb-[30rpx]">核销信息</view>
<view class="flex justify-between h-[36rpx] items-center">
<text class="text-[26rpx] text-[#626779]">核销类型</text>
<view class="text-[26rpx] text-[#333]">{{verifyInfo.type_name}}</view>
</view>
<view class="flex justify-between items-center mt-[20rpx] h-[39rpx]">
<text class="text-[28rpx] text-[#333]">核销状态</text>
<view class="text-[28rpx] text-[#333]">已核销</view>
<view class="flex justify-between h-[36rpx] items-center mt-[20rpx]">
<text class="text-[26rpx] text-[#626779]">核销状态</text>
<view class="text-[26rpx] text-[#333]">已核销</view>
</view>
<view class="flex justify-between items-center mt-[20rpx] h-[39rpx]">
<text class="text-[28rpx]">核销时间</text>
<view class="text-[#333333] text-[28rpx]">{{verifyInfo.create_time}}</view>
<view class="flex justify-between h-[36rpx] items-center mt-[20rpx]">
<text class="text-[26rpx] text-[#626779]">核销时间</text>
<view class="text-[#333333] text-[26rpx]">{{verifyInfo.create_time}}</view>
</view>
<view class="flex justify-between items-center mt-[20rpx] h-[39rpx]">
<text class="text-[28rpx]">核销人员</text>
<view class="text-[#333333] text-[28rpx]">{{verifyInfo.member ? verifyInfo.member.nickname : '--'}}</view>
<view class="flex justify-between h-[36rpx] items-center mt-[20rpx]">
<text class="text-[26rpx] text-[#626779]">核销人员</text>
<view class="text-[#333333] text-[26rpx]">{{verifyInfo.member ? verifyInfo.member.nickname : '--'}}</view>
</view>
<view class="flex items-center justify-between mt-[20rpx]" v-for="(item,index) in verifyInfo.value.content.fixed">
<text class="text-[28rpx] text-[#333]">{{item.title}}</text>
<view class="text-[28rpx] text-[#333]">{{item.value}}</view>
<view class="flex items-center h-[36rpx] justify-between mt-[20rpx]" v-for="(item,index) in verifyInfo.value.content.fixed">
<text class="text-[26rpx] text-[#626779]">{{item.title}}</text>
<view class="text-[26rpx] text-[#333]">{{item.value}}</view>
</view>
</view>
<view v-for="(item,index) in verifyInfo.value.content.diy" :key="index" class="text-[#838383] bg-white p-[20rpx] rounded-[16rpx] mt-[20rpx]">
<view class="text-[28rpx] text-[#333333] font-bold leading-[39rpx] h-[39rpx]">{{item.title}}</view>
<view class="flex items-center justify-between h-[39rpx] mt-[20rpx]" v-for="(subItem,subIndex) in item.list" :key="subIndex" :class="{'mt-30rpx' : subIndex == '0'}">
<text class="text-[28rpx] text-[#333]">{{subItem.title}}</text>
<view class="text-[28rpx] text-[#333]">{{subItem.value}}</view>
<view v-for="(item,index) in verifyInfo.value.content.diy" :key="index" class="card-template mt-[20rpx]">
<view class="text-[32rpx] text-[#333333] font-500 leading-[1.2] mb-[30rpx]">{{item.title}}</view>
<view class="flex items-center h-[36rpx] justify-between mt-[20rpx]" v-for="(subItem,subIndex) in item.list" :key="subIndex" :class="{'mt-30rpx' : subIndex == '0'}">
<text class="text-[26rpx] text-[#626779]">{{subItem.title}}</text>
<view class="text-[26rpx] text-[#333]">{{subItem.value}}</view>
</view>
</view>
</view>
@ -59,9 +59,9 @@
import { t } from '@/locale'
const loading = ref(true)
let code = ref('');
onLoad((option)=> {
if (option.code) code.value = option.code;
const code = ref('');
onLoad((option:any)=> {
if (option.code) code.value = option.code;
})
onShow(() => {
@ -70,12 +70,11 @@
}
})
let verifyInfo = ref({})
const verifyInfo = ref({})
const getVerifyDetailFn = ()=>{
loading.value = true;
getVerifyDetail(code.value).then((res:any) =>{
verifyInfo.value = res.data;
console.log("verifyInfo.value",verifyInfo.value);
loading.value = false;
})
}

View File

@ -2,8 +2,8 @@
<view :style="themeColor()">
<view class="w-[100vw] min-h-[100vh] bg-[#f8f8f8]" v-if="!loading">
<view class="w-full bg-[#fff] verify-box h-[760rpx]">
<view class="text-[var(--primary-color)] fixed top-[30rpx] right-[30rpx] flex items-center" @click="redirect({url:'/app/pages/verify/record'})">
<image class="w-[24rpx] h-[28rpx]" :src="img('static/resource/images/verify/history.png')"/>
<view class="text-[var(--primary-color)] fixed top-[40rpx] right-[30rpx] flex items-center" @click="redirect({url:'/app/pages/verify/record'})">
<image class="w-[26rpx] h-[28rpx]" :src="img('static/resource/images/verify/history.png')"/>
<text class="text-[26rpx] ml-[10rpx]">核销记录</text>
</view>
<view v-show="operationType == 'sweepCode'" class="flex flex-col items-center justify-center">
@ -11,43 +11,43 @@
<image class="w-[354rpx] h-[354rpx]" :src="img('static/resource/images/verify/saoma.png')"/>
</view>
<view class="mt-[40rpx] text-[32rpx]">点击扫描二维码</view>
<view class="mt-[20rpx] text-[#999] text-[26rpx] font-400 pb-[142rpx]">扫描二维码进行核销</view>
<view class="mt-[20rpx] text-[#8288A2] text-[26rpx] font-400 pb-[142rpx]">扫描二维码进行核销</view>
</view>
<view v-show="operationType == 'manualInput'">
<view class="flex pt-[126rpx] pb-[30rpx] items-center justify-center">
<view class="flex justify-center items-center flex-col pr-[30rpx]">
<view class="flex pt-[126rpx] items-center justify-center">
<view class="flex justify-center items-center flex-col pr-[30rpx] w-[130rpx]">
<image class="w-[100rpx] h-[100rpx]" :src="img('static/resource/images/verify/shuruhexiaoma.png')"/>
<view class="text-[26rpx] h-[36rpx] leading-[36rpx] mt-[12rpx]">验证核销码</view>
</view>
<image class="w-[74rpx] h-[12rpx] mb-[50rpx]" :src="img('static/resource/images/verify/youjiantou.png')"/>
<view class="flex justify-center items-center flex-col pl-[30rpx]">
<view class="flex justify-center items-center flex-col pl-[30rpx] w-[130rpx]">
<image class="w-[100rpx] h-[100rpx]" :src="img('static/resource/images/verify/hexiao1.png')"/>
<view class="text-[26rpx] h-[36rpx] leading-[36rpx] mt-[12rpx]">核销</view>
</view>
</view>
<view class="mt-[50rpx]">
<view class="h-[90rpx] border-[2rpx] border-solid border-[#eee] rounded-[12rpx] box-border p-[20rpx] mx-[60rpx] flex items-center" >
<view class="h-[90rpx] border-[2rpx] border-solid border-[#DCE0EF] rounded-[16rpx] box-border p-[20rpx] mx-[60rpx] flex items-center" >
<text class="nc-iconfont nc-icon-saotiaoxingmaV6xx text-[44rpx] text-[#EF000C]"></text>
<input type="text" placeholder="请输入核销码" class="h-[90rpx] border-none text-start ml-[30rpx] text-[28rpx] flex-1" placeholder-class="_placeholder" v-model="verify_code" :focus="isFocus" ref="input"/>
</view>
<view class="h-[88rpx] min-w-[630rpx] bg-[var(--primary-color)] text-[#fff] flex items-center justify-center !text-[32rpx] rounded-[50rpx] h-[88rpx] mx-[60rpx] mt-[146rpx] relative z-1" @click="confirm">确认</view>
<view class="h-[88rpx] min-w-[630rpx] text-[#fff] flex items-center justify-center !text-[32rpx] save-btn rounded-[50rpx] h-[88rpx] mx-[60rpx] mt-[146rpx] relative z-1" @click="confirm">确认</view>
</view>
</view>
</view>
<view class="w-[630rpx] h-[100rpx] bg-[#fff] mx-[auto] mt-[220rpx] rounded-[90rpx] flex relative action-type-wrap">
<view class="relative w-[51%] rounded-[50rpx] z-0 flex flex-col items-center justify-center" @click="changeOperationType('sweepCode')" :class="{'xuanZhong1': operationType == 'sweepCode'}">
<view class="mt-[10rpx]"><text class="nc-iconfont nc-icon-saoyisaoV6xx !text-[42rpx]"></text></view>
<view class="text-[24rpx] leading-[34rpx] h-[34rpx] mt-[-6rpx]">扫码核销</view>
<view class="relative w-[51%] pr-[50rpx] box-border rounded-[50rpx] z-0 flex flex-col items-center justify-center" @click="changeOperationType('sweepCode')" :class="{'xuanZhong1': operationType == 'sweepCode'}">
<text class="nc-iconfont nc-icon-saoyisaoV6xx !text-[40rpx]"></text>
<view class="text-[24rpx] leading-[1] mt-[10rpx]">扫码核销</view>
</view>
<view class="flex flex-col items-center flex-col w-[120rpx] h-[120rpx] bg-[#FF7354] rounded-[50%] absolute top-[-10rpx] left-[255rpx] heXiao text-white z-10 shrink-0">
<view class="nc-iconfont nc-icon-saotiaoxingmaV6xx ns-gradient-otherpages-member-balance-balance-rechange !text-[44rpx] mt-[19rpx]"></view>
<view class="text-[24rpx] mt-[8rpx] leading-[34rpx] h-[34rpx]">核销台</view>
</view>
<view class="relative w-[51%] rounded-[50rpx] z-0 flex flex-col items-center justify-center" :class="{'xuanZhong': operationType == 'manualInput'}" @click="changeOperationType('manualInput')">
<view class="ml-[20rpx] mt-[10rpx]"><text class="iconfont iconVector-77 !text-[42rpx]"></text></view>
<view class="ml-[20rpx] text-[24rpx] leading-[34rpx] h-[34rpx] mt-[-6rpx]" @click="focus">手动输入</view>
<view class="relative w-[51%] pl-[50rpx] box-border rounded-[50rpx] z-0 flex flex-col items-center justify-center" :class="{'xuanZhong': operationType == 'manualInput'}" @click="changeOperationType('manualInput')">
<text class="iconfont iconVector-77 !text-[40rpx]"></text>
<view class="ml-[20rpx] text-[24rpx] leading-[1] mt-[10rpx]" @click="focus">手动输入</view>
</view>
</view>
@ -68,7 +68,7 @@
import { t } from '@/locale'
import wechat from '@/utils/wechat'
let operationType = ref('manualInput'); //
const operationType = ref('manualInput'); //
// #ifdef H5
operationType.value = 'manualInput';
// #endif
@ -76,12 +76,11 @@
operationType.value = 'sweepCode';
// #endif
let isFocus = ref(false)
let verify_code = ref('');
let loading = ref(true)
const isFocus = ref(false)
const verify_code = ref('');
const loading = ref(true)
onShow(() => {
if(getToken())
checkIsVerifier();
if(getToken()) checkIsVerifier();
})
//
@ -93,7 +92,16 @@
icon: 'none'
});
setTimeout(() => {
uni.navigateBack();
if(getCurrentPages().length > 1){
uni.navigateBack({
delta: 1
});
}else{
redirect({
url: '/app/pages/member/index',
mode: 'reLaunch'
});
}
}, 1000);
}else{
loading.value = false;
@ -135,8 +143,6 @@
let isLoading = false;
const confirm = () => {
if(isLoading) return false;
isLoading = true;
var reg = /[\S]+/;
if (!reg.test(verify_code.value)) {
uni.showToast({
@ -146,6 +152,9 @@
return false;
}
if(isLoading) return false;
isLoading = true;
getVerifierInfo(verify_code.value).then((res:any) =>{
isLoading = false;
redirect({ url: '/app/pages/verify/verify', param: { code: verify_code.value} })
@ -173,7 +182,7 @@
</script>
<style lang="scss" scoped>
.action-type-wrap {
box-shadow: 0 6px 6px 0 rgba(0, 0, 0, 0.03), 0 4px 2px 0 rgba(0, 0, 0, 0.04);;
box-shadow: 0 6px 6px 0 rgba(0, 0, 0, 0.03), 0 4px 2px 0 rgba(0, 0, 0, 0.04);
}
.heXiao{
background: linear-gradient( 180deg, #FF7354 0%, #FF020F 100%), #EF000C;
@ -191,10 +200,17 @@
height: 354rpx;
box-shadow: 0 8px 8px 0 rgba(0, 0, 0, 0.03), 0 6px 3px 0 rgba(0, 0, 0, 0.02);
border-radius: 50%;
margin: 146rpx auto 0rpx;
margin-top: 146rpx;
}
.verify-box {
border-bottom-left-radius: 400rpx 60rpx;
border-bottom-right-radius: 400rpx 60rpx;
}
.save-btn{
background: linear-gradient( 94deg, #FB7939 0%, #FE120E 99%), #EF000C;
}
._placeholder{
color: #8288A2;
font-size: 26rpx;
}
</style>

View File

@ -1,46 +1,69 @@
<template>
<view class="bg-[#f8f8f8] min-h-screen overflow-hidden" :style="themeColor()">
<mescroll-body ref="mescrollRef" top="30rpx" @init="mescrollInit" @down="downCallback" @up="geVerifyRecordFn">
<view class="ml-[30rpx] mr-[30rpx]">
<view class="fixed left-0 right-0 top-0 z-99 bg-[#fff] px-[var(--sidebar-m)]">
<view class="py-[14rpx] flex items-center justify-between">
<view class="flex-1 flex items-center h-[60rpx] bg-[#F8F9FD] rounded-[30rpx] px-[20rpx] mr-[30rpx]">
<u-input class="flex-1" maxlength="50" v-model="keyword" @confirm="searchTypeFn()" placeholder="请输入搜索关键词" placeholderClass="text-[#8288A2] text-[24rpx]" fontSize="26rpx" clearable border="none"></u-input>
<text class="nc-iconfont nc-icon-sousuo-duanV6xx1 text-[32rpx] ml-[18rpx] !text-[#999]" @click="searchTypeFn()"></text>
</view>
<view class="nc-iconfont nc-icon-riliV6xx !text-[30rpx] leading-[36rpx]" @click="handleSelect"></view>
</view>
</view>
<mescroll-body ref="mescrollRef" top="108rpx" @init="mescrollInit" :down="{ use: false }" @up="geVerifyRecordFn">
<view class="sidebar-marign">
<block v-for="(item,index) in list" :key="item.id">
<view class="w-full flex flex-col mb-3 bg-[#fff] px-[20rpx] box-border rounded-[18rpx] " @click="toLink(item)">
<view class="flex items-center pb-[30rpx] pt-[20rpx] leading-[1]">
<view class="nc-iconfont nc-icon-hexiaotaiV6xx pr-[10rpx]"></view>
<text class="truncate max-w-[590rpx] text-[#333333] text-[26rpx]">核销码{{ item.code }}</text>
<view class="w-full flex flex-col mb-[20rpx] card-template" @click="toLink(item)">
<view class="flex items-center mb-[30rpx] leading-[1]">
<view class="nc-iconfont nc-icon-hexiaotaiV6xx !text-[26rpx] pr-[10rpx]"></view>
<text class="truncate text-[#333333] text-[26rpx]">核销码{{ item.code }}</text>
</view>
<view class="flex flex-1" v-for="(dataItem,dataIndex) in item.value.list" :key="dataIndex">
<image class="w-[100rpx] h-[100rpx] rounded-[8rpx]" mode="aspectFit" v-if="dataItem.cover" :src="img(dataItem.cover)"></image>
<image class="w-[100rpx] h-[100rpx] rounded-[8rpx]" mode="aspectFit" v-else :src="img('addon/tourism/tourism/member/hotel.png')"></image>
<view class="flex flex-col flex-1 ml-[20rpx] mt-[3rpx]">
<view class="leading-[1.4] multi-hidden text-28rpx text-[#333]">{{dataItem.name}}</view>
<view class="self-end text-[28rpx]">x1</view>
<view class="flex flex-1" v-for="(dataItem,dataIndex) in item.value.list" :key="dataIndex">
<u--image class="rounded-[8rpx] overflow-hidden" width="120rpx" height="120rpx" :src="img(dataItem.cover ? dataItem.cover : '')" model="aspectFill">
<template #error>
<image class="w-[120rpx] h-[120rpx] rounded-[8rpx] overflow-hidden" :src="img('static/resource/images/diy/shop_default.jpg')" mode="aspectFill"></image>
</template>
</u--image>
<view class="flex flex-col flex-1 justify-between ml-[20rpx] py-[4rpx]" >
<view class="leading-[1.3] multi-hidden text-[28rpx] text-[#333]">{{dataItem.name}}</view>
<view class="self-end text-[26rpx] mt-[10rpx] text-[#626779]">x1</view>
</view>
</view>
<view class="flex bg-[#F8F9FD] py-[20rpx] px-[20rpx] rounded-[12rpx] mt-[20rpx]">
<view class="flex-1">
<view class="text-[22rpx] text-[#8288A2] mb-[10rpx] leading-[30rpx]">核销时间</view>
<view class="text-[26rpx] text-[#333] leading-[36rpx]">{{ item.create_time }}</view>
</view>
<view class="flex-1">
<view class="text-[22rpx] text-[#8288A2] mb-[10rpx] leading-[30rpx]">核销员</view>
<view class="text-[26rpx] text-[#333] leading-[36rpx]">{{ item.member ? item.member.nickname : '--' }}</view>
</view>
</view>
</view>
<view class="flex flex-col bg-[#F6F6F6] p-[20rpx] rounded-[12rpx] mt-[20rpx] mb-[20rpx]">
<text class="text-[#333333] text-[26rpx] h-[36rpx] leading-[36rpx]">核销时间{{ item.create_time }}</text>
<text class="text-[#333333] text-[26rpx] h-[36rpx] mt-[10rpx] truncate leading-[36rpx]">核销员{{ item.member ? item.member.nickname : '--' }}</text>
</view>
</view>
</block>
</view>
<mescroll-empty :option="{'icon': img('static/resource/images/empty.png')}" v-if="!list.length && loading"></mescroll-empty>
<view class="mx-[30rpx] rounded-[16rpx] noData flex items-center justify-center" v-if="!list.length && loading">
<mescroll-empty :option="{tip : '暂无核销记录'}"></mescroll-empty>
</view>
</mescroll-body>
<!-- 时间选择 -->
<select-date ref="selectDateRef" @confirm="confirmFn" />
</view>
</template>
<script setup lang="ts">
import { ref, reactive, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import MescrollBody from '@/components/mescroll/mescroll-body/mescroll-body.vue'
import MescrollEmpty from '@/components/mescroll/mescroll-empty/mescroll-empty.vue'
import useMescroll from '@/components/mescroll/hooks/useMescroll.js'
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
import { getVerifyRecords } from '@/app/api/verify'
import { img, redirect } from '@/utils/common'
import selectDate from '@/components/select-date/select-date.vue';
let list = ref<Array<Object>>([])
let loading = ref<boolean>(false)
const keyword = ref<string>('')
const create_time = ref([])
const list = ref<Array<Object>>([])
const loading = ref<boolean>(false)
const { mescrollInit, downCallback, getMescroll } = useMescroll(onPageScroll, onReachBottom)
const geVerifyRecordFn = (mescroll) => {
@ -48,6 +71,8 @@
let data : object = {
page: mescroll.num,
limit: mescroll.size,
keyword:keyword.value,
create_time: create_time.value
};
getVerifyRecords(data).then((res) => {
@ -68,7 +93,37 @@
const toLink = (data: AnyObject)=> {
redirect({ url: '/app/pages/verify/detail', param: { code: data.code } })
}
//
const searchTypeFn = () =>{
getMescroll().resetUpScroll();
}
//
const selectDateRef = ref()
const handleSelect = () =>{
selectDateRef.value.show = true
}
//
const confirmFn = (data) =>{
create_time.value = data;
list.value = []
getMescroll().resetUpScroll();
}
</script>
<style lang="scss" scoped>
:deep(.uni-picker-view-content){
z-index: 10;
}
:deep(.uni-picker-view-indicator::before){
border: none !important;
}
:deep(.uni-picker-view-indicator::after){
border: none !important;
}
.noData{
height: calc(100vh - 132rpx - constant(safe-area-inset-bottom));
height: calc(100vh - 132rpx - env(safe-area-inset-bottom));
}
</style>

View File

@ -2,60 +2,50 @@
<view :style="themeColor()" class="bg-[#f8f8f8] min-h-[100vh] overflow-hidden">
<block v-if="!loading && verifyInfo && verifyInfo.value">
<view class="w-full bg-[#fff] flex justify-center">
<view class="text-[var(--primary-color)] absolute top-[30rpx] right-[30rpx] flex" @click="redirect({url:'/app/pages/verify/record'})">
<image class="w-[24rpx] h-[28rpx]" :src="img('static/resource/images/verify/history.png')"/>
<text class="text-[26rpx] leading-[30.47rpx] ml-[10rpx] h-[36rpx] leading-[36rpx]">核销记录</text>
<view class="text-[var(--primary-color)] absolute top-[40rpx] right-[30rpx] flex items-center" @click="redirect({url:'/app/pages/verify/record'})">
<image class="w-[26rpx] h-[28rpx]" :src="img('static/resource/images/verify/history.png')"/>
<text class="text-[26rpx] ml-[10rpx]">核销记录</text>
</view>
<view class="flex pt-[126rpx] pb-[30rpx] items-center">
<view class="flex justify-center items-center flex-col pr-[30rpx]">
<view class="flex pt-[120rpx] pb-[30rpx] items-center">
<view class="flex justify-center items-center flex-col pr-[30rpx] w-[130rpx]">
<image class="w-[100rpx] h-[100rpx]" :src="img('static/resource/images/verify/yanzhenghexiaoma.png')"/>
<view class="text-[26rpx] mt-[12rpx] h-[36rpx] leading-[36rpx]">验证核销码</view>
</view>
<image class="w-[74rpx] h-[12rpx] mb-[50rpx]" :src="img('static/resource/images/verify/youjiantou.png')"/>
<view class="flex justify-center items-center flex-col pl-[30rpx]">
<view class="flex justify-center items-center flex-col pl-[30rpx] w-[130rpx]">
<image class="w-[100rpx] h-[100rpx]" :src="img('static/resource/images/verify/hexiao.png')"/>
<view class="text-[26rpx] mt-[12rpx] h-[36rpx] leading-[36rpx]">确定核销</view>
</view>
</view>
</view>
<view class="bg-[#fff] rounded-[16rpx] mt-[20rpx] mx-[30rpx] h-[200rpx]">
<view class="flex" v-for="(item,index) in verifyInfo.value.list" :key="index">
<image class="w-[150rpx] h-[150rpx] ml-[20rpx] mt-[30rpx] rounded-[8rpx]" mode="aspectFit" v-if="item.cover" :src="img(item.cover)"></image>
<image class="w-[150rpx] h-[150rpx] ml-[20rpx] mt-[30rpx] rounded-[8rpx]" mode="aspectFit" v-else :src="img('addon/tourism/tourism/member/hotel.png')"></image>
<view class="flex flex-col flex-1 ml-[10rpx]">
<view class="mt-[33rpx] ml-[20rpx] max-w-[432rpx] multi-hidden">{{item.name}}</view>
<view class="card-template mt-[20rpx] sidebar-marign">
<view class="flex" :class="{'mb-[20rpx]': (verifyInfo.value.list.length - 1 != index)}" v-for="(item,index) in verifyInfo.value.list" :key="index">
<image class="w-[150rpx] h-[150rpx] rounded-[8rpx]" mode="aspectFill" v-if="item.cover" :src="img(item.cover)"></image>
<image class="w-[150rpx] h-[150rpx] rounded-[8rpx]" mode="aspectFill" v-else :src="img('addon/tourism/tourism/member/hotel.png')"></image>
<view class="flex flex-col flex-1 ml-[20rpx] py-[4rpx]">
<view class="leading-[1.3] multi-hidden">{{item.name}}</view>
<view class="self-end text-[#626779] text-[28rpx] mt-[10rpx]">x1</view>
</view>
</view>
</view>
<view class="bg-[#fff] rounded-[16rpx] mx-[30rpx] mt-[20rpx]">
<view class="pt-[20rpx] pl-[20rpx] text-[28rpx] font-bold h-[39rpx] leading-[39rpx]">核销信息</view>
<view class="text-[28rpx] pb-[20rpx]">
<view class="flex pt-[30rpx] items-center justify-between px-[20rpx]">
<text class="text-[28rpx] text-[#333333] h-[39rpx] leading-[39rpx]">核销类型</text>
<view class="text-[28rpx] text-[#333333] h-[39rpx] leading-[39rpx]">{{verifyInfo.type_name}}</view>
</view>
<view class="flex pt-[30rpx] items-center justify-between px-[20rpx]" v-for="(item,index) in verifyInfo.value.content.fixed">
<text class="text-[28rpx] text-[#333333] h-[39rpx] leading-[39rpx]">{{item.title}}</text>
<view class="text-[28rpx] text-[#333333] h-[39rpx] leading-[39rpx]">{{item.value}}</view>
</view>
<view class="card-template mt-[20rpx] sidebar-marign">
<view class="text-[32rpx] font-500 leading-[1.3]">核销信息</view>
<view class="flex pt-[30rpx] items-center justify-between min-h-[36rpx]">
<text class="text-[26rpx] text-[#626779]">核销类型</text>
<view class="text-[26rpx] text-[#333333]">{{verifyInfo.type_name}}</view>
</view>
<view class="flex pt-[20rpx] items-center justify-between min-h-[36rpx]" v-for="(item,index) in verifyInfo.value.content.fixed">
<text class="text-[26rpx] text-[#626779]">{{item.title}}</text>
<view class="text-[26rpx] text-[#333333]">{{item.value}}</view>
</view>
</view>
<view v-for="(item,index) in verifyInfo.value.content.diy" :key="index" class="bg-[#fff] rounded-[16rpx] mx-[30rpx] mt-[20rpx]">
<view class="pt-[20rpx] pl-[20rpx] text-[28rpx] font-bold h-[39rpx] leading-[39rpx]">{{item.title}}</view>
<view class="text-[28rpx] pb-[20rpx]">
<view class="flex pt-[30rpx] items-center justify-between px-[20rpx]" v-for="(subItem,subIndex) in item.list" :key="subIndex">
<text class="text-[28rpx] text-[#333333] h-[39rpx] leading-[39rpx]">{{subItem.title}}</text>
<div v-if="subIndex === 0" class="flex items-center">
<text class="text-[28rpx] text-[#333333] h-[39rpx] leading-[39rpx] mr-[10rpx]">{{ subItem.value }}</text>
<view class="w-[1rpx] h-[20rpx] bg-[#999999] mr-[10rpx]"></view>
<view class="text-[#EF900A]" @click="copy(subItem.value)">复制</view>
</div>
<div v-else>
<text class="text-[28rpx] text-[#333333] h-[39rpx] leading-[39rpx]">{{ subItem.value }}</text>
</div>
</view>
<view v-for="(item,index) in verifyInfo.value.content.diy" :key="index" class="card-template mt-[20rpx] sidebar-marign">
<view class="text-[32rpx] font-500 leading-[1.3]">{{item.title}}</view>
<view class="flex items-center justify-between min-h-[36rpx]" :class="{'pt-[30rpx]': subIndex==0, 'pt-[20rpx]': subIndex!=0}" v-for="(subItem,subIndex) in item.list" :key="subIndex">
<text class="text-[26rpx] text-[#626779]">{{subItem.title}}</text>
<text class="text-[26rpx] text-[#333333]">{{ subItem.value }}</text>
</view>
</view>
@ -68,26 +58,23 @@
<script setup lang="ts">
import { ref } from 'vue';
import { onLoad ,onShow} from '@dcloudio/uni-app'
import { img,redirect, isWeixinBrowser, getToken } from '@/utils/common';
import { img,redirect, getToken } from '@/utils/common';
import { getVerifierInfo, getCheckVerifier, verify } from '@/app/api/verify'
import { copy } from '@/utils/common';
import { t } from '@/locale'
const loading = ref(true)
const verifyDetail = ref<AnyObject | null>(null)
let code = ref('');
onLoad((option)=> {
if (option.code) code.value = option.code;
//
if (option.scene) {
let sceneParams = decodeURIComponent(option.scene);
sceneParams = sceneParams.split('&');
if (sceneParams.length) {
sceneParams.forEach(item => {
if (item.indexOf('code') != -1) code.value = item.split('-')[1];
});
}
}
const code = ref('');
onLoad((option:any)=> {
if (option.code) code.value = option.code;
//
if (option.scene) {
let sceneParams: any = decodeURIComponent(option.scene).split('&');
if (sceneParams.length) {
sceneParams.forEach((item: any) => {
if (item.indexOf('code') != -1) code.value = item.split('-')[1];
});
}
}
})
onShow(() => {
@ -106,7 +93,16 @@
icon: 'none'
});
setTimeout(() => {
uni.navigateBack();
if(getCurrentPages().length > 1){
uni.navigateBack({
delta: 1
});
}else{
redirect({
url: '/app/pages/member/index',
mode: 'reLaunch'
});
}
}, 1000);
}else{
loading.value = false;
@ -114,13 +110,18 @@
})
}
let verifyInfo = ref({})
const verifyInfo = ref({})
const getVerifierInfoFn = ()=>{
loading.value = true;
getVerifierInfo(code.value).then((res:any) =>{
verifyInfo.value = res.data;
loading.value = false;
})
}).catch(() => {
setTimeout(() => {
loading.value = false;
redirect({ url: '/app/pages/verify/index', param: {}, mode: 'redirectTo' })
}, 1000);
})
}
let isLoading = false;
const verifyFn = ()=>{
@ -128,8 +129,12 @@
isLoading = true;
verify(code.value).then((res:any) =>{
isLoading = false;
uni.showToast({
title: '核销成功',
icon: 'none'
});
setTimeout(() => {
isLoading = false;
redirect({ url: '/app/pages/verify/index', param: {}, mode: 'redirectTo' })
}, 1000);
}).catch(() => {

View File

@ -8,17 +8,25 @@
<script setup lang="ts">
import { onLoad } from '@dcloudio/uni-app';
import { ref } from 'vue';
import { redirect } from '@/utils/common';
const src = ref('')
onLoad((option : any) => {
src.value = decodeURIComponent(option.src);
src.value = option.src ? decodeURIComponent(option.src) : '';
})
const navigateBack = () => {
uni.navigateBack({
delta: 1
});
if(getCurrentPages().length > 1){
uni.navigateBack({
delta: 1
});
}else{
redirect({
url: '/app/pages/index/index',
mode: 'reLaunch'
});
}
}
</script>

View File

@ -73,7 +73,6 @@
data.city && (selected.city = data.city)
data.district && (selected.district = data.district)
})
.catch()
}
},{
immediate:true

View File

@ -0,0 +1,198 @@
<template>
<u-popup :show="show" @close="show = false" mode="center" :round="10" :closeable="true" :safeAreaInsetBottom="false" zIndex="10086">
<view @touchmove.prevent.stop class="max-w-[630rpx] w-[630rpx] box-border">
<view class="text-center py-[50rpx] text-[32rpx] font-500 leading-[46rpx]">{{t('bindMobile')}}</view>
<view class="px-[50rpx] pb-[50rpx]">
<u-form labelPosition="left" :model="formData" errorType='toast' :rules="rules" ref="formRef">
<u-form-item label="" prop="mobile" :borderBottom="true">
<input v-model="formData.mobile" :placeholder="t('mobilePlaceholder')" class=" w-full h-[50rpx] leading-[50rpx] !bg-transparent !px-[20rpx] text-[26rpx] text-[#333]" :disabled="real_name_input" placeholder-class="bind-mobile" />
</u-form-item>
<view class="mt-[20rpx]">
<u-form-item label="" prop="mobile_code" :borderBottom="true">
<input v-model="formData.mobile_code" :placeholder="t('codePlaceholder')" class=" box-border w-full h-[50rpx] leading-[50rpx] !bg-transparent !px-[20rpx] text-[26rpx] text-[#333]" :disabled="real_name_input" placeholder-class="bind-mobile" />
<template #right>
<sms-code :mobile="formData.mobile" type="bind_mobile" v-model="formData.mobile_key"></sms-code>
</template>
</u-form-item>
</view>
<view class="flex items-baseline mt-[20rpx] pl-[10rpx]" v-if="config.agreement_show">
<u-checkbox-group>
<u-checkbox activeColor="var(--primary-color)" :checked="isAgree" shape="shape" size="12" @change="agreeChange" :customStyle="{marginTop: '0rpx',marginBottom: '0rpx'}" :label=" t('agreeTips')" labelSize="22rpx" labelColor="#8288A2" />
</u-checkbox-group>
<view class="text-[22rpx] text-[#8288A2] leading-[30rpx] flex flex-wrap">
<view @click="redirect({ url: '/app/pages/auth/agreement?key=service' })">
<text class="text-primary">{{ t('userAgreement') }}</text>
</view>
<view @click="redirect({ url: '/app/pages/auth/agreement?key=privacy' })">
<text class="text-primary">{{ t('privacyAgreement') }}</text>
</view>
</view>
</view>
<view class="mt-[120rpx]">
<button class="primary-btn-bg text-[26rpx] text-[#fff] !h-[80rpx] leading-[80rpx] rounded-full font-bold" :loading="loading" :loadingText="t('binding')" @click="handleBind">{{t('bind')}}</button>
</view>
<!-- #ifdef MP-WEIXIN -->
<view class="mt-[20rpx]">
<u-button :customStyle="{border:'none',color:'var(--primary-color)',fontSize:'26rpx',height:'40rpx', lineHeight:'40rpx'}" :text="t('mobileQuickLogin')" open-type="getPhoneNumber" @getphonenumber="mobileAuth" @click="checkWxPrivacy"></u-button>
</view>
<!-- #endif -->
</u-form>
</view>
</view>
<!-- #ifdef MP-WEIXIN -->
<!-- 小程序隐私协议 -->
<wx-privacy-popup ref="wxPrivacyPopupRef"></wx-privacy-popup>
<!-- #endif -->
</u-popup>
</template>
<script setup lang="ts">
import { ref, reactive, computed, onMounted } from 'vue'
import { t } from '@/locale'
import { bindMobile } from '@/app/api/member'
import useMemberStore from '@/stores/member'
import useConfigStore from '@/stores/config'
import { redirect } from '@/utils/common'
const show = ref(false)
const memberStore = useMemberStore()
const info = computed(() => memberStore.info)
const config = computed(() => {
return useConfigStore().login
})
const wxPrivacyPopupRef:any = ref(null)
//
const checkWxPrivacy = ()=>{
wxPrivacyPopupRef.value.proactive();
}
const loading = ref(false)
const isAgree = ref(false)
const formData = reactive({
mobile: '',
mobile_code: '',
mobile_key: ''
})
let real_name_input = ref(true);
onMounted(() => {
//
setTimeout(()=>{
real_name_input.value = false;
},800)
});
uni.getStorageSync('openid') && (Object.assign(formData, { openid: uni.getStorageSync('openid') }))
uni.getStorageSync('pid') && (Object.assign(formData, { pid: uni.getStorageSync('pid') }))
uni.getStorageSync('unionid') && (Object.assign(formData, { unionid: uni.getStorageSync('unionid') }))
const rules = {
'mobile': [
{
type: 'string',
required: true,
message: t('mobilePlaceholder'),
trigger: ['blur', 'change'],
},
{
validator(rule, value, callback) {
let mobile = /^1[3-9]\d{9}$/;
if (!mobile.test(value)){
callback(new Error('请输入正确的手机号'))
} else {
callback()
}
},
message: t('mobileError'),
trigger: ['change', 'blur'],
}
],
'mobile_code': {
type: 'string',
required: true,
message: t('codePlaceholder'),
trigger: ['blur', 'change']
}
}
const agreeChange = () => {
isAgree.value = !isAgree.value
}
const formRef = ref(null)
const handleBind = () => {
formRef.value.validate().then(() => {
if (loading.value) return
loading.value = true
bindMobile(formData).then((res) => {
memberStore.getMemberInfo()
if(info.value.mobile){
uni.removeStorageSync('isbindmobile');
}
show.value = false
}).catch(() => {
loading.value = false
})
})
}
const mobileAuth = (e) => {
if (!isAgree.value && config.value.agreement_show) {
uni.showToast({
title: `${ t('pleaceAgree') }${ t('userAgreement') }》《${ t('privacyAgreement') }`,
icon: 'none'
})
return
}
if (e.detail.errMsg == 'getPhoneNumber:ok') {
uni.showLoading({ title: '' })
bindMobile({
mobile_code: e.detail.code
}).then((res) => {
uni.hideLoading()
memberStore.getMemberInfo()
if(res.msg == 1){
uni.removeStorageSync('isbindmobile');
}
show.value = false
}).catch((res) => {
setTimeout(() => {
show.value = false
uni.hideLoading()
}, 2000);
})
}
if (e.detail.errno == 104) {
let msg = '用户未授权隐私权限';
uni.showToast({ title: msg, icon: 'none' })
}
if (e.detail.errMsg == "getPhoneNumber:fail user deny") {
let msg = '用户拒绝获取手机号码';
uni.showToast({ title: msg, icon: 'none' })
}
}
const open = ()=> {
show.value = true
}
defineExpose({
open
})
</script>
<style lang="scss" scoped>
:deep(.bind-mobile){
color:#8288A2;
font-size: 26rpx;
}
</style>

View File

@ -4,11 +4,11 @@
<view class="text-base">{{ t('getAvatarNickname') }}</view>
<view class="text-sm mt-[18rpx] text-gray-400">{{ t('getAvatarNicknameTips') }}</view>
</view>
<u-form labelPosition="left" :model="formData" errorType='toast' :rules="rules" ref="formRef">
<u-form labelPosition="left" :model="formData" errorType='toast' :rules="rules" ref="formRef" labelWidth="65">
<view class="mx-[30rpx]">
<view class="mt-[20rpx]">
<u-form-item :label="t('headimg')" prop="headimg" :border-bottom="true">
<button class="m-0 my-[10rpx] p-0 w-[140rpx] h-[140rpx]" open-type="chooseAvatar" @chooseavatar="onChooseAvatar">
<button class="m-0 my-[10rpx] p-0 w-[140rpx] h-[140rpx]" open-type="chooseAvatar" @chooseavatar="onChooseAvatar" @click="checkWxPrivacy">
<view class="w-full h-full flex items-center justify-center overflow-hidden">
<u-image :src="img(formData.headimg)" width="140rpx" height="140rpx" v-if="formData.headimg" mode="aspectFill"></u-image>
<u-icon name="plus" v-else></u-icon>
@ -18,22 +18,31 @@
<u-form-item :label=" t('nickname')" prop="nickname" :border-bottom="true">
<input type="nickname" v-model="formData.nickname" :placeholder="t('nicknamePlaceholder')" @blur="bindNickname">
</u-form-item>
<u-form-item :label=" t('mobile')" prop="mobile" :border-bottom="true" v-if="isBindMobile">
<input type="mobile" v-model="formData.mobile" :disabled="true" v-if="formData.mobile">
<u-button :customStyle="{border:'none',color: 'var(--primary-color)',width:'140rpx', textAlign:'left',margin:'0rpx'}" :text="t('getMobile')" open-type="getPhoneNumber" @getphonenumber="mobileAuth" @click="checkWxPrivacy" v-else></u-button>
</u-form-item>
</view>
</view>
<view class="p-[30rpx] mt-[20rpx]">
<u-button type="primary" :loading="loading" :text="t('confirm')" shape="circle" @click="confirm"></u-button>
<button :loading="loading" class="bg-[var(--primary-color)] text-[#fff] h-[80rpx] leading-[80rpx] rounded-[100rpx] text-[28rpx]" @click="confirm">{{t('confirm')}}</button>
</view>
</u-form>
<!-- #ifdef MP-WEIXIN -->
<!-- 小程序隐私协议 -->
<wx-privacy-popup ref="wxPrivacyPopupRef"></wx-privacy-popup>
<!-- #endif -->
</u-popup>
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch } from 'vue'
import { ref, reactive, computed, watch,onMounted } from 'vue'
import { t } from '@/locale'
import useMemberStore from '@/stores/member'
import { img } from '@/utils/common'
import { modifyMember } from '@/app/api/member'
import { img, getToken } from '@/utils/common'
import { modifyMember, bindMobile } from '@/app/api/member'
import { fetchBase64Image } from '@/app/api/system'
import { useLogin } from '@/hooks/useLogin'
const show = ref(false)
const loading = ref(false)
@ -42,16 +51,34 @@
const formData = reactive({
nickname: '',
headimg: ''
headimg: '',
mobile: '',
})
watch(() => info.value, () => {
if (info.value) {
formData.nickname = info.value.nickname
formData.headimg = info.value.headimg
formData.mobile = info.value.mobile
}
}, { immediate: true })
let isBindMobile = ref(null)
onMounted(()=>{
uni.getStorageSync('openid') && (Object.assign(formData, { openid: uni.getStorageSync('openid') }))
uni.getStorageSync('pid') && (Object.assign(formData, { pid: uni.getStorageSync('pid') }))
uni.getStorageSync('unionid') && (Object.assign(formData, { unionid: uni.getStorageSync('unionid') }))
isBindMobile.value = uni.getStorageSync('isbindmobile');
})
const wxPrivacyPopupRef:any = ref(null)
//
const checkWxPrivacy = ()=>{
wxPrivacyPopupRef.value.proactive();
}
const onChooseAvatar = (e) => {
uni.getFileSystemManager().readFile({
filePath: e.detail.avatarUrl, //
@ -80,6 +107,12 @@
required: true,
message: t('nicknamePlaceholder'),
trigger: ['blur', 'change'],
},
'mobile': {
type: 'string',
required: isBindMobile.value ? true : false,
message: t('mobileTips'),
trigger: ['blur', 'change'],
}
}
@ -106,8 +139,44 @@
}).catch(() => {
loading.value = false
})
// #ifdef MP-WEIXIN
const login = useLogin()
if( info.value && !info.value.weapp_openid){
login.getAuthCode('',true)
}
// #endif
})
}
const mobileAuth = (e) => {
if (e.detail.errMsg == 'getPhoneNumber:ok') {
uni.showLoading({ title: '' })
bindMobile({
openid: formData.openid,
mobile_code: e.detail.code
}).then((res) => {
uni.hideLoading()
memberStore.getMemberInfo()
if(info.value.mobile){
uni.removeStorageSync('isbindmobile');
}
}).catch((res) => {
setTimeout(() => {
uni.hideLoading()
}, 2000);
})
}
if (e.detail.errno == 104) {
let msg = '用户未授权隐私权限';
uni.showToast({ title: msg, icon: 'none' })
}
if (e.detail.errMsg == "getPhoneNumber:fail user deny") {
let msg = '用户拒绝获取手机号码';
uni.showToast({ title: msg, icon: 'none' })
}
}
defineExpose({
show

View File

@ -89,25 +89,25 @@ export default {
}
.mescroll-empty .empty-icon {
width: 320rpx;
height: 320rpx;
width: 348rpx;
height: 348rpx;
}
.mescroll-empty .empty-tip {
margin-top: 20rpx;
font-size: 24rpx;
color: gray;
}
.mescroll-empty .empty-btn {
display: inline-block;
margin-top: 40rpx;
min-width: 200rpx;
padding: 18rpx;
display: inline-block;
min-width: 220rpx;
height: 66rpx;
line-height: 66rpx;
font-size: 28rpx;
border: 1rpx solid #e04b28;
border: 1rpx solid #EF000C;
border-radius: 60rpx;
color: #e04b28;
color: #EF000C;
}
.mescroll-empty .empty-btn:active {

View File

@ -0,0 +1,99 @@
<template>
<view class="contact-wrap">
<slot></slot>
<button
type="default"
hover-class="none"
open-type="contact"
class="contact-button"
@click="contactService"
:send-message-title="props.sendMessageTitle"
:send-message-path="props.sendMessagePath"
:send-message-img="props.sendMessageImg"
:show-message-card="true">
</button>
<u-popup :show="popupShow" @close="popupShow = false" mode="center" :round="5" :safeAreaInsetBottom="false">
<view @touchmove.prevent.stop>
<view class="py-[25rpx] text-sm leading-none border-0 border-solid border-b-[2rpx] border-[#eee] flex items-center justify-between">
<text class="ml-[30rpx]">联系客服</text>
<text class="mr-[20rpx] nc-iconfont nc-icon-guanbiV6xx text-[35rpx]" @click="popupShow = false"></text>
</view>
<view class="px-6 py-3 w-[480rpx] h-[100rpx] text-sm" v-if="siteInfo && siteInfo.phone">
<view class="mb-[10rpx]">客服电话</view>
<view @click="callPhone" class="text-primary truncate">{{ siteInfo.phone }}</view>
</view>
<view class="px-6 py-3 w-[480rpx] h-[100rpx] leading-[100rpx] text-sm" v-else>抱歉商家暂无客服请线下联系</view>
<button @click="popupShow = false"
class="!mx-[30rpx] !mb-[40rpx] !w-auto !h-[70rpx] text-[24rpx] leading-[70rpx] rounded-full text-white !bg-[#ff4500] !text-[#fff]">
我知道了
</button>
</view>
</u-popup>
</view>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import useSystemStore from '@/stores/system'
const props = defineProps({
sendMessageTitle: {
type: String,
default: ''
},
sendMessagePath: {
type: String,
default: ''
},
sendMessageImg: {
type: String,
default: ''
}
})
const systemStore = useSystemStore()
const siteInfo:any = computed(() => {
return systemStore.site;
})
const popupShow = ref(false);
const contactService = () => {
// #ifdef H5
popupShow.value = true;
// #endif
}
//
const callPhone = () => {
uni.makePhoneCall({
phoneNumber: siteInfo.value.phone
});
}
defineExpose({})
</script>
<style lang="scss" scoped>
.contact-wrap {
width: 100%;
height: 100%;
position: relative;
.contact-button {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 5;
padding: 0;
margin: 0;
opacity: 0;
overflow: hidden;
}
}
</style>

View File

@ -25,7 +25,7 @@
</view>
</scroll-view>
<view class="p-[30rpx]">
<u-button type="primary" :loading="loading" :text="t('pay.confirmPay')" shape="circle" @click="confirmPay"></u-button>
<button class="primary-btn-bg h-[80rpx] rounded-[50rpx] leading-[80rpx] text-[28rpx] text-[#fff]" hover-class="none" :loading="loading" @click="confirmPay">{{t('pay.confirmPay')}}</button>
</view>
</view>
</u-popup>

View File

@ -0,0 +1,199 @@
<template>
<u-popup :show="show" @close="show = false" mode="bottom" :round="10" zIndex="10090">
<view>
<view class="py-[30rpx] px-[40rpx] flex items-center justify-between">
<view class="text-center flex-1 text-[32rpx] font-500 leading-[44rpx]">选择时间</view>
<view class="nc-iconfont nc-icon-guanbiV6xx text-[36rpx] text-primary" @click="show = false"></view>
</view>
<view class="px-[30rpx] mb-[20rpx] mt-[10rpx]">
<view class="flex items-center justify-between mb-[30rpx]">
<view class="w-[160rpx] h-[60rpx] box-border leading-[60rpx] rounded-[30rpx] bg-[#F4F6FA] text-center text-[26rpx] text-[#666] border-[2rpx] border-solid border-[#F4F6FA]" v-for="(item,index) in curselectDate" :key="'a'+index" :class="{'text-primary !border-[var(--primary-color)] !bg-[rgba(239,0,12,0.04)]': currentValue.type == item.type}" @click="loadDateFn(item)">{{item.name}}</view>
</view>
<view class="flex items-center justify-between">
<view class="w-[316rpx] h-[60rpx] box-border leading-[60rpx] rounded-[30rpx] bg-[#F4F6FA] text-center text-[26rpx] text-[#666] border-[2rpx] border-solid border-[#F4F6FA]" :class="{'text-primary !border-[var(--primary-color)] !bg-[rgba(239,0,12,0.04)]': currentValue.type == 'first'}" @click="currentValue.type = 'first'">{{dateList.nowDate[0].substr(0,10)}}</view>
<view class="nc-iconfont nc-icon-jianV6xx"></view>
<view class="w-[316rpx] h-[60rpx] box-border leading-[60rpx] rounded-[30rpx] bg-[#F4F6FA] text-center text-[26rpx] text-[#666] border-[2rpx] border-solid border-[#F4F6FA]" :class="{'text-primary !border-[var(--primary-color)] !bg-[rgba(239,0,12,0.04)]': currentValue.type == 'second'}" @click="currentValue.type = 'second'">{{dateList.nowDate[1].substr(0,10)}}</view>
</view>
</view>
<view>
<picker-view indicator-class="!h-[70rpx] !bg-[#F4F6FA]" :value="dateList.curIndex" @change="bindChange" class="w-[750rpx] px-[60rpx] h-[396rpx] box-border">
<picker-view-column>
<view class="text-center leading-[70rpx] text-[28rpx]" v-for="(item,index) in dateList.years" :key="index">{{item}}</view>
</picker-view-column>
<picker-view-column>
<view class="text-center leading-[70rpx] text-[28rpx]" v-for="(item,index) in dateList.months" :key="index">{{item}}</view>
</picker-view-column>
<picker-view-column>
<view class="text-center leading-[70rpx] text-[28rpx]" v-for="(item,index) in dateList.days" :key="index">{{item}}</view>
</picker-view-column>
</picker-view>
</view>
<view class="px-[30rpx] pb-[30rpx] pt-[20rpx] flex justify-between">
<button class="w-[330rpx] h-[88rpx] text-[var(--primary-color)] text-[32rpx] leading-[84rpx] border-[2rpx] border-solid border-[var(--primary-color)] rounded-[100rpx] bg-transparent" hover-class="none" @click="reset">重置</button>
<button class="w-[330rpx] h-[88rpx] text-[#fff] text-[32rpx] leading-[88rpx] border-[0] rounded-[100rpx] primary-btn-bg" shape="circle" hover-class="none" @click="save">确定</button>
</view>
</view>
</u-popup>
</template>
<script setup lang="ts">
import { ref,reactive } from 'vue'
const emits = defineEmits(['confirm'])
//
const show = ref(false)
let create_time = ref([])
//
const init = () =>{
const date = new Date();
const years = []
const months = []
const days = []
const year = date.getFullYear()
const month = date.getMonth();
const day = date.getDate()
for (let i = 1990; i <= date.getFullYear()+2; i++) {
years.push(i)
}
for (let i = 1; i <= 12; i++) {
months.push(i)
}
let dayCount = getDaysInMonth(year, month+1)
for (let i = 1; i <= dayCount; i++) {
days.push(i)
}
let yearIndex = years.indexOf(year)
let curIndex = [yearIndex, month, day-1]
let nowDate = `${year}-${month + 1 < 10 ? '0' + (month + 1) :(month + 1) }-${day < 10 ? '0' + day :day }`
let nowDateStart = `${year}-${month + 1 < 10 ? '0' + (month + 1) :(month + 1) }-${day < 10 ? '0' + day :day } 00:00:00`
let nowDateEnd = `${year}-${month + 1 < 10 ? '0' + (month + 1) :(month + 1) }-${day < 10 ? '0' + day :day } 23:59:59`
let lastMonthDate = new Date(date.getFullYear(),month - 1,date.getDate())
let lastThreeMonthDate = new Date(date.getFullYear(),month - 3,date.getDate())
let halfYear = new Date(date.getFullYear(), month - 6, date.getDate())
let lastYear =new Date(date.getFullYear() - 1, month, date.getDate())
const formatDate = (dateTime:any) => {
const yearTime = dateTime.getFullYear()
const monthTime = dateTime.getMonth() + 1
const dayTime = dateTime.getDate()
return `${yearTime}-${monthTime < 10 ? '0' + monthTime : monthTime}-${dayTime < 10 ? '0' + dayTime :dayTime } 00:00:00`
}
return {
years,
months,
days,
curIndex,
nowDate,
nowDateStart,
nowDateEnd,
lastMonth: formatDate(lastMonthDate),
lastThreeMonth: formatDate(lastThreeMonthDate),
halfYear: formatDate(halfYear),
lastYear: formatDate(lastYear)
}
}
const getDaysInMonth = (year, month) => {
let date = new Date(year, month, 0).getDate()
return date
}
const getDaysCount = (year, month) =>{
let count = getDaysInMonth(year, month)
let days = []
for (let i = 1; i <= count; i++) {
days.push(i)
}
return days
}
const dateList = reactive({
years: init().years,
months: init().months,
days: init().days,
curIndex:init().curIndex, //
nowDate:[init().nowDateStart,init().nowDateEnd] //
})
const bindChange = (e) =>{
const val = e.detail.value
let year = dateList.years[val[0]]
let month= dateList.months[val[1]]
let day = dateList.days[val[2]]
// ,
dateList.days = getDaysCount(year, month)
if(currentValue.value.type == 'first'){
dateList.nowDate[0] = `${year}-${month < 10 ? '0' + month :month }-${day < 10 ? '0' + day :day } 00:00:00`
}else if(currentValue.value.type == 'second'){
dateList.nowDate[1] = `${year}-${month < 10 ? '0' + month :month }-${day < 10 ? '0' + day :day } 23:59:59`
}
}
const curselectDate = reactive([
{
time:[init().lastMonth,init().nowDateEnd],
type:'lastMonth',
name:'近1个月'
},
{
time:[init().lastThreeMonth,init().nowDateEnd],
type:'lastThreeMonth',
name:'近3个月'
},
{
time:[init().halfYear,init().nowDateEnd],
type:'halfYear',
name:'近半年'
},
{
time:[init().lastYear,init().nowDateEnd],
type:'lastYear',
name:'近一年'
}
])
//
let currentValue = ref({
type: 'first',
time: []
})
const loadDateFn = (data) =>{
currentValue.value.type = data.type
currentValue.value.time = data.time
dateList.nowDate[0] = currentValue.value.time[0]
dateList.nowDate[1] = currentValue.value.time[1]
}
const save = () =>{
if(currentValue.value.type == 'first' ||currentValue.value.type == 'second'){
create_time.value = dateList.nowDate
let start = new Date(create_time.value[0]).getTime()
let end = new Date(create_time.value[1]).getTime()
if( start > end){
uni.showToast({ title: '开始时间不能大于结束时间', icon: 'none' })
return
}
}else{
create_time.value = currentValue.value.time
}
emits('confirm',create_time.value)
show.value = false
}
const reset = () =>{
currentValue.value.type = 'first'
dateList.curIndex = init().curIndex
dateList.nowDate = [init().nowDateStart,init().nowDateEnd]
}
defineExpose({
show
})
</script>
<style scoped>
:deep(.uni-picker-view-content){
z-index: 10;
}
:deep(.uni-picker-view-indicator::before){
border: none !important;
}
:deep(.uni-picker-view-indicator::after){
border: none !important;
}
</style>

View File

@ -52,7 +52,7 @@
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
import { ref } from 'vue';
import { img, copy } from '@/utils/common';
import { getPoster } from '@/app/api/system'
@ -155,17 +155,17 @@ const saveGoodsPoster = () => {
});
},
fail: (err) => {
if(err.errno == 104){
let msg = '用户未授权隐私权限,将图像保存到相册失败';
uni.showToast({title: msg, icon: 'none'})
}else if (err.errMsg == "saveImageToPhotosAlbum:fail auth deny" ||
if (err.errno == 104) {
let msg = '用户未授权隐私权限,将图像保存到相册失败';
uni.showToast({ title: msg, icon: 'none' })
} else if (err.errMsg == "saveImageToPhotosAlbum:fail auth deny" ||
err.errMsg == "saveImageToPhotosAlbum:fail:auth denied") {
show.value = true;
}else if(err.errMsg == "saveImageToPhotosAlbum:fail cancel"){
show.value = true;
} else if (err.errMsg == "saveImageToPhotosAlbum:fail cancel") {
let msg = '用户取消将图片保存到相册';
uni.showToast({title: msg, icon: 'none'})
}else{
uni.showToast({title: err.errMsg, icon: 'none'})
uni.showToast({ title: msg, icon: 'none' })
} else {
uni.showToast({ title: err.errMsg, icon: 'none' })
}
}
});

View File

@ -1,7 +1,7 @@
<template>
<view :class="{'text-primary': sendSms.canGetCode.value, 'text-gray-300': !sendSms.canGetCode.value}" @click="handleSend">{{ sendSms.tips.value }}</view>
<view class="text-[26rpx]" :class="{'text-primary': sendSms.canGetCode.value, 'text-gray-300': !sendSms.canGetCode.value}" @click="handleSend">{{ sendSms.tips.value }}</view>
<u-code :seconds="sendSms.seconds" :change-text="sendSms.changeText" ref="smsRef" @change="sendSms.codeChange"></u-code>
<u-modal :show="show" :title="t('captchaTitle')" :confirm-text="t('confirm')" :cancel-text="t('cancel')" :show-cancel-button="true" @cancel="show = false" @confirm="handleConfirm">
<u-modal :show="show" :title="t('captchaTitle')" :confirm-text="t('confirm')" :cancel-text="t('cancel')" :show-cancel-button="true" @cancel="show = false" @confirm="handleConfirm" confirmColor="var(--primary-color)">
<view class="flex mt-[20rpx]">
<u-input :placeholder="t('captchaPlaceholder')" border="surround" v-model="formData.captcha_code"></u-input>
<image :src="captcha.image.value" class="h-[76rpx] ml-[20rpx]" mode="heightFix" @click="captcha.refresh()"></image>
@ -38,7 +38,7 @@ const smsRef = ref(null)
const sendSms = useSendSms(smsRef)
const show = ref(false)
const formData = reactive<requestMobileParam>({
const formData:any = reactive({
mobile: '',
captcha_code: '',
captcha_key: '',

View File

@ -1,16 +1,15 @@
<template>
<!-- diyStore.mode !='decorate' && topStatusBarData topStatusBarData.style == 'style-5 为了兼容风格五 -->
<view class="ns-navbar-wrap" v-if="diyStore.mode !='decorate' && topStatusBarData || diyStore.mode =='decorate' && topStatusBarData && topStatusBarData.style == 'style-5' " :class="topStatusBarData.style">
<view class="u-navbar" :style="{ backgroundColor: bgColor}">
<view class="ns-navbar-wrap" v-if="diyStore.mode !='decorate' && topStatusBarData" :class="topStatusBarData.style">
<view class="u-navbar" :class="{'fixed': props.scrollBool != -1, 'absolute': props.scrollBool == -1}" :style="{ backgroundColor: bgColor}">
<view class="navbar-inner" :style="{ width: '100%', height: placeholderHeight + 'px' }">
<view v-if="topStatusBarData.style == 'style-1'" class="content-wrap" :class="[topStatusBarData.textAlign]" :style="navbarInnerStyle">
<view v-if="isBack && isBackShow" class="back-wrap text-[26px] nc-iconfont nc-icon-zuoV6xx" :style="{ color: topStatusBarData.textColor || titleColor }" @tap="goBack"></view>
<view v-if="isBack && isBackShow" class="back-wrap -ml-[16rpx] text-[27px] nc-iconfont nc-icon-zuoV6xx" :style="{ color: titleTextColor }" @tap="goBack"></view>
<view class="title-wrap" :style="styleOneFontSize">
{{ data.title }}
</view>
</view>
<view v-if="topStatusBarData.style == 'style-2'" class="content-wrap" :style="navbarInnerStyle" @click="diyStore.toRedirect(topStatusBarData.link)">
<view v-if="isBack && isBackShow" class="back-wrap text-[26px] nc-iconfont nc-icon-zuoV6xx" :style="{ color: topStatusBarData.textColor || titleColor }" @tap="goBack"></view>
<view v-if="isBack && isBackShow" class="back-wrap -ml-[16rpx] text-[27px] nc-iconfont nc-icon-zuoV6xx" :style="{ color: titleTextColor }" @tap="goBack"></view>
<view class="title-wrap" :style="{ color: topStatusBarData.textColor }">
<view>
<image :src="img(topStatusBarData.imgUrl)" mode="heightFix"></image>
@ -20,7 +19,7 @@
</view>
<view v-if="topStatusBarData.style == 'style-3'" :style="navbarInnerStyle" class="content-wrap">
<view v-if="isBack && isBackShow" class="back-wrap text-[26px] nc-iconfont nc-icon-zuoV6xx" :style="{ color: topStatusBarData.textColor || titleColor }" @tap="goBack"></view>
<view v-if="isBack && isBackShow" class="back-wrap -ml-[16rpx] text-[27px] nc-iconfont nc-icon-zuoV6xx" :style="{ color: titleTextColor }" @tap="goBack"></view>
<view class="title-wrap" @click="diyStore.toRedirect(topStatusBarData.link)">
<image :src="img(topStatusBarData.imgUrl)" mode="heightFix"></image>
</view>
@ -32,33 +31,32 @@
</view>
<view v-if="topStatusBarData.style == 'style-4'" :style="navbarInnerStyle" class="content-wrap">
<view v-if="isBack && isBackShow" class="back-wrap text-[26px] nc-iconfont nc-icon-zuoV6xx" :style="{ color: topStatusBarData.textColor || titleColor }" @tap="goBack"></view>
<view v-if="isBack && isBackShow" class="back-wrap -ml-[16rpx] text-[27px] nc-iconfont nc-icon-zuoV6xx" :style="{ color: titleTextColor }" @tap="goBack"></view>
<text class="nc-iconfont nc-icon-dizhiguanliV6xx text-[28rpx]" :style="{ color: topStatusBarData.textColor }"></text>
<view class="title-wrap" @click="reposition()" :style="{ color: topStatusBarData.textColor }">{{ currentPosition }}</view>
<text class="nc-iconfont nc-icon-youV6xx text-[26rpx]" @click="reposition()" :style="{ color: topStatusBarData.textColor }"></text>
</view>
<!-- #ifdef MP-WEIXIN -->
<view v-if="topStatusBarData.style == 'style-5'" class="content-wrap" :style="navbarInnerStyle">
<view v-if="isBack && isBackShow" class="back-wrap text-[26px] nc-iconfont nc-icon-zuoV6xx" :style="{ color: topStatusBarData.textColor || titleColor }" @tap="goBack"></view>
</view>
<!-- #endif -->
</view>
</view>
<!-- 风格5填充 -->
<view v-if="topStatusBarData.style == 'style-5'" :style="style5Height"></view>
<!-- 解决fixed定位后导航栏塌陷的问题 -->
<view class="u-navbar-placeholder" :style="{ width: '100%', paddingTop: placeholderHeight + 'px' }"></view>
<!-- #ifdef MP-WEIXIN -->
<!-- 小程序隐私协议 -->
<wx-privacy-popup ref="wxPrivacyPopup"></wx-privacy-popup>
<wx-privacy-popup ref="wxPrivacyPopupRef"></wx-privacy-popup>
<!-- #endif -->
</view>
</template>
<script setup lang="ts">
import { ref, computed, watch, onMounted, getCurrentInstance, nextTick } from 'vue';
import { img, getLocation, locationStorage } from '@/utils/common';
import { getAddressByLatlng } from '@/app/api/system';
import useSystemStore from '@/stores/system';
import useDiyStore from '@/app/stores/diy';
import manifestJson from '@/manifest.json'
//
let systemInfo = uni.getSystemInfoSync();
let platform = systemInfo.platform;
@ -68,15 +66,8 @@ let menuButtonInfo = {};
menuButtonInfo = uni.getMenuButtonBoundingClientRect();
// #endif
import { ref, computed, watch, onMounted, getCurrentInstance, nextTick } from 'vue';
import { img, getLocation, locationStorage } from '@/utils/common';
import { getAddressByLatlng } from '@/app/api/system';
import useSystemStore from '@/stores/system';
import useDiyStore from '@/app/stores/diy';
import manifestJson from '@/manifest.json'
const diyStore = useDiyStore();
// param{arrowLink => isShowArrow => tabbarBg => }
const props = defineProps({
data: {
type: Object,
@ -92,9 +83,9 @@ const props = defineProps({
type: Function,
default: null
},
scrollTop: {
scrollBool: {
type: [String, Number],
default: '0'
default: -1
},
//
isBack: {
@ -148,32 +139,50 @@ const styleOneFontSize = computed(() => {
} else if (platform === 'android') {
// (Android)
style += 'font-size: 36rpx;';
style += 'font-weight: 500;';
}
// #endif
style += `color: ${topStatusBarData.value.textColor};`;
style += `color: ${titleTextColor.value};`;
if(topStatusBarData.value.style == 'style-1'){
style += `text-align: ${topStatusBarData.value.textAlign};`;
}
return style;
})
const bgColor = computed(() => {
var color = '';
if (topStatusBarData.value.isTransparent) {
//
color = 'transparent';
if (props.scrollTop) {
color = topStatusBarData.value.bgColor;
} else {
color = 'transparent';
}
const titleTextColor = computed(()=>{
let color = '';
if (props.scrollBool == 1) {
color = topStatusBarData.value.rollTextColor;
} else {
color = '#fff';
color = topStatusBarData.value.textColor;
}
return color;
})
const bgColor = computed(() => {
let color = '';
if (props.scrollBool == 1) {
color = topStatusBarData.value.rollBgColor;
} else {
color = topStatusBarData.value.bgColor;
}
return color;
})
/******************************* 存储滚动值-start ***********************/
//
let componentsScrollVal = uni.getStorageSync('componentsScrollValGroup')
if(componentsScrollVal){
componentsScrollVal.TopTabbar = 0
uni.setStorageSync('componentsScrollValGroup', componentsScrollVal);
}else{
let obj = {
TopTabbar: 0
}
uni.setStorageSync('componentsScrollValGroup', obj);
}
/******************************* 存储滚动值-end ***********************/
/******************************* 返回按钮-start ***********************/
let isBackShow = ref(false);
let pages = getCurrentPages();
@ -309,29 +318,6 @@ const getQueryVariable = (variable:any)=> {
}
/******************************* 定位-end ***********************/
/******************************* 风格五-start ***********************/
let style5Height = ref('')
watch(() => topStatusBarData.value.style, (nval, oval)=> {
if(topStatusBarData.value.style == 'style-5'){
style5Height.value = '';
if(data.value.imgWidth && data.value.imgHeight) {
let sysWidth = systemInfo.windowWidth
let sysHeight = sysWidth / data.value.imgWidth * data.value.imgHeight
style5Height.value += `width:100%;`
// #ifdef H5
sysHeight = sysHeight - 88; //使88
style5Height.value += `padding-top:${ sysHeight }px;`
style5Height.value += `height:0;` //h5
// #endif
// #ifdef MP
sysHeight = sysHeight - menuButtonInfo.top - menuButtonInfo.height - 5; //[padding-bottompadding-top]
style5Height.value += `padding-top:${ sysHeight }px;`
// #endif
}
}
},{immediate: true, deep:true})
/******************************* 风格五-end ***********************/
onMounted(() => {
navbarPlaceholderHeight();
if (pages.length > 1) {
@ -349,10 +335,8 @@ const refresh = ()=>{
}
}
// ,1,
defineExpose({
refresh,
scrollValue: 1
refresh
})
</script>
@ -368,7 +352,6 @@ defineExpose({
.u-navbar {
width: 100%;
transition: background 0.3s;
position: fixed;
left: 0;
right: 0;
top: 0;
@ -511,6 +494,7 @@ defineExpose({
margin: 0 10rpx;
max-width: 360rpx;
font-size: 27rpx;
line-height: normal;
}
.nearby-store-name {

View File

@ -23,7 +23,7 @@
const agree = ref(false)
const showPop = ref(false)
const privacyAuthorization = ref(null)
const privacyAuthorization: any = ref(null)
const privacyResolves = new Set()
const closeOtherPagePopUpHooks = new Set()
@ -33,9 +33,9 @@
const emits = defineEmits(['agree','disagree'])
//
const init = ()=>{
const init = ()=> {
if (wx.onNeedPrivacyAuthorization) {
wx.onNeedPrivacyAuthorization((resolve) => {
wx.onNeedPrivacyAuthorization((resolve: any) => {
if (typeof privacyAuthorization.value === 'function') {
privacyAuthorization.value(resolve)
}
@ -45,7 +45,7 @@
//
const curPageShow = ()=> {
privacyAuthorization.value = resolve => {
privacyAuthorization.value = (resolve: any) => {
privacyResolves.add(resolve)
//
popUp()
@ -56,7 +56,7 @@
}
onMounted(()=>{
//
//
try {
wx.getPrivacySetting({
success(res:any) {
@ -72,7 +72,7 @@
}
});
//
//
const openPrivacyContract = ()=> {
wx.openPrivacyContract({
success(res) {
@ -95,15 +95,15 @@
//
const handleDisagree = ()=> {
privacyResolves.forEach(resolve => {
privacyResolves.forEach((resolve: any) => {
resolve({
event: 'disagree',
})
})
privacyResolves.clear()
//
//
disPopUp()
//退
// 退
uni.showModal({
content: '未同意隐私协议,无法使用相关功能',
confirmColor: useConfigStore().themeColor['--primary-color'],
@ -115,7 +115,7 @@
//
const handleAgree = ()=> {
privacyResolves.forEach(resolve => {
privacyResolves.forEach((resolve: any) => {
resolve({
event: 'agree',
buttonId: 'agree-btn'
@ -127,24 +127,25 @@
emits('agree')
}
//
//
const popUp = ()=> {
if (showPop.value === false) {
showPop.value = true
}
}
//
//
const disPopUp = ()=> {
if (showPop.value === true) {
showPop.value = false
}
}
//
const proactive =()=> {
if (wx.getPrivacySetting) {
wx.getPrivacySetting({
success: (res) => {
success: (res: any) => {
if (res.needAuthorization) {
popUp()
//
@ -158,6 +159,10 @@
emits('agree')
}
}
defineExpose({
proactive
})
</script>
<style lang="scss" scoped>

View File

@ -1,7 +1,7 @@
import {ref, reactive, computed} from 'vue';
import {onLoad, onShow, onPullDownRefresh, onPageScroll} from '@dcloudio/uni-app';
import {img, handleOnloadParams} from '@/utils/common';
import {getDiyInfo} from '@/app/api/diy';
import { ref, reactive, computed } from 'vue';
import { onLoad, onShow, onPullDownRefresh, onPageScroll, onUnload } from '@dcloudio/uni-app';
import { img, handleOnloadParams } from '@/utils/common';
import { getDiyInfo } from '@/app/api/diy';
import useDiyStore from '@/app/stores/diy';
export function useDiy(params: any = {}) {
@ -33,31 +33,25 @@ export function useDiy(params: any = {}) {
return diyData;
}
})
const isShowTopTabbar = ref(false);
const pageStyle = () => {
var style = '';
if (data.value.global.pageStartBgColor) {
if (data.value.global.pageStartBgColor && data.value.global.pageEndBgColor) style += `background:linear-gradient(${data.value.global.pageGradientAngle},${data.value.global.pageStartBgColor},${data.value.global.pageEndBgColor});`;
if (data.value.global.pageStartBgColor && data.value.global.pageEndBgColor) style += `background:linear-gradient(${ data.value.global.pageGradientAngle },${ data.value.global.pageStartBgColor },${ data.value.global.pageEndBgColor });`;
else style += 'background-color:' + data.value.global.pageStartBgColor + ';';
}
style += 'min-height:calc(100vh - 50px);';
if (data.value.global.bgUrl) {
style += `background-image:url('${img(data.value.global.bgUrl)}');`;
style += `background-image:url('${ img(data.value.global.bgUrl) }');`;
}
if (data.value.global.bgHeightScale) {
style += `background-size: 100% ${data.value.global.bgHeightScale}%;`;
style += `background-size: 100% ${ data.value.global.bgHeightScale }%;`;
}
// #ifdef H5
// 导航栏风格五 - 兼容
if(data.value.global && data.value.global.topStatusBar && data.value.global.topStatusBar.style == "style-5"){
style += `background-position-y: -176rpx;`;
}
// #endif
return style;
};
@ -106,7 +100,7 @@ export function useDiy(params: any = {}) {
diyData.value.forEach((item: any, index) => {
item.pageStyle = '';
if (item.pageStartBgColor) {
if (item.pageStartBgColor && item.pageEndBgColor) item.pageStyle += `background:linear-gradient(${item.pageGradientAngle},${item.pageStartBgColor},${item.pageEndBgColor});`;
if (item.pageStartBgColor && item.pageEndBgColor) item.pageStyle += `background:linear-gradient(${ item.pageGradientAngle },${ item.pageStartBgColor },${ item.pageEndBgColor });`;
else item.pageStyle += 'background-color:' + item.pageStartBgColor + ';';
}
@ -141,6 +135,14 @@ export function useDiy(params: any = {}) {
})
}
// 监听页面卸载
const onUnloadLifeCycle = () => {
onUnload(() => {
// 兼容轮播搜索组件-切换分类时,导致个人中心白屏
diyStore.topFixedStatus = 'home'
})
}
// 监听下拉刷新事件
const onPullDownRefreshLifeCycle = () => {
onPullDownRefresh(() => {
@ -166,6 +168,7 @@ export function useDiy(params: any = {}) {
pageStyle,
onLoad: onLoadLifeCycle,
onShow: onShowLifeCycle,
onUnload: onUnloadLifeCycle,
onPullDownRefresh: onPullDownRefreshLifeCycle,
onPageScroll: onPageScrollLifeCycle,
}

View File

@ -1,5 +1,12 @@
import { redirect, isWeixinBrowser, urlDeconstruction } from '@/utils/common'
import { weappLogin, wechatLogin, wechatUser, wechatUserLogin } from '@/app/api/auth'
import {
weappLogin,
updateWeappOpenid,
wechatLogin,
updateWechatOpenid,
wechatUser,
wechatUserLogin
} from '@/app/api/auth'
import { getWechatAuthCode } from '@/app/api/system'
import useMemberStore from '@/stores/member'
import useConfigStore from '@/stores/config'
@ -8,20 +15,20 @@ export function useLogin() {
/**
*
*/
const setLoginBack = (data : redirectOptions) => {
const setLoginBack = (data: redirectOptions) => {
uni.setStorage({ key: 'loginBack', data })
setTimeout(() => {
const config = useConfigStore()
// #ifdef MP-WEIXIN
if (!uni.getStorageSync('autoLoginLock') && uni.getStorageSync('openid') && config.login.is_bind_mobile) {
redirect({ url: '/app/pages/auth/bind', mode: 'redirectTo' })
uni.setStorageSync('isbindmobile', true)
return
}
// #endif
// #ifdef H5
if (!uni.getStorageSync('autoLoginLock') && isWeixinBrowser() && uni.getStorageSync('openid') && config.login.is_bind_mobile) {
redirect({ url: '/app/pages/auth/bind', mode: 'redirectTo' })
uni.setStorageSync('isbindmobile', true)
return
}
// #endif
@ -36,7 +43,7 @@ export function useLogin() {
uni.removeStorageSync('autoLoginLock')
uni.getStorage({
key: 'loginBack',
success: (data : AnyObject) => {
success: (data: AnyObject) => {
data ? redirect(data.data) : redirect({ url: '/app/pages/index/index', mode: 'switchTab' })
},
fail: (res) => {
@ -48,57 +55,114 @@ export function useLogin() {
/**
*
*/
const authLogin = (code : string | null) => {
let obj = {};
// #ifdef MP-WEIXIN
obj.code = code;
uni.getStorageSync('pid') && (Object.assign(obj, { pid: uni.getStorageSync('pid') }))
weappLogin(obj).then((res : AnyObject) => {
if (res.data.token) {
useMemberStore().setToken(res.data.token)
setTimeout(() => {
const memberInfo = useMemberStore().info
memberInfo && memberInfo.weapp_openid && uni.setStorageSync('openid', memberInfo.weapp_openid)
}, 1000)
} else {
uni.setStorageSync('openid', res.data.openid)
uni.setStorageSync('unionid', res.data.unionid)
}
})
const authLogin = (code: string | null,backFlag = false,callback: any = null) => {
let obj = {};
// #ifdef MP-WEIXIN
obj.code = code;
uni.getStorageSync('pid') && (Object.assign(obj, { pid: uni.getStorageSync('pid') }))
weappLogin(obj).then((res: AnyObject) => {
if (res.data.token) {
useMemberStore().setToken(res.data.token)
const config = useConfigStore()
setTimeout(() => {
const memberInfo = useMemberStore().info
memberInfo && memberInfo.weapp_openid && uni.setStorageSync('openid', memberInfo.weapp_openid)
// 开启绑定手机号标识
if (uni.getStorageSync('isbindmobile')) {
uni.removeStorageSync('isbindmobile');
}
if (config.login.is_bind_mobile && memberInfo && !memberInfo.mobile) {
uni.setStorageSync('isbindmobile', true)
}
if(backFlag) handleLoginBack() //一键登录返回
}, 1000)
} else {
uni.setStorageSync('openid', res.data.openid)
uni.setStorageSync('unionid', res.data.unionid)
if(callback) callback({
openid: uni.getStorageSync('openid'),
unionid: uni.getStorageSync('unionid')
})
}
}).catch((err) => {
uni.showToast({ title: err.msg, icon: 'none' })
})
// #endif
// #ifdef H5
obj.code = code;
uni.getStorageSync('pid') && (Object.assign(obj, { pid: uni.getStorageSync('pid') }))
wechatUser(obj).then((user_res : AnyObject) => {
if(user_res.data){
wechatUserLogin(user_res.data).then((res : AnyObject) => {
if (res.data.token) {
useMemberStore().setToken(res.data.token)
setTimeout(() => {
const memberInfo = useMemberStore().info
memberInfo && memberInfo.wx_openid && uni.setStorageSync('openid', memberInfo.wx_openid)
}, 1000)
} else {
uni.setStorageSync('openid', res.data.openid)
uni.setStorageSync('unionid', res.data.unionid)
}
})
}
})
obj.code = code;
uni.getStorageSync('pid') && (Object.assign(obj, { pid: uni.getStorageSync('pid') }))
wechatUser(obj).then((user_res: AnyObject) => {
if (user_res.data) {
wechatUserLogin(user_res.data).then((res: AnyObject) => {
if (res.data.token) {
useMemberStore().setToken(res.data.token)
const config = useConfigStore()
setTimeout(() => {
const memberInfo = useMemberStore().info
memberInfo && memberInfo.wx_openid && uni.setStorageSync('openid', memberInfo.wx_openid)
// 开启绑定手机号标识
if (uni.getStorageSync('isbindmobile')) {
uni.removeStorageSync('isbindmobile');
}
if (config.login.is_bind_mobile && memberInfo && !memberInfo.mobile) {
uni.setStorageSync('isbindmobile', true)
}
}, 1000)
} else {
uni.setStorageSync('openid', res.data.openid)
uni.setStorageSync('unionid', res.data.unionid)
}
})
}
}).catch((err) => {
if (err.msg == -1) {
getAuthCode('snsapi_userinfo')
} else {
uni.showToast({ title: err.msg, icon: 'none' })
}
})
// #endif
}
/**
* openid
*/
const updateOpenid = (code: string | null) => {
let obj = {};
// #ifdef MP-WEIXIN
obj.code = code;
updateWeappOpenid(obj).then((res) => {
useMemberStore().getMemberInfo()
setTimeout(() => {
const memberInfo = useMemberStore().info
memberInfo && memberInfo.weapp_openid && uni.setStorageSync('openid', memberInfo.weapp_openid)
}, 1000)
})
// #endif
// #ifdef H5
obj.code = code;
updateWechatOpenid(obj).then((res) => {
useMemberStore().getMemberInfo()
setTimeout(() => {
const memberInfo = useMemberStore().info
memberInfo && memberInfo.wx_openid && uni.setStorageSync('openid', memberInfo.wx_openid)
}, 1000)
})
// #endif
}
/**
*
* updateFlagoppenid
* backFlag
*/
const getAuthCode = (scopes : 'snsapi_base' | 'snsapi_userinfo' = 'snsapi_base') => {
const getAuthCode = (scopes: '' | 'snsapi_base' | 'snsapi_userinfo' = 'snsapi_base', updateFlag: boolean = false, backFlag: boolean = false,callback = null) => {
// #ifdef MP-WEIXIN
wx.login({
success(res) {
if (res.code) {
authLogin(res.code)
updateFlag ? updateOpenid(res.code) : authLogin(res.code,backFlag,callback)
} else {
console.log('登录失败!' + res.errMsg)
}
@ -107,7 +171,7 @@ export function useLogin() {
// #endif
// #ifdef H5
let url = `${location.origin}${location.pathname}`
let url = `${ location.origin }${ location.pathname }`
let query = urlDeconstruction(location.href).query
query.code && (delete query.code)
Object.keys(query).length && (url += uni.$u.queryParams(query))
@ -115,7 +179,7 @@ export function useLogin() {
getWechatAuthCode({
url,
scopes
}).then((res : AnyObject) => {
}).then((res: AnyObject) => {
location.href = res.data.url
})
// #endif
@ -125,6 +189,7 @@ export function useLogin() {
setLoginBack,
handleLoginBack,
authLogin,
updateOpenid,
getAuthCode
}
}

View File

@ -5,39 +5,39 @@ import { sendSms } from '@/app/api/system'
export function useSendSms(smsRef: AnyObject | null) {
const tips = ref(t('getSmsCode'))
const seconds = 90
const changeText = 'X' + t('smsCodeChangeText')
const canGetCode = computed(() =>{
const changeText = 'X' + t('smsCodeChangeText')
const canGetCode = computed(() => {
return smsRef.value ? smsRef.value.canGetCode : true
})
/**
*
*/
const send = async (param:requestMobileParam) => {
const send = async(param: requestMobileParam) => {
if (!canGetCode.value) return
smsRef.value.start()
let result: string | boolean = false
await sendSms(param).then(res=>{
await sendSms(param).then(res => {
if (res.code == 1) {
result = res.data.key
} else {
smsRef.value.reset()
result = false
}
}).catch(err=>{
}).catch(err => {
result = false
smsRef.value.reset()
})
return result
}
const codeChange = (text: string)=>{
const codeChange = (text: string) => {
tips.value = text
}
return {
tips: tips,
seconds,

View File

@ -7,138 +7,139 @@ import wechat from '@/utils/wechat'
// #endif
export const useShare = () => {
var wechatOptions: any = {};
var wechatOptions: any = {};
var weappOptions:any = {};
var weappOptions: any = {};
const wechatInit = () => {
if (!isWeixinBrowser()) return;
// 初始化sdk
wechat.init();
}
const wechatInit = () => {
if (!isWeixinBrowser()) return;
// 初始化sdk
wechat.init();
}
// 微信公众号分享
const wechatShare = () => {
if (!isWeixinBrowser()) return;
wechat.share(wechatOptions);
}
// 微信公众号分享
const wechatShare = () => {
if (!isWeixinBrowser()) return;
wechat.share(wechatOptions);
}
const getQuery = ()=>{
let query:any = currShareRoute().params;
let wap_member_id = uni.getStorageSync('wap_member_id');
if (wap_member_id) {
query.mid = wap_member_id;
}
const getQuery = () => {
let query: any = currShareRoute().params;
let wap_member_id = uni.getStorageSync('wap_member_id');
if (wap_member_id) {
query.mid = wap_member_id;
}
let queryStr = [];
for (let key in query) {
queryStr.push(key + '=' + query[key]);
}
let queryStr = [];
for (let key in query) {
queryStr.push(key + '=' + query[key]);
}
return queryStr
return queryStr
}
}
const setShare = (options : any = {}) => {
if(currRoute() == '' || currRoute().indexOf('app/pages/index/close') != -1 || currRoute().indexOf('app/pages/index/nosite') != -1) return;
const setShare = (options: any = {}) => {
if (currRoute() == '' || currRoute().indexOf('app/pages/index/close') != -1 || currRoute().indexOf('app/pages/index/nosite') != -1) return;
let queryStr = getQuery();
let queryStr = getQuery();
// #ifdef H5
// #ifdef H5
let h5Link = location.origin + location.pathname + (queryStr.length > 0 ? '?' + queryStr.join('&') : '');
let h5Link = location.origin + location.pathname + (queryStr.length > 0 ? '?' + queryStr.join('&') : '');
wechatOptions = {
link: h5Link
}
wechatOptions = {
link: h5Link
}
// #endif
// #endif
// #ifdef MP-WEIXIN
weappOptions = {
path: '/' + currRoute() + (queryStr.length > 0 ? '?' + queryStr.join('&') : ''),
query: queryStr.join('&'),
}
// #endif
// #ifdef MP-WEIXIN
weappOptions = {
path: '/' + currRoute() + (queryStr.length > 0 ? '?' + queryStr.join('&') : ''),
query: queryStr.join('&'),
}
// #endif
if (options && options.wechat && options.weapp) {
if (options && options.wechat && options.weapp) {
// #ifdef H5
wechatOptions.title = options.wechat.title || ''
wechatOptions.link = options.wechat.link || h5Link
wechatOptions.desc = options.wechat.desc || ''
wechatOptions.imgUrl = options.wechat.url ? img(options.wechat.url) : ''
wechatShare()
// #endif
// #ifdef H5
wechatOptions.title = options.wechat.title || ''
wechatOptions.link = options.wechat.link || h5Link
wechatOptions.desc = options.wechat.desc || ''
wechatOptions.imgUrl = options.wechat.url ? img(options.wechat.url) : ''
wechatShare()
// #endif
// #ifdef MP-WEIXIN
weappOptions.title = options.weapp.title || ''
weappOptions.query = options.weapp.path || queryStr.join('&')
weappOptions.imageUrl = options.weapp.url ? img(options.weapp.url) : ''
// #endif
// #ifdef MP-WEIXIN
weappOptions.title = options.weapp.title || ''
weappOptions.query = options.weapp.path || queryStr.join('&')
weappOptions.imageUrl = options.weapp.url ? img(options.weapp.url) : ''
// #endif
} else {
getShareInfo({
route: '/' + currRoute(),
params: JSON.stringify(currShareRoute().params)
}).then((res: any) => {
let data = res.data;
uni.setStorageSync('weappOptions', weappOptions)
} else {
getShareInfo({
route: '/' + currRoute(),
params: JSON.stringify(currShareRoute().params)
}).then((res: any) => {
let data = res.data;
// #ifdef H5
let wechat = data.wechat;
if (wechat) {
wechatOptions.title = wechat.title
wechatOptions.desc = wechat.desc
wechatOptions.imgUrl = wechat.url ? img(wechat.url) : ''
}else{
wechatOptions.title = document.title;
wechatOptions.desc = ''
}
wechatShare()
// #endif
// #ifdef H5
let wechat = data.wechat;
if (wechat) {
wechatOptions.title = wechat.title
wechatOptions.desc = wechat.desc
wechatOptions.imgUrl = wechat.url ? img(wechat.url) : ''
} else {
wechatOptions.title = document.title;
wechatOptions.desc = ''
}
wechatShare()
// #endif
// #ifdef MP-WEIXIN
let weapp = data.weapp;
if (weapp) {
weappOptions.title = weapp.title
weappOptions.imageUrl = weapp.url ? img(weapp.url) : ''
}
// #endif
// #ifdef MP-WEIXIN
let weapp = data.weapp;
if (weapp) {
weappOptions.title = weapp.title
weappOptions.imageUrl = weapp.url ? img(weapp.url) : ''
}
// #endif
})
}
uni.setStorageSync('weappOptions', weappOptions)
}
uni.setStorageSync('weappOptions', weappOptions)
})
}
}
// 小程序分享,分享给好友
const shareApp = (options = {}) => {
onShareAppMessage(() => {
let config:any= uni.getStorageSync('weappOptions')
if(!config) config = {}
return {
...config,
...options
}
})
// 小程序分享,分享给好友
const shareApp = (options = {}) => {
onShareAppMessage(() => {
let config: any = uni.getStorageSync('weappOptions')
if (!config) config = {}
return {
...config,
...options
}
})
}
}
// 小程序分享,分享到朋友圈
const shareTime = (options = {}) => {
onShareTimeline(() => {
let config:any= uni.getStorageSync('weappOptions')
if(!config) config = {}
return {
...config,
...options
}
})
}
// 小程序分享,分享到朋友圈
const shareTime = (options = {}) => {
onShareTimeline(() => {
let config: any = uni.getStorageSync('weappOptions')
if (!config) config = {}
return {
...config,
...options
}
})
}
return {
wechatInit:wechatInit,
setShare: setShare,
onShareAppMessage: shareApp,
onShareTimeline: shareTime,
}
return {
wechatInit: wechatInit,
setShare: setShare,
onShareAppMessage: shareApp,
onShareTimeline: shareTime,
}
}

View File

@ -4,11 +4,11 @@ import { getWeappTemplateId } from '@/app/api/system'
*
*/
export const useSubscribeMessage = () => {
const request = (keys: string)=> {
const request = (keys: string) => {
// #ifdef MP-WEIXIN
const method = getWeappTemplateId
// #endif
// #ifdef MP
method(keys).then(({ data }) => {
uni.requestSubscribeMessage({
@ -23,7 +23,7 @@ export const useSubscribeMessage = () => {
}).catch()
// #endif
}
return {
request
}

View File

@ -27,6 +27,7 @@
"pages.member.detailed_account": "流水明细",
"pages.member.index": "",
"pages.member.personal": "个人资料",
"pages.member.contact": "客服",
"pages.pay.browser": "支付",
"pages.pay.result": "支付结果",
"pages.setting.index": "设置",

View File

@ -23,9 +23,19 @@
"headimgPlaceholder": "请设置头像",
"getAvatarNickname": "获取您的昵称头像",
"getAvatarNicknameTips": "获取用户头像、昵称完善个人资料,主要用于向用户提供具有辨识度的用户中心界面",
"mobile":"手机号",
"getMobile":"获取手机号",
"mobileTips":"请获取手机号",
"point": "积分",
"balance": "余额",
"login": "登录",
"bind": "绑定",
"binding": "绑定中",
"bindMobile": "绑定手机号",
"agreeTips": "请阅读并同意",
"pleaceAgree": "请勾选已阅读并同意",
"weixinUserAuth": "一键绑定",
"mobileQuickLogin": "手机号快捷登录",
"register": "注册",
"complete": "完成",
"close": "关闭",
@ -60,7 +70,6 @@
"reserveSuccess": "预约成功",
"cardLink": "次卡",
"myLink": "我的",
"siteStatus": "站点状态",
"reserveBtn": "去抢购",
"cardBtn": "办理",
"soldOut": "已售",

View File

@ -217,6 +217,12 @@
},
"needLogin": true
},
{
"path": "app/pages/member/contact",
"style": {
"navigationBarTitleText": "%pages.member.contact%"
}
},
{
"path": "app/pages/pay/browser",
"style": {

View File

@ -1,7 +1,6 @@
import { defineStore } from 'pinia'
import { getConfig } from '@/app/api/auth'
import { getTabbarList } from '@/app/api/diy'
import { cloneDeep } from 'lodash-es'
interface loginConfig {
is_username: number | boolean,
@ -20,10 +19,10 @@ interface tabbarConfig {
interface Config {
login: loginConfig,
tabbarList:any,
tabbarList: any,
tabbar: tabbarConfig | null,
addon: String,
themeColor:any
themeColor: any
}
const useConfigStore = defineStore('config', {
@ -36,10 +35,10 @@ const useConfigStore = defineStore('config', {
is_bind_mobile: 0,
agreement_show: 0
},
tabbarList:{},
tabbarList: {},
tabbar: null,
addon: '',
themeColor:''
themeColor: ''
}
},
actions: {
@ -54,9 +53,9 @@ const useConfigStore = defineStore('config', {
})
},
async getTabbarConfig() {
await getTabbarList({}).then((res:any)=>{
await getTabbarList({}).then((res: any) => {
this.tabbarList = res.data;
}).catch(()=>{
}).catch(() => {
})
},
// 获取主色调
@ -68,7 +67,7 @@ const useConfigStore = defineStore('config', {
if (this.themeColor) {
let style = '';
for (let k in this.themeColor) {
style += `${k}:${this.themeColor[k]};`;
style += `${ k }:${ this.themeColor[k] };`;
}
return style;
}

View File

@ -1,24 +1,24 @@
import { defineStore } from 'pinia'
import { setToken, removeToken, redirect } from '@/utils/common'
import { getMemberInfo,getMemberLevel } from '@/app/api/member'
import { getMemberInfo, getMemberLevel } from '@/app/api/member'
import { logout } from '@/app/api/auth'
import useConfigStore from '@/stores/config'
interface Member {
token : string | null
info : AnyObject | null
levelList : Array<any> | null
token: string | null
info: AnyObject | null
levelList: Array<any> | null
}
const useMemberStore = defineStore('member', {
state: () : Member => {
state: (): Member => {
return {
token: uni.getStorageSync(import.meta.env.VITE_REQUEST_STORAGE_TOKEN_KEY),
info: null,
levelList:null
levelList: null
}
},
actions: {
async setToken(token : string) {
async setToken(token: string) {
this.token = token
setToken(token)
await this.getMemberInfo()
@ -27,32 +27,38 @@ const useMemberStore = defineStore('member', {
if (!this.token) return
await getMemberInfo().then((res: any) => {
this.info = res.data
uni.setStorageSync('wap_member_info',this.info)
uni.setStorageSync('wap_member_id',res.data.member_id)
}).catch(async () => {
uni.setStorageSync('wap_member_info', this.info)
uni.setStorageSync('wap_member_id', res.data.member_id)
}).catch(async() => {
await this.logout()
})
},
async logout(isRedirect : boolean = false) {
async logout(isRedirect: boolean = false) {
if (!this.token) return
this.token = ''
this.info = null
uni.setStorageSync('autoLoginLock', true)
if(useConfigStore().login.is_auth_register){
uni.setStorageSync('autoLoginLock', true) // todo 普通账号退出登录,在进行三方账号登录不会自动登录
}
await logout().then(() => {
removeToken()
uni.removeStorageSync('wap_member_info');
uni.removeStorageSync('openid');
uni.removeStorageSync('isbindmobile');
isRedirect && redirect({ url: '/app/pages/index/index', mode: 'switchTab' })
}).catch(() => {
removeToken()
uni.removeStorageSync('wap_member_info');
uni.removeStorageSync('openid');
uni.removeStorageSync('isbindmobile');
isRedirect && redirect({ url: '/app/pages/index/index', mode: 'switchTab' })
})
},
getMemberLevel(){
getMemberLevel().then((res:any)=>{
this.levelList = res.data
})
}
getMemberLevel() {
getMemberLevel().then((res: any) => {
this.levelList = res.data
})
}
}
})

View File

@ -1,6 +1,5 @@
import { defineStore } from 'pinia'
import { getSiteInfo, getMap } from '@/app/api/system'
import { redirect } from '@/utils/common'
interface System {
site: AnyObject | null,

View File

@ -4,9 +4,10 @@
--primary-color-disabled: #9acafc;
--primary-color-light: #ecf5ff;
--page-bg-color: #f7f7f7;
--sidebar-m: 20rpx;
--rounded-angle: 16rpx;
}
// 字体设置
// 价格字体设置
@font-face {
font-family: 'myFont';
/* #ifdef MP */
@ -16,10 +17,10 @@
src: url('@/styles/custom.ttf') format('truetype');
/* #endif */
}
.price-font{
font-family: 'myFont','-apple-system', 'BlinkMacSystemFont', 'Helvetica Neue', 'Helvetica', 'Segoe UI', 'Arial', 'Roboto', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft Yahei','sans-serif';
}
}
// 全局基础样式
uni-page-body {
line-height: 1.8;
@ -42,6 +43,72 @@ button[type='primary'],uni-button[type='primary']{
background-color: var(--primary-color) !important;
}
// 提交按钮背景颜色
.primary-btn-bg{
background: linear-gradient( 94deg, #FB7939 0%, #FE120E 99%), #EF000C;
}
// 侧边栏宽度
.sidebar-marign{
margin-left: var(--sidebar-m) !important;
margin-right: var(--sidebar-m) !important;
}
// 圆角
.rounded-angle{
border-radius: var(--rounded-angle);
}
// 卡片模块
.card-template{
padding: 30rpx;
border-radius: var(--rounded-angle);
background-color: #fff;
box-sizing: border-box;
}
// 适用于左边tab切换右边是日期参考页面如我的佣金销售奖励
.tab-style-1{
@apply box-border flex items-center justify-between;
padding: 0 var(--sidebar-m) 20rpx;
.tab-left{
@apply flex whitespace-nowrap;
.tab-left-item{
@apply font-400;
margin-left: 0;
margin-right: 40rpx;
color: #626779;
line-height: 40rpx;
font-size: 28rpx;
&.class-select{
position: relative;
font-weight: 500;
color: var(--primary-color);
&::before {
content: "";
position: absolute;
bottom: -14rpx;
height: 6rpx;
border-radius: 100rpx;
background-color: var(--primary-color);
width: 40rpx;
left: 50%;
transform: translateX(-50%);
}
}
}
}
.tab-right{
@apply flex items-center;
.tab-right-date{
font-size: 28rpx !important;
color: #333;
margin-right: 10rpx;
}
.tab-right-icon{
font-size: 30rpx !important;
}
}
}
/* 单行超出隐藏 */
.using-hidden {
word-break: break-all;
@ -105,3 +172,14 @@ button[type='primary'],uni-button[type='primary']{
color: #999;
}
/****************** u-cell-end *********************/
/******************** u-toolbar__wrapper__confirm start **********************/
.u-toolbar__wrapper__confirm{
color: var(--primary-color) !important;
}
/******************** u-toolbar__wrapper__confirm end **********************/
/******************** 物流 state **********************/
.u-steps-item__line.u-steps-item__line--column{
height:100% !important;
}
/******************** 物流 state **********************/

View File

@ -2,7 +2,7 @@
width: 100%;
height: 100%;
box-sizing: border-box;
background-size: contain;
background-size: 100%;
background-repeat: no-repeat !important;
}

View File

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 3952239 */
src: url('//at.alicdn.com/t/c/font_3952239_da988xfzfy9.woff2?t=1718609129756') format('woff2'),
url('//at.alicdn.com/t/c/font_3952239_da988xfzfy9.woff?t=1718609129756') format('woff'),
url('//at.alicdn.com/t/c/font_3952239_da988xfzfy9.ttf?t=1718609129756') format('truetype');
src: url('//at.alicdn.com/t/c/font_3952239_mvhdfb735e.woff2?t=1719994029682') format('woff2'),
url('//at.alicdn.com/t/c/font_3952239_mvhdfb735e.woff?t=1719994029682') format('woff'),
url('//at.alicdn.com/t/c/font_3952239_mvhdfb735e.ttf?t=1719994029682') format('truetype');
}
.iconfont {
@ -13,6 +13,30 @@
-moz-osx-font-smoothing: grayscale;
}
.iconyouV6xx:before {
content: "\e648";
}
.iconguanzhuV6xx:before {
content: "\e79b";
}
.iconxihuanV6mm:before {
content: "\e691";
}
.iconfapiao:before {
content: "\e86b";
}
.iconlishijiluV6xx:before {
content: "\e6f6";
}
.iconchaochangyoujiantouV6xx:before {
content: "\e6fc";
}
.iconyuanhu:before {
content: "\e644";
}

View File

@ -1,7 +1,7 @@
.member-record-list{
@apply min-h-[100vh];
.member-record-item{
@apply relative mx-4 border-solid border-t-0 border-l-0 border-r-0 border-b-1 border-[#ECEBEC] py-3;
@apply relative sidebar-marign border-solid border-t-0 border-l-0 border-r-0 border-b-1 border-[#ECEBEC] py-3 mx-[var(--sidebar-m)];
.name{
@apply text-sm;
}
@ -12,10 +12,10 @@
color: #FF0D3E;
}
.money{
@apply absolute right-3 top-4 text-base font-bold;
@apply absolute right-0 top-4 text-base font-bold;
}
.state{
@apply absolute right-3 top-11 text-[#8D8C8D] text-xs;
@apply absolute right-0 top-11 text-[#8D8C8D] text-xs;
}
}
}

View File

@ -1,8 +1,8 @@
@font-face {
font-family: "nc-iconfont"; /* Project id 4567203 */
src: url('//at.alicdn.com/t/c/font_4567203_jiym07jhp7i.woff2?t=1718104706175') format('woff2'),
url('//at.alicdn.com/t/c/font_4567203_jiym07jhp7i.woff?t=1718104706175') format('woff'),
url('//at.alicdn.com/t/c/font_4567203_jiym07jhp7i.ttf?t=1718104706175') format('truetype');
src: url('//at.alicdn.com/t/c/font_4567203_fc0pt9szyn7.woff2?t=1721726440236') format('woff2'),
url('//at.alicdn.com/t/c/font_4567203_fc0pt9szyn7.woff?t=1721726440236') format('woff'),
url('//at.alicdn.com/t/c/font_4567203_fc0pt9szyn7.ttf?t=1721726440236') format('truetype');
}
.nc-iconfont {
@ -13,6 +13,18 @@
-moz-osx-font-smoothing: grayscale;
}
.nc-icon-a-xiangshangV6xx1:before {
content: "\e799";
}
.nc-icon-a-xiangxiaV6xx1:before {
content: "\e796";
}
.nc-icon-fuzhiV6xx1:before {
content: "\e76c";
}
.nc-icon-kefuV6xx1:before {
content: "\e76a";
}

View File

@ -7,7 +7,7 @@ const loginBack = useLogin()
/**
*
*/
export function checkNeedLogin(route: AnyObject){
export function checkNeedLogin(route: AnyObject) {
const pages = getNeedLoginPages()
if (pages.includes(route.path) && !getToken()) {

View File

@ -2,6 +2,8 @@ import { getTabbarPages } from './pages'
import useDiyStore from '@/app/stores/diy'
import useMemberStore from '@/stores/member'
import useSystemStore from '@/stores/system'
import useConfigStore from '@/stores/config'
import { getNeedLoginPages } from '@/utils/pages'
/**
*
@ -11,6 +13,14 @@ export const redirect = (redirect : redirectOptions) => {
if (useDiyStore().mode == 'decorate') return
let { url, mode, param, success, fail, complete } = redirect
const config = useConfigStore()
// 如果未开启普通账号登录注册,不展示登录注册页面
if(!getToken() && getNeedLoginPages().indexOf(url) != -1 && !config.login.is_username && !config.login.is_mobile && !config.login.is_bind_mobile){
uni.showToast({ title: '商家未开启普通账号登录注册', icon: 'none' })
return
}
mode = mode || 'navigateTo'
const tabBar = getTabbarPages()
tabBar.includes(url) && (mode = 'switchTab')
@ -442,3 +452,8 @@ const isArray = (value: any) => {
return Object.prototype.toString.call(value) === '[object Array]'
}
// px转rpx
export function pxToRpx(px: any) {
const screenWidth = uni.getSystemInfoSync().screenWidth;
return (750 * Number.parseInt(px)) / screenWidth;
}

View File

@ -1,6 +1,6 @@
import { language } from '@/locale'
import { checkNeedLogin } from '@/utils/auth'
import { redirect, getToken, isWeixinBrowser } from '@/utils/common'
import { getToken } from '@/utils/common'
import { memberLog } from '@/app/api/auth'
import useConfigStore from "@/stores/config";
import { useShare } from '@/hooks/useShare'
@ -81,7 +81,7 @@ const setAddonName = async (path: string) => {
// 设置插件应用的主色调,排除系统
if (route != 'app') {
try {
const theme = await import(`../addon/${route}/utils/theme.json`)
const theme = await import(`../addon/${ route }/utils/theme.json`)
configStore.themeColor = theme.default
uni.setStorageSync('current_theme_color', JSON.stringify(theme.default));
} catch (e) {
@ -89,10 +89,11 @@ const setAddonName = async (path: string) => {
}
}
}
// 加载分享
const loadShare = () => {
const { setShare } = useShare()
setShare()
}
}

View File

@ -4,16 +4,16 @@ import pagesJson from '@/pages.json'
*
*/
export function getNeedLoginPages() {
const pages = []
const pages: any = []
// 获取主包中需要登录的页面
pagesJson.pages.forEach(item => {
if (item.needLogin) pages.push(`/${item.path}`)
if (item.needLogin) pages.push(`/${ item.path }`)
})
// 获取分包中需要登录的页面
if (pagesJson.subPackages) {
pagesJson.subPackages.forEach(subPackages => {
subPackages.pages.forEach(item => {
if (item.needLogin) pages.push(`/${subPackages.root}/${item.path}`)
if (item.needLogin) pages.push(`/${ subPackages.root }/${ item.path }`)
})
})
}
@ -24,21 +24,21 @@ export function getNeedLoginPages() {
*
*/
export function getAppPages() {
const pages = []
const pages: any = []
// 获取主包中需要登录的页面
pagesJson.pages.forEach(item => {
pages.push(`/${item.path}`)
pages.push(`/${ item.path }`)
})
return pages
}
export function getSubPackagesPages() {
const pages = []
const pages: any = []
// 获取分包中需要登录的页面
if (pagesJson.subPackages) {
pagesJson.subPackages.forEach(subPackages => {
subPackages.pages.forEach(item => {
pages.push(`/${subPackages.root}/${item.path}`)
pages.push(`/${ subPackages.root }/${ item.path }`)
})
})
}
@ -49,7 +49,9 @@ export function getSubPackagesPages() {
* tabbar
*/
export function getTabbarPages() {
return pagesJson.tabBar.list.map(item => { return `/${item.pagePath}` })
return pagesJson.tabBar.list.map(item => {
return `/${ item.pagePath }`
})
}
/**

View File

@ -4,181 +4,182 @@ import { getToken, getAppChannel, redirect, currRoute } from './common'
import qs from 'qs'
interface RequestConfig {
showErrorMessage ?: boolean
showSuccessMessage ?: boolean
showErrorMessage?: boolean
showSuccessMessage?: boolean
}
interface RequestOptions extends UniNamespace.RequestOptions, RequestOptions { }
interface RequestOptions extends UniNamespace.RequestOptions, RequestOptions {
}
class Request {
private baseUrl : string
private baseUrl: string
private config : RequestOptions = {
url: '',
header: {}
}
private config: RequestOptions = {
url: '',
header: {}
}
constructor() {
// #ifdef H5
this.baseUrl = import.meta.env.VITE_APP_BASE_URL || `${location.origin}/api/`
// #endif
// #ifndef H5
this.baseUrl = import.meta.env.VITE_APP_BASE_URL
// #endif
this.baseUrl.substr(-1) != '/' && (this.baseUrl += '/')
constructor() {
// #ifdef H5
this.baseUrl = import.meta.env.VITE_APP_BASE_URL || `${ location.origin }/api/`
// #endif
// #ifndef H5
this.baseUrl = import.meta.env.VITE_APP_BASE_URL
// #endif
this.baseUrl.substr(-1) != '/' && (this.baseUrl += '/')
try {
this.config.header[import.meta.env.VITE_REQUEST_HEADER_CHANNEL_KEY] = getAppChannel()
} catch (e) {
}
try {
this.config.header[import.meta.env.VITE_REQUEST_HEADER_CHANNEL_KEY] = getAppChannel()
} catch (e) {
}
}
}
/**
*
*/
private requestInterceptors() {
// 携带token
try {
getToken() && (this.config.header[import.meta.env.VITE_REQUEST_HEADER_TOKEN_KEY] = getToken())
this.config.header[import.meta.env.VITE_REQUEST_HEADER_CHANNEL_KEY] = getAppChannel()
} catch (e) {
}
}
/**
*
*/
private requestInterceptors() {
// 携带token
try {
getToken() && (this.config.header[import.meta.env.VITE_REQUEST_HEADER_TOKEN_KEY] = getToken())
this.config.header[import.meta.env.VITE_REQUEST_HEADER_CHANNEL_KEY] = getAppChannel()
} catch (e) {
}
}
public get(url : string, data : AnyObject = {}, config : RequestConfig = {}) {
return this.request('GET', url, data, config)
}
public get(url: string, data: AnyObject = {}, config: RequestConfig = {}) {
return this.request('GET', url, data, config)
}
public post(url : string, data : AnyObject = {}, config : RequestConfig = {}) {
return this.request('POST', url, data, config)
}
public post(url: string, data: AnyObject = {}, config: RequestConfig = {}) {
return this.request('POST', url, data, config)
}
public put(url : string, data : AnyObject = {}, config : RequestConfig = {}) {
return this.request('PUT', url, data, config)
}
public put(url: string, data: AnyObject = {}, config: RequestConfig = {}) {
return this.request('PUT', url, data, config)
}
public delete(url : string, config : RequestConfig = {}) {
return this.request('DELETE', url, {}, config)
}
public delete(url: string, config: RequestConfig = {}) {
return this.request('DELETE', url, {}, config)
}
/**
*
*/
public upload(url : string, data : AnyObject = {}, config : RequestConfig = {}) {
this.requestInterceptors()
/**
*
*/
public upload(url: string, data: AnyObject = {}, config: RequestConfig = {}) {
this.requestInterceptors()
const params = Object.assign(uni.$u.deepClone(this.config), config, {
url: this.baseUrl + url,
...data
})
const params = Object.assign(uni.$u.deepClone(this.config), config, {
url: this.baseUrl + url,
...data
})
return new Promise((resolve, reject) => {
uni.uploadFile({
...params,
success: res => {
const data = JSON.parse(res.data)
if (data.code == 1) {
this.config.showSuccessMessage && uni.showToast({ title: data.msg, icon: 'none' })
resolve(data)
} else {
if (data.code == 0 || data.code == 400) {
if (this.config.showErrorMessage !== false) uni.showToast({ title: data.msg, icon: 'none' })
} else {
this.handleAuthError(data.code)
}
reject(data)
}
},
fail: res => {
reject(res)
}
})
})
}
/**
*
*/
private request(method : string, url : string, data ?: AnyObject, config : RequestConfig = {}) {
this.requestInterceptors()
const params = Object.assign(uni.$u.deepClone(this.config), config,{
url: this.baseUrl + url,
method
})
if (params.method.toUpperCase() == 'GET') {
params.url += '?' + qs.stringify(data);
} else {
params.data = data;
}
return new Promise((resolve, reject) => {
uni.request({
...params,
success: res => {
const data = res.data
if (data.code == 1) {
config.showSuccessMessage && uni.showToast({ title: data.msg, icon: 'none' })
resolve(data)
} else {
return new Promise((resolve, reject) => {
uni.uploadFile({
...params,
success: res => {
const data = JSON.parse(res.data)
if (data.code == 1) {
this.config.showSuccessMessage && uni.showToast({ title: data.msg, icon: 'none' })
resolve(data)
} else {
if (data.code == 0 || data.code == 400) {
if (config.showErrorMessage !== false) uni.showToast({ title: data.msg, icon: 'none' })
} else {
if (this.config.showErrorMessage !== false) uni.showToast({ title: data.msg, icon: 'none' })
} else {
this.handleAuthError(data.code)
}
reject(data)
}
},
fail: res => {
reject(res)
},
complete: (res) => {
this.handleRequestFail(res)
}
})
})
}
reject(data)
}
},
fail: res => {
reject(res)
}
})
})
}
private handleAuthError(code : number) {
switch (code) {
case 401:
useMemberStore().logout()
break;
case 402:
if(currRoute().indexOf('app/pages/index/close') != -1) return;
redirect({url: '/app/pages/index/close', mode: 'reLaunch'})
break;
case 403:
if(currRoute().indexOf('app/pages/index/nosite') != -1) return;
redirect({url: '/app/pages/index/nosite', mode: 'reLaunch'})
break;
}
}
/**
*
*/
private request(method: string, url: string, data ?: AnyObject, config: RequestConfig = {}) {
this.requestInterceptors()
private handleRequestFail(res) {
if (res.errMsg && res.errMsg == "request:ok") {
if (typeof res.data == 'string') {
// #ifdef H5
const err = (isUrl(this.baseUrl) ? this.baseUrl : location.origin + this.baseUrl) + t('baseUrlError')
// #endif
// #ifndef H5
const err = this.baseUrl + t('baseUrlError')
// #endif
uni.showToast({icon: 'none', title: err })
return
}
}
if (res.errMsg == 'request:fail') {
uni.showToast({ icon: 'none', title: this.baseUrl + t('requestFail') })
return
}
if (res.errMsg && res.errMsg == 'request:fail url not in domain list') {
uni.showToast({ icon: 'none', title: this.baseUrl + t('notInDomainList') });
return
}
}
const params = Object.assign(uni.$u.deepClone(this.config), config, {
url: this.baseUrl + url,
method
})
if (params.method.toUpperCase() == 'GET') {
params.url += '?' + qs.stringify(data);
} else {
params.data = data;
}
return new Promise((resolve, reject) => {
uni.request({
...params,
success: res => {
const data = res.data
if (data.code == 1) {
config.showSuccessMessage && uni.showToast({ title: data.msg, icon: 'none' })
resolve(data)
} else {
if (data.code == 0 || data.code == 400) {
if (config.showErrorMessage !== false) uni.showToast({ title: data.msg, icon: 'none' })
} else {
this.handleAuthError(data.code)
}
reject(data)
}
},
fail: res => {
reject(res)
},
complete: (res) => {
this.handleRequestFail(res)
}
})
})
}
private handleAuthError(code: number) {
switch (code) {
case 401:
useMemberStore().logout()
break;
case 402:
if (currRoute().indexOf('app/pages/index/close') != -1) return;
redirect({ url: '/app/pages/index/close', mode: 'reLaunch' })
break;
case 403:
if (currRoute().indexOf('app/pages/index/nosite') != -1) return;
redirect({ url: '/app/pages/index/nosite', mode: 'reLaunch' })
break;
}
}
private handleRequestFail(res) {
if (res.errMsg && res.errMsg == "request:ok") {
if (typeof res.data == 'string') {
// #ifdef H5
const err = (isUrl(this.baseUrl) ? this.baseUrl : location.origin + this.baseUrl) + t('baseUrlError')
// #endif
// #ifndef H5
const err = this.baseUrl + t('baseUrlError')
// #endif
uni.showToast({ icon: 'none', title: err })
return
}
}
if (res.errMsg == 'request:fail') {
uni.showToast({ icon: 'none', title: this.baseUrl + t('requestFail') })
return
}
if (res.errMsg && res.errMsg == 'request:fail url not in domain list') {
uni.showToast({ icon: 'none', title: this.baseUrl + t('notInDomainList') });
return
}
}
}
export default new Request()

View File

@ -10,31 +10,31 @@ export function uniStorage(){
const getStorageSync = uni.getStorageSync
const removeStorage = uni.removeStorage
const removeStorageSync = uni.removeStorageSync
uni.setStorage = (options: UniNamespace.SetStorageOptions)=> {
options.key = handleKey(options.key)
setStorage(options)
}
uni.setStorageSync = (key: string, data: any) => {
setStorageSync(handleKey(key), data)
}
uni.getStorage = (options: UniNamespace.GetStorageOptions) => {
options.key = handleKey(options.key)
getStorage(options)
}
uni.getStorageSync = (key: string) => {
return getStorageSync(handleKey(key))
}
uni.removeStorage = (options: UniNamespace.RemoveStorageOptions) => {
options.key = handleKey(options.key)
removeStorage(options)
}
uni.removeStorageSync = (key: string) => {
return removeStorageSync(handleKey(key))
}
}
}

View File

@ -0,0 +1,58 @@
import { ref } from 'vue';
import { onPageScroll } from '@dcloudio/uni-app';
export function topTabar() {
const param = ref({
title:'',
topStatusBar: {
style: 'style-1',
bgColor: 'transparent',
rollBgColor: '#fff',
textColor: '#fff',
rollTextColor: '#333'
}
})
let scrollVal = ref(1); // 默认的传入滚动值
let scrollBool = ref(-1);
// 设置初始数据
const setTopTabbarParam = (data: Object = {}) => {
if(data && typeof data != 'object') return param
for(let key in data){
if(key == 'title'){
param.value.title = data.title || '';
}else if(key == 'topStatusBar' && data.topStatusBar){
for(let subKey in data.topStatusBar){
param.value.topStatusBar[subKey] = data.topStatusBar[subKey]
}
}else{
param.value[key] = data[key]
}
}
return param.value;
}
onPageScroll((e)=>{
if(e.scrollTop <= 0){
// -1 表示页面滚动值小于零,头部组件随页面下拉而下来
scrollBool.value = -1;
}else if(e.scrollTop > scrollVal.value){
// 1 表示页面滚动值大于传入滚动值,头部组件随页面上拉背景、文字颜色采用滚动后的变量
scrollBool.value = 1
}else{
// 2 表示页面滚动值小于传入滚动值,头部组件随页面下拉背景、文字颜色采用滚动前的变量
scrollBool.value = 2
}
})
const getScrollBool = () => {
return scrollBool.value;
}
return {
getScrollBool,
setTopTabbarParam
}
}