Commit 67af4c8eabfb3b83000026a0a78b26ba26875cbb

Authored by 刘淇
1 parent 48ff5b95

工作台 如果没有子节点就不渲染父节点

pages/mine/index.vue
@@ -8,19 +8,19 @@ @@ -8,19 +8,19 @@
8 <view class="user-info-wrap"> 8 <view class="user-info-wrap">
9 <!-- 头像 --> 9 <!-- 头像 -->
10 <up-avatar 10 <up-avatar
11 - :src="'/static/imgs/default-avatar.png'" 11 + :src="userStore.isLogin ? userInfo.avatar : '/static/imgs/default-avatar.png'"
12 size="100rpx" 12 size="100rpx"
13 shape="circle" 13 shape="circle"
14 class="user-avatar" 14 class="user-avatar"
15 ></up-avatar> 15 ></up-avatar>
16 16
17 - <!-- 用户名+手机号+角色 --> 17 + <!-- 用户名+手机号 -->
18 <view class="user-info-content"> 18 <view class="user-info-content">
19 - <view class="user-name">{{ userInfo.username || '未登录' }}</view>  
20 - <view class="user-phone">{{ userInfo.nickname || '--------' }}</view> 19 + <view class="user-name">{{ userStore.isLogin ? userInfo.username : '未登录' }}</view>
  20 + <view class="user-phone">{{ userStore.isLogin ? userInfo.nickname : '--------' }}</view>
21 </view> 21 </view>
22 22
23 - <!-- 登录/编辑入口 --> 23 + <!-- 登录入口 -->
24 <up-button 24 <up-button
25 v-if="!userStore.isLogin" 25 v-if="!userStore.isLogin"
26 type="primary" 26 type="primary"
@@ -32,9 +32,8 @@ @@ -32,9 +32,8 @@
32 </view> 32 </view>
33 </view> 33 </view>
34 34
35 -  
36 <!-- 退出登录按钮 (仅登录状态显示) --> 35 <!-- 退出登录按钮 (仅登录状态显示) -->
37 - <view v-if="userStore.isLogin" class="logout-btn-wrap "> 36 + <view v-if="userStore.isLogin" class="logout-btn-wrap">
38 <up-button 37 <up-button
39 type="primary" 38 type="primary"
40 size="large" 39 size="large"
@@ -43,77 +42,64 @@ @@ -43,77 +42,64 @@
43 退出登录 42 退出登录
44 </up-button> 43 </up-button>
45 </view> 44 </view>
46 -  
47 -  
48 </view> 45 </view>
49 </template> 46 </template>
50 47
51 <script setup lang="ts"> 48 <script setup lang="ts">
52 -import { ref } from 'vue'  
53 -import { useUserStore } from '@/pinia/user' // 匹配你的 Pinia 路径  
54 -import { onShow } from '@dcloudio/uni-app'  
55 - 49 +import { computed } from 'vue'
  50 +import { useUserStore } from '@/pinia/user'
  51 +import { showModal, onShow } from '@dcloudio/uni-app'
56 // 初始化Pinia仓库 52 // 初始化Pinia仓库
57 const userStore = useUserStore() 53 const userStore = useUserStore()
58 -const userInfo = userStore.userInfo.user  
59 -import { getDictList, getDictLabel, getDictSimpleList } from '@/common/utils/dict';  
60 -// 示例1:获取ai_image_status的完整字典列表  
61 -const aiImageStatusList = ref([]);  
62 -// 示例2:获取ai_image_status中value=10的label  
63 -const aiImageStatus10Label = ref('');  
64 -  
65 -// 获取ai_image_status的完整列表(包含所有字段)  
66 -aiImageStatusList.value = getDictList('ai_image_status');  
67 -// 获取ai_image_status中value=10的label  
68 -aiImageStatus10Label.value = getDictLabel('ai_image_status', 10);  
69 -console.log('13')  
70 -console.log(aiImageStatusList.value)  
71 -console.log(aiImageStatus10Label.value)  
72 -  
73 -// 可选:获取仅包含value和label的简化列表  
74 -const simpleList = getDictSimpleList('ai_image_status');  
75 -console.log('简化列表:', simpleList);  
76 -console.log('24')  
77 -  
78 -  
79 54
  55 +// 计算属性获取用户信息(响应式)
  56 +const userInfo = computed(() => userStore.userInfo.user || {})
80 57
81 -// 页面显示时检查登录状态(同步缓存)  
82 -onShow(() => {  
83 - // 触发登录状态检查,确保缓存和Pinia同步  
84 - userStore.checkLogin()  
85 -})  
86 -  
87 -// 处理登录(跳转到登录页) 58 +/**
  59 + * 处理登录跳转
  60 + */
