leo 1 неделя назад
Родитель
Сommit
e3578da818
6 измененных файлов с 1865 добавлено и 1595 удалено
  1. 81 76
      App.vue
  2. 302 264
      pages/equipMange/index/index.vue
  3. 860 811
      pages/index/index.vue
  4. 444 395
      pages/login/login.vue
  5. 11 12
      pages/my/index/index.vue
  6. 167 37
      util/QueryPermission.js

+ 81 - 76
App.vue

@@ -1,81 +1,86 @@
 <script>
-	// export default {
-	// 	onShow: function() {
-	// 		console.log('App Show app页面')
-	// 	},
-	// 	onHide: function() {
-	// 		console.log('App Hide')
-	// 	},
-	// 	  // 分享给朋友
-	// 	  onShareAppMessage() {
-	// 	    return {
-	// 	      title: '云飞智控', // 分享标题
-	// 	      path: 'pages/index/index', // 分享路径,通常包含页面参数
-	// 	      imageUrl: 'http://www.hnyfwlw.com:8006/data/home_logo/log1.jpg', // 分享图片,可选
-	// 	      success: (res) => {
-	// 	        // 分享成功回调
-	// 	        uni.showToast({
-	// 	          title: '分享成功',
-	// 	          icon: 'success'
-	// 	        })
-	// 	      },
-	// 	      fail: (err) => {
-	// 	        // 分享失败回调
-	// 	        console.log('分享失败', err)
-	// 	      }
-	// 	    }
-	// 	  },
-	// 	  // 分享到朋友圈(基础库2.11.3+)
-	// 	  onShareTimeline() {
-	// 	    return {
-	// 	      title:  '云飞智控', // 分享标题
-	// 	      query: 'id=123', // 页面参数,不同于分享给朋友的path,这里用query
-	// 	      imageUrl: 'http://www.hnyfwlw.com:8006/data/home_logo/log1.jpg' // 分享图片,可选
-	// 	    }
-	// 	  }
-	// }
-	// App.vue
-	export default {
-		
-	  onLaunch() {
-	    // 监听分享到朋友圈
-		uni.showShareMenu({
-		  withShareTicket: true,
-		  menus: ['shareAppMessage', 'shareTimeline']
-		})
-	  },
-	  onShareTimeline() {
-	    return {
-	      title:  'AI 诊病虫,智控赋新农~', // 分享标题
-	      query: 'id=123', // 页面参数,不同于分享给朋友的path,这里用query
-	      imageUrl: 'http://www.hnyfwlw.com:8006/data/home_logo/log1.jpg' // 分享图片,可选
-	    }
-	  },
-	  // 全局分享给朋友
-	  onShareAppMessage() {
-	    return {
-	      title: 'AI 诊病虫,智控赋新农~',
-	      path: '/pages/index/index',
-	      imageUrl: ''
-	    }
-	  }
-	}
+import { fetchPermissionList } from './util/QueryPermission.js';
+// export default {
+// 	onShow: function() {
+// 		console.log('App Show app页面')
+// 	},
+// 	onHide: function() {
+// 		console.log('App Hide')
+// 	},
+// 	  // 分享给朋友
+// 	  onShareAppMessage() {
+// 	    return {
+// 	      title: '云飞智控', // 分享标题
+// 	      path: 'pages/index/index', // 分享路径,通常包含页面参数
+// 	      imageUrl: 'http://www.hnyfwlw.com:8006/data/home_logo/log1.jpg', // 分享图片,可选
+// 	      success: (res) => {
+// 	        // 分享成功回调
+// 	        uni.showToast({
+// 	          title: '分享成功',
+// 	          icon: 'success'
+// 	        })
+// 	      },
+// 	      fail: (err) => {
+// 	        // 分享失败回调
+// 	        console.log('分享失败', err)
+// 	      }
+// 	    }
+// 	  },
+// 	  // 分享到朋友圈(基础库2.11.3+)
+// 	  onShareTimeline() {
+// 	    return {
+// 	      title:  '云飞智控', // 分享标题
+// 	      query: 'id=123', // 页面参数,不同于分享给朋友的path,这里用query
+// 	      imageUrl: 'http://www.hnyfwlw.com:8006/data/home_logo/log1.jpg' // 分享图片,可选
+// 	    }
+// 	  }
+// }
+// App.vue
+export default {
+  onLaunch() {
+    // 已登录时提前拉取权限列表,保证“未经过首页”等特殊入口也能拿到权限数据(非阻塞)
+    if (uni.getStorageSync('session_key')) {
+      fetchPermissionList();
+    }
+
+    // 监听分享到朋友圈
+    uni.showShareMenu({
+      withShareTicket: true,
+      menus: ['shareAppMessage', 'shareTimeline'],
+    });
+  },
+  onShareTimeline() {
+    return {
+      title: 'AI 诊病虫,智控赋新农~', // 分享标题
+      query: 'id=123', // 页面参数,不同于分享给朋友的path,这里用query
+      imageUrl: 'http://www.hnyfwlw.com:8006/data/home_logo/log1.jpg', // 分享图片,可选
+    };
+  },
+  // 全局分享给朋友
+  onShareAppMessage() {
+    return {
+      title: 'AI 诊病虫,智控赋新农~',
+      path: '/pages/index/index',
+      imageUrl: '',
+    };
+  },
+};
 </script>
 <style lang="scss">
-	@import "style/font/iconfont.css";
-	@import "./static/iconfont/iconfont.css";
+@import 'style/font/iconfont.css';
+@import './static/iconfont/iconfont.css';
 
-	html {
-		box-sizing: border-box;
-		font-size: 28rpx;
-	}
+html {
+  box-sizing: border-box;
+  font-size: 28rpx;
+}
 
-	.status_bar {
-		height: 40px;
-		width: 100%;
-		background-color: #FFFFFF;
-		position: fixed;
-		top: 0;
-		z-index: 99999;
-	}
-</style>
+.status_bar {
+  height: 40px;
+  width: 100%;
+  background-color: #ffffff;
+  position: fixed;
+  top: 0;
+  z-index: 99999;
+}
+</style>

+ 302 - 264
pages/equipMange/index/index.vue

@@ -1,281 +1,319 @@
 <template>
