2232
This commit is contained in:
parent
53cb4a7b89
commit
4e191d6c39
|
|
@ -4,8 +4,21 @@ import * as utils3 from './system/router';
|
|||
import * as utils4 from './system/request';
|
||||
// 动态合并所有导出到 yds 对象
|
||||
export const com = {
|
||||
...utils1,
|
||||
...utils2,
|
||||
...utils3,
|
||||
...utils4,
|
||||
...utils1,
|
||||
...utils2,
|
||||
...utils3,
|
||||
...utils4,
|
||||
};
|
||||
|
||||
|
||||
export const useLogin = async () => {
|
||||
return new Promise((resolve) => {
|
||||
uni.login({
|
||||
provider: 'weixin', //使用微信登录
|
||||
success: function (loginRes) {
|
||||
// console.log(loginRes);
|
||||
resolve(loginRes.code)
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -13,9 +13,12 @@ export const preloadConfigData = async () => {
|
|||
configData.value = {
|
||||
config: res
|
||||
};
|
||||
console.log("configData.value",configData.value);
|
||||
console.log("configData.value", configData.value);
|
||||
};
|
||||
|
||||
export const getConfigData = () => {
|
||||
export const getConfigData = async () => {
|
||||
if (configData.value == null) {
|
||||
await preloadConfigData();
|
||||
}
|
||||
return configData.value;
|
||||
}
|
||||
28
common/server/interface/article.js
Normal file
28
common/server/interface/article.js
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import request from '@/common/system/request';
|
||||
|
||||
|
||||
/**
|
||||
* 获取单个文章内容
|
||||
* @param {number} id 文章ID
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
export const getArticleDetail = async (id) => {
|
||||
const res = await request.getOrCache("Article/GetArticleDetail", { id });
|
||||
if (res.code == 0) {
|
||||
return res.data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取通知列表
|
||||
* @param {Object} params 查询参数
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
export const noticeList = async (params) => {
|
||||
const res = await request.post("Article/NoticeList", params);
|
||||
if (res.code == 0) {
|
||||
return res.data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
import request from '@/common/system/request';
|
||||
|
||||
|
||||
/**
|
||||
* 查询用户是否可以成为分销商
|
||||
* 匿名登录
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
export const getDistributionInfo = async () => {
|
||||
const res = await request.post("Distribution/Info");
|
||||
export const getAnonymousLogin = async (code) => {
|
||||
const res = await request.post("user/UseAnonymousLogin", { code: code });
|
||||
if (res.code == 0) {
|
||||
return res.data;
|
||||
}
|
||||
|
|
@ -13,12 +14,13 @@ export const getDistributionInfo = async () => {
|
|||
}
|
||||
|
||||
/**
|
||||
* 申请成为分销商接口
|
||||
* @param {Object} data 分销商申请数据
|
||||
* @returns {Promise<any>}
|
||||
* 微信小程序授权拉取手机号码并登录
|
||||
* @param {*} code
|
||||
* @param {*} sessionAuthId
|
||||
* @returns
|
||||
*/
|
||||
export const applyDistribution = async (data) => {
|
||||
const res = await request.post("Distribution/ApplyDistribution", data);
|
||||
export const ueWxPhoneNumberLogin = async (code, sessionAuthId) => {
|
||||
const res = await request.post("user/UseWxPhoneNumberLogin", { code: code, sessionAuthId: sessionAuthId });
|
||||
if (res.code == 0) {
|
||||
return res.data;
|
||||
}
|
||||
|
|
@ -26,12 +28,13 @@ export const applyDistribution = async (data) => {
|
|||
}
|
||||
|
||||
/**
|
||||
* 获取分销商排行
|
||||
* @param {Object} params 分页参数
|
||||
* @returns {Promise<any>}
|
||||
* 微信小程序匿名授权登录,手机号已授权过
|
||||
* @param {*} code
|
||||
* @param {*} sessionAuthId
|
||||
* @returns
|
||||
*/
|
||||
export const getDistributionRanking = async (params) => {
|
||||
const res = await request.post("Distribution/GetDistributionRanking", params);
|
||||
export const useWxAnonymousLogin = async (sessionAuthId) => {
|
||||
const res = await request.post("user/UseWxAnonymousLogin", { sessionAuthId: sessionAuthId });
|
||||
if (res.code == 0) {
|
||||
return res.data;
|
||||
}
|
||||
|
|
@ -39,25 +42,13 @@ export const getDistributionRanking = async (params) => {
|
|||
}
|
||||
|
||||
/**
|
||||
* 获取我的订单统计
|
||||
* @returns {Promise<any>}
|
||||
* 获取用户信息
|
||||
* @returns
|
||||
*/
|
||||
export const getOrderSum = async () => {
|
||||
const res = await request.post("Distribution/GetOrderSum");
|
||||
export const getUserInfo = async () => {
|
||||
const res = await request.post("user/GetUserInfo");
|
||||
if (res.code == 0) {
|
||||
return res.data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取我的下级用户数量
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
export const getTeamSum = async () => {
|
||||
const res = await request.post("Distribution/GetTeamSum");
|
||||
if (res.code == 0) {
|
||||
return res.data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
0
common/server/login.js
Normal file
0
common/server/login.js
Normal file
18
common/server/user.js
Normal file
18
common/server/user.js
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { getUserInfo } from '@/common/server/interface/user'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export var userInfo = ref(null);
|
||||
|
||||
export const loadUserInfo = async () => {
|
||||
const res = await getUserInfo();
|
||||
if (res == null) {
|
||||
|
||||
userInfo.value = null;
|
||||
uni.removeStorageSync('tokenInfo');
|
||||
uni.removeStorageSync('userInfo');
|
||||
return;
|
||||
}
|
||||
userInfo.value = res;
|
||||
uni.setStorageSync('userInfo', res);
|
||||
}
|
||||
|
||||
|
|
@ -101,7 +101,7 @@ class request {
|
|||
return new Promise((resolve, reject) => {
|
||||
// 使用传入的method而不是重新声明
|
||||
const requestMethod = method.toUpperCase();
|
||||
const token = uni.getStorageSync('token');
|
||||
|
||||
let data = { ...fromData }; // 创建数据的深拷贝,避免修改原数据
|
||||
|
||||
// 构建请求URL和提取主机名
|
||||
|
|
@ -122,9 +122,10 @@ class request {
|
|||
const header = {
|
||||
'content-type': 'application/json'
|
||||
};
|
||||
if(token!=null&&token!=""){
|
||||
header['Authorization']='Bearer ' + token;
|
||||
}
|
||||
const tokenInfo = uni.getStorageSync('tokenInfo');
|
||||
if (tokenInfo != null && tokenInfo != "") {
|
||||
header['Authorization'] = 'Bearer ' + tokenInfo.token;
|
||||
}
|
||||
|
||||
const startDate = Date.now();
|
||||
|
||||
|
|
|
|||
|
|
@ -29,5 +29,6 @@ export const navigateToAccountLogin = (page = "") => {
|
|||
* @param {String} type 协议类型
|
||||
*/
|
||||
export const navigateToAgreement = (type) => {
|
||||
// navigateTo(`/pages/other/agreement?type=${type}`);
|
||||
|
||||
navigateTo(`/pages/other/agreement?type=${type}`);
|
||||
};
|
||||
4
components.d.ts
vendored
4
components.d.ts
vendored
|
|
@ -8,8 +8,12 @@ export {}
|
|||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
Container: typeof import('./components/com/page/container.vue')['default']
|
||||
MahjongCard: typeof import('./components/index/MahjongCard.vue')['default']
|
||||
NoData: typeof import('./components/com/page/no-data.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
UniNavBar: typeof import('./components/uni-nav-bar/uni-nav-bar.vue')['default']
|
||||
UniStatusBar: typeof import('./components/uni-nav-bar/uni-status-bar.vue')['default']
|
||||
}
|
||||
}
|
||||
|
|
|
|||
132
components/com/page/container.vue
Normal file
132
components/com/page/container.vue
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
<!-- 详情 -->
|
||||
<template>
|
||||
<view>
|
||||
<z-paging ref="paging" refresher-only @onRefresh="onRefresh">
|
||||
<template #top>
|
||||
<uniNavBar :title="title" @clickLeft="onClickLeft" :leftIcon="leftIcon" />
|
||||
</template>
|
||||
<view class="page-container">
|
||||
<view class="page-container__content">
|
||||
<view class="page-container__not-data" v-if="showNotData">
|
||||
|
||||
</view>
|
||||
<view class="page-container__loading" v-if="showLoading" @click.stop="mengban">
|
||||
|
||||
</view>
|
||||
<slot></slot>
|
||||
</view>
|
||||
</view>
|
||||
</z-paging>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ref,
|
||||
computed
|
||||
} from 'vue'
|
||||
import {
|
||||
uniNavBar
|
||||
} from '@/components/uni-nav-bar/uni-nav-bar.vue'
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
showBack: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showNotData: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
refresh: {
|
||||
type: Function,
|
||||
default: function(refresh) {
|
||||
// refresh.complete();
|
||||
}
|
||||
},
|
||||
showLoading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
let paging = ref(null);
|
||||
const leftIcon = computed(() => {
|
||||
if (props.showBack) {
|
||||
return "/static/back.png";
|
||||
}
|
||||
});
|
||||
const onClickLeft = () => {
|
||||
if (props.showBack) {
|
||||
uni.navigateBack();
|
||||
}
|
||||
}
|
||||
const onRefresh = () => {
|
||||
if (props.refresh) {
|
||||
props.refresh(paging.value);
|
||||
} else {
|
||||
paging.value.complete();
|
||||
}
|
||||
}
|
||||
const getPaging = () => {
|
||||
return paging.value;
|
||||
}
|
||||
const mengban = () => {
|
||||
|
||||
}
|
||||
defineExpose({
|
||||
getPaging
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page-container {
|
||||
width: 100vw;
|
||||
min-height: 100vh;
|
||||
box-sizing: border-box;
|
||||
|
||||
|
||||
&__content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&__divider {
|
||||
width: 100%;
|
||||
height: 4rpx;
|
||||
background-color: #e5e5e5;
|
||||
/* 使用较浅的灰色 */
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
margin-bottom: 10rpx;
|
||||
/* 在分割线下方添加一些间距 */
|
||||
}
|
||||
|
||||
&__not-data {
|
||||
width: 100%;
|
||||
height: 80vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__loading {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
// background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
58
components/com/page/no-data.vue
Normal file
58
components/com/page/no-data.vue
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<template>
|
||||
<view class="empty-state">
|
||||
<image class="empty-image" :src="imageSrc" mode="aspectFit"></image>
|
||||
<text class="empty-text">{{ message }}</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
// 空状态显示的图片,默认使用kong.png
|
||||
imageSrc: {
|
||||
type: String,
|
||||
default: '/static/no_content.png'
|
||||
},
|
||||
// 空状态显示的文本
|
||||
message: {
|
||||
type: String,
|
||||
default: '暂无数据'
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.empty-state {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
// border: 1px solid red;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
animation: emptyFadeIn 0.5s ease-out;
|
||||
// background-color: #F7F7F7;
|
||||
}
|
||||
|
||||
.empty-image {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
@keyframes emptyFadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20rpx);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
360
components/uni-nav-bar/uni-nav-bar.vue
Normal file
360
components/uni-nav-bar/uni-nav-bar.vue
Normal file
|
|
@ -0,0 +1,360 @@
|
|||
<template>
|
||||
<view class="uni-navbar" :class="{ 'uni-dark': dark, 'uni-nvue-fixed': fixed }">
|
||||
<view class="uni-navbar__content"
|
||||
:class="{ 'uni-navbar--fixed': fixed, 'uni-navbar--shadow': shadow, 'uni-navbar--border': border }"
|
||||
:style="{ 'background-color': themeBgColor, 'border-bottom-color': themeColor }">
|
||||
<status-bar v-if="statusBar" />
|
||||
<view :style="{ color: themeColor, backgroundColor: themeBgColor, height: navbarHeight }"
|
||||
class="uni-navbar__header">
|
||||
<view @tap="onClickLeft" class="uni-navbar__header-btns uni-navbar__header-btns-left"
|
||||
:style="{ width: leftIconWidth }">
|
||||
<slot name="left">
|
||||
<view class="uni-navbar__content_view" v-if="leftIcon.length > 0">
|
||||
<image :src="leftIcon" mode="aspectFill" style="width: 22px; height: 22px;" />
|
||||
</view>
|
||||
<view :class="{ 'uni-navbar-btn-icon-left': !leftIcon.length > 0 }" class="uni-navbar-btn-text"
|
||||
v-if="leftText.length">
|
||||
<text :style="{ color: themeColor, fontSize: '12px' }">{{ leftText }}</text>
|
||||
</view>
|
||||
</slot>
|
||||
</view>
|
||||
<view class="uni-navbar__header-container " @tap="onClickTitle">
|
||||
<slot>
|
||||
<view class="uni-navbar__header-container-inner" v-if="title.length > 0">
|
||||
<text class="uni-nav-bar-text uni-ellipsis-1" :style="{ color: themeColor }">{{ title
|
||||
}}</text>
|
||||
</view>
|
||||
</slot>
|
||||
</view>
|
||||
<view @click="onClickRight" class="uni-navbar__header-btns uni-navbar__header-btns-right"
|
||||
:style="{ width: rightIconWidth }">
|
||||
<slot name="right">
|
||||
<view v-if="rightIcon.length">
|
||||
<image :src="rightIcon" mode="aspectFill" style="width: 22px; height: 22px;" />
|
||||
|
||||
</view>
|
||||
<view class="uni-navbar-btn-text" v-if="rightText.length && !rightIcon.length">
|
||||
<text class="uni-nav-bar-right-text" :style="{ color: themeColor }">{{ rightText }}</text>
|
||||
</view>
|
||||
</slot>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- #ifndef APP-NVUE -->
|
||||
<view class="uni-navbar__placeholder" v-if="fixed">
|
||||
<status-bar v-if="statusBar" />
|
||||
<view class="uni-navbar__placeholder-view" :style="{ height: navbarHeight }" />
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import statusBar from "./uni-status-bar.vue";
|
||||
const getVal = (val) => typeof val === 'number' ? val + 'px' : val;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* NavBar 自定义导航栏
|
||||
* @description 导航栏组件,主要用于头部导航
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=52
|
||||
* @property {Boolean} dark 开启黑暗模式
|
||||
* @property {String} title 标题文字
|
||||
* @property {String} leftText 左侧按钮文本
|
||||
* @property {String} rightText 右侧按钮文本
|
||||
* @property {String} leftIcon 左侧按钮图标(图标类型参考 [Icon 图标](http://ext.dcloud.net.cn/plugin?id=28) type 属性)
|
||||
* @property {String} rightIcon 右侧按钮图标(图标类型参考 [Icon 图标](http://ext.dcloud.net.cn/plugin?id=28) type 属性)
|
||||
* @property {String} color 图标和文字颜色
|
||||
* @property {String} backgroundColor 导航栏背景颜色
|
||||
* @property {Boolean} fixed = [true|false] 是否固定顶部
|
||||
* @property {Boolean} statusBar = [true|false] 是否包含状态栏
|
||||
* @property {Boolean} shadow = [true|false] 导航栏下是否有阴影
|
||||
* @property {Boolean} stat 是否开启统计标题上报
|
||||
* @event {Function} clickLeft 左侧按钮点击时触发
|
||||
* @event {Function} clickRight 右侧按钮点击时触发
|
||||
* @event {Function} clickTitle 中间标题点击时触发
|
||||
*/
|
||||
export default {
|
||||
name: "UniNavBar",
|
||||
components: {
|
||||
statusBar
|
||||
},
|
||||
emits: ['clickLeft', 'clickRight', 'clickTitle'],
|
||||
props: {
|
||||
dark: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
leftText: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
rightText: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
leftIcon: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
rightIcon: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
fixed: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
backgroundColor: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
statusBar: {
|
||||
type: [Boolean, String],
|
||||
default: true
|
||||
},
|
||||
shadow: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
border: {
|
||||
type: [Boolean, String],
|
||||
default: true
|
||||
},
|
||||
height: {
|
||||
type: [Number, String],
|
||||
default: 44
|
||||
},
|
||||
leftWidth: {
|
||||
type: [Number, String],
|
||||
default: 60
|
||||
},
|
||||
rightWidth: {
|
||||
type: [Number, String],
|
||||
default: 60
|
||||
},
|
||||
stat: {
|
||||
type: [Boolean, String],
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
themeBgColor() {
|
||||
if (this.dark) {
|
||||
// 默认值
|
||||
if (this.backgroundColor) {
|
||||
return this.backgroundColor
|
||||
} else {
|
||||
return this.dark ? '#333' : '#FFF'
|
||||
}
|
||||
}
|
||||
return this.backgroundColor || '#FFF'
|
||||
},
|
||||
themeColor() {
|
||||
if (this.dark) {
|
||||
// 默认值
|
||||
if (this.color) {
|
||||
return this.color
|
||||
} else {
|
||||
return this.dark ? '#fff' : '#333'
|
||||
}
|
||||
}
|
||||
return this.color || '#333'
|
||||
},
|
||||
navbarHeight() {
|
||||
return getVal(this.height)
|
||||
},
|
||||
leftIconWidth() {
|
||||
return getVal(this.leftWidth)
|
||||
},
|
||||
rightIconWidth() {
|
||||
return getVal(this.rightWidth)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (uni.report && this.stat && this.title !== '') {
|
||||
uni.report('title', this.title)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onClickLeft() {
|
||||
this.$emit("clickLeft");
|
||||
},
|
||||
onClickRight() {
|
||||
this.$emit("clickRight");
|
||||
},
|
||||
onClickTitle() {
|
||||
this.$emit("clickTitle");
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$nav-height: 44px;
|
||||
|
||||
.uni-nvue-fixed {
|
||||
/* #ifdef APP-NVUE */
|
||||
position: sticky;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-navbar {
|
||||
// box-sizing: border-box;
|
||||
}
|
||||
|
||||
.uni-nav-bar-text {
|
||||
/* #ifdef APP-PLUS */
|
||||
font-size: 34rpx;
|
||||
/* #endif */
|
||||
/* #ifndef APP-PLUS */
|
||||
font-size: 14px;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-nav-bar-right-text {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.uni-navbar__content {
|
||||
position: relative;
|
||||
// background-color: #fff;
|
||||
// box-sizing: border-box;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-navbar__content_view {
|
||||
// box-sizing: border-box;
|
||||
}
|
||||
|
||||
.uni-navbar-btn-text {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
line-height: 12px;
|
||||
}
|
||||
|
||||
.uni-navbar__header {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
padding: 0 10px;
|
||||
flex-direction: row;
|
||||
height: $nav-height;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.uni-navbar__header-btns {
|
||||
/* #ifndef APP-NVUE */
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-wrap: nowrap;
|
||||
flex-direction: row;
|
||||
width: 120rpx;
|
||||
// padding: 0 6px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
/* #ifdef H5 */
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-navbar__header-btns-left {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
width: 120rpx;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.uni-navbar__header-btns-right {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
// width: 150rpx;
|
||||
// padding-right: 30rpx;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.uni-navbar__header-container {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex: 1;
|
||||
padding: 0 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uni-navbar__header-container-inner {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex: 1;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 12px;
|
||||
overflow: hidden;
|
||||
// box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
.uni-navbar__placeholder-view {
|
||||
height: $nav-height;
|
||||
}
|
||||
|
||||
.uni-navbar--fixed {
|
||||
position: fixed;
|
||||
z-index: 99;
|
||||
/* #ifdef H5 */
|
||||
left: var(--window-left);
|
||||
right: var(--window-right);
|
||||
/* #endif */
|
||||
/* #ifndef H5 */
|
||||
left: 0;
|
||||
right: 0;
|
||||
/* #endif */
|
||||
|
||||
}
|
||||
|
||||
.uni-navbar--shadow {
|
||||
box-shadow: 0 1px 6px #ccc;
|
||||
}
|
||||
|
||||
.uni-navbar--border {
|
||||
border-bottom-width: 1rpx;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-color: #eee;
|
||||
}
|
||||
|
||||
.uni-ellipsis-1 {
|
||||
overflow: hidden;
|
||||
/* #ifndef APP-NVUE */
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
/* #endif */
|
||||
/* #ifdef APP-NVUE */
|
||||
lines: 1;
|
||||
text-overflow: ellipsis;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
// 暗主题配置
|
||||
.uni-dark {}
|
||||
</style>
|
||||
31
components/uni-nav-bar/uni-status-bar.vue
Normal file
31
components/uni-nav-bar/uni-status-bar.vue
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<template>
|
||||
<view :style="{ height: statusBarHeight }" class="uni-status-bar">
|
||||
<slot />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'UniStatusBar',
|
||||
data() {
|
||||
|
||||
return {
|
||||
// #ifdef MP-WEIXIN
|
||||
statusBarHeight: uni.getWindowInfo().statusBarHeight + 'px',
|
||||
// #endif
|
||||
// #ifndef MP-WEIXIN
|
||||
statusBarHeight: uni.getSystemInfoSync().statusBarHeight + 'px',
|
||||
// #endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" >
|
||||
.uni-status-bar {
|
||||
// width: 750rpx;
|
||||
height: 20px;
|
||||
// height: var(--status-bar-height);
|
||||
}
|
||||
</style>
|
||||
24
pages.json
24
pages.json
|
|
@ -1,4 +1,12 @@
|
|||
{
|
||||
"easycom": {
|
||||
"autoscan": true,
|
||||
"custom": {
|
||||
// 通用规则:匹配 guyu 下任意子目录的组件,格式 <目录名>-<组件名>
|
||||
"^com-([a-z]+)-(.*)": "@/components/com/$1/$2.vue"
|
||||
|
||||
}
|
||||
},
|
||||
"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
|
||||
{
|
||||
"path" : "pages/index/loading",
|
||||
|
|
@ -55,6 +63,22 @@
|
|||
"navigationBarTitleText": "",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/other/agreement",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : "",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "components/com/page/container",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : "",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
|
|
|
|||
|
|
@ -9,71 +9,193 @@
|
|||
|
||||
<view class="column" style="width: 90%; margin: 80rpx auto 0;">
|
||||
|
||||
<view class="row" style="justify-content: space-between; width: 100%; align-items: center;">
|
||||
|
||||
<text style="font-size: 26rpx;">我的头像</text>
|
||||
|
||||
<image src="" style="width: 90rpx; height: 90rpx; background-color: aquamarine; border-radius: 50%;"
|
||||
mode=""></image>
|
||||
<view class="row"
|
||||
style="justify-content: space-between; width: 100%; align-items: center; margin-top: 40rpx; font-size: 26rpx;">
|
||||
<text style="">我的UID</text>
|
||||
<text style="">{{ user.id }}</text>
|
||||
</view>
|
||||
|
||||
<view style="width: 100%; height: 1rpx; background-color: antiquewhite; margin-top: 20rpx;"></view>
|
||||
|
||||
<view class="row" style="justify-content: space-between; width: 100%; align-items: center; margin-top: 40rpx; font-size: 26rpx;">
|
||||
<view class="row"
|
||||
style="justify-content: space-between; width: 100%; align-items: center;margin-top:20rpx;">
|
||||
|
||||
<text style="font-size: 26rpx;">我的头像</text>
|
||||
<button class="avatar-wrapper" open-type="chooseAvatar" @chooseavatar="onChooseAvatar">
|
||||
<image :src="user.avatarImage"
|
||||
style="width: 70rpx; height: 70rpx; background-color: aquamarine; border-radius: 50%;" mode="">
|
||||
</image>
|
||||
</button>
|
||||
|
||||
</view>
|
||||
|
||||
<view style="width: 100%; height: 1rpx; background-color: antiquewhite; margin-top: 20rpx;"></view>
|
||||
|
||||
<view class="row"
|
||||
style="justify-content: space-between; width: 100%; align-items: center; margin-top: 40rpx; font-size: 26rpx;">
|
||||
|
||||
<text style="">我的昵称</text>
|
||||
|
||||
<input type="text" v-model="userName" style="text-align: right;" />
|
||||
<input type="nickname" v-model="user.nickName" style="text-align: right;" />
|
||||
</view>
|
||||
|
||||
<view style="width: 100%; height: 1rpx; background-color: antiquewhite; margin-top: 20rpx;"></view>
|
||||
|
||||
<view class="row" style="justify-content: space-between; width: 100%; align-items: center; margin-top: 40rpx; font-size: 26rpx;">
|
||||
|
||||
|
||||
<view class="row"
|
||||
style="justify-content: space-between; width: 100%; align-items: center; margin-top: 40rpx; font-size: 26rpx;">
|
||||
|
||||
<text style="">我的年龄</text>
|
||||
|
||||
<input type="text" v-model="userAge" style="text-align: right;" />
|
||||
|
||||
<picker mode="selector" :value="ageIndex" :range="ageOptions" @change="onAgeChange">
|
||||
<view class="picker-text">
|
||||
{{ ageOptions[ageIndex] }}岁
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
|
||||
<view style="width: 100%; height: 1rpx; background-color: antiquewhite; margin-top: 20rpx;"></view>
|
||||
|
||||
<view class="row" style="justify-content: space-between; width: 100%; align-items: center; margin-top: 40rpx; font-size: 26rpx;">
|
||||
<text style="">我的UID</text>
|
||||
<text style="">{{userId}}</text>
|
||||
|
||||
<view class="row"
|
||||
style="justify-content: space-between; width: 100%; align-items: center; margin-top: 40rpx; font-size: 26rpx;">
|
||||
|
||||
<text style="">我的性别</text>
|
||||
|
||||
<picker mode="selector" :value="genderIndex" :range="genderOptions" @change="onGenderChange">
|
||||
<view class="picker-text">
|
||||
{{ genderOptions[genderIndex] }}
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
|
||||
<view style="width: 100%; height: 1rpx; background-color: antiquewhite; margin-top: 20rpx;"></view>
|
||||
|
||||
|
||||
|
||||
</view>
|
||||
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
userName: "树下的胖子",
|
||||
userAge:"30",
|
||||
userId:"132546"
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goBack() {
|
||||
// 返回上一页
|
||||
uni.navigateBack({
|
||||
delta: 1
|
||||
});
|
||||
},
|
||||
}
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { userInfo } from '@/common/server/user'
|
||||
|
||||
// 性别选项
|
||||
const genderOptions = ['男', '女']
|
||||
const genderIndex = ref(0)
|
||||
|
||||
// 年龄选项 (18-90岁)
|
||||
const ageOptions = Array.from({ length: 73 }, (_, i) => i + 18)
|
||||
const ageIndex = ref(0)
|
||||
|
||||
const user = ref({
|
||||
avatarImage: userInfo.value.avatarImage,
|
||||
nickName: userInfo.value.nickName,
|
||||
age: userInfo.value.age ?? 18,
|
||||
id: userInfo.value.id,
|
||||
sex: userInfo.value.sex == 1 ? '男' : '女'
|
||||
})
|
||||
|
||||
onLoad(() => {
|
||||
console.log("userInfo", userInfo.value);
|
||||
// 根据用户性别设置picker的初始值
|
||||
if (userInfo.value.sex === '女') {
|
||||
genderIndex.value = 1
|
||||
} else {
|
||||
genderIndex.value = 0
|
||||
}
|
||||
|
||||
// 根据用户年龄设置picker的初始值
|
||||
const userAge = userInfo.value.age ?? 18
|
||||
const ageIndexValue = Math.max(0, Math.min(72, userAge - 18))
|
||||
ageIndex.value = ageIndexValue
|
||||
})
|
||||
// 方法
|
||||
const goBack = () => {
|
||||
// 返回上一页
|
||||
uni.navigateBack({
|
||||
delta: 1
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 选择头像
|
||||
*/
|
||||
const onChooseAvatar = (e) => {
|
||||
if (e && e.detail && e.detail.avatarUrl) {
|
||||
// user.value.avatarImage = e.detail.avatarUrl;
|
||||
convertToBase64(user.value.avatarImage);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 性别选择变化
|
||||
*/
|
||||
const onGenderChange = (e) => {
|
||||
genderIndex.value = e.detail.value
|
||||
user.value.sex = genderOptions[genderIndex.value]
|
||||
}
|
||||
|
||||
/**
|
||||
* 年龄选择变化
|
||||
*/
|
||||
const onAgeChange = (e) => {
|
||||
ageIndex.value = e.detail.value
|
||||
user.value.age = ageOptions[ageIndex.value]
|
||||
}
|
||||
|
||||
/**
|
||||
* 将图片转换为Base64
|
||||
*/
|
||||
const convertToBase64 = (filePath) => {
|
||||
console.log(filePath);
|
||||
uni.getFileSystemManager().readFile({
|
||||
filePath: filePath,
|
||||
encoding: "base64",
|
||||
success: (res) => {
|
||||
user.value.avatarImage = "data:image/png;base64," + res.data;
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error("读取文件失败:", err);
|
||||
uni.showToast({
|
||||
title: "图片处理失败",
|
||||
icon: "none",
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.content {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
.content {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.avatar-wrapper {
|
||||
margin: 0rpx;
|
||||
float: right;
|
||||
border-radius: 128rpx;
|
||||
overflow: hidden;
|
||||
border: 0rpx solid #F3F3F3;
|
||||
background-color: transparent;
|
||||
padding: 0;
|
||||
line-height: normal;
|
||||
|
||||
&::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 170rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.picker-text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #333;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -21,16 +21,26 @@
|
|||
<view class="login-form">
|
||||
<!-- 一键登录按钮 -->
|
||||
<view class="one-click-login">
|
||||
<view class="quick-login-btn" @click="handleOneClickLogin" :class="{ disabled: loading }">
|
||||
<button v-if="agreedToTerms && isMobile" class="quick-login-btn" :class="{ disabled: loading }"
|
||||
open-type="getPhoneNumber" @getphonenumber="mobileClickLogin">
|
||||
<text>{{ loading ? '登录中...' : '一键登录' }}</text>
|
||||
</view>
|
||||
</button>
|
||||
<button v-if="!agreedToTerms" class="quick-login-btn" :class="{ disabled: loading }"
|
||||
@click="agreementClickLogin">
|
||||
<text>{{ loading ? '登录中...' : '一键登录' }}</text>
|
||||
</button>
|
||||
<button v-if="agreedToTerms && !isMobile" class="quick-login-btn" :class="{ disabled: loading }"
|
||||
@click="anonymousLoginClickLogin">
|
||||
<text>{{ loading ? '登录中...' : '一键登录' }}</text>
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<!-- 用户协议同意 -->
|
||||
<view class="agreement-section">
|
||||
<view class="agreement-checkbox" @click="toggleAgreement">
|
||||
|
||||
<checkbox :value="agreedToTerms" :checked="agreedToTerms" style="transform:scale(0.5);margin-top: -8rpx;" />
|
||||
<checkbox :value="agreedToTerms" :checked="agreedToTerms"
|
||||
style="transform:scale(0.5);margin-top: -8rpx;" />
|
||||
<text class="agreement-text">
|
||||
我已阅读并同意
|
||||
<text class="agreement-link" @click.stop="showUserAgreement">《用户协议》</text>
|
||||
|
|
@ -49,8 +59,14 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
|
||||
import {
|
||||
ref,
|
||||
reactive,
|
||||
computed
|
||||
} from 'vue'
|
||||
import { useLogin } from '@/common/com'
|
||||
import { getAnonymousLogin, ueWxPhoneNumberLogin, useWxAnonymousLogin } from '@/common/server/interface/user'
|
||||
import { userInfo, loadUserInfo } from '@/common/server/user'
|
||||
// 响应式数据
|
||||
const loading = ref(false)
|
||||
const agreedToTerms = ref(false)
|
||||
|
|
@ -60,7 +76,7 @@ const toggleAgreement = () => {
|
|||
agreedToTerms.value = !agreedToTerms.value
|
||||
}
|
||||
|
||||
const handleOneClickLogin = async () => {
|
||||
const agreementClickLogin = async () => {
|
||||
if (loading.value) return
|
||||
|
||||
if (!agreedToTerms.value) {
|
||||
|
|
@ -70,37 +86,66 @@ const handleOneClickLogin = async () => {
|
|||
})
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
const mobileClickLogin = async (e) => {
|
||||
console.log(e) // 动态令牌
|
||||
console.log(e.detail.code) // 动态令牌
|
||||
var code = e.detail.code;
|
||||
loading.value = true
|
||||
|
||||
try {
|
||||
// 这里调用一键登录API(如运营商一键登录)
|
||||
// const response = await oneClickLoginApi()
|
||||
var response = await ueWxPhoneNumberLogin(code, sessionAuthId);
|
||||
if (response == null) {
|
||||
uni.showToast({
|
||||
title: '登录失败,请重试',
|
||||
icon: 'error'
|
||||
})
|
||||
return;
|
||||
}
|
||||
uni.setStorageSync("tokenInfo", response);
|
||||
|
||||
// 模拟一键登录成功
|
||||
await new Promise(resolve => setTimeout(resolve, 2000))
|
||||
|
||||
// 生成随机手机号用于演示
|
||||
const randomPhone = '138' + Math.floor(Math.random() * 100000000).toString().padStart(8, '0')
|
||||
|
||||
// 保存登录状态
|
||||
uni.setStorageSync('userInfo', {
|
||||
phone: randomPhone,
|
||||
nickname: '用户' + randomPhone.slice(-4),
|
||||
uid: 'U' + Date.now(),
|
||||
avatar: '@@:app/nouser.png',
|
||||
rating: 4.6,
|
||||
reputation: 5.0,
|
||||
cardQuality: 4.5,
|
||||
cardSkill: 4.5,
|
||||
pigeonCount: 0
|
||||
})
|
||||
|
||||
await loadUserInfo();
|
||||
uni.showToast({
|
||||
title: '登录成功',
|
||||
icon: 'success'
|
||||
})
|
||||
});
|
||||
// 延迟跳转
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1500)
|
||||
|
||||
} catch (error) {
|
||||
console.error('一键登录失败:', error)
|
||||
uni.showToast({
|
||||
title: '登录失败,请重试',
|
||||
icon: 'error'
|
||||
})
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
const anonymousLoginClickLogin = async (e) => {
|
||||
console.log('aaa');
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
// 这里调用一键登录API(如运营商一键登录)
|
||||
// const response = await oneClickLoginApi()
|
||||
var response = await useWxAnonymousLogin(sessionAuthId);
|
||||
if (response == null) {
|
||||
uni.showToast({
|
||||
title: '登录失败,请重试',
|
||||
icon: 'error'
|
||||
})
|
||||
return;
|
||||
}
|
||||
uni.setStorageSync("tokenInfo", response);
|
||||
await loadUserInfo();
|
||||
uni.showToast({
|
||||
title: '登录成功',
|
||||
icon: 'success'
|
||||
});
|
||||
// 延迟跳转
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
|
|
@ -122,22 +167,32 @@ const skipLogin = () => {
|
|||
}
|
||||
|
||||
const showUserAgreement = () => {
|
||||
uni.showModal({
|
||||
title: '用户协议',
|
||||
content: '这里是用户协议的内容...\n\n1. 用户权利和义务\n2. 服务条款\n3. 免责声明\n4. 其他条款',
|
||||
showCancel: false,
|
||||
confirmText: '我知道了'
|
||||
})
|
||||
com.navigateToAgreement('userAgreement');
|
||||
|
||||
}
|
||||
|
||||
const showPrivacyPolicy = () => {
|
||||
uni.showModal({
|
||||
title: '隐私政策',
|
||||
content: '这里是隐私政策的内容...\n\n1. 信息收集\n2. 信息使用\n3. 信息保护\n4. 信息共享',
|
||||
showCancel: false,
|
||||
confirmText: '我知道了'
|
||||
})
|
||||
com.navigateToAgreement('privacyPolicy');
|
||||
}
|
||||
let isMobile = ref(false);
|
||||
let sessionAuthId = null;
|
||||
async function AnonymousLogin() {
|
||||
var code = await useLogin();
|
||||
console.log("res", code);
|
||||
var res = await getAnonymousLogin(code);
|
||||
if (res.user == 0) {
|
||||
isMobile.value = true;
|
||||
}
|
||||
sessionAuthId = res.sessionAuthId;
|
||||
}
|
||||
onLoad(() => {
|
||||
AnonymousLogin();
|
||||
/* uni.login({
|
||||
|
||||
}) */
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
@ -166,7 +221,7 @@ const showPrivacyPolicy = () => {
|
|||
position: absolute;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
border-radius: 50rpx;
|
||||
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
content: '';
|
||||
|
|
@ -174,20 +229,20 @@ const showPrivacyPolicy = () => {
|
|||
background: rgba(255, 255, 255, 0.8);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
|
||||
&.cloud-1 {
|
||||
width: 120rpx;
|
||||
height: 40rpx;
|
||||
top: 15%;
|
||||
left: 10%;
|
||||
|
||||
|
||||
&::before {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
top: -25rpx;
|
||||
left: 10rpx;
|
||||
}
|
||||
|
||||
|
||||
&::after {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
|
|
@ -195,20 +250,20 @@ const showPrivacyPolicy = () => {
|
|||
right: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&.cloud-2 {
|
||||
width: 100rpx;
|
||||
height: 35rpx;
|
||||
top: 25%;
|
||||
right: 15%;
|
||||
|
||||
|
||||
&::before {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
top: -20rpx;
|
||||
left: 8rpx;
|
||||
}
|
||||
|
||||
|
||||
&::after {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
|
|
@ -216,20 +271,20 @@ const showPrivacyPolicy = () => {
|
|||
right: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&.cloud-3 {
|
||||
width: 80rpx;
|
||||
height: 30rpx;
|
||||
top: 70%;
|
||||
left: 20%;
|
||||
|
||||
|
||||
&::before {
|
||||
width: 35rpx;
|
||||
height: 35rpx;
|
||||
top: -17rpx;
|
||||
left: 6rpx;
|
||||
}
|
||||
|
||||
|
||||
&::after {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
|
|
@ -246,7 +301,7 @@ const showPrivacyPolicy = () => {
|
|||
height: 15rpx;
|
||||
background: #8B4513;
|
||||
border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%;
|
||||
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
|
|
@ -258,13 +313,13 @@ const showPrivacyPolicy = () => {
|
|||
left: -5rpx;
|
||||
transform: rotate(-20deg);
|
||||
}
|
||||
|
||||
|
||||
&.bird-1 {
|
||||
top: 20%;
|
||||
right: 25%;
|
||||
animation: fly 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
|
||||
&.bird-2 {
|
||||
top: 60%;
|
||||
left: 15%;
|
||||
|
|
@ -277,7 +332,7 @@ const showPrivacyPolicy = () => {
|
|||
position: absolute;
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
|
|
@ -286,7 +341,7 @@ const showPrivacyPolicy = () => {
|
|||
background: radial-gradient(circle, #FFB6C1 30%, #FF69B4 70%);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
|
|
@ -298,19 +353,19 @@ const showPrivacyPolicy = () => {
|
|||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
|
||||
&.flower-1 {
|
||||
top: 40%;
|
||||
left: 8%;
|
||||
animation: sway 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
|
||||
&.flower-2 {
|
||||
top: 80%;
|
||||
right: 10%;
|
||||
animation: sway 2.5s ease-in-out infinite reverse;
|
||||
}
|
||||
|
||||
|
||||
&.flower-3 {
|
||||
top: 50%;
|
||||
right: 30%;
|
||||
|
|
@ -320,22 +375,53 @@ const showPrivacyPolicy = () => {
|
|||
|
||||
// 动画效果
|
||||
@keyframes fly {
|
||||
0%, 100% { transform: translateX(0) translateY(0); }
|
||||
25% { transform: translateX(10rpx) translateY(-5rpx); }
|
||||
50% { transform: translateX(20rpx) translateY(0); }
|
||||
75% { transform: translateX(10rpx) translateY(5rpx); }
|
||||
|
||||
0%,
|
||||
100% {
|
||||
transform: translateX(0) translateY(0);
|
||||
}
|
||||
|
||||
25% {
|
||||
transform: translateX(10rpx) translateY(-5rpx);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translateX(20rpx) translateY(0);
|
||||
}
|
||||
|
||||
75% {
|
||||
transform: translateX(10rpx) translateY(5rpx);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sway {
|
||||
0%, 100% { transform: rotate(0deg); }
|
||||
25% { transform: rotate(2deg); }
|
||||
50% { transform: rotate(0deg); }
|
||||
75% { transform: rotate(-2deg); }
|
||||
|
||||
0%,
|
||||
100% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
25% {
|
||||
transform: rotate(2deg);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
75% {
|
||||
transform: rotate(-2deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shine {
|
||||
0% { transform: translateX(-100%) translateY(-100%) rotate(45deg); }
|
||||
100% { transform: translateX(100%) translateY(100%) rotate(45deg); }
|
||||
0% {
|
||||
transform: translateX(-100%) translateY(-100%) rotate(45deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateX(100%) translateY(100%) rotate(45deg);
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
|
|
@ -391,7 +477,7 @@ const showPrivacyPolicy = () => {
|
|||
border: 4rpx solid #FFE4B5;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
|
|
@ -403,7 +489,7 @@ const showPrivacyPolicy = () => {
|
|||
transform: rotate(45deg);
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
|
||||
&:active::before {
|
||||
animation: shine 0.6s ease-in-out;
|
||||
}
|
||||
|
|
@ -443,7 +529,7 @@ const showPrivacyPolicy = () => {
|
|||
line-height: 1.5;
|
||||
|
||||
.agreement-link {
|
||||
color: #FF69B4;
|
||||
color: blue;
|
||||
text-decoration: underline;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
|
@ -462,4 +548,4 @@ const showPrivacyPolicy = () => {
|
|||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
@ -6,14 +6,24 @@
|
|||
<text>加载中...</text>
|
||||
</view>
|
||||
|
||||
<view class="row" style="margin-top: 150rpx; align-items: center; margin-left: 40rpx;">
|
||||
<image :src="userInfo.avatar" style="width: 80rpx; height: 80rpx; border-radius: 50%;" mode=""></image>
|
||||
<view v-if="userInfo != null" class="row" style="margin-top: 150rpx; align-items: center; margin-left: 40rpx;">
|
||||
<image :src="userInfo.avatarImage" style="width: 80rpx; height: 80rpx; border-radius: 50%;" mode="">
|
||||
</image>
|
||||
<view class="column" style="margin-left: 50rpx; font-size: 24rpx;">
|
||||
<view class="row" @click="toEditInfo()" style="align-items: center;">
|
||||
<text>{{ userInfo.nickname }}</text>
|
||||
<text>{{ userInfo.nickName }}</text>
|
||||
</view>
|
||||
<text v-if="userInfo.uid" style="margin-top: 10rpx;">UID:{{ userInfo.uid }}</text>
|
||||
<text v-else style="margin-top: 10rpx; color: #999;" @click="toLogin()">点击登录</text>
|
||||
<text style="margin-top: 10rpx;">UID:{{ userInfo.id }}</text>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="row" style="margin-top: 150rpx; align-items: center; margin-left: 40rpx;">
|
||||
<image src="@@:app/nouser.png" style="width: 80rpx; height: 80rpx; border-radius: 50%;" mode=""></image>
|
||||
<view class="column" style="margin-left: 50rpx; font-size: 24rpx;">
|
||||
<view class="row" @click="toEditInfo()" style="align-items: center;">
|
||||
<text>未登录</text>
|
||||
</view>
|
||||
<text style="margin-top: 10rpx; color: #999;" @click="toLogin()">点击登录</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="column" @click="currentAppointment ? openPop() : null"
|
||||
|
|
@ -21,7 +31,7 @@
|
|||
|
||||
<!-- 无预约状态 -->
|
||||
<view v-if="!currentAppointment" class="row" style="align-items: center; margin: 20rpx;">
|
||||
<image src="/static/no_content.png" style="width: 150rpx; height: 150rpx;" mode=""></image>
|
||||
<image src="@@:app/static/no_content.png" style="width: 150rpx; height: 150rpx;" mode=""></image>
|
||||
<text style="margin-left: 40rpx;">当前没有预约</text>
|
||||
</view>
|
||||
|
||||
|
|
@ -32,7 +42,7 @@
|
|||
currentAppointment.duration }}
|
||||
</text>
|
||||
<text style="font-size: 24rpx; margin-left: 20rpx; margin-top: 10rpx;">{{ currentAppointment.room
|
||||
}}</text>
|
||||
}}</text>
|
||||
|
||||
<view class="row"
|
||||
style="font-size: 24rpx; margin-left: 20rpx; margin-top: 20rpx; align-items: center; margin-bottom: 20rpx;">
|
||||
|
|
@ -49,7 +59,8 @@
|
|||
</view>
|
||||
|
||||
|
||||
<view class="column" style="width: 90%; border-radius: 10rpx; background-color: #F2F3F5; margin: 40rpx auto 0;">
|
||||
<view v-if="userInfo != null" class="column"
|
||||
style="width: 90%; border-radius: 10rpx; background-color: #F2F3F5; margin: 40rpx auto 0;">
|
||||
|
||||
|
||||
<view class="row" style="align-items: center; margin-top: 30rpx; margin-left: 20rpx;">
|
||||
|
|
@ -77,6 +88,29 @@
|
|||
|
||||
</view>
|
||||
|
||||
<view v-else class="column"
|
||||
style="width: 90%; border-radius: 10rpx; background-color: #F2F3F5; margin: 40rpx auto 0;">
|
||||
<view class="row" style="align-items: center; margin-top: 30rpx; margin-left: 20rpx;">
|
||||
<text style="font-size: 24rpx;">我的评分</text>
|
||||
<text style="font-size: 24rpx; color: #999; margin-left: 10rpx;">未评分</text>
|
||||
<text style="font-size: 24rpx; margin-left: 180rpx;">我的信誉</text>
|
||||
<text style="font-size: 24rpx; color: #999; margin-left: 10rpx;">未评级</text>
|
||||
</view>
|
||||
|
||||
<view class="row" style="align-items: center; margin-top: 20rpx; margin-left: 20rpx;">
|
||||
<text style="font-size: 24rpx;">牌品</text>
|
||||
<uni-rate style="margin-left: 20rpx;" :readonly="true" />
|
||||
</view>
|
||||
|
||||
<view class="row" style="align-items: center; margin-top: 20rpx; margin-left: 20rpx;">
|
||||
<text style="font-size: 24rpx;">牌技</text>
|
||||
<uni-rate style="margin-left: 20rpx;" :readonly="true" />
|
||||
</view>
|
||||
|
||||
<text style="font-size: 24rpx; margin: 20rpx;">鸽子数 0次</text>
|
||||
|
||||
</view>
|
||||
|
||||
<view class="row" style="width: 90%; margin: 40rpx auto 0;">
|
||||
|
||||
<view class="column" @click="toAppointment()" style="align-items: center;">
|
||||
|
|
@ -166,7 +200,7 @@
|
|||
<view class="column"
|
||||
style="width: 100%; background-color: #E3E2E2; margin-top: 20rpx; border-radius: 10rpx; font-size: 22rpx;">
|
||||
<text style="margin: 20rpx 20rpx 10rpx; font-size: 24rpx;">房间号:{{ appointmentDetail.roomInfo.roomNumber
|
||||
}},{{ appointmentDetail.roomInfo.price }}</text>
|
||||
}},{{ appointmentDetail.roomInfo.price }}</text>
|
||||
<text style="margin: 10rpx 20rpx;">人数:{{ appointmentDetail.roomInfo.playerCount }}人</text>
|
||||
<text style="margin: 10rpx 20rpx;">玩法类型:{{ appointmentDetail.roomInfo.gameType }}</text>
|
||||
<text style="margin: 10rpx 20rpx;">具体规则:{{ appointmentDetail.roomInfo.rules }}</text>
|
||||
|
|
@ -177,7 +211,7 @@
|
|||
style="width: 100%; background-color: #E3E2E2; margin-top: 20rpx; border-radius: 10rpx; font-size: 22rpx;">
|
||||
<text style="margin: 20rpx 20rpx 10rpx; font-size: 24rpx;">是否禁烟:{{
|
||||
appointmentDetail.requirements.smoking
|
||||
}}</text>
|
||||
}}</text>
|
||||
<text style="margin: 10rpx 20rpx;">性别:{{ appointmentDetail.requirements.gender }}</text>
|
||||
<text style="margin: 10rpx 20rpx 20rpx;">信誉:{{ appointmentDetail.requirements.reputation }}</text>
|
||||
</view>
|
||||
|
|
@ -202,6 +236,7 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { userInfo, loadUserInfo } from '@/common/server/user'
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
|
||||
// 响应式数据
|
||||
|
|
@ -210,16 +245,16 @@ const infoPop = ref(null)
|
|||
const loading = ref(false)
|
||||
|
||||
// 用户信息 - 未登录状态
|
||||
const userInfo = reactive({
|
||||
nickname: '未登录',
|
||||
uid: '',
|
||||
avatar: '@@:app/nouser.png',
|
||||
rating: 0,
|
||||
reputation: 0,
|
||||
cardQuality: 0,
|
||||
cardSkill: 0,
|
||||
pigeonCount: 0
|
||||
})
|
||||
// const userInfo = reactive({
|
||||
// nickname: '未登录',
|
||||
// uid: '',
|
||||
// avatar: '@@:app/nouser.png',
|
||||
// rating: 0,
|
||||
// reputation: 0,
|
||||
// cardQuality: 0,
|
||||
// cardSkill: 0,
|
||||
// pigeonCount: 0
|
||||
// })
|
||||
|
||||
// 当前预约信息
|
||||
const currentAppointment = ref(null)
|
||||
|
|
@ -301,20 +336,12 @@ const toAppointment = () => {
|
|||
|
||||
const toEditInfo = () => {
|
||||
// 未登录状态,跳转到登录页面
|
||||
if (!userInfo.uid) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '请先登录',
|
||||
showCancel: false,
|
||||
success: () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/me/login'
|
||||
});
|
||||
}
|
||||
if (userInfo == null) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/me/login'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
uni.navigateTo({
|
||||
url: '/pages/me/edit-info'
|
||||
});
|
||||
|
|
@ -396,16 +423,14 @@ onMounted(() => {
|
|||
})
|
||||
|
||||
// 页面显示时重新加载数据(用于登录后刷新)
|
||||
// onShow(() => {
|
||||
// // 检查是否有登录状态
|
||||
// const savedUserInfo = uni.getStorageSync('userInfo')
|
||||
// if (savedUserInfo && savedUserInfo.uid) {
|
||||
// // 如果已登录,更新用户信息
|
||||
// Object.assign(userInfo, savedUserInfo)
|
||||
// // 重新加载预约信息
|
||||
// loadCurrentAppointment()
|
||||
// }
|
||||
// })
|
||||
onShow(() => {
|
||||
// 检查是否有登录状态
|
||||
// getUserInfoData();
|
||||
})
|
||||
onLoad(async () => {
|
||||
console.log('kiad');
|
||||
await loadUserInfo();
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
|
|
|||
155
pages/other/agreement.vue
Normal file
155
pages/other/agreement.vue
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
<template>
|
||||
<view>
|
||||
<com-page-container :title="title" showBack>
|
||||
<view class="agreement-container">
|
||||
<rich-text v-if="article != null" :nodes="article.contentBody" class="agreement-content"></rich-text>
|
||||
</view>
|
||||
</com-page-container>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { getArticleDetail } from '@/common/server/interface/article'
|
||||
import { getConfigData } from '@/common/server/config'
|
||||
let title = ref('')
|
||||
const article = ref(null)
|
||||
let configData = null;
|
||||
onLoad(async (option) => {
|
||||
console.log(option);
|
||||
if (configData == null) {
|
||||
configData = await getConfigData()
|
||||
}
|
||||
console.log("configData", configData.config);
|
||||
|
||||
if (option.type != null) {
|
||||
if (option.type == 'userAgreement') {
|
||||
title = "用户协议";
|
||||
article.value = await getArticleDetail(configData.config.userAgreementId)
|
||||
} else if (option.type == 'privacyPolicy') {
|
||||
title = "隐私协议";
|
||||
article.value = await getArticleDetail(configData.config.privacyPolicyId)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.agreement-container {
|
||||
padding: 20rpx;
|
||||
background-color: #fff;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.agreement-content {
|
||||
line-height: 1.8;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
/* 富文本内容样式优化 */
|
||||
.agreement-content :deep(h1),
|
||||
.agreement-content :deep(h2),
|
||||
.agreement-content :deep(h3) {
|
||||
color: #2c3e50;
|
||||
font-weight: bold;
|
||||
margin: 30rpx 0 20rpx 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.agreement-content :deep(h1) {
|
||||
font-size: 36rpx;
|
||||
border-bottom: 2rpx solid #e0e0e0;
|
||||
padding-bottom: 15rpx;
|
||||
}
|
||||
|
||||
.agreement-content :deep(h2) {
|
||||
font-size: 32rpx;
|
||||
color: #34495e;
|
||||
}
|
||||
|
||||
.agreement-content :deep(h3) {
|
||||
font-size: 30rpx;
|
||||
color: #34495e;
|
||||
}
|
||||
|
||||
.agreement-content :deep(p) {
|
||||
margin: 15rpx 0;
|
||||
text-indent: 0;
|
||||
line-height: 1.8;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.agreement-content :deep(ul),
|
||||
.agreement-content :deep(ol) {
|
||||
margin: 15rpx 0;
|
||||
padding-left: 40rpx;
|
||||
}
|
||||
|
||||
.agreement-content :deep(li) {
|
||||
margin: 8rpx 0;
|
||||
line-height: 1.6;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.agreement-content :deep(strong),
|
||||
.agreement-content :deep(b) {
|
||||
font-weight: bold;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.agreement-content :deep(em),
|
||||
.agreement-content :deep(i) {
|
||||
font-style: italic;
|
||||
color: #7f8c8d;
|
||||
}
|
||||
|
||||
.agreement-content :deep(a) {
|
||||
color: #3498db;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.agreement-content :deep(blockquote) {
|
||||
border-left: 6rpx solid #3498db;
|
||||
padding-left: 20rpx;
|
||||
margin: 20rpx 0;
|
||||
background-color: #f8f9fa;
|
||||
padding: 20rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.agreement-content :deep(code) {
|
||||
background-color: #f1f2f6;
|
||||
padding: 4rpx 8rpx;
|
||||
border-radius: 4rpx;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.agreement-content :deep(pre) {
|
||||
background-color: #f8f9fa;
|
||||
padding: 20rpx;
|
||||
border-radius: 8rpx;
|
||||
overflow-x: auto;
|
||||
margin: 20rpx 0;
|
||||
}
|
||||
|
||||
.agreement-content :deep(table) {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 20rpx 0;
|
||||
}
|
||||
|
||||
.agreement-content :deep(th),
|
||||
.agreement-content :deep(td) {
|
||||
border: 1rpx solid #ddd;
|
||||
padding: 12rpx;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.agreement-content :deep(th) {
|
||||
background-color: #f8f9fa;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue
Block a user