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

339 lines
9.0 KiB

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