图书馆小程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

329 lines
8.8 KiB

2 months ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
2 months ago
1 month ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
1 month ago
1 month ago
2 months ago
1 month ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
1 month ago
1 month ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
1 month ago
1 month ago
2 months ago
1 month ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
  1. <template>
  2. <view style="padding-bottom: 20px;">
  3. <view class="top-user-bar">
  4. <image class="top-bar-bg" src="@/static/images/mingqi-beij@2x.png" mode="aspectFill"></image>
  5. <view class="user-info">
  6. <!-- 👇 这里修改点击头像跳转到个人资料页 -->
  7. <view class="avatar-btn" @click="toUserInfoPage">
  8. <image v-if="userInfo.avatarUrl" :src="userInfo.avatarUrl" class="avatar-img"></image>
  9. <image v-else src="@/static/images/avatar.png" class="avatar-img"></image>
  10. </view>
  11. <view class="user-info-text">
  12. <text class="user-name" @click="toUserInfoPage">{{ userInfo.nickName || '未登录' }}</text>
  13. <text class="user-card" v-if="cardNo">读者证{{ cardNo }}</text>
  14. </view>
  15. </view>
  16. <view class="user-menu">
  17. <view class="menu-item" @click="toCheckLogin('收藏')">
  18. <image class="menu-icon" src="@/static/images/menu-sc.png" mode="scaleToFill" />
  19. <text class="menu-txt">收藏</text>
  20. </view>
  21. <view class="menu-item" @click="toCheckLogin('借阅')">
  22. <image class="menu-icon" src="@/static/images/menu-jy.png" mode="scaleToFill" />
  23. <text class="menu-txt">借阅</text>
  24. </view>
  25. </view>
  26. </view>
  27. <view class="submenu-box">
  28. <view class="submenu-item" @click="toCheckLogin('我的留言')">
  29. <uni-icons custom-prefix="iconfont" type="icon-liuyan" size="20"></uni-icons>
  30. <text class="left-txt">我的留言</text>
  31. </view>
  32. <view class="submenu-item" @click="toUserInfoPage">
  33. <uni-icons custom-prefix="iconfont" type="icon-shezhi" size="20"></uni-icons>
  34. <text class="left-txt">个人资料</text>
  35. </view>
  36. <!-- <view class="submenu-item" @click="toCheckLogin('修改密码')">
  37. <uni-icons custom-prefix="iconfont" type="icon-xiugai" size="20"></uni-icons>
  38. <text class="left-txt">修改密码</text>
  39. </view> -->
  40. <view class="submenu-item" @click="toCheckLogin('解绑读者证')">
  41. <uni-icons custom-prefix="iconfont" type="icon-UIsheji_menjinxitong-28" size="20"></uni-icons>
  42. <text class="left-txt">解绑读者证</text>
  43. </view>
  44. <!-- <view v-if="isBindLibraryCard" class="submenu-item" @click="toLogOut()">
  45. <uni-icons custom-prefix="iconfont" type="icon-tuichu" size="20"></uni-icons>
  46. <text class="left-txt">退出账号</text>
  47. </view> -->
  48. </view>
  49. <view>
  50. <uni-popup ref="alertDialog" type="dialog">
  51. <uni-popup-dialog
  52. type="info" cancelText="取消" confirmText="确定"
  53. title="提示" content="请您绑定读者证!"
  54. @confirm="dialogConfirm" @close="dialogClose">
  55. </uni-popup-dialog>
  56. </uni-popup>
  57. </view>
  58. </view>
  59. </template>
  60. <script>
  61. import config from '@/utils/config'
  62. import { FetchBindRead, FetchFindAllReaderByOpenId } from '@/api/user';
  63. const USER_KEY = 'user-info';
  64. const READLIST = 'reader-card-list';
  65. export default {
  66. data() {
  67. return {
  68. userInfo: {},
  69. cardNo: "",
  70. isBindLibraryCard: false,
  71. };
  72. },
  73. onLoad() {
  74. this.loadUserInfo();
  75. },
  76. onShow() {
  77. this.loadUserInfo();
  78. },
  79. methods:{
  80. toUserInfoPage() {
  81. uni.navigateTo({
  82. url: '/subpkg/pages/user-info/user-info'
  83. });
  84. },
  85. // 调用接口:头像+昵称 → 成功后统一保存缓存
  86. async bindUserInfo(avatar, nickname) {
  87. const openId = uni.getStorageSync('wx_login_code') || '';
  88. const params = {
  89. avatar,
  90. libcode: "1201",
  91. nickname,
  92. openid: openId
  93. };
  94. const res = await FetchBindRead(params);
  95. const userInfo = {
  96. nickName: nickname,
  97. avatarUrl: avatar
  98. };
  99. uni.setStorageSync(USER_KEY, userInfo);
  100. this.userInfo = userInfo;
  101. },
  102. // 加载用户信息(从接口获取)
  103. async loadUserInfo() {
  104. try {
  105. const openId = uni.getStorageSync('wx_login_code');
  106. const readerList = uni.getStorageSync(READLIST) || [];
  107. // 从接口获取用户信息(昵称、头像)
  108. if (openId) {
  109. const res = await FetchFindAllReaderByOpenId({
  110. libcode: '1201',
  111. openId: openId
  112. });
  113. if (res.code === 200 && res.data) {
  114. // 只赋值用户信息,不处理读者证
  115. this.userInfo = {
  116. nickName: res.data.nickName || res.data.nickname || '',
  117. avatarUrl: res.data.avatarUrl || res.data.avatar || ''
  118. };
  119. uni.setStorageSync(USER_KEY, this.userInfo);
  120. } else {
  121. this.userInfo = uni.getStorageSync(USER_KEY) || {};
  122. }
  123. } else {
  124. this.userInfo = uni.getStorageSync(USER_KEY) || {};
  125. }
  126. // 找到默认读者证
  127. const defaultCard = readerList.find(item => item.bindDefault === true);
  128. this.cardNo = defaultCard ? defaultCard.bindValue : (readerList[0]?.bindValue || '');
  129. this.isBindLibraryCard = readerList.length > 0;
  130. } catch (err) {
  131. // 异常降级:读缓存
  132. console.error('加载用户信息失败:', err)
  133. const readerList = uni.getStorageSync(READLIST) || [];
  134. this.userInfo = uni.getStorageSync(USER_KEY) || {};
  135. const defaultCard = readerList.find(item => item.bindDefault === true);
  136. this.cardNo = defaultCard ? defaultCard.bindValue : (readerList[0]?.bindValue || '');
  137. this.isBindLibraryCard = readerList.length > 0;
  138. }
  139. },
  140. // 校验登录:只根据 有没有读者证 判断
  141. toCheckLogin(pageName) {
  142. const readerList = uni.getStorageSync(READLIST) || [];
  143. // 没有绑定读者证 → 弹窗
  144. if (readerList.length === 0) {
  145. this.dialogToggle();
  146. return;
  147. }
  148. // 已绑定 → 正常跳转
  149. const routeMap = {
  150. '借阅': '/subpkg/pages/myLending/myLending',
  151. '我的留言': '/subpkg/pages/feedback-list/feedback-list',
  152. // '修改密码': '/subpkg/pages/change-password/change-password',
  153. '收藏': '/subpkg/pages/collect-list/collect-list',
  154. // '个人资料': '/subpkg/pages/user-info/user-info',
  155. '解绑读者证': '/subpkg/pages/reader-card/reader-card'
  156. }
  157. const url = routeMap[pageName]
  158. if (url) {
  159. uni.navigateTo({ url })
  160. }
  161. },
  162. dialogToggle() {
  163. this.$refs.alertDialog.open();
  164. },
  165. dialogConfirm() {
  166. uni.navigateTo({ url: "/pages/login/login" });
  167. },
  168. dialogClose() {},
  169. // 退出登录
  170. toLogOut() {
  171. uni.showModal({
  172. title: '确认退出',
  173. content: '确定要退出当前账号吗?',
  174. success: (res) => {
  175. if (res.confirm) {
  176. // 清空缓存
  177. uni.removeStorageSync(USER_KEY);
  178. uni.removeStorageSync(READLIST);
  179. // 重置
  180. this.userInfo = {};
  181. this.cardNo = "";
  182. this.isBindLibraryCard = false;
  183. uni.showToast({ title: '退出成功', icon: 'success' });
  184. uni.switchTab({ url: "/pages/home/home" });
  185. }
  186. }
  187. });
  188. },
  189. }
  190. }
  191. </script>
  192. <style lang="scss" scoped>
  193. .top-user-bar{
  194. position: relative;
  195. width: 100%;
  196. height: 150px;
  197. display: flex;
  198. align-items: center;
  199. color: $uni-white;
  200. .top-bar-bg{
  201. position: absolute;
  202. left: 0;
  203. top: 0;
  204. display: block;
  205. width: 100%;
  206. height: 100%;
  207. z-index: 1;
  208. }
  209. .user-info{
  210. position: absolute;
  211. left: 0;
  212. top: 0;
  213. z-index: 99;
  214. display: flex;
  215. justify-content: flex-start;
  216. .avatar-btn {
  217. background: transparent;
  218. margin-top: 19px;
  219. margin-left: 28px;
  220. &::after{ border: none !important; }
  221. .avatar-img {
  222. width: 62px;
  223. height: 62px;
  224. border-radius: 50%;
  225. object-fit: cover;
  226. }
  227. }
  228. .user-info-text{
  229. display: flex;
  230. flex-direction: column;
  231. align-items: flex-start;
  232. justify-content: flex-start;
  233. margin: 26px 16px 0 16px;
  234. .user-name{
  235. font-size: 20px;
  236. font-weight: 500;
  237. color: #fff;
  238. line-height: 28px;
  239. }
  240. .user-card{
  241. margin-top: 5px;
  242. font-size: 12px;
  243. font-weight: 40;
  244. color: #fff;
  245. line-height: 17px;
  246. }
  247. }
  248. }
  249. .user-menu{
  250. position: absolute;
  251. bottom: -60px;
  252. left: 0;
  253. background-color: #fff;
  254. z-index: 99;
  255. display: flex;
  256. justify-content: flex-start;
  257. width: calc(100% - 40px);
  258. margin: 0 20px;
  259. border-radius: 6px;
  260. box-shadow: 0px 2px 15px 0px rgba(0, 0, 0, .1);
  261. .menu-item{
  262. display: flex;
  263. flex-direction: column;
  264. align-items: center;
  265. justify-content: center;
  266. padding: 0 30px;
  267. height: 100px;
  268. .menu-icon{
  269. width: 32px;
  270. height: 32px;
  271. margin-bottom: 10px;
  272. }
  273. .menu-txt{
  274. color: #636365;
  275. font-size: 13px;
  276. }
  277. }
  278. }
  279. }
  280. .submenu-box{
  281. margin-top: 80px;
  282. background-color: #fff;
  283. display: flex;
  284. flex-direction: column;
  285. align-items: center;
  286. justify-content: center;
  287. .submenu-item{
  288. display: flex;
  289. align-items: center;
  290. justify-content: flex-start;
  291. width: calc(100% - 40px);
  292. background-color: #fff;
  293. border-bottom: 1px solid #f4f4f4;
  294. height: 45px;
  295. padding: 0 20px;
  296. ::v-deep .uni-icons{
  297. color: #343434 !important;
  298. }
  299. .left-txt{
  300. color: #343434;
  301. font-size: 14px;
  302. width: calc(100% - 50px);
  303. white-space: nowrap;
  304. overflow: hidden;
  305. text-overflow: ellipsis;
  306. margin-left: 10px;
  307. }
  308. }
  309. }
  310. </style>