-	<view class="">
-		<view class="status_bar"></view>
-		<view class="" style="position: relative;top: 40px;">
-			<view style="position: fixed;z-index: 100;">
-				<uni-nav-bar left-icon="back" left-text="返回" title="用户管理" @clickLeft="clickLeft"></uni-nav-bar>
-			</view>
-			<view class="uinput-box">
-				<view class="uinputs">
-					<u-input v-model="argument.username" :type="type" :border="border" placeholder="请输入用户名称"
-						input-align="center" :clearable="border" :custom-style="uinputstyle" @input="searchinput" />
-					<u-icon name="search" class="search" size="30" @click="search"></u-icon>
-				</view>
-			</view>
-			<view class="userlists">
-				<view class="userlist-li" v-for="(item,index) in userlists" :kex="index">
-					<image :src="$imageURL+'/bigdata_app'+'/image/fourMoodBase/touxiang.png'" mode="">
-					</image>
-					<p class="userlist-li-city">{{item.username}}</p>
-					<p class="userlist-li-eamil">{{item.mobile}}</p>
-					<view class="loginbox" v-if="item.device_level != 1">
-						<p class="loginp" @click="userloginbtn(item)">一键登录</p>
-						<!-- <p class="logininfo" @click="userOperation(item)">查看详情</p> -->
-					</view>
-				</view>
-			</view>
-		</view>
-		<view class="top" v-if="isTop" @click="top">
-			<image :src="$imageURL+'/bigdata_app'+'/image/6209a98f0cb3b5086f2ca36152c9269.png'"
-				mode=""></image>
-		</view>
-	</view>
+  <view class="">
+    <view class="status_bar"></view>
+    <view class="" style="position: relative; top: 40px">
+      <view style="position: fixed; z-index: 100">
+        <uni-nav-bar
+          left-icon="back"
+          left-text="返回"
+          title="用户管理"
+          @clickLeft="clickLeft"
+        ></uni-nav-bar>
+      </view>
+      <view class="uinput-box">
+        <view class="uinputs">
+          <u-input
+            v-model="argument.username"
+            :type="type"
+            :border="border"
+            placeholder="请输入用户名称"
+            input-align="center"
+            :clearable="border"
+            :custom-style="uinputstyle"
+            @input="searchinput"
+          />
+          <u-icon
+            name="search"
+            class="search"
+            size="30"
+            @click="search"
+          ></u-icon>
+        </view>
+      </view>
+      <view class="userlists">
+        <view
+          class="userlist-li"
+          v-for="(item, index) in userlists"
+          :kex="index"
+        >
+          <image
+            :src="
+              $imageURL + '/bigdata_app' + '/image/fourMoodBase/touxiang.png'
+            "
+            mode=""
+          >
+          </image>
+          <p class="userlist-li-city">{{ item.username }}</p>
+          <p class="userlist-li-eamil">{{ item.mobile }}</p>
+          <view class="loginbox" v-if="item.device_level != 1">
+            <p class="loginp" @click="userloginbtn(item)">一键登录</p>
+            <!-- <p class="logininfo" @click="userOperation(item)">查看详情</p> -->
+          </view>
+        </view>
+      </view>
+    </view>
+    <view class="top" v-if="isTop" @click="top">
+      <image
+        :src="
+          $imageURL +
+          '/bigdata_app' +
+          '/image/6209a98f0cb3b5086f2ca36152c9269.png'
+        "
+        mode=""
+      ></image>
+    </view>
+  </view>
 </template>
 
 <script>
