Browse Source

读者证板块

master
xuhuajiao 1 month ago
parent
commit
aa424a2abe
  1. 21
      api/article.js
  2. 9
      api/book.js
  3. 19
      api/hot.js
  4. 21
      api/video.js
  5. 99
      pages/home/home.vue
  6. 92
      pages/user/user.vue
  7. 151
      subpkg/pages/reader-card/reader-card copy.vue
  8. 191
      subpkg/pages/reader-card/reader-card.vue
  9. 148
      subpkg/pages/unbind-card/unbind-card.vue
  10. 245
      subpkg/pages/user-info/user-info.vue

21
api/article.js

@ -1,21 +0,0 @@
import request from '../utils/request';
/**
* 获取文章详情
*/
export function getArticleDetail(data) {
return request({
url: '/article/details',
data
});
}
/**
* 获取文章评论列表
*/
export function getArticleCommentList(data) {
return request({
url: '/article/comment/list',
data
});
}

9
api/book.js

@ -1,5 +1,14 @@
import request from '../utils/request'; import request from '../utils/request';
// 查询读者当前借阅(群)
export function FetchRdloanlist(data) {
return request({
url: '/api/screenSetting/rdloanlist',
data
})
}
// 图书推荐 // 图书推荐
export function FetchInitScreenBookRecommend(data) { export function FetchInitScreenBookRecommend(data) {
return request({ return request({

19
api/hot.js

@ -1,19 +0,0 @@
import request from '../utils/request';
export function getHotTabs() {
return request({
url: '/hot/tabs'
});
}
/**
* 热搜文章列表
*/
export function getHotListFromTabType(type) {
return request({
url: '/hot/list',
data: {
type
}
});
}

21
api/video.js

@ -1,21 +0,0 @@
import request from '../utils/request';
/**
* 热播视频列表
*/
export function getHotVideoList(data) {
return request({
url: '/video/list',
data
});
}
/**
* 获取视频弹幕列表
*/
export function getVideoDanmuList(data) {
return request({
url: '/video/danmu',
data
});
}

99
pages/home/home.vue

@ -90,7 +90,7 @@
</view> </view>
<view class="menu-label">电子证</view> <view class="menu-label">电子证</view>
</view> </view>
<view class="menu-item">
<view class="menu-item" @click="onToUser">
<view class="menu-icon"> <view class="menu-icon">
<uni-icons custom-prefix="iconfont" type="icon-yonghuxinxi-gerenxinxi" size="20"></uni-icons> <uni-icons custom-prefix="iconfont" type="icon-yonghuxinxi-gerenxinxi" size="20"></uni-icons>
</view> </view>
@ -119,7 +119,7 @@
<text class="info-title">读者证号</text> <text class="info-title">读者证号</text>
<text class="info-num">{{ item.bindValue }}</text> <text class="info-num">{{ item.bindValue }}</text>
</view> </view>
<view class="default-tag" v-if="item.bindDefault">默认证</view>
<view class="default-tag" v-if="item.bindDefault">默认证</view>
</view> </view>
</swiper-item> </swiper-item>
</swiper> </swiper>
@ -173,7 +173,7 @@ export default {
token: "", token: "",
userInfo: {}, userInfo: {},
isBindLibraryCard: false, isBindLibraryCard: false,
readerCardList: [], //
readerCardList: [], //
baseUrl: config.baseUrl, baseUrl: config.baseUrl,
}; };
}, },
@ -226,8 +226,13 @@ export default {
if (res.code === 200 && res.data.length > 0) { if (res.code === 200 && res.data.length > 0) {
this.isBindLibraryCard = true; this.isBindLibraryCard = true;
this.readerCardList = res.data;
uni.setStorageSync(READLIST, res.data);
// 👉
const defaultCard = res.data.find(item => item.bindDefault === true);
const otherCards = res.data.filter(item => !item.bindDefault);
//
this.readerCardList = defaultCard ? [defaultCard, ...otherCards] : res.data;
uni.setStorageSync(READLIST, this.readerCardList);
} else { } else {
this.isBindLibraryCard = false; this.isBindLibraryCard = false;
this.readerCardList = []; this.readerCardList = [];
@ -236,22 +241,15 @@ export default {
} catch (err) { } catch (err) {
console.error('初始化失败:', err); console.error('初始化失败:', err);
//
const list = uni.getStorageSync(READLIST) || []; const list = uni.getStorageSync(READLIST) || [];
this.readerCardList = list;
//
const defaultCard = list.find(item => item.bindDefault === true);
const otherCards = list.filter(item => !item.bindDefault);
this.readerCardList = defaultCard ? [defaultCard, ...otherCards] : list;
this.isBindLibraryCard = list.length > 0; this.isBindLibraryCard = list.length > 0;
} }
}, },
//
formatTime(timestamp) {
if (!timestamp) return ''
const date = new Date(timestamp)
const year = date.getFullYear()
const month = (date.getMonth() + 1).toString().padStart(2, '0')
const day = date.getDate().toString().padStart(2, '0')
return `${year}-${month}-${day}`
},
async getRecommendBooks() { async getRecommendBooks() {
try { try {
const res = await FetchInitScreenBookRecommend({ libcode: '1201' }); const res = await FetchInitScreenBookRecommend({ libcode: '1201' });
@ -263,7 +261,6 @@ export default {
this.isLoading = false this.isLoading = false
} }
}, },
goToBookDetail(item) { goToBookDetail(item) {
uni.navigateTo({ uni.navigateTo({
url: "/subpkg/pages/book-detail/book-detail?isbn=" + item.isbn url: "/subpkg/pages/book-detail/book-detail?isbn=" + item.isbn
@ -276,7 +273,7 @@ export default {
url: "/subpkg/pages/book-list/book-list" url: "/subpkg/pages/book-list/book-list"
}) })
}, },
//
onToSearch() { onToSearch() {
uni.switchTab({ uni.switchTab({
url: "/pages/search/search" url: "/pages/search/search"
@ -288,63 +285,6 @@ export default {
url: "/pages/login/login" url: "/pages/login/login"
}); });
}, },
// toCheckLogin(pageName) {
// // code
// uni.login({
// success: (res) => {
// if (res.code) {
// console.log('res',res)
// console.log(" code", res.code);
// const params = {
// libcode: '1201',
// code: res.code
// }
// FetchOpenId(params).then(res => {
// console.log('openId',res)
// if(res.code === 200 && res.data){
// uni.setStorageSync("wx_login_code", res.data);
// const data = {
// libcode: '1201',
// openId: res.data
// }
// FetchFindAllReaderBindByOpenId(data).then(res => {
// console.log('',res)
// if (res.code === 200 && res.data.length > 0) {
// this.isBindLibraryCard = true;
// this.readerCardList = res.data;
// uni.setStorageSync(READLIST, res.data);
// } else {
// this.isBindLibraryCard = false;
// uni.navigateTo({
// url: "/pages/login/login"
// });
// }
// })
// .catch(err => {
// console.error('', err);
// })
// }
// })
// .catch(err => {
// console.error('openId', err);
// })
// } else {
// uni.showToast({
// title: "",
// icon: "error"
// });
// }
// },
// fail: () => {
// uni.showToast({
// title: "",
// icon: "error"
// });
// }
// });
// },
toRanking(){ toRanking(){
uni.navigateTo({ uni.navigateTo({
url: "/subpkg/pages/ranking/ranking" url: "/subpkg/pages/ranking/ranking"
@ -371,6 +311,7 @@ export default {
url: '/subpkg/pages/feedback-list/feedback-list' url: '/subpkg/pages/feedback-list/feedback-list'
}); });
}, },
//
toLibraryCard() { toLibraryCard() {
// //
if (this.isBindLibraryCard) { if (this.isBindLibraryCard) {
@ -381,6 +322,12 @@ export default {
uni.navigateTo({ url: "/pages/login/login" }); uni.navigateTo({ url: "/pages/login/login" });
} }
}, },
//
onToUser() {
uni.switchTab({
url: "/pages/user/user"
});
},
onToScan() { onToScan() {
uni.scanCode({ uni.scanCode({
onlyFromCamera: true, onlyFromCamera: true,

92
pages/user/user.vue

@ -3,15 +3,15 @@
<view class="top-user-bar"> <view class="top-user-bar">
<image class="top-bar-bg" src="@/static/images/mingqi-beij@2x.png" mode="aspectFill"></image> <image class="top-bar-bg" src="@/static/images/mingqi-beij@2x.png" mode="aspectFill"></image>
<view class="user-info"> <view class="user-info">
<!-- 点击选择头像 -->
<button open-type="chooseAvatar" @chooseavatar="onChooseAvatar" class="avatar-btn">
<!-- 👇 这里修改点击头像跳转到个人资料页 -->
<view class="avatar-btn" @click="toUserInfoPage">
<image v-if="userInfo.avatarUrl" :src="userInfo.avatarUrl" class="avatar-img"></image> <image v-if="userInfo.avatarUrl" :src="userInfo.avatarUrl" class="avatar-img"></image>
<image v-else src="@/static/images/avatar.png" class="avatar-img"></image> <image v-else src="@/static/images/avatar.png" class="avatar-img"></image>
</button>
</view>
<view class="user-info-text"> <view class="user-info-text">
<text class="user-name">{{ userInfo.nickName || '未登录' }}</text>
<text class="user-card">{{ cardNo || '' }}</text>
<text class="user-name" @click="toUserInfoPage">{{ userInfo.nickName || '未登录' }}</text>
<text class="user-card" v-if="cardNo">读者证{{ cardNo }}</text>
</view> </view>
</view> </view>
<view class="user-menu"> <view class="user-menu">
@ -31,22 +31,22 @@
<uni-icons custom-prefix="iconfont" type="icon-liuyan" size="20"></uni-icons> <uni-icons custom-prefix="iconfont" type="icon-liuyan" size="20"></uni-icons>
<text class="left-txt">我的留言</text> <text class="left-txt">我的留言</text>
</view> </view>
<view class="submenu-item" @click="toCheckLogin('个人资料')">
<view class="submenu-item" @click="toUserInfoPage">
<uni-icons custom-prefix="iconfont" type="icon-shezhi" size="20"></uni-icons> <uni-icons custom-prefix="iconfont" type="icon-shezhi" size="20"></uni-icons>
<text class="left-txt">个人资料</text> <text class="left-txt">个人资料</text>
</view> </view>
<view class="submenu-item" @click="toCheckLogin('修改密码')">
<!-- <view class="submenu-item" @click="toCheckLogin('修改密码')">
<uni-icons custom-prefix="iconfont" type="icon-xiugai" size="20"></uni-icons> <uni-icons custom-prefix="iconfont" type="icon-xiugai" size="20"></uni-icons>
<text class="left-txt">修改密码</text> <text class="left-txt">修改密码</text>
</view>
</view> -->
<view class="submenu-item" @click="toCheckLogin('解绑读者证')"> <view class="submenu-item" @click="toCheckLogin('解绑读者证')">
<uni-icons custom-prefix="iconfont" type="icon-UIsheji_menjinxitong-28" size="20"></uni-icons> <uni-icons custom-prefix="iconfont" type="icon-UIsheji_menjinxitong-28" size="20"></uni-icons>
<text class="left-txt">解绑读者证</text> <text class="left-txt">解绑读者证</text>
</view> </view>
<view v-if="isBindLibraryCard" class="submenu-item" @click="toLogOut()">
<!-- <view v-if="isBindLibraryCard" class="submenu-item" @click="toLogOut()">
<uni-icons custom-prefix="iconfont" type="icon-tuichu" size="20"></uni-icons> <uni-icons custom-prefix="iconfont" type="icon-tuichu" size="20"></uni-icons>
<text class="left-txt">退出账号</text> <text class="left-txt">退出账号</text>
</view>
</view> -->
</view> </view>
<view> <view>
@ -82,38 +82,11 @@ export default {
onShow() { onShow() {
this.loadUserInfo(); this.loadUserInfo();
}, },
methods: {
//
async onChooseAvatar(e) {
const tempFilePath = e.detail.avatarUrl;
try {
// 1.
const uploadRes = await new Promise((resolve, reject) => {
uni.uploadFile({
url: config.baseUrl + '/api/fileRelevant/uploadWxAvatarImg',
filePath: tempFilePath,
name: 'file',
success: resolve,
reject: reject
})
})
const resData = JSON.parse(uploadRes.data);
const imgId = resData.data;
if (!imgId) {
uni.showToast({ title: '头像上传失败', icon: 'none' });
return;
}
const avatarUrl = config.baseUrl + '/api/fileRelevant/getImg?imgType=5&imgId=' + imgId;
// 2. +
await this.bindUserInfo(avatarUrl, this.userInfo.nickName || '小图');
uni.showToast({ title: '头像更新成功', icon: 'success' });
} catch (err) {
console.error('头像处理失败:', err);
uni.showToast({ title: '头像更新失败', icon: 'none' });
}
methods:{
toUserInfoPage() {
uni.navigateTo({
url: '/subpkg/pages/user-info/user-info'
});
}, },
// + // +
@ -125,18 +98,12 @@ export default {
nickname, nickname,
openid: openId openid: openId
}; };
// 1.
const res = await FetchBindRead(params); const res = await FetchBindRead(params);
// 2.
const userInfo = { const userInfo = {
nickName: nickname, nickName: nickname,
avatarUrl: avatar avatarUrl: avatar
}; };
uni.setStorageSync(USER_KEY, userInfo); uni.setStorageSync(USER_KEY, userInfo);
// 3.
this.userInfo = userInfo; this.userInfo = userInfo;
}, },
@ -167,7 +134,6 @@ export default {
this.userInfo = uni.getStorageSync(USER_KEY) || {}; this.userInfo = uni.getStorageSync(USER_KEY) || {};
} }
// ===================== =====================
// //
const defaultCard = readerList.find(item => item.bindDefault === true); const defaultCard = readerList.find(item => item.bindDefault === true);
this.cardNo = defaultCard ? defaultCard.bindValue : (readerList[0]?.bindValue || ''); this.cardNo = defaultCard ? defaultCard.bindValue : (readerList[0]?.bindValue || '');
@ -175,6 +141,7 @@ export default {
} catch (err) { } catch (err) {
// //
console.error('加载用户信息失败:', err)
const readerList = uni.getStorageSync(READLIST) || []; const readerList = uni.getStorageSync(READLIST) || [];
this.userInfo = uni.getStorageSync(USER_KEY) || {}; this.userInfo = uni.getStorageSync(USER_KEY) || {};
const defaultCard = readerList.find(item => item.bindDefault === true); const defaultCard = readerList.find(item => item.bindDefault === true);
@ -194,18 +161,17 @@ export default {
} }
// //
if(pageName === '借阅'){
uni.navigateTo({ url: '/subpkg/pages/myLending/myLending' });
}else if(pageName === '我的留言'){
uni.navigateTo({ url: '/subpkg/pages/feedback-list/feedback-list' });
}else if(pageName === '修改密码'){
uni.navigateTo({ url: '/subpkg/pages/change-password/change-password' });
}else if(pageName === '收藏'){
uni.navigateTo({ url: '/subpkg/pages/collect-list/collect-list' });
}else if(pageName === '个人资料'){
uni.navigateTo({ url: '/subpkg/pages/user-info/user-info' });
}else if(pageName === '解绑读者证'){
uni.navigateTo({ url: '/subpkg/pages/unbind-card/unbind-card' });
const routeMap = {
'借阅': '/subpkg/pages/myLending/myLending',
'我的留言': '/subpkg/pages/feedback-list/feedback-list',
// '': '/subpkg/pages/change-password/change-password',
'收藏': '/subpkg/pages/collect-list/collect-list',
// '': '/subpkg/pages/user-info/user-info',
'解绑读者证': '/subpkg/pages/reader-card/reader-card'
}
const url = routeMap[pageName]
if (url) {
uni.navigateTo({ url })
} }
}, },
@ -276,6 +242,7 @@ export default {
width: 62px; width: 62px;
height: 62px; height: 62px;
border-radius: 50%; border-radius: 50%;
object-fit: cover;
} }
} }
.user-info-text{ .user-info-text{
@ -293,9 +260,10 @@ export default {
.user-card{ .user-card{
margin-top: 5px; margin-top: 5px;
font-size: 12px; font-size: 12px;
font-weight: 400;
font-weight: 40;
color: #fff; color: #fff;
line-height: 17px; line-height: 17px;
opacity: 0.9;
} }
} }
} }

151
subpkg/pages/reader-card/reader-card copy.vue

@ -0,0 +1,151 @@
<template>
<view class="reader-card">
<image class="card-top-bg" src="@/static/images/card-img1.png" mode="widthFix" />
<view class="card-list">
<view
class="card-list-item"
v-for="(item, index) in cardList"
:key="item.id"
@click="handleSelectItem(item.bindValue)"
:class="{ active: selectedValue === item.bindValue }"
>
<image class="card-left-img" src="@/static/images/card-img2.png" mode="widthFix" />
<view class="card-right-info">
<text class="info-title">读者证号</text>
<text class="info-num">{{ item.bindValue }}</text>
</view>
<radio :value="item.bindValue" :checked="selectedValue === item.bindValue"/>
</view>
<view class="add-card-btn" @click="toAddReaderCard">
<uni-icons type="plus" size="20" color="#01a4fe"></uni-icons>
<text>新增读者证</text>
</view>
</view>
</view>
</template>
<script>
import { FetchFindAllReaderBindByOpenId, FetchSetDefaultReadCard } from '@/api/user';
const READLIST = 'reader-card-list';
export default {
data() {
return {
selectedValue: '',
cardList: [],
}
},
onLoad() {},
onShow() {
this.getBindReaderCardList();
},
methods: {
async getBindReaderCardList() {
try {
const openId = uni.getStorageSync('wx_login_code');
if (!openId) {
uni.showToast({ title: '未获取到用户信息', icon: 'none' });
return;
}
const data = { libcode: '1201', openId: openId };
const res = await FetchFindAllReaderBindByOpenId(data);
if (res.code === 200 && res.data.length > 0) {
this.cardList = res.data;
uni.setStorageSync(READLIST, res.data);
// bindDefault = true
const defaultCard = this.cardList.find(item => item.bindDefault === true);
this.selectedValue = defaultCard ? defaultCard.bindValue : this.cardList[0].bindValue;
} else {
this.cardList = [];
uni.setStorageSync(READLIST, []);
this.selectedValue = '';
}
} catch (err) {
this.cardList = uni.getStorageSync(READLIST) || [];
const defaultCard = this.cardList.find(item => item.bindDefault === true);
this.selectedValue = defaultCard ? defaultCard.bindValue : this.cardList[0]?.bindValue || '';
}
},
//
handleSelectItem(value) {
const oldValue = this.selectedValue;
const openId = uni.getStorageSync('wx_login_code');
if (value === oldValue) return;
uni.showModal({
title: '提示',
content: '确定切换默认读者证吗?',
success: async (res) => {
if (!res.confirm) {
this.selectedValue = oldValue;
return;
}
try {
const result = await FetchSetDefaultReadCard({
bindType: 'rdid',
bindValue: value,
libcode: '1201',
openid: openId
});
if (result.code === 200) {
this.selectedValue = value;
uni.setStorageSync('currentReaderCard', value);
uni.showToast({ title: '默认证切换成功', icon: 'success' });
} else {
this.selectedValue = oldValue;
uni.showToast({ title: result.msg || '切换失败', icon: 'none' });
}
} catch (err) {
this.selectedValue = oldValue;
uni.showToast({ title: '切换失败', icon: 'none' });
}
}
});
},
toAddReaderCard() {
uni.navigateTo({ url: "/pages/login/login" });
},
}
}
</script>
<style lang="scss" scoped>
.reader-card{
position: relative;
min-height: 100vh;
background-color: #f5f5f5;
.card-top-bg{
position: absolute;
left: 0;
top: 0;
width: 100%;
display: block;
}
.add-card-btn {
display: flex;
align-items: center;
justify-content: center;
margin-top: 15px;
height: 44px;
border: 1px dashed #01a4fe;
border-radius: 8px;
color: #01a4fe;
font-size: 15px;
uni-icons {
margin-right: 6px;
}
}
}
</style>

191
subpkg/pages/reader-card/reader-card.vue

@ -2,8 +2,11 @@
<view class="reader-card"> <view class="reader-card">
<image class="card-top-bg" src="@/static/images/card-img1.png" mode="widthFix" /> <image class="card-top-bg" src="@/static/images/card-img1.png" mode="widthFix" />
<view class="edit-btn" @click="toggleEditMode">
{{ isEditMode ? '完成' : '解绑' }}
</view>
<view class="card-list"> <view class="card-list">
<!-- 点击整个item触发切换 -->
<view <view
class="card-list-item" class="card-list-item"
v-for="(item, index) in cardList" v-for="(item, index) in cardList"
@ -15,80 +18,106 @@
<view class="card-right-info"> <view class="card-right-info">
<text class="info-title">读者证号</text> <text class="info-title">读者证号</text>
<text class="info-num">{{ item.bindValue }}</text> <text class="info-num">{{ item.bindValue }}</text>
<text class="default-tag" v-if="item.bindDefault">默认证</text>
</view> </view>
<radio :value="item.bindValue" :checked="selectedValue === item.bindValue"/>
<radio v-if="isEditMode" :value="item.bindValue" :checked="selectedValue === item.bindValue"/>
</view> </view>
<view class="add-card-btn" @click="toAddReaderCard">
<view class="add-card-btn" @click="toAddReaderCard" v-if="!isEditMode">
<uni-icons type="plus" size="20" color="#01a4fe"></uni-icons> <uni-icons type="plus" size="20" color="#01a4fe"></uni-icons>
<text>新增读者证</text> <text>新增读者证</text>
</view> </view>
</view> </view>
<!-- 编辑模式显示底部解绑按钮 -->
<button
v-if="isEditMode"
class="unbind-btn"
:disabled="!selectedValue"
:class="{disabled: !selectedValue}"
@click="handleUnbind"
>
确认解绑
</button>
</view> </view>
</template> </template>
<script> <script>
import { FetchFindAllReaderBindByOpenId, FetchSetDefaultReadCard } from '@/api/user';
import {
FetchFindAllReaderBindByOpenId,
FetchSetDefaultReadCard,
FetchUnbindReadCard
} from '@/api/user';
const READLIST = 'reader-card-list'; const READLIST = 'reader-card-list';
export default { export default {
data() { data() {
return { return {
isEditMode: false,
selectedValue: '', selectedValue: '',
cardList: [], cardList: [],
} }
}, },
onLoad() {},
onShow() { onShow() {
this.getBindReaderCardList(); this.getBindReaderCardList();
}, },
methods: { methods: {
// +
toggleEditMode() {
this.isEditMode = !this.isEditMode;
this.selectedValue = '';
},
//
async getBindReaderCardList() { async getBindReaderCardList() {
try { try {
const openId = uni.getStorageSync('wx_login_code'); const openId = uni.getStorageSync('wx_login_code');
if (!openId) {
uni.showToast({ title: '未获取到用户信息', icon: 'none' });
return;
}
if (!openId) return;
const data = { libcode: '1201', openId: openId };
const res = await FetchFindAllReaderBindByOpenId(data);
const res = await FetchFindAllReaderBindByOpenId({
libcode: '1201',
openId: openId
});
if (res.code === 200 && res.data.length > 0) { if (res.code === 200 && res.data.length > 0) {
this.cardList = res.data; this.cardList = res.data;
uni.setStorageSync(READLIST, res.data); uni.setStorageSync(READLIST, res.data);
// bindDefault = true
const defaultCard = this.cardList.find(item => item.bindDefault === true);
this.selectedValue = defaultCard ? defaultCard.bindValue : this.cardList[0].bindValue;
} else { } else {
this.cardList = []; this.cardList = [];
uni.setStorageSync(READLIST, []);
this.selectedValue = ''; this.selectedValue = '';
uni.setStorageSync(READLIST, []);
} }
} catch (err) { } catch (err) {
this.cardList = uni.getStorageSync(READLIST) || []; this.cardList = uni.getStorageSync(READLIST) || [];
const defaultCard = this.cardList.find(item => item.bindDefault === true);
this.selectedValue = defaultCard ? defaultCard.bindValue : this.cardList[0]?.bindValue || '';
} }
}, },
//
//
handleSelectItem(value) { handleSelectItem(value) {
const oldValue = this.selectedValue;
const openId = uni.getStorageSync('wx_login_code');
//
if (this.isEditMode) {
this.selectedValue = this.selectedValue === value ? '' : value;
return;
}
//
if (value === oldValue) return;
//
const currentDefault = this.cardList.find(item => item.bindDefault === true);
if (currentDefault && currentDefault.bindValue === value) {
uni.showToast({
title: '当前已是默认证,请勿重复操作',
icon: 'none'
});
return;
}
const openId = uni.getStorageSync('wx_login_code');
uni.showModal({ uni.showModal({
title: '提示', title: '提示',
content: '确定切换默认读者证吗?', content: '确定切换默认读者证吗?',
success: async (res) => { success: async (res) => {
if (!res.confirm) {
this.selectedValue = oldValue;
return;
}
if (!res.confirm) return;
try { try {
const result = await FetchSetDefaultReadCard({ const result = await FetchSetDefaultReadCard({
@ -99,23 +128,76 @@ export default {
}); });
if (result.code === 200) { if (result.code === 200) {
this.selectedValue = value;
uni.setStorageSync('currentReaderCard', value); uni.setStorageSync('currentReaderCard', value);
await this.getBindReaderCardList();
uni.showToast({ title: '默认证切换成功', icon: 'success' }); uni.showToast({ title: '默认证切换成功', icon: 'success' });
} else {
this.selectedValue = oldValue;
uni.showToast({ title: result.msg || '切换失败', icon: 'none' });
} }
} catch (err) { } catch (err) {
this.selectedValue = oldValue;
uni.showToast({ title: '切换失败', icon: 'none' }); uni.showToast({ title: '切换失败', icon: 'none' });
} }
} }
}); });
}, },
//
radioChange() {},
//
async handleUnbind() {
if (!this.selectedValue) {
uni.showToast({ title: '请选择要解绑的读者证', icon: 'none' });
return;
}
const openId = uni.getStorageSync('wx_login_code');
const unbindItem = this.cardList.find(item => item.bindValue === this.selectedValue);
const isUnbindDefault = unbindItem?.bindDefault === true;
uni.showModal({
title: '提示',
content: `确定要解绑读者证【${this.selectedValue}】吗?`,
success: async (res) => {
if (!res.confirm) return;
try {
const result = await FetchUnbindReadCard({
bindType: "rdid",
bindValue: this.selectedValue,
libcode: "1201",
openid: openId
});
if (result.code === 200) {
uni.showToast({ title: '解绑成功', icon: 'success' });
//
this.selectedValue = '';
await this.getBindReaderCardList();
// ==============================================
// +
//
// ==============================================
if (isUnbindDefault && this.cardList.length > 0) {
const newValue = this.cardList[0].bindValue;
await FetchSetDefaultReadCard({
bindType: 'rdid',
bindValue: newValue,
libcode: '1201',
openid: openId
});
uni.setStorageSync('currentReaderCard', newValue);
await this.getBindReaderCardList();
}
//
if (this.cardList.length === 0) {
setTimeout(() => uni.navigateBack(), 1500);
}
}
} catch (err) {
uni.showToast({ title: '解绑失败', icon: 'none' });
}
}
});
},
toAddReaderCard() { toAddReaderCard() {
uni.navigateTo({ url: "/pages/login/login" }); uni.navigateTo({ url: "/pages/login/login" });
@ -135,9 +217,17 @@ export default {
left: 0; left: 0;
top: 0; top: 0;
width: 100%; width: 100%;
display: block;
} }
.edit-btn{
position: absolute;
right: 20px;
top: 20px;
z-index: 100;
font-size: 15px;
}
//
.card-list{ .card-list{
position: absolute; position: absolute;
left: 0; left: 0;
@ -180,17 +270,29 @@ export default {
font-size: 16px; font-size: 16px;
color: #333; color: #333;
font-weight: bold; font-weight: bold;
padding-bottom: 12px;
padding-bottom: 4px;
} }
.info-num{ .info-num{
font-size: 14px; font-size: 14px;
color: #999; color: #999;
} }
.default-tag{
width: 46px;
font-size: 12px;
color: #01a4fe;
border: 1px solid #01a4fe;
border-radius: 4px;
padding: 2px 0;
text-align: center;
display: inline-block;
margin-top: 4px;
}
} }
} }
} }
.add-card-btn { .add-card-btn {
display: flex; display: flex;
align-items: center; align-items: center;
@ -206,5 +308,22 @@ export default {
margin-right: 6px; margin-right: 6px;
} }
} }
.unbind-btn{
position: fixed;
bottom: 40px;
left: 0;
right: 0;
width: calc(100% - 40px);
margin: 0 auto;
padding: 4px 0;
color: #fff;
background-color: #01a4fe;
border-radius: 23px;
font-size: 16px;
&.disabled{
background-color: #ccc;
}
}
} }
</style> </style>

148
subpkg/pages/unbind-card/unbind-card.vue

@ -3,7 +3,6 @@
<image class="card-top-bg" src="@/static/images/card-img1.png" mode="widthFix" /> <image class="card-top-bg" src="@/static/images/card-img1.png" mode="widthFix" />
<view class="card-list"> <view class="card-list">
<!-- 点击选择要解绑的读者证 -->
<view <view
class="card-list-item" class="card-list-item"
v-for="(item, index) in cardList" v-for="(item, index) in cardList"
@ -16,21 +15,10 @@
<text class="info-title">读者证号</text> <text class="info-title">读者证号</text>
<text class="info-num">{{ item.bindValue }}</text> <text class="info-num">{{ item.bindValue }}</text>
</view> </view>
<uni-icons
type="checkmark"
size="24"
color="#01a4fe"
v-if="selectedValue === item.bindValue"
></uni-icons>
<radio :value="item.bindValue" :checked="selectedValue === item.bindValue"/>
</view> </view>
<!-- <view class="add-card-btn" @click="toAddReaderCard">
<uni-icons type="plus" size="20" color="#01a4fe"></uni-icons>
<text>新增读者证</text>
</view> -->
</view> </view>
<!-- 底部解绑按钮 -->
<button <button
class="unbind-btn" class="unbind-btn"
:disabled="!selectedValue" :disabled="!selectedValue"
@ -45,7 +33,8 @@
<script> <script>
import { import {
FetchFindAllReaderBindByOpenId, FetchFindAllReaderBindByOpenId,
FetchUnbindReadCard
FetchUnbindReadCard,
FetchSetDefaultReadCard
} from '@/api/user'; } from '@/api/user';
const READLIST = 'reader-card-list'; const READLIST = 'reader-card-list';
@ -53,16 +42,14 @@ const READLIST = 'reader-card-list';
export default { export default {
data() { data() {
return { return {
selectedValue: '', //
selectedValue: '',
cardList: [], cardList: [],
} }
}, },
onLoad() {},
onShow() { onShow() {
this.getBindReaderCardList(); this.getBindReaderCardList();
}, },
methods: { methods: {
//
async getBindReaderCardList() { async getBindReaderCardList() {
try { try {
const openId = uni.getStorageSync('wx_login_code'); const openId = uni.getStorageSync('wx_login_code');
@ -85,9 +72,7 @@ export default {
} }
}, },
//
handleSelectItem(value) { handleSelectItem(value) {
//
if (this.selectedValue === value) { if (this.selectedValue === value) {
this.selectedValue = ''; this.selectedValue = '';
} else { } else {
@ -96,7 +81,7 @@ export default {
}, },
// //
handleUnbind() {
async handleUnbind() {
if (!this.selectedValue) { if (!this.selectedValue) {
uni.showToast({ title: '请选择要解绑的读者证', icon: 'none' }); uni.showToast({ title: '请选择要解绑的读者证', icon: 'none' });
return; return;
@ -105,13 +90,18 @@ export default {
const openId = uni.getStorageSync('wx_login_code'); const openId = uni.getStorageSync('wx_login_code');
if (!openId) return; if (!openId) return;
//
const unbindItem = this.cardList.find(item => item.bindValue === this.selectedValue);
const isUnbindDefault = unbindItem?.bindDefault === true;
uni.showModal({ uni.showModal({
title: '提示', title: '提示',
content: `确定要解绑【${this.selectedValue}】吗?`,
content: `确定要解绑读者证${this.selectedValue}】吗?`,
success: async (res) => { success: async (res) => {
if (res.confirm) {
if (!res.confirm) return;
try { try {
//
// 1.
const result = await FetchUnbindReadCard({ const result = await FetchUnbindReadCard({
bindType: "rdid", bindType: "rdid",
bindValue: this.selectedValue, bindValue: this.selectedValue,
@ -119,24 +109,48 @@ export default {
openid: openId openid: openId
}); });
if (result.code === 200) {
if (result.code !== 200) {
uni.showToast({ title: result.msg || '解绑失败', icon: 'none' });
return;
}
uni.showToast({ title: '解绑成功', icon: 'success' }); uni.showToast({ title: '解绑成功', icon: 'success' });
this.selectedValue = ''; this.selectedValue = '';
this.getBindReaderCardList(); //
} else {
uni.showToast({ title: result.msg || '解绑失败', icon: 'none' });
//
await this.getBindReaderCardList();
if (isUnbindDefault && this.cardList.length > 0) {
const newDefaultCard = this.cardList[0];
const newValue = newDefaultCard.bindValue;
const setResult = await FetchSetDefaultReadCard({
bindType: 'rdid',
bindValue: newValue,
libcode: '1201',
openid: openId
});
if (setResult.code === 200) {
uni.setStorageSync('currentReaderCard', newValue);
//
await this.getBindReaderCardList();
uni.showToast({ title: '已自动设置默认证', icon: 'success' });
} }
}
if (this.cardList.length === 0) {
setTimeout(() => {
uni.navigateBack();
}, 1500);
}
} catch (err) { } catch (err) {
uni.showToast({ title: '解绑失败', icon: 'none' }); uni.showToast({ title: '解绑失败', icon: 'none' });
} }
} }
}
}); });
}, },
toAddReaderCard() {
uni.navigateTo({ url: "/pages/login/login" });
},
} }
} }
</script> </script>
@ -155,75 +169,6 @@ export default {
display: block; display: block;
} }
.card-list{
position: absolute;
left: 0;
top: 60px;
width: calc(100% - 24px);
height: calc(100vh - 195px);
overflow-y: auto;
padding: 12px;
z-index: 999;
.card-list-item{
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
margin-bottom: 12px;
border: 2px solid #C6C6E2;
border-radius: 8px;
background: rgba(241,241,249,0.4);
cursor: pointer;
transition: all 0.2s;
&.active{
border-color: #01a4fe;
background: rgba(1, 164, 254, 0.1);
}
.card-left-img{
width: 80px;
margin-right: 12px;
display: block;
}
.card-right-info{
flex: 1;
display: flex;
flex-direction: column;
.info-title{
font-size: 16px;
color: #333;
font-weight: bold;
padding-bottom: 12px;
}
.info-num{
font-size: 14px;
color: #999;
}
}
}
}
.add-card-btn {
display: flex;
align-items: center;
justify-content: center;
margin-top: 15px;
height: 44px;
border: 1px dashed #01a4fe;
border-radius: 8px;
color: #01a4fe;
font-size: 15px;
uni-icons {
margin-right: 6px;
}
}
.unbind-btn{ .unbind-btn{
position: fixed; position: fixed;
bottom: 40px; bottom: 40px;
@ -236,7 +181,6 @@ export default {
background-color: #01a4fe; background-color: #01a4fe;
border-radius: 23px; border-radius: 23px;
font-size: 16px; font-size: 16px;
border: none;
&.disabled{ &.disabled{
background-color: #ccc; background-color: #ccc;
} }

245
subpkg/pages/user-info/user-info.vue

@ -1,75 +1,147 @@
<template> <template>
<view class="user-info-page"> <view class="user-info-page">
<!-- 昵称 -->
<view class="form-item">
<text class="label">昵称</text>
<input class="input" v-model="userInfo.nickname" placeholder="请输入昵称" />
<uni-icons type="right" size="18"></uni-icons>
</view>
<!-- 性别picker 选择 -->
<view class="form-item">
<text class="label">性别</text>
<picker class="picker" :value="genderIndex" :range="genderList" @change="onGenderChange">
<view class="picker-text">{{ userInfo.gender || "请选择" }}</view>
</picker>
<uni-icons type="right" size="18"></uni-icons>
</view>
<!-- 年龄 -->
<view class="form-item">
<text class="label">年龄</text>
<input class="input" v-model="userInfo.age" placeholder="请输入年龄" type="number" />
<uni-icons type="right" size="18"></uni-icons>
<view class="user-info-section">
<!-- 点击获取头像 -->
<button open-type="chooseAvatar" @chooseavatar="onChooseAvatar" class="avatar-btn">
<image v-if="avatarUrl" :src="avatarUrl" class="avatar-img"></image>
<image v-else src="@/static/images/avatar.png" class="avatar-img"></image>
<text class="tip-text">点击更换头像</text>
</button>
</view> </view>
<!-- 职业 -->
<!-- 昵称 -->
<view class="form-item"> <view class="form-item">
<text class="label">职业</text>
<input class="input" v-model="userInfo.job" placeholder="请输入职业" />
<uni-icons type="right" size="18"></uni-icons>
<text class="label">昵称</text>
<input
class="input"
type="nickname"
v-model="nickName"
placeholder="请输入昵称"
/>
<uni-icons type="right" size="18" color="#ccc"></uni-icons>
</view> </view>
<!-- 保存按钮 --> <!-- 保存按钮 -->
<view class="save-box"> <view class="save-box">
<button class="save-btn" @click="saveUserInfo">保存</button>
<button class="save-btn" @click="saveUserInfo">保存修改</button>
</view> </view>
</view> </view>
</template> </template>
<script> <script>
import config from '@/utils/config'
import { FetchBindRead } from '@/api/user';
// key
const USER_KEY = 'user-info';
export default { export default {
data() { data() {
return { return {
//
userInfo: {
nickname: "小图",
gender: "女",
age: "",
job: ""
},
//
genderList: ["男", "女", "保密"],
genderIndex: 1 //
nickName: '',
avatarUrl: ''
}; };
}, },
onLoad() {
//
this.loadUserInfo();
},
methods: { methods: {
//
onGenderChange(e) {
const index = e.detail.value;
this.genderIndex = index;
this.userInfo.gender = this.genderList[index];
//
loadUserInfo() {
const userInfo = uni.getStorageSync(USER_KEY) || {};
this.nickName = userInfo.nickName || '';
this.avatarUrl = userInfo.avatarUrl || '';
},
//
async onChooseAvatar(e) {
const tempFilePath = e.detail.avatarUrl;
uni.showLoading({ title: '上传中...' });
try {
// 1.
const uploadRes = await new Promise((resolve, reject) => {
uni.uploadFile({
url: config.baseUrl + '/api/fileRelevant/uploadWxAvatarImg',
filePath: tempFilePath,
name: 'file',
success: resolve,
fail: reject
})
});
const resData = JSON.parse(uploadRes.data);
const imgId = resData.data;
if (!imgId) {
uni.showToast({ title: '头像上传失败', icon: 'none' });
return;
}
//
const avatarUrl = config.baseUrl + '/api/fileRelevant/getImg?imgType=5&imgId=' + imgId;
this.avatarUrl = avatarUrl;
uni.showToast({ title: '头像选择成功,点击保存生效', icon: 'success' });
} catch (err) {
console.error('头像上传失败:', err);
uni.showToast({ title: '头像更新失败', icon: 'none' });
} finally {
uni.hideLoading();
}
}, },
//
saveUserInfo() {
console.log("要保存的信息:", this.userInfo);
// +
async saveUserInfo() {
//
if (!this.nickName.trim()) {
uni.showToast({ title: '请输入昵称', icon: 'none' });
return;
}
uni.showLoading({ title: '保存中...' });
try {
const openId = uni.getStorageSync('wx_login_code') || '';
const params = {
avatar: this.avatarUrl,
libcode: "1201",
nickname: this.nickName,
openid: openId
};
//
await FetchBindRead(params);
//
//
const userInfo = {
nickName: this.nickName,
avatarUrl: this.avatarUrl
};
uni.setStorageSync(USER_KEY, userInfo);
uni.showToast({
title: '保存成功',
icon: 'success'
});
//
setTimeout(() => {
uni.navigateBack();
}, 1500);
} catch (error) {
console.error('保存失败:', error);
uni.showToast({ uni.showToast({
title: "保存成功",
icon: "success"
title: '保存失败,请重试',
icon: 'none'
}); });
} finally {
uni.hideLoading();
}
} }
} }
}; };
@ -79,61 +151,82 @@ export default {
.user-info-page { .user-info-page {
background-color: #f5f5f5; background-color: #f5f5f5;
min-height: 100vh; min-height: 100vh;
padding: 10px;
padding: 20rpx;
box-sizing: border-box; box-sizing: border-box;
padding-bottom: 80px;
} }
/* 头像区域 */
.user-info-section {
background: #fff;
padding: 40rpx 0;
border-radius: 12rpx;
margin-bottom: 20rpx;
display: flex;
flex-direction: column;
align-items: center;
}
.avatar-btn {
background: transparent;
display: flex;
flex-direction: column;
align-items: center;
&::after {
border: none;
}
}
.avatar-img {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
object-fit: cover;
margin-bottom: 10rpx;
}
.tip-text {
font-size: 26rpx;
color: #999;
}
/* 表单项 */
.form-item { .form-item {
background-color: #fff; background-color: #fff;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding: 0 10px 0 15px;
height: 50px;
border-bottom: 1px solid #eee;
padding: 0 30rpx;
height: 88rpx;
border-radius: 12rpx;
margin-bottom: 20rpx;
} }
.label { .label {
width: 100px;
font-size: 16px;
font-size: 30rpx;
color: #333; color: #333;
width: 120rpx;
} }
/* 输入框样式 */
.input { .input {
flex: 1; flex: 1;
font-size: 16px;
color: #333;
text-align: right;
margin-right: 6px;
}
/* 选择器样式 */
.picker {
flex: 1;
display: flex;
justify-content: flex-end;
margin-right: 6px;
}
.picker-text {
font-size: 16px;
font-size: 30rpx;
color: #333; color: #333;
text-align: right; text-align: right;
} }
/* 保存按钮 */ /* 保存按钮 */
.save-box { .save-box {
position: fixed;
left: 15px;
right: 15px;
bottom: 30px;
margin-top: 60rpx;
padding: 0 20rpx;
} }
.save-btn { .save-btn {
padding: 5px 0;
height: 88rpx;
line-height: 88rpx;
background-color: #007aff; background-color: #007aff;
color: #fff; color: #fff;
border-radius: 23px;
font-size: 16px;
border-radius: 44rpx;
font-size: 32rpx;
} }
</style> </style>
Loading…
Cancel
Save