39f68355 by lttnew

道馆页面更改

1 parent a4aa5d24
......@@ -5,7 +5,9 @@
"WebFetch(domain:minimax-algeng-chat-tts.oss-cn-wulanchabu.aliyuncs.com)",
"Bash(node -c pages/index/perfect.vue)",
"Bash(git checkout:*)",
"Bash(git restore:*)"
"Bash(git restore:*)",
"Bash(git:*)",
"Bash(python3 -c \"import json,sys; d=json.load\\(sys.stdin\\); print\\('tabBar list:', [l['pagePath'] for l in d.get\\('tabBar',{}\\).get\\('list',[]\\)]\\)\")"
]
}
}
......
......@@ -11,22 +11,28 @@
baseUrl_api: '',
user: null
},
onLaunch: function(options) {
onLaunch: async function(options) {
console.log('App Launch', options);
this.globalData.baseUrl_api = config.baseUrl_api;
let userName = uni.getStorageSync('userName')
if (userName) {
getInfo().then(() => {
this.globalData.isLogin = true
await getInfo(this)
this.globalData.isLogin = true
// 道馆用户跳转到道馆首页
const deptType = this.globalData.deptType
const userType = this.globalData.userType
// 道馆判断:deptType=6 或者 userType='4'
if (deptType == 6 || deptType == '6' || userType == '4') {
uni.reLaunch({
url: '/pages/index/home'
url: '/pages/index/daoGuanPerson'
})
}).catch(() => {
} else {
uni.reLaunch({
url: '/login/login'
url: '/pages/index/home'
})
})
}
return
}
......@@ -62,4 +68,4 @@
/*每个页面公共css */
@import '/common/uni.css';
@import '/common/mystyle.scss';
</style>
\ No newline at end of file
</style>
......
......@@ -10,7 +10,13 @@ function pcLogin(data) {
params: data
}).then((res) => {
uni.setStorageSync('token', 'Bearer ' + res.data.token)
pcLoginOpenId()
return new Promise((resolve) => {
pcLoginOpenId()
// 延迟一下确保 token 设置完成
setTimeout(() => {
resolve()
}, 100)
})
}).then(getInfo)
}
......@@ -98,14 +104,16 @@ function loginByPhone(phonenumber, code) {
}
// 获取用户详细信息
function getInfo() {
return request({
url: '/getInfo',
method: 'get'
}).then(res => {
const userStore = useUserStore()
const app = getApp()
const user = res.data.user
function getInfo(appInstance) {
console.log('getInfo 开始调用')
return request({
url: '/getInfo',
method: 'get'
}).then(res => {
console.log('getInfo 成功', res.data)
const userStore = useUserStore()
const app = appInstance || getApp()
const user = res.data.user
uni.setStorageSync('userName', user.userName)
uni.removeStorageSync('webUserName')
......@@ -126,6 +134,12 @@ function getInfo() {
} else {
app.globalData.userType = '3'
}
console.log('getInfo跳转判断 - deptType:', deptType, 'userType:', app.globalData.userType)
// 道馆用户跳转道馆首页
return res
}).catch(err => {
console.error('getInfo 失败:', err)
})
}
......
<template>
<view class="dao-guan-tab-bar">
<image
v-if="currentIndex >= 0"
:src="config.baseUrl_api + '/fs/static/img/toolbar.png'"
class="dg-tab-bar-bg"
mode="scaleToFill"
:style="{ left: tabBgLeft }"
></image>
<view
v-for="(item, index) in tabs"
:key="index"
class="dg-tab-item"
:class="{ active: currentIndex === index }"
@click="handleClick(index, item.url)"
>
<image :src="currentIndex === index ? item.activeIcon : item.icon" class="dg-tab-icon"></image>
<text class="dg-tab-text">{{ item.text }}</text>
</view>
</view>
</template>
<script setup>
import config from '@/config.js'
import { computed, ref } from 'vue'
const props = defineProps({
currentIndex: {
type: Number,
default: 0
}
})
const emit = defineEmits(['switch'])
const switching = ref(false)
const tabs = [
{ text: '人员', url: '/pages/index/daoGuanPerson', icon: '/static/img/tool01.png', activeIcon: '/static/img/tool01_dwn.png' },
{ text: '订单', url: '/pages/index/daoGuanOrder', icon: '/static/img/tool02.png', activeIcon: '/static/img/tool02_dwn.png' },
{ text: '通知', url: '/pages/index/daoGuanNotice', icon: '/static/img/tool03.png', activeIcon: '/static/img/tool03_dwn.png' },
{ text: '级位', url: '/pages/index/daoGuanLevel', icon: '/static/img/tool04.png', activeIcon: '/static/img/tool04_dwn.png' },
{ text: '我的', url: '/pages/index/daoGuanMy', icon: '/static/img/tool05.png', activeIcon: '/static/img/tool05_dwn.png' },
]
const tabBgLeft = computed(() => {
if (props.currentIndex < 0) return '0'
return `${props.currentIndex * 20}%`
})
const handleClick = (index, url) => {
if (switching.value || index === props.currentIndex) return
switching.value = true
emit('switch', index, url)
uni.redirectTo({
url,
fail: () => {
switching.value = false
}
})
}
</script>
<style lang="scss" scoped>
.dao-guan-tab-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 120rpx;
display: flex;
justify-content: flex-start;
align-items: stretch;
padding-bottom: env(safe-area-inset-bottom);
z-index: 9999;
background-color: #d9d9d9;
overflow: hidden;
}
.dg-tab-bar-bg {
position: absolute;
top: 0rpx;
width: 20%;
height: calc(100% - 35rpx);
z-index: 0;
transition: left 0.3s ease;
pointer-events: none;
}
.dg-tab-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 20%;
height: 100%;
position: relative;
z-index: 1;
}
.dg-tab-icon {
width: 50rpx;
height: 50rpx;
margin-bottom: 4rpx;
}
.dg-tab-text {
font-size: 20rpx;
color: #666;
}
.dg-tab-item.active .dg-tab-text {
color: #C30D23;
font-weight: bold;
}
</style>
<template>
<view class="role-entry-page">
<!-- 全屏背景图 -->
<image :src="config.loginImage_api + '/fs/static/dg/bg@3x.png'" class="page-bg" mode="aspectFill"></image>
<!-- 顶部 Logo 区域 -->
<view class="header-wrapper">
<view class="logo-box">
<image :src="config.loginImage_api + '/fs/static/dg/ztx_b.svg'" class="logo" mode="aspectFit"></image>
</view>
</view>
<!-- 功能按钮区域 -->
<view class="btn-container">
<view @click="goToPage('/personal/addVip_per')">
<image :src="config.loginImage_api + '/fs/static/dg/btn01@3x.png'" class="btn-item"></image>
</view>
<view @click="goToPage('/personal/home')">
<image :src="config.loginImage_api + '/fs/static/dg/btn02@3x.png'" class="btn-item"></image>
</view>
<view @click="goToPage('/login/loginC')">
<image :src="config.loginImage_api + '/fs/static/dg/btn03@3x.png'" class="btn-item"></image>
</view>
</view>
</view>
</template>
<script setup>
import {ref} from 'vue'
import {onShow} from '@dcloudio/uni-app'
import config from '@/config.js'
onShow(() => {
uni.hideLoading();
})
const goToPage = (url) => {
uni.navigateTo({
url,
})
}
</script>
<style lang="scss" scoped>
.role-entry-page {
width: 100%;
min-height: 100vh;
position: relative;
padding: 20rpx;
box-sizing: border-box;
}
.page-bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
}
.header-wrapper {
text-align: center;
// padding: 40rpx 0;
border-radius: 16rpx;
margin-top: 100rpx;
}
.btn-container {
display: flex;
flex-direction: column;
align-items: center;
margin: 0 auto;
img, image {
width: 509rpx;
height: 117rpx;
margin: 40rpx 0;
}
}
.loading-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 999;
}
.loading-content {
color: white;
font-size: 28rpx;
}
</style>
<template>
<view class="role-entry-page">
<!-- 全屏背景图 -->
<image :src="config.baseUrl_api + '/fs/static/img/home_bg.png'" class="page-bg" mode="aspectFill"></image>
<!-- 顶部 Logo 区域 -->
<!-- <view class="header-wrapper">
<view class="logo-box">
<image :src="config.loginImage_api + '/fs/static/dg/ztx_b.svg'" class="logo" mode="aspectFit"></image>
</view>
</view> -->
<!-- 功能按钮区域 -->
<view class="btn-container">
<view
class="entry-btn"
:class="{ active: activeEntry === 'unit' }"
@click="goUnitLogin"
>
<image :src="activeEntry === 'unit' ? '/static/img/home_btn2.png' : '/static/img/home_btn.png'" class="btn-bg" mode="scaleToFill"></image>
<text>单位会员入口</text>
</view>
<view
class="entry-btn"
:class="{ active: activeEntry === 'personal' }"
@click="showLoginPopup"
>
<image :src="activeEntry === 'personal' ? '/static/img/home_btn2.png' : '/static/img/home_btn.png'" class="btn-bg" mode="scaleToFill"></image>
<text>个人会员入口</text>
</view>
</view>
<!-- 个人会员登录注册弹框 -->
<uni-popup ref="loginPopup" :mask-click="true" type="center" @change="handlePopupChange">
<view class="login-popup-content">
<!-- <view class="popup-title">请选择办理方式</view> -->
<view class="popup-btn active-btn" @click="goToPage('/personal/addVip_per')">
个人会员注册
</view>
<view class="popup-btn plain-btn" @click="goToPage('/personal/home')">
个人会员登录
</view>
</view>
</uni-popup>
</view>
</template>
<script setup>
import {ref} from 'vue'
import {onShow} from '@dcloudio/uni-app'
import config from '@/config.js'
const loginPopup = ref(null)
const activeEntry = ref('')
onShow(() => {
uni.hideLoading();
})
const showLoginPopup = () => {
activeEntry.value = 'personal'
loginPopup.value.open()
}
const goUnitLogin = () => {
activeEntry.value = 'unit'
uni.navigateTo({
url: '/login/loginC',
})
}
const goToPage = (url) => {
loginPopup.value?.close()
uni.navigateTo({
url,
})
}
const handlePopupChange = (e) => {
if (!e.show && activeEntry.value === 'personal') {
activeEntry.value = ''
}
}
</script>
<style lang="scss" scoped>
.role-entry-page {
width: 100%;
min-height: 100vh;
position: relative;
padding: 20rpx 0;
box-sizing: border-box;
overflow: hidden;
}
.page-bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
}
.header-wrapper {
text-align: center;
// padding: 40rpx 0;
border-radius: 16rpx;
margin-top: 100rpx;
}
.btn-container {
display: flex;
flex-direction: column;
align-items: center;
margin: 0 auto;
padding-top: 1040rpx;
gap: 52rpx;
}
.entry-btn {
position: relative;
width: 424rpx;
height: 86rpx;
display: flex;
align-items: center;
justify-content: center;
color: #2f2f2f;
font-size: 34rpx;
font-weight: 700;
letter-spacing: 2rpx;
}
.entry-btn.active {
color: #fff;
}
.btn-bg {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.entry-btn text {
position: relative;
z-index: 1;
}
.loading-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 999;
}
.loading-content {
color: white;
font-size: 28rpx;
}
.login-popup-content {
width: 560rpx;
background: #fff;
border-radius: 28rpx;
padding: 42rpx 42rpx 50rpx;
display: flex;
flex-direction: column;
align-items: center;
box-shadow: 0 20rpx 60rpx rgba(50, 0, 0, 0.25);
}
.popup-title {
margin-bottom: 22rpx;
color: #222;
font-size: 34rpx;
font-weight: 700;
}
.popup-btn {
position: relative;
width: 424rpx;
height: 86rpx;
line-height: 86rpx;
text-align: center;
border-radius: 16rpx;
font-size: 34rpx;
font-weight: 700;
margin: 18rpx 0;
box-sizing: border-box;
}
.active-btn {
background: linear-gradient(90deg, #ff9a00 0%, #e50012 100%);
color: #fff;
}
.plain-btn {
background: #fff;
color: #2f2f2f;
border: 4rpx solid #0b94d2;
box-shadow: inset 4rpx 0 0 #f7a100;
}
</style>
......
......@@ -118,25 +118,29 @@
<view class="popup-title">系统提示</view>
<view class="popup-content">
<view class="popup-text">尊敬的用户,您好!</view>
<view class="popup-text">在开始注册团体会员前,请您提前准备好以下材料,以便顺利完成申请</view>
<view class="popup-text">开始注册单位会员前,请提前准备以下材料(建议拍照或扫描,确保文字清晰、无遮挡)</view>
<view class="popup-item">
<text class="popup-num ml10">1.</text>
单位营业执照
</view>
<view class="popup-desc">请提供清晰的营业执照原件照片或扫描件(加盖公章更佳)</view>
<view class="popup-desc">原件照片或扫描件(加盖公章更佳)</view>
<view class="popup-item">
<text class="popup-tip">!</text>
<text class="popup-num"> 2.</text>
法人身份证正反面照片
法人身份证
</view>
<view class="popup-desc">请分别上传身份证正面及反面清晰照片</view>
<view class="popup-desc">确保信息完整、无遮挡、无模糊</view>
<view class="popup-desc">正、反面清晰照片(信息完整、无模糊)</view>
<!-- <view class="popup-desc">确保信息完整、无遮挡、无模糊</view> -->
<view class="popup-item">
<text class="popup-num ml10">3.</text>
机构照片
</view>
<view class="popup-desc">请提供体现单位实际经营或办公环境的照片1-2张</view>
<view class="popup-desc">如门头、办公场所、活动场地等(能展示机构真实存在即可)</view>
<view class="popup-desc">1–2张能体现单位真实经营或办公环境的照片,例如:门头、办公场所、活动场地等</view>
<!-- <view class="popup-desc">如门头、办公场所、活动场地等(能展示机构真实存在即可)</view> -->
<view class="popup-text">
<!-- <text class="popup-num ml10">3.</text> -->
感谢您的配合,祝您注册顺利!
</view>
</view>
<view class="popup-btns">
<view class="popup-btn cancel" @click="closeRegisterPopup">取消</view>
......@@ -151,7 +155,7 @@
import {onLoad, onReady} from '@dcloudio/uni-app';
import {ref, nextTick} from 'vue'
import config from '@/config.js'
import {getCodeImg, getSmsCodeImg, pcLogin, loginByPhone} from '@/common/login.js'
import {getCodeImg, getSmsCodeImg, pcLogin, loginByPhone, getInfo} from '@/common/login.js'
const isActive = ref(0)
const agree = ref(false)
......@@ -182,6 +186,14 @@ const countDown = ref({
const app = getApp()
function goHomeAfterLogin() {
const deptType = app.globalData.deptType
const userType = app.globalData.userType
uni.reLaunch({
url: (deptType == 6 || deptType == '6' || userType == '4') ? '/pages/index/daoGuanPerson' : '/pages/index/home'
})
}
onLoad(() => {
getCode()
if (uni.showShareMenu) {
......@@ -220,9 +232,12 @@ function login() {
}
if (loading.value) return;
loading.value = true
pcLogin(form.value).then((res) => {
pcLogin(form.value).then(() => {
app.globalData.isLogin = true
uni.redirectTo({url: '/pages/index/home'})
goHomeAfterLogin()
}).catch((err) => {
console.error('登录失败:', err)
uni.showToast({title: '登录失败', icon: 'none'})
}).finally(() => {
loading.value = false
})
......@@ -244,9 +259,8 @@ function login() {
loading.value = true
loginByPhone(form2.value.telNo, form2.value.code)
.then(() => {
loading.value = false
app.globalData.isLogin = true
uni.redirectTo({url: '/pages/index/home'})
goHomeAfterLogin()
}).finally(() => {
loading.value = false
})
......
......@@ -22,7 +22,7 @@
<!-- 温馨提示 -->
<view v-if="form.selfSelect == '1'" class="tip-box">
<text class="tip-text">温馨提示:
您可以自行录入考官信息,如果暂时没有合适的考官,也可以选择由省跆协指派(支持多选)进行考点申报,同时请尽快完成考点考官的认证。
您可以自行录入考官信息,如果暂时没有考官,可以选择由省跆协指派进行考点申报,请尽快完成考点考官的认证。
</text>
</view>
......
......@@ -48,8 +48,12 @@
<!-- 金额说明 -->
<view class="card notice-card">
<view class="notice-line">1. 请通过网上银行(网银)或银行柜台或手机银行向以下账号划转款项。</view>
<view class="notice-line">2. 转账金额与订单金额必须保持一致,不得多转、少转。</view>
<view class="danger-title">
<text>请使用认证机构下的账号进行对公转账。</text>
</view>
<view class="notice-line">1. 本订单将为您保留7天,请您及时支付;逾期未支付,订单将自动取消。</view>
<view class="notice-line">2. 请通过网上银行(网银)或银行柜台或手机银行向以下账号划转款项。</view>
<view class="notice-line">3. 转账金额与订单金额必须保持一致,不得多转、少转。</view>
</view>
<!-- 温馨提示 -->
......@@ -293,6 +297,14 @@ function handelClose() {
}
}
}
.danger-title{
display: flex;
align-items: center;
font-size: 28rpx;
color: #F56C6C;
font-weight: 600;
margin-bottom: 16rpx;
}
/* 温馨提示 */
.warning-card {
......
......@@ -20,6 +20,56 @@
}
},
{
"path": "pages/index/daoGuanPerson",
"style": {
"navigationBarTitleText": "人员",
"backgroundColor": "#ffffff",
"navigationStyle": "custom",
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#ffffff"
}
},
{
"path": "pages/index/daoGuanLevel",
"style": {
"navigationBarTitleText": "级位",
"backgroundColor": "#ffffff",
"navigationStyle": "custom",
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#ffffff"
}
},
{
"path": "pages/index/daoGuanOrder",
"style": {
"navigationBarTitleText": "订单",
"backgroundColor": "#ffffff",
"navigationStyle": "custom",
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#ffffff"
}
},
{
"path": "pages/index/daoGuanNotice",
"style": {
"navigationBarTitleText": "通知",
"backgroundColor": "#ffffff",
"navigationStyle": "custom",
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#ffffff"
}
},
{
"path": "pages/index/daoGuanMy",
"style": {
"navigationBarTitleText": "我的",
"backgroundColor": "#ffffff",
"navigationStyle": "custom",
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#ffffff"
}
},
{
"path": "pages/webview/webview",
"style": {
"navigationBarTitleText": "中国跆拳道协会",
......@@ -189,6 +239,7 @@
}
}
],
"globalStyle": {
"navigationStyle": "default",
"navigationBarTextStyle": "black",
......
<template>
<view class="level-page">
<view class="hero">
<image class="hero-bg" :src="config.baseUrl_api + '/fs/static/img/top.png'" mode="aspectFill"></image>
<view class="hero-brand">
<view class="brand-cn">中国跆拳道协会</view>
<view class="brand-en">CHINESE TAEKWONDO ASSOCIATION</view>
</view>
</view>
<view class="content-panel">
<image class="panel-bg" :src="config.baseUrl_api + '/fs/static/img/red_bg2.png'" mode="scaleToFill"></image>
<view class="panel-content">
<view class="section-title">
<view class="title-cn">级位考试</view>
<view style="width:50rpx;height:8rpx;background:#C30D23;margin-top:20rpx;"></view>
<view class="title-en">LEVEL EXAM</view>
</view>
<view class="level-grid">
<image class="level-card" :src="config.baseUrl_api + '/fs/static/img/jw_btn01.png'" mode="aspectFit" @click="goPath('/level/addApply')"></image>
<image class="level-card" :src="config.baseUrl_api + '/fs/static/img/jw_btn02.png'" mode="aspectFit" @click="goPath('/personalVip/addChangeLevel')"></image>
<image class="level-card" :src="config.baseUrl_api + '/fs/static/img/jw_btn03.png'" mode="aspectFit" @click="goPath('/level/apply')"></image>
<image class="level-card" :src="config.baseUrl_api + '/fs/static/img/jw_btn04.png'" mode="aspectFit" @click="goPath('/personalVip/changeLevel')"></image>
</view>
</view>
</view>
<dao-guan-tab-bar :currentIndex="3" @switch="onTabSwitch" />
</view>
</template>
<script setup>
import config from '@/config.js'
import DaoGuanTabBar from '@/components/dao-guan-tab-bar.vue'
const onTabSwitch = () => {
// tab switch handled by component
}
const goPath = (url) => {
uni.navigateTo({ url })
}
</script>
<style lang="scss" scoped>
.level-page {
position: relative;
min-height: 100vh;
overflow-x: hidden;
background: #ededf0;
overflow-y: hidden;
// padding-bottom: calc(120rpx + env(safe-area-inset-bottom));
box-sizing: border-box;
}
.hero {
position: relative;
height: 1060rpx;
overflow: hidden;
z-index: 1;
}
.hero-bg {
position: absolute;
left: 0;
top: -116px;
width: 100%;
height: 100%;
}
.hero-brand {
position: relative;
z-index: 1;
padding: calc(env(safe-area-inset-top) + 170rpx) 44rpx 0;
color: #fff;
}
.brand-cn {
font-size: 38rpx;
letter-spacing: 2rpx;
}
.brand-en {
margin-top: 8rpx;
color: rgba(255, 255, 255, 0.62);
font-size: 16rpx;
}
.content-panel {
position: relative;
z-index: 3;
min-height: 760rpx;
margin-top: -300rpx;
overflow: visible;
}
.panel-bg {
position: absolute;
left: 0;
top: -674rpx;
z-index:10;
width: 100%;
height: 1700rpx;
}
.panel-content {
position: relative;
z-index: 12;
padding: 0rpx 46rpx 40rpx;
}
.section-title {
margin-bottom: 30rpx;
}
.title-cn {
color: #2a2a2a;
font-size: 58rpx;
line-height: 1;
}
.title-en {
margin-top: 12rpx;
color: #9a9a9a;
font-size: 24rpx;
font-weight: 700;
}
.level-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 14rpx 14rpx;
}
.level-card {
width: 100%;
height: 236rpx;
border-radius: 10rpx;
}
</style>
<template>
<view class="page dao-my-page">
<image class="page-red-bg" :src="config.baseUrl_api + '/fs/static/img/red_bg.png'" mode="scaleToFill"></image>
<view class="profile-hero">
<view class="hero-content">
<view class="profile-row">
<view class="avatar-wrap">
<image v-if="state.user.avatar" :src="state.user.avatar" mode="aspectFill"/>
<image v-else :src="config.baseUrl_api + '/fs/static/nodata.png'" mode="aspectFill"/>
</view>
<!-- <view class="profile-main">
<view class="name-row">
<view class="dept-name">{{ state.user?.dept?.deptName || deptInfo.deptName || memberInfo.name || '--' }}</view>
<view class="member-badge">
<text class="badge-star"></text>
<text>金牌会员</text>
</view>
</view>
<view class="id-row">
<text>ID:{{ memberInfo.menCode || memberInfo.memberCode || memberInfo.memberNo || state.user?.userName || '--' }}</text>
<text class="join-days">您已加入{{ joinDays }}</text>
</view>
</view> -->
</view>
<view class="motto">每一次的成功都不是偶然,是千锤百炼,永不放弃的结果。{{ state.user?.dept?.deptName || '龙威天成跆拳道馆' }},以专业铸就辉煌!</view>
<view class="edit-btn" @click="goPath('/myCenter/teamInfo')">修改资料</view>
</view>
</view>
<view class="menu-panel">
<image class="menu-bg" :src="config.baseUrl_api + '/fs/static/img/red_bg2.png'" mode="scaleToFill"></image>
<view class="menu-item" @click="goPath('/myCenter/teamInfo')">
<view class="menu-left">
<image class="menu-icon" :src="config.baseUrl_api + '/fs/static/img/user01.png'" mode="aspectFit"></image>
<text>单位信息</text>
</view>
<text class="arrow">></text>
</view>
<view class="menu-item" @click="goPath('/myCenter/auth')">
<view class="menu-left">
<image class="menu-icon" :src="config.baseUrl_api + '/fs/static/img/user02.png'" mode="aspectFit"></image>
<text>会员认证</text>
</view>
<text class="arrow">></text>
</view>
<view class="menu-item" @click="goPath('/myCenter/safe')">
<view class="menu-left">
<image class="menu-icon" :src="config.baseUrl_api + '/fs/static/img/user03.png'" mode="aspectFit"></image>
<text>账号安全</text>
</view>
<text class="arrow">></text>
</view>
</view>
<view class="logout-area">
<button class="logout-btn" @click="loginOut">退出登录</button>
</view>
<!-- 底部导航 -->
<dao-guan-tab-bar :currentIndex="4" @switch="onTabSwitch" />
</view>
</template>
<script setup>
import * as api from '@/common/api.js';
import * as loginServer from '@/common/login.js';
import config from '@/config.js'
import {
onLoad,
onShow,
onReady,
onPullDownRefresh
} from '@dcloudio/uni-app';
import {
ref, reactive, computed,
getCurrentInstance
} from 'vue';
import DaoGuanTabBar from '@/components/dao-guan-tab-bar.vue'
const {
proxy
} = getCurrentInstance()
const app = getApp();
const userType = ref('1')
const memberInfo = ref({})
const deptInfo = ref({})
let proId;
const svId = ref(null);
const numData = ref({});
const messageList = ref([])
const state = reactive({
user: {},
roleGroup: {},
postGroup: {}
})
const joinDays = computed(() => {
const value = memberInfo.value.createTime || memberInfo.value.joinTime || memberInfo.value.createDate
if (!value) return '--'
const start = new Date(String(value).replace(/-/g, '/')).getTime()
if (!start) return '--'
const days = Math.floor((Date.now() - start) / (24 * 60 * 60 * 1000)) + 1
return days > 0 ? days : 1
})
onShow(() => {
if (app.globalData.isLogin) {
init()
} else {
app.firstLoadCallback = () => {
init()
};
}
})
onLoad(option => {
if (option.scene) {
proId = decodeURIComponent(option.scene);
} else {
proId = option.proId;
}
if (uni.showShareMenu) {
uni.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
});
}
});
function loginOut() {
uni.showModal({
content: `确认退出吗?`,
success: function (res) {
if (res.confirm) {
loginServer.logout().finally(() => {
let path = '/login/login';
uni.reLaunch({
url: path
});
})
}
}
})
}
function getUser() {
api.getUserProfile().then((response) => {
state.user = response.data.user
if (state.user.avatar && state.user.avatar.indexOf('http') == -1) {
state.user.avatar = config.baseUrl_api + state.user.avatar
}
state.roleGroup = response.data.roleGroup
state.postGroup = response.data.postGroup
uni.hideLoading();
})
}
function init() {
uni.showLoading({
title: '加载中'
});
getUser()
loginServer.getMyOwnMemberInfo().then(res => {
userType.value = app.globalData.userType
memberInfo.value = app.globalData.memberInfo
deptInfo.value = app.globalData.dept || {}
uni.hideLoading();
})
}
function goPath(url) {
uni.navigateTo({
url: url
})
}
function onTabSwitch(index, url) {
// tab switch handled by component
}
</script>
<style lang="scss" scoped>
.dao-my-page {
position: relative;
min-height: 100vh;
width: 100vw;
overflow-x: hidden;
box-sizing: border-box;
padding-bottom: calc(210rpx + env(safe-area-inset-bottom));
background: #ededf0;
}
.page-red-bg {
position: absolute;
left: 0;
top: 0;
z-index: 0;
width: 100%;
height: 720rpx;
}
.profile-hero {
position: relative;
z-index: 1;
min-height: 460rpx;
}
.hero-content {
position: relative;
z-index: 2;
padding: calc(env(safe-area-inset-top) + 126rpx) 48rpx 0;
color: #fff;
}
.profile-row {
display: flex;
align-items: center;
}
.avatar-wrap {
width: 132rpx;
height: 132rpx;
padding: 6rpx;
flex: 0 0 132rpx;
overflow: hidden;
border-radius: 50%;
background: #fff;
box-shadow: 0 8rpx 26rpx rgba(65, 0, 0, 0.28);
image {
width: 100%;
height: 100%;
border-radius: 50%;
}
}
.profile-main {
flex: 1;
min-width: 0;
margin-left: 26rpx;
}
.name-row,
.id-row {
display: flex;
align-items: center;
justify-content: space-between;
}
.dept-name {
max-width: 330rpx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 34rpx;
font-weight: 700;
}
.member-badge {
display: flex;
align-items: center;
gap: 8rpx;
color: #dba12d;
font-size: 24rpx;
white-space: nowrap;
}
.badge-star {
color: #f7c342;
font-size: 24rpx;
}
.id-row {
margin-top: 12rpx;
color: rgba(255, 255, 255, 0.86);
font-size: 26rpx;
}
.join-days {
margin-left: 18rpx;
white-space: nowrap;
}
.motto {
margin-top: 52rpx;
color: rgba(255, 255, 255, 0.86);
font-size: 24rpx;
line-height: 1.75;
}
.edit-btn {
width: 168rpx;
height: 48rpx;
margin: 34rpx 0 0 auto;
border-radius: 6rpx;
background: #fff;
color: #333;
font-size: 24rpx;
line-height: 48rpx;
text-align: center;
}
.menu-panel {
position: relative;
z-index: 2;
min-height: 560rpx;
margin-top: -72rpx;
padding: 178rpx 48rpx 0;
overflow: hidden;
}
.menu-bg {
position: absolute;
left: 0;
top: -400rpx;
z-index: 0;
width: 100%;
height: 1400rpx;
}
.menu-item {
position: relative;
z-index: 1;
display: flex;
align-items: center;
justify-content: space-between;
height: 132rpx;
color: #111;
font-size: 31rpx;
font-weight: 700;
}
.menu-left {
display: flex;
align-items: center;
}
.menu-icon {
width: 38rpx;
height: 38rpx;
margin-right: 18rpx;
}
.arrow {
color: #111;
font-size: 42rpx;
font-weight: 400;
line-height: 1;
}
.logout-area {
position: fixed;
left: 0;
right: 0;
bottom: calc(124rpx + env(safe-area-inset-bottom));
z-index: 9998;
padding: 16rpx 48rpx 18rpx;
background: transparent;
box-sizing: border-box;
}
.logout-btn {
height: 76rpx;
border-radius: 50rpx;
background: #ad181f;
color: #fff;
font-size: 28rpx;
line-height: 76rpx;
}
.logout-btn::after {
border: none;
}
</style>
<template>
<view class="notice-page">
<z-paging
ref="paging"
v-model="dataList"
class="notice-paging"
emptyViewImg="/static/nodata.png"
@query="queryList"
>
<template #top>
<view class="notice-hero">
<view class="hero-title-row">
<view>
<view class="hero-title">中国跆拳道协会</view>
<view class="hero-subtitle">CHINESE TAEKWONDO ASSOCIATION</view>
</view>
<view class="hero-page-title">
<text>协会资讯</text>
<view class="title-line"></view>
</view>
</view>
<view class="search-bar">
<uni-easyinput
v-model="query.keyword"
:input-border="false"
class="search-input"
placeholder="请输入公告标题"
placeholderStyle="font-size:28rpx;color:#999"
prefixIcon="search"
@confirm="handleSearch"
@clear="handleSearch"
/>
<view class="search-btn" @click="handleSearch">搜索</view>
</view>
</view>
<!-- <view class="notice-tabs">
<view class="tab-item active">公告</view>
</view> -->
</template>
<view class="notice-list">
<view v-for="item in dataList" :key="item.id || item.noteId" class="notice-item" @click="goDetail(item)">
<view class="notice-title">{{ item.name || item.title || '--' }}</view>
<view v-if="item.introduction || item.remark || item.content" class="notice-summary">
{{ item.introduction || item.remark || item.content }}
</view>
<image
v-if="getCover(item)"
:src="getCover(item)"
class="notice-cover"
mode="aspectFill"
/>
<view class="notice-meta">
<text>{{ formatDate(item.belongTime || item.createTime || item.publishTime) }}</text>
<!-- <view class="meta-right">
<text class="heart">♡</text>
<text>{{ item.readNum || item.views || item.likeNum || 0 }}</text>
<text class="more">...</text>
</view> -->
</view>
</view>
</view>
</z-paging>
<dao-guan-tab-bar :currentIndex="2" @switch="onTabSwitch" />
</view>
</template>
<script setup>
import { ref, reactive } from 'vue'
import * as api from '@/common/api.js'
import dayjs from 'dayjs'
import DaoGuanTabBar from '@/components/dao-guan-tab-bar.vue'
const dataList = ref([])
const paging = ref(null)
const query = reactive({
keyword: ''
})
const queryList = (pageNum, pageSize) => {
api.notice({
pageNum,
pageSize,
name: query.keyword
}).then(res => {
paging.value?.complete(res.rows || [])
}).catch(() => {
paging.value?.complete(false)
})
}
const handleSearch = () => {
paging.value?.reload()
}
const getCover = (item) => {
return item.coverUrl || item.cover || item.picUrl || item.imageUrl || item.imgUrl || ''
}
const formatDate = (value) => {
if (!value) return ''
return dayjs(value).format('YYYY-MM-DD')
}
const goDetail = (item) => {
uni.navigateTo({
url: `/pages/index/newsDetail?noteId=${item.noteId}`
})
}
const onTabSwitch = () => {
// tab switch handled by component
}
</script>
<style lang="scss" scoped>
.notice-page {
position: relative;
min-height: 100vh;
background: #ededf0;
box-sizing: border-box;
}
.notice-hero {
padding: calc(env(safe-area-inset-top) + 88rpx) 40rpx 34rpx;
background: linear-gradient(135deg, #b00005 0%, #760000 100%);
color: #fff;
}
.hero-title-row {
display: flex;
justify-content: space-between;
align-items: flex-end;
margin-bottom: 42rpx;
}
.hero-title {
font-size: 38rpx;
letter-spacing: 2rpx;
}
.hero-subtitle {
margin-top: 8rpx;
color: rgba(255, 255, 255, 0.6);
font-size: 16rpx;
}
.hero-page-title {
color: #f4b536;
font-size: 36rpx;
font-weight: 500;
text-align: right;
}
.title-line {
width: 54rpx;
height: 6rpx;
margin: 14rpx 0 0 auto;
border-radius: 10rpx;
background: #f4b536;
}
.search-bar {
display: flex;
align-items: center;
height: 64rpx;
border-radius: 34rpx;
background: #fff;
overflow: hidden;
}
.search-input {
flex: 1;
:deep(.uni-easyinput__content) {
height: 64rpx;
padding: 0 18rpx 0 28rpx;
border-radius: 34rpx;
background: #fff;
}
}
.search-btn {
width: 88rpx;
height: 52rpx;
margin-right: 6rpx;
border-radius: 28rpx;
background: #c91c34;
color: #fff;
font-size: 24rpx;
font-weight: 700;
line-height: 52rpx;
text-align: center;
}
.notice-tabs {
display: flex;
align-items: center;
padding: 24rpx 40rpx 8rpx;
}
.tab-item {
position: relative;
margin-right: 54rpx;
padding-bottom: 14rpx;
color: #555;
font-size: 30rpx;
}
.tab-item.active {
color: #c30d23;
font-weight: 700;
}
.tab-item.active::after {
content: '';
position: absolute;
left: 50%;
bottom: 0;
width: 52rpx;
height: 4rpx;
border-radius: 4rpx;
background: #c30d23;
transform: translateX(-50%);
}
.notice-paging {
height: 100vh;
background: #ededf0;
}
.notice-list {
padding: 0 10rpx calc(160rpx + env(safe-area-inset-bottom));
}
.notice-item {
margin-bottom: 34rpx;
background: #fff;
padding: 24rpx;
border-radius: 16rpx;
margin: 20rpx;
}
.notice-title {
color: #111;
font-size: 31rpx;
font-weight: 800;
line-height: 1.42;
}
.notice-summary {
display: -webkit-box;
margin-top: 12rpx;
overflow: hidden;
color: #666;
font-size: 25rpx;
line-height: 1.45;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.notice-cover {
width: 100%;
height: 330rpx;
margin-top: 14rpx;
border-radius: 0;
background: #ddd;
}
.notice-meta {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 10rpx;
color: #999;
font-size: 24rpx;
}
.meta-right {
display: flex;
align-items: center;
gap: 8rpx;
}
.heart {
font-size: 28rpx;
}
.more {
margin-left: 14rpx;
letter-spacing: 2rpx;
}
</style>
......@@ -552,13 +552,14 @@
<uni-popup ref="examPointPopup" :mask-click="false" type="center">
<view class="dialog-wrapper exam-dialog">
<view class="dialog-close" @click="closeExamPointDialog"></view>
<view class="dialog-icon success-icon">
<uni-icons color="#29c490" size="48" type="checkmark"></uni-icons>
</view>
<view class="dialog-icon success-icon">
<uni-icons color="#ffffff" size="40" type="check"></uni-icons>
</view>
<view class="dialog-title">申请成为考点</view>
<view class="dialog-message">
<text>恭喜您成为中国跆拳道协会团体会员!</text>
<text>恭喜您成为中国跆拳道协会单位会员!</text>
<text>根据协会考点管理办法,需成为考点单位才能进行考级业务的办理。</text>
<text>是否现在申请成为考点?</text>
</view>
<view class="dialog-footer">
<button class="dialog-btn cancel" @click="closeExamPointDialog">取消</button>
......@@ -1049,11 +1050,11 @@ function checkDialogs() {
refreshCaptcha()
bindingPhonePopup.value.open()
}
console.log(99,app.globalData.memberInfo?.activeStatus,app.globalData.authenticationStatus,user.hintFlag,app.globalData.deptType,memberInfoData.isPoints,app.globalData.deptType)
// 申请考点条件: activeStatus=1 && authenticationStatus=2 && hintFlag=1 && deptType=6 && isPoints=1
if (app.globalData.memberInfo?.activeStatus == 1 &&
app.globalData.authenticationStatus == 2 &&
user.hintFlag == 1 &&
app.globalData.deptType == 6 &&
memberInfoData.isPoints == 1) {
examPointPopup.value.open()
......@@ -1481,7 +1482,7 @@ function checkDialogs() {
}
.success-icon {
color: #29c490;
color: #29c490;
}
/* 密码提示弹框样式 */
......
......@@ -13,7 +13,8 @@
useUserStore
} from '../../store/modules/user';
const userStore = useUserStore()
const userStore = useUserStore()
const app = getApp()
onShow(() => {
let user = userStore.user
......@@ -25,11 +26,21 @@
}
let userName = uni.getStorageSync('userName')
console.log('userName', userName)
console.log('app.globalData.userType ', app.globalData.userType )
if (userName) {
uni.reLaunch({
if(app.globalData.userType == 4){
uni.reLaunch({
url: '/pages/index/daoGuanPerson'
})
return
}else{
uni.reLaunch({
url: '/pages/index/home'
})
return
})
return
}
}
let webUserName = uni.getStorageSync('webUserName')
......@@ -43,4 +54,4 @@
</script>
<style scope lang="scss">
</style>
\ No newline at end of file
</style>
......
......@@ -204,7 +204,6 @@ import {
import config from "/config.js";
import {
wxLogin,
logout,
getWebInfo
} from '@/common/login.js';
import {useUserStore} from "@/store/modules/user.js";
......@@ -238,6 +237,9 @@ const showConfirm = ref(false)
let hasOpenedBindPopup = false
onShow(() => {
// 重置绑定弹框标志,确保每次进入页面都能正确弹出
hasOpenedBindPopup = false
let webUserName = uni.getStorageSync('webUserName')
if (!webUserName) {
// 登录后需要等待数据加载完成
......@@ -245,7 +247,13 @@ onShow(() => {
getWebInfo().then(() => {
// 数据加载完成后检查是否需要弹出绑定框
checkAndOpenBindPopup()
}).catch(() => {
// getWebInfo 失败时也检查一下
checkAndOpenBindPopup()
})
}).catch(() => {
// wxLogin 失败时也检查一下
checkAndOpenBindPopup()
})
} else {
// 已登录,直接检查
......@@ -516,14 +524,23 @@ const cancelLogout = () => {
};
// 确认退出登录
const confirmLogout = () => {
// 调用退出登录接口
logout().then(() => {
// 跳转到登录页
uni.reLaunch({
url: '/login/login'
})
});
const confirmLogout = async () => {
showConfirm.value = false
uni.showLoading({ title: '退出中...', mask: true })
// 调用解绑接口
await to(unbindUser())
// 清除缓存和用户信息
uni.removeStorageSync('webUserName')
userStore.setPerInfo(null)
userStore.setUser(null)
// 跳转到登录页
uni.reLaunch({
url: '/login/login'
})
};
</script>
......
<template>
<view class="hasfixedbottom">
<view class="searchbar">
<uni-easyinput placeholderStyle="font-size:30rpx" :input-border="false" prefixIcon="search"
v-model="queryParams.perName" placeholder="搜索姓名或证件号码" @blur="getList" @clear="getList">
</uni-easyinput>
<view class="invertedbtn-red" @click="goVipList">+ 添加会员</view>
<view class="invertedbtn-red" @click="showAddPopup">+ 添加</view>
<view class="invertedbtn-red" @click="goVipList">+ 在线选择</view>
</view>
<view style="padding:0 20rpx">
......@@ -58,6 +60,33 @@
</view>
</view>
</uni-popup>
<!-- 添加会员弹框 -->
<uni-popup ref="addPopup" type="center">
<view class="add-popup">
<view class="popup-title">添加会员</view>
<view class="popup-form">
<view class="form-item">
<view class="form-label">证件类型</view>
<view class="form-input">
<picker :value="idcListIndex" :range="idcList" range-key="label" @change="onIdcTypeChange">
<view class="picker-value">{{ idcList[idcListIndex]?.label }}</view>
</picker>
</view>
</view>
<view class="form-item">
<view class="form-label">证件号</view>
<view class="form-input">
<input v-model="addForm.idcCode" placeholder="请输入证件号" placeholder-class="placeholder-class"/>
</view>
</view>
</view>
<view class="popup-btns">
<view class="popup-btn cancel" @click="closeAddPopup">取消</view>
<view class="popup-btn confirm" @click="confirmAdd">确定</view>
</view>
</view>
</uni-popup>
</view>
</template>
......@@ -78,7 +107,18 @@
const nowYear = ref(1)
const nowItem = ref({})
const pickView = ref(null)
const addPopup = ref(null)
const visible = ref(true)
const addForm = ref({
idcCode: '',
idType: '0'
})
const idcList = ref([
{ label: '身份证', value: '0' },
{ label: '来往大陆(内地)通行证', value: '1' },
{ label: '香港身份证', value: '5' }
])
const idcListIndex = ref(0)
const yearlist = ref([{
text: '一年',
value: 1
......@@ -197,6 +237,50 @@
url: `/myCenter/payOrder?rangeId=${queryParams.value.rangeId}`
})
}
// 显示添加弹框
function showAddPopup() {
addForm.value.idcCode = ''
idcListIndex.value = 0
addPopup.value.open()
}
// 关闭添加弹框
function closeAddPopup() {
addPopup.value.close()
}
// 证件类型选择
function onIdcTypeChange(e) {
idcListIndex.value = e.detail.value
addForm.value.idType = idcList.value[idcListIndex.value].value
}
// 确认添加
async function confirmAdd() {
if (!addForm.value.idcCode) {
uni.showToast({ title: '请输入证件号', icon: 'none' })
return
}
if (!queryParams.value.rangeId) {
uni.showToast({ title: '缺少rangeId', icon: 'none' })
return
}
try {
await api.memberInsertPersons({
rangeId: queryParams.value.rangeId,
year: 1,
idcCode: addForm.value.idcCode
})
uni.showToast({ title: '添加成功', icon: 'success' })
closeAddPopup()
getList()
getCount()
} catch (e) {
console.error(e)
}
}
</script>
<style scoped lang="scss">
......@@ -301,4 +385,86 @@
font-size: 32rpx;
border: none;
}
/* 添加会员弹框 */
.add-popup {
width: 600rpx;
background: #ffffff;
border-radius: 24rpx;
overflow: hidden;
}
.popup-title {
font-size: 32rpx;
font-weight: 500;
color: #333;
text-align: center;
padding: 40rpx 30rpx 20rpx;
}
.popup-form {
padding: 20rpx 30rpx 40rpx;
}
.form-item {
display: flex;
align-items: center;
margin-bottom: 24rpx;
}
.form-item:last-child {
margin-bottom: 0;
}
.form-label {
width: 140rpx;
font-size: 28rpx;
color: #333;
flex-shrink: 0;
}
.form-input {
flex: 1;
background: #f5f5f5;
border-radius: 12rpx;
padding: 20rpx 24rpx;
}
.form-input input {
font-size: 28rpx;
color: #333;
width: 100%;
}
.picker-value {
font-size: 28rpx;
color: #333;
}
.placeholder-class {
color: #999;
}
.popup-btns {
display: flex;
border-top: 1rpx solid #eee;
}
.popup-btn {
flex: 1;
height: 100rpx;
line-height: 100rpx;
text-align: center;
font-size: 30rpx;
}
.popup-btn.cancel {
color: #666;
border-right: 1rpx solid #eee;
}
.popup-btn.confirm {
color: #E60012;
font-weight: 500;
}
</style>
\ No newline at end of file
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!