-	import {
-		Debounce,
-		Throttle
-	} from "../../../util/anitthro.js"
-	export default {
-		data() {
-			return {
-				value: '',
-				type: 'text',
-				border: false,
-				uinputstyle: {
-					"margin": "16rpx 0",
-					'background': "#f3f3f3",
-					"border-radius": "25px"
-				},
-				userlists: [],
-				argument: {
-					page: 1,
-					page_size: 10,
-					username: ''
-				},
-				isTop: false,
-				addtf: false
-			}
-		},
-		methods: {
-			async getState(argument) {
-				const res = await this.$myRequest({
-					url: '/api/api_gateway?method=user.login.users_info',
-					data: {
-						page: argument.page,
-						page_size: argument.page_size,
-						username: argument.username
-					}
-				})
-				this.userlists = this.userlists.concat(res.data)
-			},
-			async userlogin(uid) {
-				const res = await this.$myRequest({
-					url: '/api/api_gateway?method=user.login.auto_login',
-					data: {
-						uid
-					}
-				})
-				let session_key = res.session_key
-				uni.setStorage({
-					key: 'session_key',
-					data: session_key,
-					success: () => {
-						// 添加全局标识,刷新数据
-						uni.setStorageSync('refreshData',	Date.now())
-						uni.switchTab({
-							url: "../../index/index"
-						})
-						uni.showToast({
-							title: "登录成功!",
-							icon: "none"
-						})
-					}
-				})
-			},
-			clickLeft() {
-				// uni.switchTab({
-				// 	url: "../../index/index"
-				// })
-				uni.navigateBack({
-					delta: 1
-				})
-			},
-			userOperation(item) { //跳转用户信息页面
-				item = JSON.stringify(item)
-				uni.navigateTo({
-					url: './useroperation?item=' + item,
-				})
-			},
-			userloginbtn(item){
-				this.userlogin(item.uid)
-			},
-			search() { //搜索用户
-				this.userlists = []
-				this.getState(this.argument)
-			},
-			searchinput() {
-				this.argument.page = 1
-				Debounce(() => {
-					this.userlists = []
-					this.getState(this.argument)
-				}, 1000)()
-			},
-			top() {
-				uni.pageScrollTo({
-					scrollTop: 0,
-					duration: 500
-				})
-			}
-		}, //user.login.users_info
-		onLoad() {
-			this.getState(this.argument)
-			uni.getStorage({
-				key:"jurisdiction",
-				success:(res)=>{
-					console.log(JSON.parse(res.data))
-					let items = JSON.parse(res.data).filter((item)=>{
-						return item.pur_id == 28//"系统管理"
-					})
-					let items2 = items[0].children.filter((item)=>{
-						return item.pur_id == 29//"用户管理"
-					})
-					var arr = items2[0].children
-					console.log(arr)
-					for(var i =0;i<arr.length;i++){
-						switch (arr[i].pur_id){
-							case 116://"添加用户"
-								this.addtf = true
-								break
-						}
-					}
-				},
-			})
-		},
-		onReachBottom() {
-			this.argument.page++
-			this.getState(this.argument)
-		},
-		onPullDownRefresh() {
-			this.getState(this.argument)
-			setTimeout(function() {
-				uni.stopPullDownRefresh(); //停止下拉刷新动画
-			}, 1000);
-		},
-		onBackPress(options) {
-			if (options.from === 'navigateBack') {
-				return false;
-			}
-			this.clickLeft();
-			return true;
-		},
-		onPageScroll(e) { //nvue暂不支持滚动监听,可用bindingx代替
-			if (e.scrollTop > 200) { //距离大于200时显示
-				this.isTop = true
-			} else { //距离小于200时隐藏
-				this.isTop = false
-			}
-		},
-	}
+import { Debounce, Throttle } from '../../../util/anitthro.js';
+export default {
+  data() {
+    return {
+      value: '',
+      type: 'text',
+      border: false,
+      uinputstyle: {
+        margin: '16rpx 0',
+        background: '#f3f3f3',
+        'border-radius': '25px',
+      },
+      userlists: [],
+      argument: {
+        page: 1,
+        page_size: 10,
+        username: '',
+      },
+      isTop: false,
+      addtf: false,
+    };
+  },
+  methods: {
+    async getState(argument) {
+      const res = await this.$myRequest({
+        url: '/api/api_gateway?method=user.login.users_info',
+        data: {
+          page: argument.page,
+          page_size: argument.page_size,
+          username: argument.username,
+        },
+      });
+      this.userlists = this.userlists.concat(res.data);
+    },
+    async userlogin(uid) {
+      const res = await this.$myRequest({
+        url: '/api/api_gateway?method=user.login.auto_login',
+        data: {
+          uid,
+        },
+      });
+      let session_key = res.session_key;
+      uni.setStorage({
+        key: 'session_key',
+        data: session_key,
+        success: () => {
+          // 添加全局标识,刷新数据
+          uni.setStorageSync('refreshData', Date.now());
+          // 切换账号:先清除上一个用户的权限缓存,再用新账号拉取权限
+          this.$resetPermissionList();
+          this.$fetchPermissionList();
+          uni.switchTab({
+            url: '../../index/index',
+          });
+          uni.showToast({
+            title: '登录成功!',
+            icon: 'none',
+          });
+        },
+      });
+    },
+    clickLeft() {
+      // uni.switchTab({
+      // 	url: "../../index/index"
+      // })
+      uni.navigateBack({
+        delta: 1,
+      });
+    },
+    userOperation(item) {
+      //跳转用户信息页面
+      item = JSON.stringify(item);
+      uni.navigateTo({
+        url: './useroperation?item=' + item,
+      });
+    },
+    userloginbtn(item) {
+      this.userlogin(item.uid);
+    },
+    search() {
+      //搜索用户
+      this.userlists = [];
+      this.getState(this.argument);
+    },
+    searchinput() {
+      this.argument.page = 1;
+      Debounce(() => {
+        this.userlists = [];
+        this.getState(this.argument);
+      }, 1000)();
+    },
+    top() {
+      uni.pageScrollTo({
+        scrollTop: 0,
+        duration: 500,
+      });
+    },
+  }, //user.login.users_info
+  onLoad() {
+    this.getState(this.argument);
+    uni.getStorage({
+      key: 'jurisdiction',
+      success: (res) => {
+        console.log(JSON.parse(res.data));
+        let items = JSON.parse(res.data).filter((item) => {
+          return item.pur_id == 28; //"系统管理"
+        });
+        let items2 = items[0].children.filter((item) => {
+          return item.pur_id == 29; //"用户管理"
+        });
+        var arr = items2[0].children;
+        console.log(arr);
+        for (var i = 0; i < arr.length; i++) {
+          switch (arr[i].pur_id) {
+            case 116: //"添加用户"
+              this.addtf = true;
+              break;
+          }
+        }
+      },
+    });
+  },
+  onReachBottom() {
+    this.argument.page++;
+    this.getState(this.argument);
+  },
+  onPullDownRefresh() {
+    this.getState(this.argument);
+    setTimeout(function () {
+      uni.stopPullDownRefresh(); //停止下拉刷新动画
+    }, 1000);
+  },
+  onBackPress(options) {
+    if (options.from === 'navigateBack') {
+      return false;
+    }
+    this.clickLeft();
+    return true;
+  },
+  onPageScroll(e) {
+    //nvue暂不支持滚动监听,可用bindingx代替
+    if (e.scrollTop > 200) {
+      //距离大于200时显示
+      this.isTop = true;
+    } else {
+      //距离小于200时隐藏
+      this.isTop = false;
+    }
+  },
+};
 </script>
 1
 <style lang="scss">
-	/deep/.uni-icons {
-		font-size: 40rpx !important;
-	}
+/deep/.uni-icons {
+  font-size: 40rpx !important;
+}
 
-	.uinput-box {
-		position: fixed;
-		top: 84px;
-		z-index: 100;
-		background-color: white;
-		width: 100%;
-		display: flex;
-		justify-content: center;
-		align-items: center;
+.uinput-box {
+  position: fixed;
+  top: 84px;
+  z-index: 100;
+  background-color: white;
+  width: 100%;
+  display: flex;
+  justify-content: center;
+  align-items: center;
 
-		.uinputs {
-			width: 95%;
-			position: relative;
+  .uinputs {
+    width: 95%;
+    position: relative;
 
-			.search {
-				position: absolute;
-				top: 40rpx;
-				left: 200rpx;
-			}
-		}
-	}
+    .search {
+      position: absolute;
+      top: 40rpx;
+      left: 200rpx;
+    }
+  }
+}
 
-	.userlists {
-		width: 100%;
-		position: relative;
-		top: 180rpx;
+.userlists {
+  width: 100%;
+  position: relative;
+  top: 180rpx;
 
-		.userlist-li {
-			width: 46%;
-			height: 300rpx;
-			margin: 20rpx 0 0 20rpx;
-			float: left;
-			box-shadow: 0 0 10rpx #bcb9ca;
-			text-align: center;
+  .userlist-li {
+    width: 46%;
+    height: 300rpx;
+    margin: 20rpx 0 0 20rpx;
+    float: left;
+    box-shadow: 0 0 10rpx #bcb9ca;
+    text-align: center;
 
-			image {
-				width: 80rpx;
-				height: 80rpx;
-				margin: 40rpx 0 20rpx;
-			}
-			.userlist-li-city{
-				overflow: hidden;//溢出隐藏
-				white-space: nowrap;//禁止换行
-				text-overflow: ellipsis;//...
-			}
-			.loginbox{
-				display: flex;
-			}
-			.loginp {
-				width: 130rpx;
-				padding: 6rpx;
-				font-size: 25rpx;
-				background-color: #18B566;
-				color: #FFF;
-				margin: 20rpx auto;
-				border-radius: 31rpx;
-			}
-			.logininfo{
-				width: 130rpx;
-				padding: 6rpx;
-				font-size: 25rpx;
-				background-color: #fbb309;
-				color: #FFF;
-				margin: 20rpx auto;
-				border-radius: 31rpx;
-			}
-		}
-	}
+    image {
+      width: 80rpx;
+      height: 80rpx;
+      margin: 40rpx 0 20rpx;
+    }
+    .userlist-li-city {
+      overflow: hidden; //溢出隐藏
+      white-space: nowrap; //禁止换行
+      text-overflow: ellipsis; //...
+    }
+    .loginbox {
+      display: flex;
+    }
+    .loginp {
+      width: 130rpx;
+      padding: 6rpx;
+      font-size: 25rpx;
+      background-color: #18b566;
+      color: #fff;
+      margin: 20rpx auto;
+      border-radius: 31rpx;
+    }
+    .logininfo {
+      width: 130rpx;
+      padding: 6rpx;
+      font-size: 25rpx;
+      background-color: #fbb309;
+      color: #fff;
+      margin: 20rpx auto;
+      border-radius: 31rpx;
+    }
+  }
+}
 