88 const handleLogin = () => { 61 const handleLogin = () => {
89 - navigateTo({  
90 - url: '/pages/login/index' // 替换为你的实际登录页路径 62 + uni.navigateTo({
  63 + url: '/pages/login/index'
91 }) 64 })
92 } 65 }
93 66
94 -  
95 -  
96 -// 确认退出登录 67 +/**
  68 + * 确认退出登录(带二次确认)
  69 + */
97 const confirmLogout = async () => { 70 const confirmLogout = async () => {
  71 + console.log('13213')
98 try { 72 try {
99 - // 调用Pinia自带的logout方法(你的仓库已实现清空状态+跳转)  
100 - await userStore.logout() 73 + console.log('434')
  74 + const res = await uni.showModal({
  75 + title: '提示',
  76 + content: '确定要退出登录吗?',
  77 + confirmText: '退出',
  78 + cancelText: '取消'
  79 + })
101 80
  81 + if (res.confirm) {
  82 + await userStore.logout()
  83 + uni.showToast({ title: '退出登录成功', type: 'success' })
  84 + }
102 } catch (error) { 85 } catch (error) {
103 console.error('退出登录失败:', error) 86 console.error('退出登录失败:', error)
104 - uni.showToast({  
105 - title: '退出登录失败,请重试',  
106 - type: 'error'  
107 - })  
108 - 87 + uni.showToast({ title: '退出登录失败,请重试', type: 'error' })
109 } 88 }
110 } 89 }
111 90
  91 +// 页面显示时检查登录状态
  92 +onShow(() => {
  93 + userStore.checkLogin()
  94 +})
112 </script> 95 </script>
113 96
114 <script lang="ts"> 97 <script lang="ts">
115 export default { 98 export default {
116 - name: 'UserCenter' 99 + name: 'UserCenter',
  100 + options: {
  101 + navigationBarTitleText: '个人中心'
  102 + }
117 } 103 }
118 </script> 104 </script>
119 105
@@ -149,6 +135,10 @@ export default { @@ -149,6 +135,10 @@ export default {
149 .user-avatar { 135 .user-avatar {
150 border: 4rpx solid #ffffff; 136 border: 4rpx solid #ffffff;
151 box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1); 137 box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
  138 + transition: transform 0.2s ease;
  139 + &:active {
  140 + transform: scale(0.95);
  141 + }
152 } 142 }
153 143
154 .user-info-content { 144 .user-info-content {
@@ -166,25 +156,13 @@ export default { @@ -166,25 +156,13 @@ export default {
166 .user-phone { 156 .user-phone {
167 font-size: 26rpx; 157 font-size: 26rpx;
168 color: rgba(255, 255, 255, 0.9); 158 color: rgba(255, 255, 255, 0.9);
169 - margin-bottom: 10rpx;  
170 - }  
171 -  
172 - .user-role-tag {  
173 - background-color: rgba(255, 255, 255, 0.2);  
174 - color: #ffffff;  
175 - border: none;  
176 } 159 }
177 } 160 }
178 } 161 }
179 } 162 }
180 163
181 -  
182 // 退出登录按钮 164 // 退出登录按钮
183 .logout-btn-wrap { 165 .logout-btn-wrap {
184 margin: 200rpx 20rpx 20rpx; 166 margin: 200rpx 20rpx 20rpx;
185 - padding: 20rpx;  
186 -  
187 -  
188 } 167 }
189 -  
190 </style> 168 </style>
191 \ No newline at end of file 169 \ No newline at end of file
pages/workbench/index.vue
1 <template> 1 <template>
2 - <!-- 外层容器:包含蓝色块 + 原始内容 -->  
3 <view class="page-container"> 2 <view class="page-container">
4 - <!-- 加载页:覆盖整个容器,渲染完成后隐藏 --> 3 + <!-- 加载页 -->
5 <up-loading-page 4 <up-loading-page
6 -  
7 :loading="loading" 5 :loading="loading"
8 loading-text="加载中..." 6 loading-text="加载中..."
9 color="#577ee3" 7 color="#577ee3"
10 zIndex="1000" 8 zIndex="1000"
11 ></up-loading-page> 9 ></up-loading-page>
12 10
13 - <!-- 蓝色装饰块:#577ee3 --> 11 + <!-- 蓝色装饰块 -->
14 <view class="blue-decor-block" v-show="!loading"></view> 12 <view class="blue-decor-block" v-show="!loading"></view>
15 13
16 - <!-- 原始内容容器 --> 14 + <!-- 内容容器 -->
17 <view class="content-wrap"> 15 <view class="content-wrap">
18 - <!-- uview-plus空状态组件 --> 16 + <!-- 空状态:过滤后无数据且非加载中时显示 -->
19 <u-empty 17 <u-empty
20 - v-if="!moduleList.length && !loading" 18 + v-if="!filteredModuleList.length && !loading"
21 mode="permission" 19 mode="permission"
22 ></u-empty> 20 ></u-empty>
23 21
24 - <!-- 菜单卡片列表(替换grid为flex布局) -->  
25 - <view class="menu-card-wrap"> 22 + <!-- 菜单卡片列表:仅渲染有子节点的父模块 -->
  23 + <view class="menu-card-wrap">
