图书馆小程序
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.

362 lines
10 KiB

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
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
1 month ago
2 months 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. <button open-type="chooseAvatar" @chooseavatar="onChooseAvatar" class="avatar-btn">
  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. </button>
  11. <view class="user-info-text">
  12. <text class="user-name">{{ userInfo.nickName || '未登录' }}</text>
  13. <text class="user-card">{{ 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="toCheckLogin('个人资料')">
  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. // 选择微信头像
  81. async onChooseAvatar(e) {
  82. const tempFilePath = e.detail.avatarUrl;
  83. try {
  84. // 1. 上传头像
  85. const uploadRes = await new Promise((resolve, reject) => {
  86. uni.uploadFile({
  87. url: config.baseUrl + '/api/fileRelevant/uploadWxAvatarImg',
  88. filePath: tempFilePath,
  89. name: 'file',
  90. success: resolve,
  91. reject: reject
  92. })
  93. })
  94. const resData = JSON.parse(uploadRes.data);
  95. const imgId = resData.data;
  96. if (!imgId) {
  97. uni.showToast({ title: '头像上传失败', icon: 'none' });
  98. return;
  99. }
  100. const avatarUrl = config.baseUrl + '/api/fileRelevant/getImg?imgType=5&imgId=' + imgId;
  101. // 2. 调用接口保存(头像+昵称)
  102. await this.bindUserInfo(avatarUrl, this.userInfo.nickName || '小图');
  103. uni.showToast({ title: '头像更新成功', icon: 'success' });
  104. } catch (err) {
  105. console.error('头像处理失败:', err);
  106. uni.showToast({ title: '头像更新失败', icon: 'none' });
  107. }
  108. },
  109. // 调用接口:头像+昵称 → 成功后统一保存缓存
  110. async bindUserInfo(avatar, nickname) {
  111. const openId = uni.getStorageSync('wx_login_code') || '';
  112. const params = {
  113. avatar,
  114. libcode: "1201",
  115. nickname,
  116. openid: openId
  117. };
  118. // 1. 调用接口
  119. const res = await FetchBindRead(params);
  120. // 2. 接口成功 → 统一保存到缓存(整体缓存)
  121. const userInfo = {
  122. nickName: nickname,
  123. avatarUrl: avatar
  124. };
  125. uni.setStorageSync(USER_KEY, userInfo);
  126. // 3. 刷新页面数据
  127. this.userInfo = userInfo;
  128. },
  129. // 加载用户信息(从接口获取)
  130. async loadUserInfo() {
  131. try {
  132. const openId = uni.getStorageSync('wx_login_code');
  133. const readerList = uni.getStorageSync(READLIST) || [];
  134. // 从接口获取用户信息(昵称、头像)
  135. if (openId) {
  136. const res = await FetchFindAllReaderByOpenId({
  137. libcode: '1201',
  138. openId: openId
  139. });
  140. if (res.code === 200 && res.data) {
  141. // 只赋值用户信息,不处理读者证
  142. this.userInfo = {
  143. nickName: res.data.nickName || res.data.nickname || '',
  144. avatarUrl: res.data.avatarUrl || res.data.avatar || ''
  145. };
  146. uni.setStorageSync(USER_KEY, this.userInfo);
  147. } else {
  148. this.userInfo = uni.getStorageSync(USER_KEY) || {};
  149. }
  150. } else {
  151. this.userInfo = uni.getStorageSync(USER_KEY) || {};
  152. }
  153. // ===================== 读者证只从缓存取 =====================
  154. // 找到默认读者证
  155. const defaultCard = readerList.find(item => item.bindDefault === true);
  156. this.cardNo = defaultCard ? defaultCard.bindValue : (readerList[0]?.bindValue || '');
  157. this.isBindLibraryCard = readerList.length > 0;
  158. } catch (err) {
  159. // 异常降级:读缓存
  160. const readerList = uni.getStorageSync(READLIST) || [];
  161. this.userInfo = uni.getStorageSync(USER_KEY) || {};
  162. const defaultCard = readerList.find(item => item.bindDefault === true);
  163. this.cardNo = defaultCard ? defaultCard.bindValue : (readerList[0]?.bindValue || '');
  164. this.isBindLibraryCard = readerList.length > 0;
  165. }
  166. },
  167. // 校验登录:只根据 有没有读者证 判断
  168. toCheckLogin(pageName) {
  169. const readerList = uni.getStorageSync(READLIST) || [];
  170. // 没有绑定读者证 → 弹窗
  171. if (readerList.length === 0) {
  172. this.dialogToggle();
  173. return;
  174. }
  175. // 已绑定 → 正常跳转
  176. if(pageName === '借阅'){
  177. uni.navigateTo({ url: '/subpkg/pages/myLending/myLending' });
  178. }else if(pageName === '我的留言'){
  179. uni.navigateTo({ url: '/subpkg/pages/feedback-list/feedback-list' });
  180. }else if(pageName === '修改密码'){
  181. uni.navigateTo({ url: '/subpkg/pages/change-password/change-password' });
  182. }else if(pageName === '收藏'){
  183. uni.navigateTo({ url: '/subpkg/pages/collect-list/collect-list' });
  184. }else if(pageName === '个人资料'){
  185. uni.navigateTo({ url: '/subpkg/pages/user-info/user-info' });
  186. }else if(pageName === '解绑读者证'){
  187. uni.navigateTo({ url: '/subpkg/pages/unbind-card/unbind-card' });
  188. }
  189. },
  190. dialogToggle() {
  191. this.$refs.alertDialog.open();
  192. },
  193. dialogConfirm() {
  194. uni.navigateTo({ url: "/pages/login/login" });
  195. },
  196. dialogClose() {},
  197. // 退出登录
  198. toLogOut() {
  199. uni.showModal({
  200. title: '确认退出',
  201. content: '确定要退出当前账号吗?',
  202. success: (res) => {
  203. if (res.confirm) {
  204. // 清空缓存
  205. uni.removeStorageSync(USER_KEY);
  206. uni.removeStorageSync(READLIST);
  207. // 重置
  208. this.userInfo = {};
  209. this.cardNo = "";
  210. this.isBindLibraryCard = false;
  211. uni.showToast({ title: '退出成功', icon: 'success' });
  212. uni.switchTab({ url: "/pages/home/home" });
  213. }
  214. }
  215. });
  216. },
  217. }
  218. }
  219. </script>
  220. <style lang="scss" scoped>
  221. .top-user-bar{
  222. position: relative;
  223. width: 100%;
  224. height: 150px;
  225. display: flex;
  226. align-items: center;
  227. color: $uni-white;
  228. .top-bar-bg{
  229. position: absolute;
  230. left: 0;
  231. top: 0;
  232. display: block;
  233. width: 100%;
  234. height: 100%;
  235. z-index: 1;
  236. }
  237. .user-info{
  238. position: absolute;
  239. left: 0;
  240. top: 0;
  241. z-index: 99;
  242. display: flex;
  243. justify-content: flex-start;
  244. .avatar-btn {
  245. background: transparent;
  246. margin-top: 19px;
  247. margin-left: 28px;
  248. &::after{ border: none !important; }
  249. .avatar-img {
  250. width: 62px;
  251. height: 62px;
  252. border-radius: 50%;
  253. }
  254. }
  255. .user-info-text{
  256. display: flex;
  257. flex-direction: column;
  258. align-items: flex-start;
  259. justify-content: flex-start;
  260. margin: 26px 16px 0 16px;
  261. .user-name{
  262. font-size: 20px;
  263. font-weight: 500;
  264. color: #fff;
  265. line-height: 28px;
  266. }
  267. .user-card{
  268. margin-top: 5px;
  269. font-size: 12px;
  270. font-weight: 400;
  271. color: #fff;
  272. line-height: 17px;
  273. }
  274. }
  275. }
  276. .user-menu{
  277. position: absolute;
  278. bottom: -60px;
  279. left: 0;
  280. background-color: #fff;
  281. z-index: 99;
  282. display: flex;
  283. justify-content: flex-start;
  284. width: calc(100% - 40px);
  285. margin: 0 20px;
  286. border-radius: 6px;
  287. box-shadow: 0px 2px 15px 0px rgba(0, 0, 0, .1);
  288. .menu-item{
  289. display: flex;
  290. flex-direction: column;
  291. align-items: center;
  292. justify-content: center;
  293. padding: 0 30px;
  294. height: 100px;
  295. .menu-icon{
  296. width: 32px;
  297. height: 32px;
  298. margin-bottom: 10px;
  299. }
  300. .menu-txt{
  301. color: #636365;
  302. font-size: 13px;
  303. }
  304. }
  305. }
  306. }
  307. .submenu-box{
  308. margin-top: 80px;
  309. background-color: #fff;
  310. display: flex;
  311. flex-direction: column;
  312. align-items: center;
  313. justify-content: center;
  314. .submenu-item{
  315. display: flex;
  316. align-items: center;
  317. justify-content: flex-start;
  318. width: calc(100% - 40px);
  319. background-color: #fff;
  320. border-bottom: 1px solid #f4f4f4;
  321. height: 45px;
  322. padding: 0 20px;
  323. ::v-deep .uni-icons{
  324. color: #343434 !important;
  325. }
  326. .left-txt{
  327. color: #343434;
  328. font-size: 14px;
  329. width: calc(100% - 50px);
  330. white-space: nowrap;
  331. overflow: hidden;
  332. text-overflow: ellipsis;
  333. margin-left: 10px;
  334. }
  335. }
  336. }
  337. </style>