-	.addindent {
-		width: 100%;
-		position: fixed;
-		bottom: 0;
-		left: 0;
-		height: 80rpx;
-		text-align: center;
-		line-height: 80rpx;
-		background-color: #71cd9a;
-		color: #ffffff;
-		font-size: 16px;
-	}
+.addindent {
+  width: 100%;
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  height: 80rpx;
+  text-align: center;
+  line-height: 80rpx;
+  background-color: #71cd9a;
+  color: #ffffff;
+  font-size: 16px;
+}
 
-	.top {
-		position: fixed;
-		right: 30px;
-		bottom: 100px;
-		z-index: 100;
+.top {
+  position: fixed;
+  right: 30px;
+  bottom: 100px;
+  z-index: 100;
 
-		image {
-			width: 100rpx;
-			height: 100rpx;
-		}
-	}
+  image {
+    width: 100rpx;
+    height: 100rpx;
+  }
+}
 </style>

Разница между файлами не показана из-за своего большого размера
+ 860 - 811
pages/index/index.vue


+ 444 - 395
pages/login/login.vue

@@ -1,428 +1,477 @@
 <template>
-	<view>
-		<view class="bg">
-			<image :src="$imageURL+'/bigdata_app/log/bg.png'" mode="" class="bgimg"></image>
-		</view>
-		<!-- <view class="status_bar"></view> -->
-		<view class="apptitle">
-			云飞智控
-		</view>
-		<view class="set" @click="set" v-if="setTF">
-			<u-icon name="setting-fill" size="50" color="#fff"></u-icon>
-		</view>
-		<view class="formbox">
-			<form @submit="formSubmit">
-				<view class="uni-form-item uni-column">
-					<view class="username">
-						<u-icon name="account" size="36" style="margin-right:30rpx;color: #fff;"></u-icon>
-						<u-input class="uni-input" name="username" v-model="formdata.username"
-							placeholder-class="icon iconfont icon-bianji1" placeholder="请输入用户名"
-							placeholderStyle="color:#ffffff;" color="#FFFFFF" @blur="blur" />
-					</view>
-					<view class="passwold">
-						<u-icon name="lock" size="36" style="margin-right:30rpx;color: #fff;"></u-icon>
-						<u-input v-model="formdata.passwold" type="password" :password-icon="true" :clearable="false"
-							placeholder="请输入密码" @confirm="formSubmit" @input="passwoldddata"
-							placeholderStyle="color:#fff;" suffixIconStyle="color:#fff;" color="#fff"
-							class="uni-input" />
-					</view>
-					<view class="aboutpass">
-						<u-checkbox-group>
-							<u-checkbox v-model="checked" :label-disabled="false" size="28" @change="rempass">记住密码
-							</u-checkbox>
-						</u-checkbox-group>
-					</view>
-					<view class="uni-btn-v">
-						<button form-type="submit" @click="denglu">登 录</button>
-					</view>
-				</view>
-			</form>
-		</view>
-		<u-modal title="升级中请勿随意操作" :show-confirm-button="false" v-model="showA" :content="contentA">
-			<view class="upgradeBox">
-				<u-line-progress v-show="isShow" active-color="#19be6b" :striped="true" :percent="percentNum"
-					:striped-active="true"></u-line-progress>
-			</view>
-		</u-modal>
-	</view>
+  <view>
+    <view class="bg">
+      <image
+        :src="$imageURL + '/bigdata_app/log/bg.png'"
+        mode=""
+        class="bgimg"
+      ></image>
+    </view>
+    <!-- <view class="status_bar"></view> -->
+    <view class="apptitle"> 云飞智控 </view>
+    <view class="set" @click="set" v-if="setTF">
+      <u-icon name="setting-fill" size="50" color="#fff"></u-icon>
+    </view>
+    <view class="formbox">
+      <form @submit="formSubmit">
+        <view class="uni-form-item uni-column">
+          <view class="username">
+            <u-icon
+              name="account"
+              size="36"
+              style="margin-right: 30rpx; color: #fff"
+            ></u-icon>
+            <u-input
+              class="uni-input"
+              name="username"
+              v-model="formdata.username"
+              placeholder-class="icon iconfont icon-bianji1"
+              placeholder="请输入用户名"
+              placeholderStyle="color:#ffffff;"
+              color="#FFFFFF"
+              @blur="blur"
+            />
+          </view>
+          <view class="passwold">
+            <u-icon
+              name="lock"
+              size="36"
+              style="margin-right: 30rpx; color: #fff"
+            ></u-icon>
+            <u-input
+              v-model="formdata.passwold"
+              type="password"
+              :password-icon="true"
+              :clearable="false"
+              placeholder="请输入密码"
+              @confirm="formSubmit"
+              @input="passwoldddata"
+              placeholderStyle="color:#fff;"
+              suffixIconStyle="color:#fff;"
+              color="#fff"
+              class="uni-input"
+            />
+          </view>
+          <view class="aboutpass">
+            <u-checkbox-group>
+              <u-checkbox
+                v-model="checked"
+                :label-disabled="false"
+                size="28"
+                @change="rempass"
+                >记住密码
+              </u-checkbox>
+            </u-checkbox-group>
+          </view>
+          <view class="uni-btn-v">
+            <button form-type="submit" @click="denglu">登 录</button>
+          </view>
+        </view>
+      </form>
+    </view>
+    <u-modal
+      title="升级中请勿随意操作"
+      :show-confirm-button="false"
+      v-model="showA"
+      :content="contentA"
+    >
+      <view class="upgradeBox">
+        <u-line-progress
+          v-show="isShow"
+          active-color="#19be6b"
+          :striped="true"
+          :percent="percentNum"
+          :striped-active="true"
+        ></u-line-progress>
+      </view>
+    </u-modal>
+  </view>
 </template>
 
 <script>