26 <up-card 24 <up-card
27 :title-size="18" 25 :title-size="18"
28 :border="false" 26 :border="false"
29 :shadow="true" 27 :shadow="true"
30 :foot-border-top="false" 28 :foot-border-top="false"
31 - v-for="(parentModule, index) in moduleList" 29 + v-for="(parentModule, index) in filteredModuleList"
32 :key="`$parentModule.id_${index}`" 30 :key="`$parentModule.id_${index}`"
33 :title="parentModule.name" 31 :title="parentModule.name"
34 class="card-container" 32 class="card-container"
35 > 33 >
36 <template #body> 34 <template #body>
37 - <!-- 替换up-grid:改用flex流式布局容器 -->  
38 <view class="card-content"> 35 <view class="card-content">
39 <view 36 <view
40 v-for="(listItem, listIndex) in parentModule.children" 37 v-for="(listItem, listIndex) in parentModule.children"
@@ -62,8 +59,7 @@ @@ -62,8 +59,7 @@
62 </template> 59 </template>
63 60
64 <script setup lang="ts"> 61 <script setup lang="ts">
65 -// 原始代码完全保留,无任何修改  
66 -import { ref, nextTick } from 'vue'; 62 +import { ref, computed } from 'vue'; // 新增 computed
67 import { onShow } from '@dcloudio/uni-app'; 63 import { onShow } from '@dcloudio/uni-app';
68 import { useUserStore } from '@/pinia/user'; 64 import { useUserStore } from '@/pinia/user';
69 import globalConfig from '@/common/config/global'; 65 import globalConfig from '@/common/config/global';
@@ -91,60 +87,50 @@ const loading = ref(true); @@ -91,60 +87,50 @@ const loading = ref(true);
91 const userStore = useUserStore(); 87 const userStore = useUserStore();
92 const moduleList = ref<MenuItem[]>([]); 88 const moduleList = ref<MenuItem[]>([]);
93 89
  90 +// 计算属性:过滤出有子节点的父模块(children 存在且长度 > 0)
  91 +const filteredModuleList = computed(() => {
  92 + return moduleList.value.filter(item => {
  93 + // 确保 children 是数组且长度大于 0
  94 + return Array.isArray(item.children) && item.children.length > 0;
  95 + });
  96 +});
  97 +