-	export default {
-		data() {
-			return {
-				checked: false,
-				formdata: {
-					username: '',
-					passwold: ''
-				},
-				setbgtf: false,
-				setTF: false,
-				value: "http://8.136.98.49:8002",
-				httparr: ["http://8.136.98.49:8002", "http://dev.hnyfwlw.com"],
-				arrowtf: false,
-				showA: false, //
-				contentA: '',
-				isShow: false, //进度条
-				percentNum: 0, //在线下载进度
-				passvalue: false
-			}
-		},
-		onLoad() {
-			uni.getStorage({
-				key: 'user_pass',
-				success: (res) => {
-					if (res.data) {
-						this.formdata.passwold = res.data
-						this.checked = true
-					} else {
-						this.checked = false
-					}
-				}
-			})
-			uni.getStorage({
-				key: 'user_name',
-				success: (res) => {
-					this.formdata.username = res.data
-				}
-			})
-			uni.getStorage({
-				key: 'http',
-				success: (res) => {
-					this.value = res.data
-				}
-			})
-			this.getEquipList()
-		},
-		onShow() {
-			
-		},
-		methods: {
-			async getEquipList() {
-				const res = await this.$myRequest({
-					url: '/api/api_gateway?method=home.homes.app_version_record',
-					data: {
-						ret: "first"
-					}
-				})
-				console.log(res)
-				this.appName = res[0].app_name
-				// uni.getStorage({
-				// 	key: 'session_key',
-				// 	success: (res) => {
-				// 		console.log(res)
-				// 		if (res.data != "") {
-				// 			uni.switchTab({
-				// 				url: "../index/index"
-				// 			})
-				// 		}
-				// 	},
-				// })
-				// }
-			},
-			async formSubmit() {
-				const res = await this.$myRequest({
-					url: '/api/api_gateway?method=user.login.login_user',
-					data: {
-						username: this.formdata.username,
-						password: this.formdata.passwold
-					}
-				})
-				console.log(res.session_key)
-				let session_key = res.session_key
-				uni.setStorage({
-					key: 'session_key',
+export default {
+  data() {
+    return {
+      checked: false,
+      formdata: {
+        username: '',
+        passwold: '',
+      },
+      setbgtf: false,
+      setTF: false,
+      value: 'http://8.136.98.49:8002',
+      httparr: ['http://8.136.98.49:8002', 'http://dev.hnyfwlw.com'],
+      arrowtf: false,
+      showA: false, //
+      contentA: '',
+      isShow: false, //进度条
+      percentNum: 0, //在线下载进度
+      passvalue: false,
+    };
+  },
+  onLoad() {
+    uni.getStorage({
+      key: 'user_pass',
+      success: (res) => {
+        if (res.data) {
+          this.formdata.passwold = res.data;
+          this.checked = true;
+        } else {
+          this.checked = false;
+        }
+      },
+    });
+    uni.getStorage({
+      key: 'user_name',
+      success: (res) => {
+        this.formdata.username = res.data;
+      },
+    });
+    uni.getStorage({
+      key: 'http',
+      success: (res) => {
+        this.value = res.data;
+      },
+    });
+    this.getEquipList();
+  },
+  onShow() {},
+  methods: {
+    async getEquipList() {
+      const res = await this.$myRequest({
+        url: '/api/api_gateway?method=home.homes.app_version_record',
+        data: {
+          ret: 'first',
+        },
+      });
+      console.log(res);
+      this.appName = res[0].app_name;
+      // uni.getStorage({
+      // 	key: 'session_key',
+      // 	success: (res) => {
+      // 		console.log(res)
+      // 		if (res.data != "") {
+      // 			uni.switchTab({
+      // 				url: "../index/index"
+      // 			})
+      // 		}
+      // 	},
+      // })
+      // }
+    },
+    async formSubmit() {
+      const res = await this.$myRequest({
+        url: '/api/api_gateway?method=user.login.login_user',
+        data: {
+          username: this.formdata.username,
+          password: this.formdata.passwold,
+        },
+      });
+      console.log(res.session_key);
+      let session_key = res.session_key;
+      uni.setStorage({
+        key: 'session_key',
 
-					data: session_key,
-					success: () => {
-						uni.switchTab({
-							url: "../index/index"
-						})
-					}
-				})
-			},
-			passwoldddata() {
-				this.formdata.passwold = this.formdata.passwold.replace(/[\u4E00-\u9FA5]/g, '')
-			},
-			rempass(val) {
-				this.passvalue = val.value
-				if (val.value) {
-					uni.setStorage({
-						key: 'user_pass',
-						data: this.formdata.passwold,
-						success: function() {
-							console.log('success');
-						}
-					})
-				}
-			},
-			blur(val) {
-				uni.setStorage({
-					key: 'user_name',
-					data: val,
-					success: function() {
-						console.log('success');
-					}
-				})
-			},
-			logoTime() {
-				this.setTF = true
-			},
-			set() {
-				this.setbgtf = true
-			},
-			sethttp() {
-				uni.setStorage({
-					key: 'http',
-					data: this.value,
-					success: () => {
-						// console.log(this.value);
-						this.setbgtf = false
-						uni.showToast({
-							title: "修改成功",
-							icon: "none"
-						})
-						this.getEquipList()
-					}
-				});
-			},
-			arrow() {
-				this.arrowtf = !this.arrowtf
-			},
-			denglu() {
-				if (this.passvalue) {
-					uni.setStorage({
-						key: 'user_pass',
-						data: this.formdata.passwold,
-						success: function() {
-							console.log('success');
-						}
-					})
-				} else {
-					uni.removeStorage({
-						key: 'user_pass',
-						success: function() {
-							console.log('success');
-						}
-					})
-				}
-			}
-		}
-	}
+        data: session_key,
+        success: () => {
+          // 登录前清除可能残留的权限缓存,再用新账号拉取
+          this.$resetPermissionList();
+          this.$fetchPermissionList();
+          uni.switchTab({
+            url: '../index/index',
+          });
+        },
+      });
+    },
+    passwoldddata() {
+      this.formdata.passwold = this.formdata.passwold.replace(
+        /[\u4E00-\u9FA5]/g,
+        '',
+      );
+    },
+    rempass(val) {
+      this.passvalue = val.value;
+      if (val.value) {
+        uni.setStorage({
+          key: 'user_pass',
+          data: this.formdata.passwold,
+          success: function () {
+            console.log('success');
+          },
+        });
+      }
+    },
+    blur(val) {
+      uni.setStorage({
+        key: 'user_name',
+        data: val,
+        success: function () {
+          console.log('success');
+        },
+      });
+    },
+    logoTime() {
+      this.setTF = true;
+    },
+    set() {
+      this.setbgtf = true;
+    },
+    sethttp() {
+      uni.setStorage({
+        key: 'http',
+        data: this.value,
+        success: () => {
+          // console.log(this.value);
+          this.setbgtf = false;
+          uni.showToast({
+            title: '修改成功',
+            icon: 'none',
+          });
+          this.getEquipList();
+        },
+      });
+    },
+    arrow() {
+      this.arrowtf = !this.arrowtf;
+    },
+    denglu() {
+      if (this.passvalue) {
+        uni.setStorage({
+          key: 'user_pass',
+          data: this.formdata.passwold,
+          success: function () {
+            console.log('success');
+          },
+        });
+      } else {
+        uni.removeStorage({
+          key: 'user_pass',
+          success: function () {
+            console.log('success');
+          },
+        });
+      }
+    },
+  },
+};
 </script>
 
 <style lang="scss">
-	.bg{
-		width: 100%;
-		height: 100vh;
-		position: absolute;
-		top: 0;
-		left: 0;
-		.bgimg{
-			width: 100%;
-			height: 100%;
-		}
-	}
-	.apptitle{
-		font-size: 52rpx;
-		color: #fff;
-		width: 80%;
-		margin: 600rpx auto 40rpx;
-	}
-	.logo {
-		width: 100%;
-		height: 340rpx;
-		text-align: center;
-		display: flex;
-		align-items: center;
-		padding-top: 240rpx;
+.bg {
+  width: 100%;
+  height: 100vh;
+  position: absolute;
+  top: 0;
+  left: 0;
+  .bgimg {
+    width: 100%;
+    height: 100%;
+  }
+}
+.apptitle {
+  font-size: 52rpx;
+  color: #fff;
+  width: 80%;
+  margin: 600rpx auto 40rpx;
+}
+.logo {
+  width: 100%;
+  height: 340rpx;
+  text-align: center;
+  display: flex;
+  align-items: center;
+  padding-top: 240rpx;
 
-		image {
-			width: 280rpx;
-			margin: 0 auto;
-			height: 120rpx;
-		}
-	}
+  image {
+    width: 280rpx;
+    margin: 0 auto;
+    height: 120rpx;
+  }
+}
 
-	.set {
-		position: absolute;
-		right: 50rpx;
-		top: 150rpx;
-	}
+.set {
+  position: absolute;
+  right: 50rpx;
+  top: 150rpx;
+}
 
-	.bg {
-		width: 100%;
-		position: fixed;
-		bottom: 0;
-		left: 0;
-		z-index: -1;
+.bg {
+  width: 100%;
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  z-index: -1;
 
-		image {
-			width: 100%;
-		}
-	}
+  image {
+    width: 100%;
+  }
+}
 
-	/deep/.u-input__right-icon {
-		line-height: 35px !important;
-	}
-	.uni-form-item {
-		width: 100%;
+/deep/.u-input__right-icon {
+  line-height: 35px !important;
+}
+.uni-form-item {
+  width: 100%;
 
-		.username {
-			width: 80%;
-			margin: 0 auto;
-			display: flex;
-			margin-bottom: 40rpx;
-			padding-bottom: 10rpx;
-			border-bottom: 2rpx solid rgba(249,249,249,0.4);
+  .username {
+    width: 80%;
+    margin: 0 auto;
+    display: flex;
+    margin-bottom: 40rpx;
+    padding-bottom: 10rpx;
+    border-bottom: 2rpx solid rgba(249, 249, 249, 0.4);
 
-			.u-icon__icon {
-				margin-top: 17rpx;
-			}
+    .u-icon__icon {
+      margin-top: 17rpx;
+    }
 
-			.uni-input {
-				width: 100%;
-				color: #fff;
-			}
-			.u-input__input{
-				color: #fff !important;
-			}
-		}
+    .uni-input {
+      width: 100%;
+      color: #fff;
+    }
+    .u-input__input {
+      color: #fff !important;
+    }
+  }
 
-		.passwold {
-			width: 80%;
-			margin: 0 auto;
-			display: flex;
-			margin-bottom: 40rpx;
-			padding-bottom: 10rpx;
-			border-bottom: 2rpx solid rgba(249,249,249,0.4);
+  .passwold {
+    width: 80%;
+    margin: 0 auto;
+    display: flex;
+    margin-bottom: 40rpx;
+    padding-bottom: 10rpx;
+    border-bottom: 2rpx solid rgba(249, 249, 249, 0.4);
 
-			.u-icon__icon {
-				margin-top: 17rpx;
-			}
-			/deep/.u-input__input{
-				color: #fff;
-			}
-			.uni-input {
-				width: 100%;
-				color: #fff;
-			}
-			/deep/.uicon-eye{
-				color: #fff !important;
-			}
-		}
+    .u-icon__icon {
+      margin-top: 17rpx;
+    }
+    /deep/.u-input__input {
+      color: #fff;
+    }
+    .uni-input {
+      width: 100%;
+      color: #fff;
+    }
+    /deep/.uicon-eye {
+      color: #fff !important;
+    }
+  }
 
-		.aboutpass {
-			width: 80%;
-			margin: 0 auto;
-			display: flex;
-			justify-content: flex-end;
+  .aboutpass {
+    width: 80%;
+    margin: 0 auto;
+    display: flex;
+    justify-content: flex-end;
 
-			p {
-				color: #fff;
-				font-size: 28rpx;
-			}
-			/deep/.uicon-checkbox-mark{
-				border-color: #FF0000;
-				// color: #f00 !important;
-			}
-			/deep/.u-checkbox__label {
-				font-size: 28rpx;
-				color: #fff;
-				margin-right: 0;
-			}
-		}
+    p {
+      color: #fff;
+      font-size: 28rpx;
+    }
+    /deep/.uicon-checkbox-mark {
+      border-color: #ff0000;
+      // color: #f00 !important;
+    }
+    /deep/.u-checkbox__label {
+      font-size: 28rpx;
+      color: #fff;
+      margin-right: 0;
+    }
+  }
 
-		.uni-btn-v {
-			width: 80%;
-			margin: 112rpx auto 0;
-			position: relative;
-			z-index: 100;
+  .uni-btn-v {
+    width: 80%;
+    margin: 112rpx auto 0;
+    position: relative;
+    z-index: 100;
 
-			button {
-				width: 100%;
-				height: 90rpx;
-				line-height: 90rpx;
-				color: #FFFFFF;
-				font-size: 36rpx;
-				background-image: linear-gradient(to bottom, rgba(249,249,249,0.6), rgba(249, 249, 249, 0.1));
-				color: #5DC18B;
-			}
-		}
-	}
+    button {
+      width: 100%;
+      height: 90rpx;
+      line-height: 90rpx;
+      color: #ffffff;
+      font-size: 36rpx;
+      background-image: linear-gradient(
+        to bottom,
+        rgba(249, 249, 249, 0.6),
+        rgba(249, 249, 249, 0.1)
+      );
+      color: #5dc18b;
+    }
+  }
+}
 