94 onShow(async () => { 98 onShow(async () => {
95 try { 99 try {
96 loading.value = true; 100 loading.value = true;
97 -  
98 const rawMenuData = userStore.moduleListInfo || cache.get(globalConfig.cache.moduleListKey); 101 const rawMenuData = userStore.moduleListInfo || cache.get(globalConfig.cache.moduleListKey);
99 - const menuData = rawMenuData || [];  
100 - moduleList.value = menuData;  
101 - //  
102 - // // await nextTick();  
103 - // setTimeout(() => {  
104 - // loading.value = false;  
105 - // }, 500); 102 + moduleList.value = rawMenuData || [];
106 loading.value = false; 103 loading.value = false;
107 - console.log('菜单数据:', moduleList.value); 104 + console.log('原始菜单数据:', moduleList.value);
  105 + console.log('过滤后有子节点的父模块:', filteredModuleList.value);
108 } catch (error) { 106 } catch (error) {
109 console.error('获取菜单数据失败:', error); 107 console.error('获取菜单数据失败:', error);
110 moduleList.value = []; 108 moduleList.value = [];
111 - await nextTick();  
112 loading.value = false; 109 loading.value = false;
113 } 110 }
114 }); 111 });
115 112
116 const handleMenuClick = (item: MenuItem) => { 113 const handleMenuClick = (item: MenuItem) => {
117 if (!item.jumpUrl) { 114 if (!item.jumpUrl) {
118 - uni.showToast({  
119 - title: '暂无跳转链接',  
120 - icon: 'none',  
121 - duration: 2000  
122 - }); 115 + uni.showToast({ title: '暂无跳转链接', icon: 'none', duration: 2000 });
123 return; 116 return;
124 } 117 }
125 - console.log(item.jumpUrl);  
126 uni.navigateTo({ 118 uni.navigateTo({
127 url: item.jumpUrl, 119 url: item.jumpUrl,
128 fail: (err) => { 120 fail: (err) => {
129 console.error('页面跳转失败:', err); 121 console.error('页面跳转失败:', err);
130 - uni.showToast({  
131 - title: '页面路径错误',  
132 - icon: 'none',  
133 - duration: 2000  
134 - }); 122 + uni.showToast({ title: '页面路径错误', icon: 'none', duration: 2000 });
135 } 123 }
136 }); 124 });
137 }; 125 };
138 </script> 126 </script>
139 127
140 <style scoped lang="scss"> 128 <style scoped lang="scss">
141 -/* 原有样式保留 + 新增/调整图片居中样式 */  
142 .page-container { 129 .page-container {
143 - position: relative; // 新增:让蓝色块绝对定位生效  
144 - min-height: 100vh; // 新增:防止内容高度不足 130 + position: relative;
  131 + min-height: 100vh;
145 } 132 }
146 133
147 -/* 蓝色块样式(保留) */  
148 .blue-decor-block { 134 .blue-decor-block {
149 position: absolute; 135 position: absolute;
150 top: 0; 136 top: 0;
@@ -155,70 +141,57 @@ const handleMenuClick = (item: MenuItem) =&gt; { @@ -155,70 +141,57 @@ const handleMenuClick = (item: MenuItem) =&gt; {
155 z-index: 1; 141 z-index: 1;
156 } 142 }
157 143
158 -/* 内容容器样式(保留 + 微调) */  
159 .content-wrap { 144 .content-wrap {
160 position: relative; 145 position: relative;
161 z-index: 2; 146 z-index: 2;
162 - padding: 120px 0 0 ; // 新增左右内边距,避免卡片贴边 147 + padding: 120px 0 0;
163 display: flex; 148 display: flex;
164 flex-direction: column; 149 flex-direction: column;
165 - gap: 20rpx; // 新增:卡片之间的上下间距 150 + gap: 20rpx;
166 } 151 }
167 152
168 -/* 菜单卡片容器(新增:统一卡片外层间距) */  
169 .menu-card-wrap { 153 .menu-card-wrap {
170 width: 100%; 154 width: 100%;
171 } 155 }
172 156
173 -/* 卡片容器:重置up-card默认样式 */  
174 .card-container { 157 .card-container {
175 - --u-card-content-padding: 0; // 取消卡片默认内边距  
176 - border-radius: 8rpx; // 新增:卡片圆角  
177 - overflow: hidden; // 新增:裁剪内部元素 158 + --u-card-content-padding: 0;
  159 + border-radius: 8rpx;
  160 + overflow: hidden;
178 } 161 }
179 162
180 -/* 核心:小块容器(Flex 流式布局) */  
181 .card-content { 163 .card-content {
182 display: flex; 164 display: flex;
183 - flex-wrap: wrap; // 自动换行  
184 - gap: 20rpx; // 关键:小块之间的上下+左右间距统一  
185 - 165 + flex-wrap: wrap;
  166 + gap: 20rpx;
186 } 167 }
187 168
188 -/* 小块样式:一行最多4个,宽度自适应 + 内部flex布局 */  
189 .content-block { 169 .content-block {
190 - // 宽度计算:(100% - 3*间距) / 4 (4个元素有3个间距)  
191 width: calc((100% - 3 * 20rpx) / 4); 170 width: calc((100% - 3 * 20rpx) / 4);
192 - // 小块内部样式:改用flex布局,确保子元素居中  
193 display: flex; 171 display: flex;
194 flex-direction: column; 172 flex-direction: column;
195 - align-items: center; // 水平居中(核心:解决图片不居中问题)  
196 - justify-content: center; // 垂直居中(可选,优化视觉)  
197 - padding: 24rpx 0; 173 + align-items: center;
  174 + justify-content: center;
  175 + padding: 14rpx 0;
198 border-radius: 8rpx; 176 border-radius: 8rpx;
199 - text-align: center;  
200 - // 点击反馈  
201 touch-action: manipulation; 177 touch-action: manipulation;
202 transition: background-color 0.2s; 178 transition: background-color 0.2s;
203 } 179 }
204 180
205 -/* 小块点击态 */  
206 .content-block:active { 181 .content-block:active {
207 background-color: #e9ecef; 182 background-color: #e9ecef;
208 } 183 }
209 184
210 -/* 新增:图片居中样式(兜底保障) */  
211 .block-icon { 185 .block-icon {
212 - display: block; // 转为块级元素  
213 - margin: 0 auto; // 水平居中(双重保障) 186 + display: block;
  187 + margin: 0 auto;
214 } 188 }
215 189
216 -/* 网格文字样式(保留 + 微调) */  
217 .grid-text { 190 .grid-text {
218 font-size: 26rpx; 191 font-size: 26rpx;
219 color: #333; 192 color: #333;
220 text-align: center; 193 text-align: center;
221 margin-top: 10rpx; 194 margin-top: 10rpx;
222 - display: block; // 新增:确保文字换行 195 + display: block;
223 } 196 }
224 </style> 197 </style>
225 \ No newline at end of file 198 \ No newline at end of file