-	.setbg {
-		width: 100%;
-		height: 100vh;
-		position: absolute;
-		top: 0;
-		z-index: 99999;
+.setbg {
+  width: 100%;
+  height: 100vh;
+  position: absolute;
+  top: 0;
+  z-index: 99999;
 
-		.mengban {
-			width: 100%;
-			height: 100vh;
-			position: absolute;
-			top: 0;
-			background-color: rgba($color: #000000, $alpha: 0.5);
-		}
+  .mengban {
+    width: 100%;
+    height: 100vh;
+    position: absolute;
+    top: 0;
+    background-color: rgba($color: #000000, $alpha: 0.5);
+  }
 
-		.set_http {
-			position: absolute;
-			width: 90%;
-			left: 5%;
-			top: 30%;
+  .set_http {
+    position: absolute;
+    width: 90%;
+    left: 5%;
+    top: 30%;
 
-			.set_http_top {
-				display: flex;
-				justify-content: space-around;
-				background-color: #5DC18B;
-				height: 60px;
-				line-height: 60px;
-				color: #FFFFFF;
-				border-top-right-radius: 20px;
-				border-top-left-radius: 20px;
-				font-size: 32rpx;
-			}
+    .set_http_top {
+      display: flex;
+      justify-content: space-around;
+      background-color: #5dc18b;
+      height: 60px;
+      line-height: 60px;
+      color: #ffffff;
+      border-top-right-radius: 20px;
+      border-top-left-radius: 20px;
+      font-size: 32rpx;
+    }
 
-			.set_http_bot {
-				height: 150px;
-				background-color: #FFFFFF;
-				border-bottom-right-radius: 20px;
-				border-bottom-left-radius: 20px;
-				padding: 30px;
+    .set_http_bot {
+      height: 150px;
+      background-color: #ffffff;
+      border-bottom-right-radius: 20px;
+      border-bottom-left-radius: 20px;
+      padding: 30px;
 
-				.set_http_bot_input {
-					margin-top: 20rpx;
-					border: 2rpx solid #bdb6a6;
-					border-radius: 20rpx;
-					padding: 10rpx 40rpx 0 20rpx;
-					font-size: 32rpx;
-					height: 30px;
-					display: flex;
-					justify-content: space-between;
+      .set_http_bot_input {
+        margin-top: 20rpx;
+        border: 2rpx solid #bdb6a6;
+        border-radius: 20rpx;
+        padding: 10rpx 40rpx 0 20rpx;
+        font-size: 32rpx;
+        height: 30px;
+        display: flex;
+        justify-content: space-between;
 
-					input {
-						width: 90%;
-					}
-				}
-			}
+        input {
+          width: 90%;
+        }
+      }
+    }
 
-			.scroll-Y {
-				border: 2rpx solid #d0d0d0;
-				border-radius: 20rpx;
+    .scroll-Y {
+      border: 2rpx solid #d0d0d0;
+      border-radius: 20rpx;
 
-				.scroll-view-item {
-					padding-left: 20rpx;
-					height: 70rpx;
-					font-size: 28rpx;
-					line-height: 70rpx;
-					border-bottom: 2rpx solid #d0d0d0;
-				}
-			}
-		}
-	}
+      .scroll-view-item {
+        padding-left: 20rpx;
+        height: 70rpx;
+        font-size: 28rpx;
+        line-height: 70rpx;
+        border-bottom: 2rpx solid #d0d0d0;
+      }
+    }
+  }
+}
 
-	.upgradeBox {
-		padding: 15rpx;
-	}
+.upgradeBox {
+  padding: 15rpx;
+}
 </style>

+ 11 - 12
pages/my/index/index.vue

@@ -9,10 +9,7 @@
           <p>
             {{ usernames }}
             <view @click="userinfo" class="userinfo">
-              <u-icon
-                name="edit-pen"
-                class="edit-pen"
-              ></u-icon>
+              <u-icon name="edit-pen" class="edit-pen"></u-icon>
             </view>
           </p>
           <p>{{ userinfos.email || userinfos.mobile || '' }}</p>
@@ -147,6 +144,8 @@ export default {
         success: (res) => {
           if (res.confirm) {
             this.getlogout();
+            // 清除上一个用户的权限缓存与存储,防止残留
+            this.$resetPermissionList();
             uni.removeStorage({
               key: 'session_key',
             });
@@ -173,8 +172,8 @@ export default {
 .subject {
   width: 100%;
   height: 100vh;
-  background: #F5F6FA;
-  .subject-top{
+  background: #f5f6fa;
+  .subject-top {
     height: 450rpx;
     background-image: url('https://s3.hnyfwlw.com/webstaticimg/bigdata_app/image/personBg.png');
     background-size: cover;
@@ -207,7 +206,7 @@ export default {
 
   .personal_center {
     padding-top: 20rpx;
-    color:#ffffff;
+    color: #ffffff;
 
     p:nth-child(1) {
       width: 100%;
@@ -218,18 +217,18 @@ export default {
       align-items: center;
       justify-content: center;
     }
-    .userinfo{
+    .userinfo {
       width: 40rpx;
       height: 40rpx;
       border-radius: 16rpx;
-      color:#ffffff;
+      color: #ffffff;
       font-size: 24rpx;
       background: #00000014;
       margin-left: 16rpx;
       display: flex;
       align-items: center;
       justify-content: center;
-      .edit-pen{
+      .edit-pen {
         font-size: 20rpx;
       }
     }
@@ -250,7 +249,7 @@ export default {
     right: 30rpx;
   }
 }
-.menu{
+.menu {
   margin: 0 32rpx;
   background: #ffffff;
   border-radius: 16rpx;
@@ -261,7 +260,7 @@ export default {
 .AboutUs,
 .quit,
 .opinion {
-  display:flex;
+  display: flex;
   align-items: center;
   width: 90%;
   height: 100rpx;

+ 167 - 37
util/QueryPermission.js

@@ -1,42 +1,172 @@
-var list =[]
+import { myRequest } from './api.js';
+
+// 权限列表的内存缓存。
+// 首次成功读取后缓存在内存里,后续不再依赖每次渲染都同步读取存储,
+// 既避免了“数据还没写入存储就被读取”的偶发时序问题,也省去重复 JSON.parse。
+var permissionList = null;
+// 正在进行的拉取请求,避免并发重复调用接口
+var fetchingPromise = null;
+
+// 从本地存储同步读取并刷新缓存。
+// 读到有效数据时返回解析后的数组;否则返回 null(缓存保持不变)。
+function loadListFromStorage() {
+  try {
+    var raw = uni.getStorageSync('jurisdiction');
+    if (raw) {
+      var parsed = JSON.parse(raw);
+      if (Array.isArray(parsed)) {
+        permissionList = parsed;
+        return permissionList;
+      }
+    }
+  } catch (e) {
+    console.warn('[QueryPermission] 解析 jurisdiction 失败:', e);
+  }
+  return null;
+}
+
+// 从服务端拉取权限列表并写入存储 + 缓存。
+// 幂等:已缓存且非强制刷新时直接返回;并发调用共享同一个请求。
+// 用于“未经过首页”等无法依赖本地存储已写入的特殊场景。
+function fetchPermissionList(options = {}) {
+  const { force = false } = options;
+  if (!force && permissionList && permissionList.length) {
+    return Promise.resolve(permissionList);
+  }
+  if (fetchingPromise) {
+    return fetchingPromise;
+  }
+  fetchingPromise = (async () => {
+    try {
+      const res = await myRequest({
+        url: '/api/api_gateway?method=user.login.user_login_info',
+        data: { is_app: 1 },
+      });
+      const menuList = [];
+      (res || []).forEach((item) => {
+        if (item && item.children) {
+          menuList.push(...item.children);
+        }
+      });
+      const children = [];
+      menuList.forEach((item) => {
+        if (item && item.children) {
+          children.push(...item.children);
+        }
+      });
+      permissionList = children;
+      // 同步落盘,保证其他读取 storage 的地方也能拿到
+      uni.setStorageSync('jurisdiction', JSON.stringify(children));
+      return children;
+    } catch (e) {
+      console.warn('[QueryPermission] 拉取权限列表失败:', e);
+      return permissionList || [];
+    } finally {
+      fetchingPromise = null;
+    }
+  })();
+  return fetchingPromise;
+}
+
+// 重置权限数据:清空内存缓存,并默认清除本地存储中的权限列表。
+// 用于退出登录、一键登录(切换账号)等场景,防止上一个用户的权限残留。
+function resetPermissionList(options = {}) {
+  const { keepStorage = false } = options;
+  permissionList = null;
+  fetchingPromise = null;
+  if (!keepStorage) {
+    try {
+      uni.removeStorageSync('jurisdiction');
+    } catch (e) {
+      console.warn('[QueryPermission] 清除 jurisdiction 存储失败:', e);
+    }
+  }
+}
+
 function QueryPermission(id) {
-	if(uni.getStorageSync("jurisdiction")){
-		list = JSON.parse(uni.getStorageSync("jurisdiction"))
-	}
-	for (var i = 0; i < list.length; i++) {
-		if (list[i].children) {
-			var data = list[i].children
-			for (var j = 0; j < data.length; j++) {
-					var item = data[j]
-					if (item.pur_id == id) {
-						return true
-					}
-			}
-		}
-	}
-	return false
+  // 优先使用内存缓存;缓存为空时尝试同步读取一次存储
+  // (覆盖“模块初始化时存储还没写入、但调用时已写入”的情况)
+  var list = permissionList || loadListFromStorage() || [];
+  for (var i = 0; i < list.length; i++) {
+    if (list[i] && list[i].children) {
+      var data = list[i].children;
+      for (var j = 0; j < data.length; j++) {
+        var item = data[j];
+        if (item && item.pur_id == id) {
+          return true;
+        }
+      }
+    }
+  }
+  return false;
 }
-function getUserPermission(){
-	let list = []
-	if(uni.getStorageSync("jurisdiction")){
-		list = JSON.parse(uni.getStorageSync("jurisdiction"))
-	}
-	return list
+function getUserPermission() {
+  if (!permissionList) {
+    loadListFromStorage();
+  }
+  return permissionList || [];
 }
-function getPermissionById(node = getUserPermission(),id) {
-		for (const child of node) {			
-			if(id == child.pur_id){				
-				return child.children || []
-			}
-			if(child.children){
-				let result = getPermissionById(child.children,id) 
-				if(result){
-					return result
-				}				
-			} 
-		}
-		return null
+function getPermissionById(node = getUserPermission(), id) {
+  for (const child of node) {
+    if (id == child.pur_id) {
+      return child.children || [];
+    }
+    if (child.children) {
+      let result = getPermissionById(child.children, id);
+      if (result) {
+        return result;
+      }
+    }
+  }
+  return null;
 }
-export {
-	QueryPermission,getPermissionById,getUserPermission
+
+/**
+ * 异步预加载权限列表,解决“数据未写入存储就执行 QueryPermission”的时序问题。
+ * 在依赖权限的详情页 onLoad 中 `await ensurePermissionLoaded()`,
+ * 可保证页面渲染前权限数据已就绪:
+ *   - 缓存或本地存储里已有 -> 立即返回;
+ *   - 本地没有(未经过首页等特殊入口)-> 默认直接请求接口拉取;
+ *   - 也可设置 fromServer:false 仅轮询等待本地存储写入完成。
+ * @param {Object} options
+ * @param {number} options.timeout  最长等待时间(ms),默认 8000(仅轮询模式生效)
+ * @param {number} options.interval 轮询间隔(ms),默认 100(仅轮询模式生效)
+ * @param {boolean} options.fromServer 本地无数据时是否请求接口拉取,默认 true
+ * @returns {Promise<Array>}
+ */
+function ensurePermissionLoaded(options = {}) {
+  const { timeout = 8000, interval = 100, fromServer = true } = options;
+  // 已就绪:缓存或存储里有数据,直接返回
+  if (permissionList && permissionList.length) {
+    return Promise.resolve(permissionList);
+  }
+  if (loadListFromStorage()) {
+    return Promise.resolve(permissionList);
+  }
+  // 未经过首页等特殊情况:本地没有权限数据,默认直接请求接口拉取
+  if (fromServer) {
+    return fetchPermissionList();
+  }
+  // fromServer=false:仅轮询等待本地存储写入完成
+  return new Promise((resolve) => {
+    const start = Date.now();
+    const timer = setInterval(() => {
+      if (loadListFromStorage()) {
+        clearInterval(timer);
+        resolve(permissionList);
+      } else if (Date.now() - start >= timeout) {
+        clearInterval(timer);
+        console.warn('[QueryPermission] 预加载超时,权限数据可能未就绪');
+        resolve([]);
+      }
+    }, interval);
+  });
 }
+export {
+  QueryPermission,
+  getPermissionById,
+  getUserPermission,
+  ensurePermissionLoaded,
+  fetchPermissionList,
+  resetPermissionList,
+};