Browse Source

接口调试

master
xuhuajiao 1 month ago
parent
commit
cf70a51912
  1. 17
      api/book.js
  2. 150
      api/user.js
  3. 22
      components/book-list-item/book-list-item.vue
  4. 6
      pages.json
  5. 411
      pages/home/home.vue
  6. 324
      pages/login/login copy 2.vue
  7. 252
      pages/login/login copy.vue
  8. 297
      pages/login/login-no-clear.vue
  9. 269
      pages/login/login-pay.vue
  10. 409
      pages/login/login.vue
  11. 366
      pages/user/user.vue
  12. 2
      store/modules/user.js
  13. 11
      subpkg/pages/book-detail/book-detail.vue
  14. 74
      subpkg/pages/book-list/book-list.vue
  15. 8
      subpkg/pages/feedback-list/feedback-list.vue
  16. 480
      subpkg/pages/myLending/myLending-addpage.vue
  17. 212
      subpkg/pages/reader-card/reader-card.vue
  18. 245
      subpkg/pages/unbind-card/unbind-card.vue
  19. 14
      utils/config.js
  20. 30
      utils/request.js

17
api/book.js

@ -0,0 +1,17 @@
import request from '../utils/request';
// 图书推荐
export function FetchInitScreenBookRecommend(data) {
return request({
url: '/api/screenSetting/initScreenBookRecommend',
data
})
}
// export function FetchInitScreenBookRecommend(data) {
// return request({
// url: '/qyzt/getNewBook',
// data
// })
// }

150
api/user.js

@ -1,53 +1,157 @@
import request from '../utils/request';
/**
* 用户登录
*/
export function login(data) {
// 获取第三方url/appid/Secret/sm4_key
export function FetchInitScreenSetting(data) {
return request({
url: '/sys/login',
url: '/api/screenSetting/initScreenSetting',
data
})
}
//根据微信code 获取openId
export function FetchOpenId(data) {
return request({
url: '/api/weixin/getOpenId',
data
});
}
// 根据openid获取所有绑定读者证列表
// ?libcode=&openId=
export function FetchFindAllReaderBindByOpenId(data) {
return request({
url: '/api/weixin/findAllReaderBindByOpenId',
data
});
}
// 根据openid获取用户信息
// ?libcode=&openId=
export function FetchFindAllReaderByOpenId(data) {
return request({
url: '/api/weixin/findReaderByOpenId',
data
});
}
// 读者认证
export function FetchReaderList(data) {
return request({
url: '/api/screenSetting/searchreaderlist2',
data
});
}
// 用户绑定读者证
// {
// "openid":"小程序用户openID",
// "bindValue":"绑定值",
// "bindType":"绑定方式(rdid 读者证号 rdname读者姓名 rdcertify身份证号 othercardno其他编号 workcardno工作/学生证号 rdphone电话 rdloginid手机 cardid附属卡(IC卡))",
// "libcode":"馆代码"
// }
export function FetchBindReadCard(data) {
return request({
url: '/api/weixin/bindReadCard',
method: 'POST',
data
});
}
/**
* 关注用户
*/
export function userFollow(data) {
// 绑定用户
// {
// "avatar": "头像",
// "libcode": "馆代码",
// "nickname": "昵称",
// "openid": ""
// }
export function FetchBindRead(data) {
return request({
url: '/user/follow',
url: '/api/weixin/bindReader',
method: 'POST',
data
});
}
/**
* 发表评论
*/
export function userArticleComment(data) {
// 设置默认读者证
// {
// "bindType": "string",
// "bindValue": "string",
// "libcode": "string",
// "openid": "string"
// }
export function FetchSetDefaultReadCard(data) {
return request({
url: '/user/article/comment',
url: '/api/weixin/setDefaultReadCard',
method: 'POST',
data
});
}
/**
* 用户点赞
*/
export function userPraise(data) {
// 用户解绑读者证
// {
// "bindType": "string",
// "bindValue": "string",
// "libcode": "string",
// "openid": "string"
// }
export function FetchUnbindReadCard(data) {
return request({
url: '/user/praise',
url: '/api/weixin/unbindReadCard',
method: 'POST',
data
});
}
/**
* 用户收藏
* 用户登录
*/
export function userCollect(data) {
export function login(data) {
return request({
url: '/user/collect',
url: '/sys/login',
method: 'POST',
data
});
}
/**
* 关注用户
*/
// export function userFollow(data) {
// return request({
// url: '/user/follow',
// data
// });
// }
/**
* 发表评论
*/
// export function userArticleComment(data) {
// return request({
// url: '/user/article/comment',
// method: 'POST',
// data
// });
// }
/**
* 用户点赞
*/
// export function userPraise(data) {
// return request({
// url: '/user/praise',
// data
// });
// }
/**
* 用户收藏
*/
// export function userCollect(data) {
// return request({
// url: '/user/collect',
// data
// });
// }

22
components/book-list-item/book-list-item.vue

@ -2,16 +2,21 @@
<view class="item-container" @click="$emit('click')">
<view class="item-box">
<view class="item-box-left">
<image
<!-- <image
class="img-item"
:src="data.imgCover"
mode="scaleToFill"
/>
/> -->
<image
class="img-item"
:src="data.imgPath ? baseUrl + '/api/fileRelevant/getImg?imgType=2&imgId=' + data.imgPath : '' "
mode="scaleToFill"
></image>
</view>
<view class="item-box-right">
<view class="item-title line-clamp-2">{{ data.title || '暂无标题' }}</view>
<text class="item-author">{{ data.nickname || '佚名' }}</text>
<text class="item-publish">{{ data.publish || '暂无出版社数据' }}</text>
<view class="item-title line-clamp-2">{{ data.name || '暂无标题' }}</view>
<text class="item-author">{{ data.author || '佚名' }}</text>
<text class="item-publish">{{ data.publisher || '暂无出版社数据' }}</text>
<!-- <view class="item-desc line-clamp-2">{{ data.desc || '暂无简介' }}</view> -->
<!-- <view class="item-bottom-box">
<view class="hot-box">
@ -24,6 +29,8 @@
</template>
<script>
import config from '@/utils/config';
export default {
name: "book-list-item",
props: {
@ -32,6 +39,11 @@ export default {
required: true
}
},
data() {
return {
baseUrl: config.baseUrl
}
},
methods: {
hotNumber(num) {
if (!num) return "0";

6
pages.json

@ -150,6 +150,12 @@
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "pages/unbind-card/unbind-card",
"style": {
"navigationBarTitleText": ""
}
}
]
}

411
pages/home/home.vue

@ -45,7 +45,6 @@
</swiper-item>
</swiper>
<!-- circular -->
<swiper class="menu-swiper" interval="6000" :vertical="false" :indicator-dots="true" :autoplay="false">
<swiper-item>
<view class="menu-grid">
@ -55,12 +54,6 @@
</view>
<view class="menu-label">书目检索</view>
</view>
<view class="menu-item" @click="onToScan">
<view class="menu-icon">
<uni-icons custom-prefix="iconfont" type="icon-saomajieshu1" size="22"></uni-icons>
</view>
<view class="menu-label">扫码借书</view>
</view>
<view class="menu-item">
<view class="menu-icon">
<uni-icons custom-prefix="iconfont" type="icon-z_renew_normal" size="24"></uni-icons>
@ -97,10 +90,6 @@
</view>
<view class="menu-label">电子证</view>
</view>
</view>
</swiper-item>
<swiper-item>
<view class="menu-grid">
<view class="menu-item">
<view class="menu-icon">
<uni-icons custom-prefix="iconfont" type="icon-yonghuxinxi-gerenxinxi" size="20"></uni-icons>
@ -111,14 +100,40 @@
</swiper-item>
</swiper>
<!-- 借阅证区域登录后隐藏 -->
<view class="library-card-section" @click="toCheckLogin" v-if="!isBindLibraryCard">
<!-- 已有绑定滑动切换多个借阅证 -->
<view v-if="isBindLibraryCard" class="library-card-has">
<view class="section-title">我的借阅证</view>
<!-- 左右滑动切换证件 -->
<!-- :indicator-dots="readerCardList.length > 1"
indicator-color="#d1d1d1"
indicator-active-color="#01a4fe" -->
<swiper
class="card-swiper"
:circular="false"
>
<swiper-item v-for="item in readerCardList" :key="item.id">
<view class="card-item">
<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>
<view class="default-tag" v-if="item.bindDefault">默认证件</view>
</view>
</swiper-item>
</swiper>
</view>
<!-- 未绑定借阅证 -->
<view class="library-card-section" @click="toCheckLogin" v-else>
<view class="section-title">借阅证</view>
<image class="card-icon" src="@/static/images/card-img2.png"></image>
<view class="card-tip">您还没有绑定读者证哦</view>
<image class="card-icon" src="@/static/images/card-img2.png"></image>
<view class="card-tip">您还没有绑定读者证哦</view>
<button class="bind-btn">立即绑定</button>
</view>
<view class="recommendation-section">
<view class="section-title">
<text class="left-txt">图书推荐</text>
@ -129,9 +144,13 @@
</view>
<view class="recommendation-list">
<uni-load-more status="loading" v-if="isLoading"></uni-load-more>
<view v-else class="book-item" v-for="(item,index) in recommendedBooks" @click="goToBookDetail(item)" :key="index" >
<image class="book-cover" :src="item.cover"></image>
<view class="book-title">{{item.title}}</view>
<view v-else class="book-item" v-for="(item,index) in recommendedBooks.slice(0,3)" @click="goToBookDetail(item)" :key="index" >
<image
class="book-cover"
:src="item.imgPath ? baseUrl + '/api/fileRelevant/getImg?imgType=2&imgId=' + item.imgPath : '' "
></image>
<view class="book-title">{{item.name}}</view>
</view>
</view>
</view>
@ -140,6 +159,12 @@
</template>
<script>
import { FetchOpenId, FetchFindAllReaderBindByOpenId} from '@/api/user';
import { FetchInitScreenBookRecommend } from '@/api/book';
import config from '@/utils/config';
const READLIST = 'reader-card-list';
export default {
data() {
return {
@ -147,91 +172,179 @@ export default {
recommendedBooks: [],
token: "",
userInfo: {},
isBindLibraryCard: false // /
isBindLibraryCard: false,
readerCardList: [], //
baseUrl: config.baseUrl,
};
},
onLoad() {
this.getRecommendBooks();
this.checkLoginStatus(); //
},
//
onShow() {
this.checkLoginStatus();
this.initUserAndCheckBind();
},
methods:{
//
checkLoginStatus() {
this.loadUser();
// token
this.isBindLibraryCard = !!this.token;
// openid
async initUserAndCheckBind() {
try {
// 1. openId
let openId = uni.getStorageSync('wx_login_code');
// 2.
if (!openId) {
const loginRes = await new Promise((resolve, reject) => {
uni.login({
success: resolve,
fail: reject
});
});
if (!loginRes.code) {
uni.showToast({ title: '授权失败', icon: 'none' });
return;
}
// 3. openId
const openRes = await FetchOpenId({
libcode: '1201',
code: loginRes.code
});
if (openRes.code !== 200 || !openRes.data) {
return;
}
openId = openRes.data;
uni.setStorageSync('wx_login_code', openId);
}
// 4. openId
const res = await FetchFindAllReaderBindByOpenId({
libcode: '1201',
openId: openId
});
if (res.code === 200 && res.data.length > 0) {
this.isBindLibraryCard = true;
this.readerCardList = res.data;
uni.setStorageSync(READLIST, res.data);
} else {
this.isBindLibraryCard = false;
this.readerCardList = [];
uni.setStorageSync(READLIST, []);
}
} catch (err) {
console.error('初始化失败:', err);
//
const list = uni.getStorageSync(READLIST) || [];
this.readerCardList = list;
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}`
},
getRecommendBooks() {
setTimeout(() => {
this.recommendedBooks = [
{
isbn: '9787544741110',
title: '人工智能基础——数学知识',
cover: 'https://qiniu.aiyxlib.com/1606124577077'
},
{
isbn: '9787539938032',
title: 'Vim 8文本处理实战',
cover: 'https://qiniu.aiyxlib.com/1606178450151'
},
{
isbn: '9787536692930',
title: 'Oracle从入门到精通',
cover: 'https://qiniu.aiyxlib.com/1606123986028'
}
];
this.isLoading = false;
}, 1200);
async getRecommendBooks() {
try {
const res = await FetchInitScreenBookRecommend({ libcode: '1201' });
this.recommendedBooks = res.data || [];
console.log('图书推荐', this.recommendedBooks);
this.isLoading = false
} catch (err) {
console.error('获取图书推荐失败:', err);
this.isLoading = false
}
},
goToBookDetail(item) {
console.log('item',item)
uni.navigateTo({
url: "/subpkg/pages/book-detail/book-detail?isbn=" + item.isbn
})
},
//
getMoreBoook(){
uni.navigateTo({
url: "/subpkg/pages/book-list/book-list"
})
},
onToSearch() {
uni.switchTab({
url: "/pages/search/search"
});
},
//
loadUser() {
this.token = uni.getStorageSync("token") || ""
this.userInfo = uni.getStorageSync("user-info") || {}
//
toCheckLogin() {
uni.navigateTo({
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"
// });
// }
// });
// },
toCheckLogin(pageName) {
this.loadUser();
if (!this.token) {
uni.getUserProfile({
desc: "绑定读者证",
success: (res) => {
const userInfo = JSON.parse(res.rawData);
uni.setStorageSync("wxUserInfo", userInfo);
uni.setStorageSync("wxSignature", res.signature);
uni.navigateTo({
url: "/pages/login/login"
});
},
fail: () => {
uni.showToast({ title: "授权失败", icon: "error" });
}
});
return
}
},
toRanking(){
uni.navigateTo({
url: "/subpkg/pages/ranking/ranking"
@ -258,32 +371,31 @@ export default {
url: '/subpkg/pages/feedback-list/feedback-list'
});
},
toLibraryCard(){
uni.navigateTo({
url: '/subpkg/pages/reader-card/reader-card'
});
toLibraryCard() {
//
if (this.isBindLibraryCard) {
uni.navigateTo({ url: '/subpkg/pages/reader-card/reader-card' });
}
//
else {
uni.navigateTo({ url: "/pages/login/login" });
}
},
onToScan() {
//
uni.scanCode({
onlyFromCamera: true, //
scanType: ['barCode'], // ISBN
onlyFromCamera: true,
scanType: ['barCode'],
success: (res) => {
uni.showToast({
title: '扫码结果:'+ res.result,
icon: 'none'
})
console.log('扫码结果:', res.result)
// ISBN
let isbn = res.result || ''
// ===== ISBN =====
if (!isbn || isbn.length < 10) {
isbn = '9787020167319' //
isbn = '9787020167319'
}
//
uni.navigateTo({
url: '/subpkg/pages/book-detail/book-detail?isbn=' + isbn
})
@ -316,7 +428,7 @@ export default {
.status-cards {
display: flex;
background-color: $uni-white;
background-color: #fff;
margin: 10px;
border-radius: 8px;
padding: 20px 10px;
@ -350,7 +462,7 @@ export default {
}
.status-label {
font-size: 12px;
color: $uni-main-color;
color: #333;
}
}
@ -365,13 +477,14 @@ swiper.banner-swiper image{
swiper.menu-swiper{
width:100%;
margin-top: 10px;
background-color: $uni-white;
background-color: #fff;
}
.menu-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
.menu-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
@ -387,7 +500,7 @@ swiper.menu-swiper{
}
.menu-label {
font-size: 12px;
color: $uni-main-color;
color: #333;
text-align: center;
}
}
@ -415,7 +528,7 @@ swiper.menu-swiper{
}
.card-tip {
font-size: 12px;
color: $uni-secondary-color;
color: #999;
margin: 5px 0;
}
.bind-btn {
@ -429,7 +542,7 @@ swiper.menu-swiper{
border-radius: 28px;
background: linear-gradient(140deg, #01a4ff, #2ec8fe);
font-size: 14px;
color: $uni-white;
color: #fff;
line-height: 28px;
}
}
@ -457,10 +570,120 @@ swiper.menu-swiper{
flex-direction: row;
justify-content: flex-start;
align-items: center;
color: $uni-base-color;
color: #999;
font-size: 11px;
}
}
}
.library-card-has {
width: 100%;
padding: 20px 10px;
box-sizing: border-box;
.section-title {
font-size: 22px;
font-weight: bold;
background: linear-gradient(140deg, #01a4ff, #2ec8fe);
-webkit-background-clip: text;
color: transparent;
letter-spacing: 0.1em;
margin-bottom: 10px;
padding-left: 5px;
}
.card-list {
width: 100%;
}
// .card-item {
// position: relative;
// background: #fff;
// border-radius: 10px;
// padding: 15px;
// margin-bottom: 10px;
// box-shadow: 0 1px 6px rgba(0,0,0,0.06);
// .item-row {
// display: flex;
// margin-bottom: 8px;
// font-size: 13px;
// .label {
// color: #666;
// width: 85px;
// }
// .value {
// flex: 1;
// color: #333;
// }
// }
// .default-tag {
// position: absolute;
// right: 12px;
// top: 12px;
// font-size: 11px;
// color: #01a4fe;
// border: 1px solid #01a4fe;
// border-radius: 4px;
// padding: 2px 6px;
// }
// }
}
.card-swiper {
height: 106px; /* 固定高度,保证滑动流畅 */
.card-item{
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
border: 2px solid #C6C6E2;
border-radius: 8px;
background: rgba(241,241,249,0.4);
cursor: pointer;
&.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;
}
}
.default-tag {
position: absolute;
right: 12px;
top: 12px;
font-size: 11px;
color: #01a4fe;
border: 1px solid #01a4fe;
border-radius: 4px;
padding: 2px 6px;
}
}
}
</style>

324
pages/login/login copy 2.vue

@ -0,0 +1,324 @@
<template>
<view style="background-color: #fff; height: calc(100vh);">
<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 class="form-box">
<view class="item">
<uni-icons class="form-icon" type="person" size="24"></uni-icons>
<view class="uni-input-wrapper">
<input
class="input"
type="nickname"
v-model="nickName"
placeholder="请输入昵称"
@input="handleInput('nickName')"
/>
<uni-icons
class="clear-icon"
v-if="clearIconStatus.nickName"
@click="clearInput('nickName')"
type="close"
size="20"
></uni-icons>
</view>
</view>
<view class="item">
<uni-icons class="form-icon" custom-prefix="iconfont" type="icon-duzhezheng" size="24"></uni-icons>
<view class="uni-input-wrapper">
<input
class="input"
placeholder="请输入读者证号"
v-model="queryvalue"
@input="handleInput('queryvalue')"
/>
<uni-icons
class="clear-icon"
v-if="clearIconStatus.queryvalue"
@click="clearInput('queryvalue')"
type="close"
size="20"
></uni-icons>
</view>
</view>
<view class="item">
<uni-icons class="form-icon" type="locked" size="24"></uni-icons>
<input class="input" placeholder="请输入密码" :password="!showPwd" v-model="rdpasswd" />
<uni-icons class="form-right-icon" :type="showPwd ? 'eye-slash' : 'eye'" size="20"
@click="togglePwd"></uni-icons>
</view>
<button class="login-btn" type="primary" @click="submit">绑定</button>
</view>
<view class="tips">
温馨提示<br />
1密码默认为 <text style="color:#e74c3c">身份证后6位</text>如果身份证号最后一位为XX需要大写;
</view>
</view>
</template>
<script>
import { FetchInitScreenSetting, FetchReaderList } from '@/api/user';
const TOKEN_KEY = 'token';
const USER_KEY = 'user-info';
export default {
data() {
return {
queryvalue: '',
rdpasswd: '',
showPwd: false,
screenConfig: {},
avatarUrl: '',
nickName: '',
//
clearIconStatus: {
nickName: false,
queryvalue: false
}
};
},
onLoad() {
this.getScreenSetting();
},
methods: {
//
onChooseAvatar(e) {
console.log('获取微信头像',e)
this.avatarUrl = e.detail.avatarUrl;
},
//
handleInput(field) {
this.clearIconStatus[field] = this[field].trim().length > 0
},
//
clearInput(field) {
this[field] = ''
this.clearIconStatus[field] = false
},
//
togglePwd() {
this.showPwd = !this.showPwd;
},
async getScreenSetting() {
try {
const res = await FetchInitScreenSetting({ libcode: '1201' });
const data = res.data;
this.screenConfig = {
thirdUrl: data.open_lib_http?.context || '',
thirdAppid: data.open_lib_appId?.context || '',
thirdSecret: data.open_lib_secret?.context || '',
sm4Key: data.sm4_key?.context || ''
};
} catch (err) {
console.error('获取配置失败:', err);
}
},
async submit() {
//
this.nickName = this.nickName.trim()
this.queryvalue = this.queryvalue.trim()
if (!this.queryvalue || !this.rdpasswd) {
uni.showToast({ title: '请输入读者证号和密码', icon: 'none' });
return;
}
uni.showLoading({ title: '绑定中...' });
try {
const params = {
...this.screenConfig,
selecttype: 'rdid',
queryvalue: this.queryvalue,
rdpasswd: this.rdpasswd,
};
// {"code":200,"message":"","data":"{\"messagelist\":[{\"code\":\"R00138\",\"message\":\"\"}],\"success\":false}","timestamp":1778154499544}
// {"code":200,"message":"","data":"{\"success\":true,\"pagedata\":[{\"rdClusterCode\":null,\"rdlib\":\"GD\",\"rdid\":\"420105198509200438\",\"rdcfstate\":1}]}","timestamp":1778154647854}
// {"code":200,"message":"","data":"{\"messageList\":[{\"R00131\":\"\"}],\"success\":true,\"pagedata\":\"\"}","timestamp":1778155520501}
const res = await FetchReaderList(params);
let result = {};
try {
result = JSON.parse(res.data);
} catch (e) {
uni.hideLoading();
uni.showToast({ title: '数据解析失败', icon: 'none' });
return;
}
//
let errMsg = '';
if (result.messagelist?.length) {
const item = result.messagelist[0];
errMsg = item.message || Object.values(item)[0] || '认证失败';
}
if (result.messageList?.length) {
const item = result.messageList[0];
errMsg = item.message || Object.values(item)[0] || '认证失败';
}
//
const realSuccess = result.success === true && result.pagedata?.length > 0;
if (realSuccess) {
const loginRes = {
token: 'reader-token-' + Date.now(),
user: {
nickName: this.nickName || '小图',
avatarUrl: this.avatarUrl,
cardNo: this.queryvalue
}
};
// uni.setStorageSync(TOKEN_KEY, loginRes.token);
// uni.setStorageSync(USER_KEY, loginRes.user);
// uni.hideLoading();
// uni.showToast({ title: '', icon: 'success' });
const openId = uni.getStorageSync("wx_login_code");
const bindParams = {
...this.screenConfig,
openid: openId,
bindValue: this.queryvalue,
bindType: 'rdid',
libcode: '1201',
}
const bindRes = await FetchBindReadCard(params);
setTimeout(() => {
uni.navigateBack();
}, 1500);
} else {
uni.hideLoading();
uni.showToast({
title: errMsg || '读者证或密码错误',
icon: 'none'
});
}
} catch (err) {
uni.hideLoading();
uni.showToast({ title: '网络异常', icon: 'none' });
}
}
}
};
</script>
<style lang="scss" scoped>
.user-info-section {
display: flex;
flex-direction: column;
align-items: center;
padding: 30px 0 0 0;
.avatar-btn {
background: transparent;
display: flex;
flex-direction: column;
align-items: center;
&::after{
border: none !important;
}
.avatar-img {
width: 60px;
height: 60px;
border-radius: 50%;
}
.tip-text {
font-size: 12px;
color: #999;
}
}
}
.form-box {
padding: 20px 15px;
.item {
width: 100%;
min-height: 44px;
border-radius: 22px;
background-color: #f7f7f7;
display: flex;
align-items: center;
margin-bottom: 15px;
.input {
flex: 1;
padding: 10px;
font-size: 14px;
}
}
.uni-input-wrapper{
flex: 1;
display: flex;
align-items: center;
.input {
flex: 1;
padding: 10px;
font-size: 14px;
}
.clear-icon{
padding: 0 12px;
color: #ccc;
}
}
}
.login-btn {
margin-top: 10px;
background-color: #01a4fe !important;
border-radius: 22px;
font-size: 16px;
height: 44px;
line-height: 44px;
}
.tips {
margin: 30px 20px;
font-size: 12px;
color: #333;
line-height: 20px;
}
.form-icon {
::v-deep .uni-icons {
margin-left: 10px;
color: #01a4fe !important;
}
}
.form-right-icon {
::v-deep .uni-icons {
margin-right: 10px;
}
}
</style>

252
pages/login/login copy.vue

@ -0,0 +1,252 @@
<template>
<view style="background-color: #fff; height: calc(100vh);">
<view class="top-bar">
<image class="top-bar-bg" src="@/static/images/mingqi-beij@2x.png" mode="aspectFill"></image>
<view class="library-info">
<image class="avatar" src="@/static/images/avatar.png" mode="aspectFill"></image>
<view class="library-name">葛店经济技术开发区图书馆</view>
</view>
</view>
<view class="form-box">
<view class="item">
<uni-icons class="form-icon" type="person" size="24"></uni-icons>
<input class="input" placeholder="请输入读者证号" v-model="queryvalue" />
</view>
<view class="item">
<uni-icons class="form-icon" type="locked" size="24"></uni-icons>
<input class="input" placeholder="请输入密码" :password="!showPwd" v-model="rdpasswd" />
<uni-icons class="form-right-icon" :type="showPwd ? 'eye-slash' : 'eye'" size="20"
@click="togglePwd"></uni-icons>
</view>
<button class="login-btn" type="primary" @click="submit">绑定</button>
</view>
<view class="tips">
温馨提示<br />
1密码默认为 <text style="color:#e74c3c">身份证后6位</text>如果身份证号最后一位为XX需要大写;
</view>
</view>
</template>
<script>
import { FetchInitScreenSetting, FetchReaderList } from '@/api/user';
const TOKEN_KEY = 'token';
const USER_KEY = 'user-info';
export default {
data() {
return {
queryvalue: '',
rdpasswd: '',
showPwd: false,
screenConfig: {}
};
},
onLoad() {
this.getScreenSetting();
},
methods: {
//
togglePwd() {
this.showPwd = !this.showPwd;
},
// 1:
async getScreenSetting() {
try {
const res = await FetchInitScreenSetting({ libcode: '1201' });
const data = res.data;
// 4
this.screenConfig = {
thirdUrl: data.open_lib_http?.context || '',
thirdAppid: data.open_lib_appId?.context || '',
thirdSecret: data.open_lib_secret?.context || '',
sm4Key: data.sm4_key?.context || ''
};
console.log('已获取第三方配置:', this.screenConfig);
} catch (err) {
console.error('获取配置失败:', err);
}
},
// {"code":200,"message":"","data":"{\"messagelist\":[{\"code\":\"R00138\",\"message\":\"\"}],\"success\":false}","timestamp":1778154499544}
// {"code":200,"message":"","data":"{\"success\":true,\"pagedata\":[{\"rdClusterCode\":null,\"rdlib\":\"GD\",\"rdid\":\"420105198509200438\",\"rdcfstate\":1}]}","timestamp":1778154647854}
// {"code":200,"message":"","data":"{\"messageList\":[{\"R00131\":\"\"}],\"success\":true,\"pagedata\":\"\"}","timestamp":1778155520501}
// 2
async submit() {
if (!this.queryvalue || !this.rdpasswd) {
uni.showToast({ title: '请输入读者证号和密码', icon: 'none' });
return;
}
if (!this.screenConfig.thirdUrl) {
uni.showToast({ title: '图书馆配置加载中,请稍候重试', icon: 'none' });
return;
}
uni.showLoading({ title: '绑定中...' });
try {
const params = {
...this.screenConfig,
selecttype: 'rdid',
queryvalue: this.queryvalue,
rdpasswd: this.rdpasswd,
havecluster: ''
};
const res = await FetchReaderList(params);
// 1. JSON
let result = {};
try {
result = JSON.parse(res.data);
} catch (e) {
uni.hideLoading();
uni.showToast({ title: '数据解析失败', icon: 'none' });
return;
}
// 2.
let errMsg = '';
// messagelist
if (result.messagelist && result.messagelist.length > 0) {
const item = result.messagelist[0];
errMsg = item.message || Object.values(item)[0] || '绑定失败';
}
// messageList
if (result.messageList && result.messageList.length > 0) {
const item = result.messageList[0];
errMsg = item.message || Object.values(item)[0] || '绑定失败';
}
// 3. success=true pagedata
const realSuccess = result.success === true && result.pagedata && result.pagedata.length > 0;
if (realSuccess) {
const wxUser = uni.getStorageSync('wxUserInfo') || {};
const loginRes = {
token: 'reader-token-' + Date.now(),
user: {
nickName: wxUser.nickName || '读者',
avatarUrl: wxUser.avatarUrl || '',
cardNo: this.queryvalue
}
};
uni.setStorageSync('token', loginRes.token);
uni.setStorageSync('user-info', loginRes.user);
uni.hideLoading();
uni.showToast({ title: '绑定成功', icon: 'success' });
setTimeout(() => {
uni.navigateBack();
}, 1500);
} else {
uni.hideLoading();
uni.showToast({
title: errMsg || '读者证或密码错误',
icon: 'none'
});
}
} catch (err) {
uni.hideLoading();
console.error('绑定异常:', err);
uni.showToast({ title: '网络异常,请稍后重试', icon: 'none' });
}
}
}
};
</script>
<style lang="scss" scoped>
.top-bar {
position: relative;
width: 100%;
height: 220rpx;
.top-bar-bg {
position: absolute;
width: 100%;
height: 100%;
}
.library-info {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
padding-top: 30rpx;
.avatar {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
}
.library-name {
margin-top: 10rpx;
color: #fff;
font-size: 30rpx;
}
}
}
.form-box {
padding: 40rpx 30rpx;
.item {
width: 100%;
min-height: 80rpx;
border-radius: 40rpx;
background-color: #f7f7f7;
display: flex;
align-items: center;
margin-bottom: 30rpx;
.input {
flex: 1;
padding: 20rpx 20rpx;
font-size: 28rpx;
}
}
}
.login-btn {
margin-top: 20rpx;
background-color: #01a4fe !important;
border-radius: 40rpx;
font-size: 30rpx;
}
.tips {
margin: 60rpx 40rpx;
font-size: 24rpx;
color: #333;
line-height: 40rpx;
}
.form-icon {
::v-deep .uni-icons {
margin-left: 20rpx;
color: #01a4fe !important;
}
}
.form-right-icon {
::v-deep .uni-icons {
margin-right: 20rpx;
}
}
</style>

297
pages/login/login-no-clear.vue

@ -0,0 +1,297 @@
<template>
<view style="background-color: #fff; height: calc(100vh);">
<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 class="form-box">
<view class="item">
<uni-icons class="form-icon" type="person" size="24"></uni-icons>
<view class="uni-input-wrapper">
<input class="input" type="nickname" v-model="nickName" @blur="onNicknameBlur" placeholder="请输入昵称" @input="clearInput" />
<uni-icons class="clear-icon" v-if="showClearIcon" @click="clearIcon" type="close" size="20"></uni-icons>
</view>
</view>
<view class="item">
<uni-icons class="form-icon" custom-prefix="iconfont" type="icon-duzhezheng" size="24"></uni-icons>
<view class="uni-input-wrapper">
<input class="input" placeholder="请输入读者证号" v-model="queryvalue" @input="clearInput" />
<uni-icons class="clear-icon" v-if="showClearIcon" @click="clearIcon" type="close" size="20"></uni-icons>
</view>
</view>
<view class="item">
<uni-icons class="form-icon" type="locked" size="24"></uni-icons>
<input class="input" placeholder="请输入密码" :password="!showPwd" v-model="rdpasswd" />
<uni-icons class="form-right-icon" :type="showPwd ? 'eye-slash' : 'eye'" size="20"
@click="togglePwd"></uni-icons>
</view>
<button class="login-btn" type="primary" @click="submit">绑定</button>
</view>
<view class="tips">
温馨提示<br />
1密码默认为 <text style="color:#e74c3c">身份证后6位</text>如果身份证号最后一位为XX需要大写;
</view>
</view>
</template>
<script>
import { FetchInitScreenSetting, FetchReaderList } from '@/api/user';
const TOKEN_KEY = 'token';
const USER_KEY = 'user-info';
export default {
data() {
return {
queryvalue: '',
rdpasswd: '',
showPwd: false,
screenConfig: {},
avatarUrl: '',
nickName: '',
showClearIcon: false,
};
},
onLoad() {
this.getScreenSetting();
},
methods: {
//
onChooseAvatar(e) {
console.log('获取微信头像',e)
this.avatarUrl = e.detail.avatarUrl;
},
onNicknameBlur(e) {
this.nickName = e.detail.value.trim()
},
clearInput(event) {
this.queryvalue = event.detail.value;
if (event.detail.value.length > 0) {
this.showClearIcon = true;
} else {
this.showClearIcon = false;
}
},
clearIcon() {
this.queryvalue = '';
this.showClearIcon = false;
},
//
togglePwd() {
this.showPwd = !this.showPwd;
},
async getScreenSetting() {
try {
const res = await FetchInitScreenSetting({ libcode: '1201' });
const data = res.data;
this.screenConfig = {
thirdUrl: data.open_lib_http?.context || '',
thirdAppid: data.open_lib_appId?.context || '',
thirdSecret: data.open_lib_secret?.context || '',
sm4Key: data.sm4_key?.context || ''
};
} catch (err) {
console.error('获取配置失败:', err);
}
},
async submit() {
// if (!this.avatarUrl) {
// uni.showToast({ title: '', icon: 'none' });
// return;
// }
// if (!this.nickName) {
// uni.showToast({ title: '', icon: 'none' });
// return;
// }
if (!this.queryvalue || !this.rdpasswd) {
uni.showToast({ title: '请输入读者证号和密码', icon: 'none' });
return;
}
uni.showLoading({ title: '绑定中...' });
try {
const params = {
...this.screenConfig,
selecttype: 'rdid',
queryvalue: this.queryvalue,
rdpasswd: this.rdpasswd,
};
const res = await FetchReaderList(params);
let result = {};
try {
result = JSON.parse(res.data);
} catch (e) {
uni.hideLoading();
uni.showToast({ title: '数据解析失败', icon: 'none' });
return;
}
// 2.
let errMsg = '';
// messagelist
if (result.messagelist && result.messagelist.length > 0) {
const item = result.messagelist[0];
errMsg = item.message || Object.values(item)[0] || '绑定失败';
}
// messageList
if (result.messageList && result.messageList.length > 0) {
const item = result.messageList[0];
errMsg = item.message || Object.values(item)[0] || '绑定失败';
}
// 3. success=true pagedata
const realSuccess = result.success === true && result.pagedata && result.pagedata.length > 0;
console.log('this.avatarUrl',this.avatarUrl)
if (realSuccess) {
const loginRes = {
token: 'reader-token-' + Date.now(),
user: {
nickName: this.nickName || '小图',
avatarUrl: this.avatarUrl,
cardNo: this.queryvalue
}
};
uni.setStorageSync(TOKEN_KEY, loginRes.token);
uni.setStorageSync(USER_KEY, loginRes.user);
uni.hideLoading();
uni.showToast({ title: '绑定成功', icon: 'success' });
setTimeout(() => {
uni.navigateBack();
}, 1500);
} else {
uni.hideLoading();
uni.showToast({
title: errMsg || '读者证或密码错误',
icon: 'none'
});
}
} catch (err) {
uni.hideLoading();
uni.showToast({ title: '网络异常', icon: 'none' });
}
}
}
};
</script>
<style lang="scss" scoped>
.user-info-section {
display: flex;
flex-direction: column;
align-items: center;
padding: 30px 0 0 0;
.avatar-btn {
background: transparent;
display: flex;
flex-direction: column;
align-items: center;
&::after{
border: none !important;
}
.avatar-img {
width: 60px;
height: 60px;
border-radius: 50%;
}
.tip-text {
font-size: 12px;
color: #999;
}
}
// .nickname-box {
// width: 80%;
// margin-top: 10px;
// .nickname-input {
// width: 100%;
// padding: 10px 0;
// border-bottom: 1px solid #eee;
// text-align: center;
// font-size: 14px;
// }
// }
}
.form-box {
padding: 20px 15px;
.item {
width: 100%;
min-height: 40px;
border-radius: 20px;
background-color: #f7f7f7;
display: flex;
align-items: center;
margin-bottom: 15px;
.input {
flex: 1;
padding: 10px;
font-size: 14px;
}
}
.uni-input-wrapper{
flex: 1;
display: flex;
align-items: center;
.input {
flex: 1;
}
.clear-icon{
padding: 0 10px;
}
}
}
.login-btn {
margin-top: 10px;
background-color: #01a4fe !important;
border-radius: 20px;
font-size: 16px;
}
.tips {
margin: 30px 20px;
font-size: 12px;
color: #333;
line-height: 20px;
}
.form-icon {
::v-deep .uni-icons {
margin-left: 10px;
color: #01a4fe !important;
}
}
.form-right-icon {
::v-deep .uni-icons {
margin-right: 10px;
}
}
</style>

269
pages/login/login-pay.vue

@ -0,0 +1,269 @@
<template>
<view style="background-color: #fff; height: calc(100vh);">
<view class="top-bar">
<image class="top-bar-bg" src="@/static/images/mingqi-beij@2x.png" mode="aspectFill"></image>
<view class="library-info">
<image class="avatar" src="@/static/images/avatar.png" mode="aspectFill"></image>
<view class="library-name">葛店经济技术开发区图书馆</view>
</view>
</view>
<!-- 支付分状态展示 -->
<view class="pay-score-box" v-if="payScore">
<view class="score-item">
<uni-icons type="info" size="24" color="#01a4fe"></uni-icons>
<view class="score-text">
微信支付分<text style="color:#e74c3c; font-size:16px; font-weight:bold;">{{ payScore }}</text>
</view>
</view>
<view class="score-desc" :style="{color: payScore >= 550 ? '#07c160' : '#e74c3c'}">
{{ payScore >= 550 ? '✅ 符合办证条件(≥550分)' : '❌ 支付分不足,暂无法办证' }}
</view>
</view>
<!-- 未获取支付分时显示授权按钮 -->
<view class="auth-box" v-else>
<button class="auth-btn" @click="getPayScore">
授权查询微信支付分办证必备
</button>
</view>
<!-- 表单只有支付分达标才显示 -->
<view class="form-box" v-if="payScore && payScore >= 550">
<view class="item">
<uni-icons class="form-icon" type="person" size="24"></uni-icons>
<input class="input" placeholder="请输入读者证号" v-model="cardNo" />
</view>
<view class="item">
<uni-icons class="form-icon" type="locked" size="24"></uni-icons>
<input class="input" placeholder="请输入密码" :password="!showPwd" v-model="password" />
<uni-icons class="form-right-icon" :type="showPwd ? 'eye-slash' : 'eye'" size="20" @click="togglePwd"></uni-icons>
</view>
<button class="login-btn" type="primary" @click="submit">绑定</button>
</view>
<view class="tips">
温馨提示<br />
1密码默认为<text style="color:#e74c3c">身份证后6位</text>X大写<br />
2微信支付分550分方可办理读者证
</view>
</view>
</template>
<script>
const TOKEN_KEY = 'token';
const USER_KEY = 'user-info';
export default {
data() {
return {
cardNo: '',
password: '',
showPwd: false,
payScore: null, //
serviceId: '你的支付分service_id' //
}
},
onLoad() {
//
// this.getPayScore()
},
methods: {
togglePwd() {
this.showPwd = !this.showPwd
},
// 1.
async getPayScore() {
const _this = this
uni.showLoading({ title: '获取支付分中...' })
// 1)
uni.request({
url: 'https://你的后端.com/api/pay-score/auth',
method: 'POST',
data: {
openid: uni.getStorageSync('wxSignature') || '', // openid
service_id: this.serviceId
},
success: (res) => {
if (res.data.code !== 200) {
uni.showToast({ title: res.data.msg || '获取失败', icon: 'none' })
return
}
const { package: packageStr, out_order_no } = res.data.data
// 2) API
uni.requestPayment({
provider: 'wxpay',
type: 'payScore',
timeStamp: String(Date.now()),
package: packageStr,
//
signType: 'HMAC-SHA256',
paySign: res.data.data.paySign,
nonceStr: res.data.data.nonceStr,
success: () => {
// 3)
_this.queryPayScore(out_order_no)
},
fail: (err) => {
console.log('支付分授权失败', err)
uni.showToast({ title: '授权取消或失败', icon: 'none' })
},
complete: () => {
uni.hideLoading()
}
})
},
fail: () => {
uni.hideLoading()
uni.showToast({ title: '网络异常', icon: 'none' })
}
})
},
// 2.
async queryPayScore(outOrderNo) {
uni.showLoading({ title: '查询分数...' })
uni.request({
url: 'https://你的后端.com/api/pay-score/query',
method: 'POST',
data: { out_order_no: outOrderNo },
success: (res) => {
uni.hideLoading()
if (res.data.code === 200) {
this.payScore = res.data.data.score // 680
} else {
uni.showToast({ title: '查询失败', icon: 'none' })
}
},
fail: () => {
uni.hideLoading()
uni.showToast({ title: '查询失败', icon: 'none' })
}
})
},
// 3.
async submit() {
//
if (!this.payScore || this.payScore < 550) {
uni.showToast({ title: '支付分不足550,无法办证', icon: 'none' })
return
}
if (!this.cardNo || !this.password) {
uni.showToast({ title: '请输入读者证号和密码', icon: 'none' })
return
}
//
uni.showLoading({ title: '绑定中...' })
setTimeout(() => {
const res = {
token: 'login-token-' + Date.now(),
user: {
nickName: '读者',
cardNo: this.cardNo,
payScore: this.payScore //
}
}
uni.setStorageSync(TOKEN_KEY, res.token)
uni.setStorageSync(USER_KEY, res.user)
uni.hideLoading()
uni.showToast({ title: '绑定成功', icon: 'success' })
uni.navigateBack()
}, 800)
}
}
}
</script>
<style lang="scss" scoped>
.page {
padding: 40px 20px;
}
.form-box {
padding: 20px;
.item {
width: 100%;
min-height: 42px;
border-radius: 23px;
background-color: #f7f7f7;
border: 1px solid #f4f4f4;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
margin-bottom: 20px;
overflow: hidden;
.t-right-icon{
margin-right: 15px;
margin-left: 0;
}
.input {
flex: 1;
border-radius: 8px;
padding: 12px 15px;
font-size: 13px;
}
}
}
.login-btn {
margin-top: 20px;
background-color: #01a4fe;
border-radius: 23px;
}
.tips {
margin: 50px 30px;
font-size: 11px;
color: #000;
line-height: 22px;
}
.form-icon {
::v-deep .uni-icons{
margin-left: 10px;
color: #01a4fe !important;
}
}
.form-right-icon{
::v-deep .uni-icons{
margin-right: 10px;
}
}
/* 新增支付分样式 */
.pay-score-box {
padding: 20px;
margin: 10px 20px;
background: #f7f9ff;
border-radius: 12px;
}
.score-item {
display: flex;
align-items: center;
margin-bottom: 8px;
}
.score-text {
margin-left: 10px;
font-size: 15px;
}
.score-desc {
font-size: 13px;
padding-left: 34px;
}
.auth-box {
padding: 40px 20px;
text-align: center;
}
.auth-btn {
background: #01a4fe;
color: #fff;
border-radius: 23px;
padding: 12px 30px;
border: none;
}
</style>

409
pages/login/login.vue

@ -1,142 +1,395 @@
<template>
<view style="background-color: #fff; height: calc(100vh);">
<view class="top-bar">
<image class="top-bar-bg" src="@/static/images/mingqi-beij@2x.png" mode="aspectFill"></image>
<view class="library-info">
<view class="top-bar">
<image class="top-bar-bg" src="@/static/images/mingqi-beij@2x.png" mode="aspectFill"></image>
<view class="library-info">
<image class="avatar" src="@/static/images/avatar.png" mode="aspectFill"></image>
<view class="library-name">葛店经济技术开发区图书馆</view>
</view>
</view>
</view>
<!-- <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 class="form-box">
<!-- <view class="item">
<uni-icons class="form-icon" type="person" size="24"></uni-icons>
<view class="uni-input-wrapper">
<input
class="input"
type="nickname"
v-model="nickName"
placeholder="请输入昵称"
@input="handleInput('nickName')"
/>
<uni-icons
class="clear-icon"
v-if="clearIconStatus.nickName"
@click="clearInput('nickName')"
type="close"
size="20"
></uni-icons>
</view>
</view> -->
<view class="item">
<uni-icons class="form-icon" type="person" size="24" ></uni-icons>
<input class="input" placeholder="请输入读者证号" v-model="cardNo" />
<uni-icons class="form-icon" custom-prefix="iconfont" type="icon-duzhezheng" size="24"></uni-icons>
<view class="uni-input-wrapper">
<input
class="input"
placeholder="请输入读者证号"
v-model="queryvalue"
@input="handleInput('queryvalue')"
/>
<uni-icons
class="clear-icon"
v-if="clearIconStatus.queryvalue"
@click="clearInput('queryvalue')"
type="close"
size="20"
></uni-icons>
</view>
</view>
<view class="item">
<uni-icons class="form-icon" type="locked" size="24" ></uni-icons>
<input class="input" placeholder="请输入密码" :password="!showPwd" v-model="password" />
<uni-icons class="form-right-icon" :type="showPwd ? 'eye-slash' : 'eye'" size="20" @click="togglePwd"></uni-icons>
<uni-icons class="form-icon" type="locked" size="24"></uni-icons>
<input class="input" placeholder="请输入密码" :password="!showPwd" v-model="rdpasswd" />
<uni-icons class="form-right-icon" :type="showPwd ? 'eye-slash' : 'eye'" size="20"
@click="togglePwd"></uni-icons>
</view>
<button class="login-btn" type="primary" @click="submit">绑定</button>
</view>
<view class="tips">
温馨提示<br /> 1密码默认为<text style="color:#e74c3c">身份证后6位</text>如果身份证号最后一位为XX需要大写;
温馨提示<br />
1密码默认为 <text style="color:#e74c3c">身份证后6位</text>如果身份证号最后一位为XX需要大写;
</view>
</view>
</template>
<script>
const TOKEN_KEY = 'token';
const USER_KEY = 'user-info';
//
import { FetchInitScreenSetting, FetchReaderList, FetchBindReadCard,FetchFindAllReaderBindByOpenId } from '@/api/user';
import config from '@/utils/config';
const READLIST = 'reader-card-list';
// const USER_KEY = 'user-info';
export default {
data() {
return {
cardNo: '',
password: '',
showPwd: false //
}
queryvalue: '',
rdpasswd: '',
showPwd: false,
screenConfig: {},
avatarUrl: '',
nickName: '',
//
clearIconStatus: {
nickName: false,
queryvalue: false
}
};
},
onLoad() {
this.getScreenSetting();
},
methods: {
//
// +
onChooseAvatar(e) {
console.log('获取微信头像', e)
//
const tempFilePath = e.detail.avatarUrl;
//
uni.uploadFile({
url: config.baseUrl +'/api/fileRelevant/uploadWxAvatarImg', //
filePath: tempFilePath,
name: 'file', //
header: {
"Content-Type": "multipart/form-data"
},
success: (res) => {
console.log("上传成功原始返回:", res);
let realAvatar = '';
try {
const data = JSON.parse(res.data);
console.log('解析成功:', data)
realAvatar = data.data || data.url || ''; //
} catch (e) {
realAvatar = res.data; // URL
}
if (realAvatar) {
console.log("永久头像URL:", realAvatar);
this.avatarUrl = config.baseUrl + '/api/fileRelevant/getImg?imgType=5&imgId=' + realAvatar
} else {
uni.showToast({ title: '头像上传失败', icon: 'none' });
}
},
fail: (err) => {
console.log("上传失败", err);
uni.showToast({ title: '头像上传失败', icon: 'none' });
}
});
},
//
handleInput(field) {
this.clearIconStatus[field] = this[field].trim().length > 0
},
//
clearInput(field) {
this[field] = ''
this.clearIconStatus[field] = false
},
//
togglePwd() {
this.showPwd = !this.showPwd
this.showPwd = !this.showPwd;
},
async getScreenSetting() {
try {
const res = await FetchInitScreenSetting({ libcode: '1201' });
const data = res.data;
this.screenConfig = {
thirdUrl: data.open_lib_http?.context || '',
thirdAppid: data.open_lib_appId?.context || '',
thirdSecret: data.open_lib_secret?.context || '',
sm4Key: data.sm4_key?.context || ''
};
} catch (err) {
console.error('获取配置失败:', err);
}
},
async submit() {
if (!this.cardNo || !this.password) {
uni.showToast({ title: '请输入读者证号和密码', icon: 'none' })
return
//
this.nickName = this.nickName.trim()
this.queryvalue = this.queryvalue.trim()
if (!this.queryvalue || !this.rdpasswd) {
uni.showToast({ title: '请输入读者证号和密码', icon: 'none' });
return;
}
uni.showLoading({ title: '绑定中...' });
console.log('this.cardNo',this.cardNo)
console.log('this.password',this.password)
//
const wxUser = uni.getStorageSync('wxUserInfo') || {}
console.log('wxUser',wxUser)
const wxSign = uni.getStorageSync('wxSignature') || 'mock-openid'
console.log('wxSign',wxSign)
uni.showLoading({ title: '登录中...' })
// /sys/login
setTimeout(() => {
//
const res = {
token: 'login-token-' + Date.now(),
user: {
nickName: wxUser.nickName || '读者',
avatarUrl: wxUser.avatarUrl || '',
cardNo: this.cardNo
}
try {
const params = {
...this.screenConfig,
selecttype: 'rdid',
queryvalue: this.queryvalue,
rdpasswd: this.rdpasswd,
};
// {"code":200,"message":"","data":"{\"messagelist\":[{\"code\":\"R00138\",\"message\":\"\"}],\"success\":false}","timestamp":1778154499544}
// {"code":200,"message":"","data":"{\"success\":true,\"pagedata\":[{\"rdClusterCode\":null,\"rdlib\":\"GD\",\"rdid\":\"420105198509200438\",\"rdcfstate\":1}]}","timestamp":1778154647854}
// {"code":200,"message":"","data":"{\"messageList\":[{\"R00131\":\"\"}],\"success\":true,\"pagedata\":\"\"}","timestamp":1778155520501}
const res = await FetchReaderList(params);
let result = {};
try {
result = JSON.parse(res.data);
} catch (e) {
uni.hideLoading();
uni.showToast({ title: '数据解析失败', icon: 'none' });
return;
}
//
uni.setStorageSync(TOKEN_KEY, res.token)
uni.setStorageSync(USER_KEY, res.user)
//
let errMsg = '';
if (result.messagelist?.length) {
const item = result.messagelist[0];
errMsg = item.message || Object.values(item)[0] || '认证失败';
}
if (result.messageList?.length) {
const item = result.messageList[0];
errMsg = item.message || Object.values(item)[0] || '认证失败';
}
//
const realSuccess = result.success === true && result.pagedata?.length > 0;
if (realSuccess) {
uni.hideLoading()
uni.showToast({ title: '登录成功', icon: 'success' })
// user
uni.navigateBack()
}, 800)
//
const openId = uni.getStorageSync("wx_login_code");
const bindParams = {
openid: openId,
bindValue: this.queryvalue,
bindType: 'rdid',
libcode: '1201',
}
//
const bindRes = await FetchBindReadCard(bindParams);
console.log('绑定结果', bindRes);
if(bindRes.code === 200 ){
uni.hideLoading();
uni.showToast({
title: bindRes.data || '读者证绑定成功',
icon: 'success'
});
// const loginRes = {
// token: 'reader-token-' + Date.now(),
// user: {
// nickName: this.nickName || '',
// avatarUrl: this.avatarUrl
// }
// };
// uni.setStorageSync(USER_KEY, loginRes.user);
const data = {
libcode: '1201',
openId: openId
}
FetchFindAllReaderBindByOpenId(data).then(res => {
console.log('获取读者证列表',res)
if (res.code === 200 && res.data.length > 0) {
uni.setStorageSync(READLIST, res.data);
} else {
uni.setStorageSync(READLIST, []);
}
})
.catch(err => {
console.error('获取读者证列表失败:', err);
})
//
setTimeout(() => {
uni.navigateBack();
}, 1500);
}else{
//
uni.hideLoading()
uni.showToast({
title: bindResult.message || '绑定失败,请重试',
icon: 'none'
})
}
} else {
uni.hideLoading();
uni.showToast({
title: errMsg || '读者证或密码错误',
icon: 'none'
});
}
} catch (err) {
console.error('绑定流程异常:', err)
uni.hideLoading();
uni.showToast({ title: '网络异常或绑定失败', icon: 'none' });
}
}
}
}
};
</script>
<style lang="scss" scoped>
.page {
padding: 40px 20px;
.user-info-section {
display: flex;
flex-direction: column;
align-items: center;
padding: 30px 0 0 0;
.avatar-btn {
background: transparent;
display: flex;
flex-direction: column;
align-items: center;
&::after{
border: none !important;
}
.avatar-img {
width: 60px;
height: 60px;
border-radius: 50%;
}
.tip-text {
font-size: 12px;
color: #999;
}
}
}
.form-box {
padding: 20px;
padding: 20px 15px;
.item {
width: 100%;
min-height: 42px;
border-radius: 23px;
min-height: 44px;
border-radius: 22px;
background-color: #f7f7f7;
border: 1px solid #f4f4f4;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
margin-bottom: 20px;
overflow: hidden;
.t-right-icon{
margin-right: 15px;
margin-left: 0;
margin-bottom: 15px;
.input {
flex: 1;
padding: 10px;
font-size: 14px;
}
}
.uni-input-wrapper{
flex: 1;
display: flex;
align-items: center;
.input {
flex: 1;
border-radius: 8px;
padding: 12px 15px;
font-size: 13px;
padding: 10px;
font-size: 14px;
}
.clear-icon{
padding: 0 12px;
color: #ccc;
}
}
}
.login-btn {
margin-top: 20px;
background-color: #01a4fe;
border-radius: 23px;
margin-top: 10px;
background-color: #01a4fe !important;
border-radius: 22px;
font-size: 16px;
height: 44px;
line-height: 44px;
}
.tips {
margin: 50px 30px;
font-size: 11px;
color: #000;
line-height: 22px;
margin: 30px 20px;
font-size: 12px;
color: #333;
line-height: 20px;
}
.form-icon {
::v-deep .uni-icons{
::v-deep .uni-icons {
margin-left: 10px;
color: #01a4fe !important;
}
}
.form-right-icon{
::v-deep .uni-icons{
.form-right-icon {
::v-deep .uni-icons {
margin-right: 10px;
}
}

366
pages/user/user.vue

@ -3,196 +3,242 @@
<view class="top-user-bar">
<image class="top-bar-bg" src="@/static/images/mingqi-beij@2x.png" mode="aspectFill"></image>
<view class="user-info">
<image
class="avatar"
:src="userInfo.avatarUrl || '/static/images/default-avatar.png'"
mode="aspectFill"
></image>
<view class="user-info-text">
<text class="user-name">{{ userInfo.nickName || '未登录' }}</text>
<text class="user-card">{{ userInfo.cardNo || '' }}</text>
</view>
</view>
<view class="user-menu">
<view class="menu-item" @click="toCheckLogin('收藏')">
<image class="menu-icon" src="@/static/images/menu-sc.png" mode="scaleToFill" />
<text class="menu-txt">收藏</text>
</view>
<view class="menu-item" @click="toCheckLogin('借阅')">
<image class="menu-icon" src="@/static/images/menu-jy.png" mode="scaleToFill" />
<text class="menu-txt">借阅</text>
</view>
</view>
<!-- 点击选择头像 -->
<button open-type="chooseAvatar" @chooseavatar="onChooseAvatar" class="avatar-btn">
<image v-if="userInfo.avatarUrl" :src="userInfo.avatarUrl" class="avatar-img"></image>
<image v-else src="@/static/images/avatar.png" class="avatar-img"></image>
</button>
<view class="user-info-text">
<text class="user-name">{{ userInfo.nickName || '未登录' }}</text>
<text class="user-card">{{ cardNo || '' }}</text>
</view>
</view>
<view class="user-menu">
<view class="menu-item" @click="toCheckLogin('收藏')">
<image class="menu-icon" src="@/static/images/menu-sc.png" mode="scaleToFill" />
<text class="menu-txt">收藏</text>
</view>
<view class="menu-item" @click="toCheckLogin('借阅')">
<image class="menu-icon" src="@/static/images/menu-jy.png" mode="scaleToFill" />
<text class="menu-txt">借阅</text>
</view>
</view>
</view>
<view class="submenu-box">
<view class="submenu-item" @click="toCheckLogin('我的留言')">
<uni-icons custom-prefix="iconfont" type="icon-liuyan" size="20"></uni-icons>
<text class="left-txt">我的留言</text>
</view>
<view class="submenu-item" @click="toCheckLogin('个人资料')">
<uni-icons custom-prefix="iconfont" type="icon-shezhi" size="20"></uni-icons>
<text class="left-txt">个人资料</text>
</view>
<view class="submenu-item" @click="toCheckLogin('修改密码')">
<uni-icons custom-prefix="iconfont" type="icon-xiugai" size="20"></uni-icons>
<text class="left-txt">修改密码</text>
</view>
<view class="submenu-item" @click="toCheckLogin('挂失读者证')">
<uni-icons custom-prefix="iconfont" type="icon-UIsheji_menjinxitong-28" size="20"></uni-icons>
<text class="left-txt">挂失读者证</text>
</view>
<view v-if="!!isBindLibraryCard" class="submenu-item" @click="toLogOut()">
<uni-icons custom-prefix="iconfont" type="icon-tuichu" size="20"></uni-icons>
<text class="left-txt">退出账号</text>
</view>
</view>
<view class="submenu-box">
<view class="submenu-item" @click="toCheckLogin('我的留言')">
<uni-icons custom-prefix="iconfont" type="icon-liuyan" size="20"></uni-icons>
<text class="left-txt">我的留言</text>
</view>
<view class="submenu-item" @click="toCheckLogin('个人资料')">
<uni-icons custom-prefix="iconfont" type="icon-shezhi" size="20"></uni-icons>
<text class="left-txt">个人资料</text>
</view>
<view class="submenu-item" @click="toCheckLogin('修改密码')">
<uni-icons custom-prefix="iconfont" type="icon-xiugai" size="20"></uni-icons>
<text class="left-txt">修改密码</text>
</view>
<view class="submenu-item" @click="toCheckLogin('解绑读者证')">
<uni-icons custom-prefix="iconfont" type="icon-UIsheji_menjinxitong-28" size="20"></uni-icons>
<text class="left-txt">解绑读者证</text>
</view>
<view v-if="isBindLibraryCard" class="submenu-item" @click="toLogOut()">
<uni-icons custom-prefix="iconfont" type="icon-tuichu" size="20"></uni-icons>
<text class="left-txt">退出账号</text>
</view>
</view>
<view>
<view>
<uni-popup ref="alertDialog" type="dialog">
<uni-popup-dialog
type="info" cancelText="取消" confirmText="确定"
title="提示" content="请您绑定读者证!"
@confirm="dialogConfirm" @close="dialogClose">
</uni-popup-dialog>
</uni-popup-dialog>
</uni-popup>
</view>
</view>
</template>
<script>
import config from '@/utils/config'
import { FetchBindRead, FetchFindAllReaderByOpenId } from '@/api/user';
const USER_KEY = 'user-info';
const READLIST = 'reader-card-list';
export default {
data() {
return {
token: "",
userInfo: {},
isBindLibraryCard: false
};
userInfo: {},
cardNo: "",
isBindLibraryCard: false,
};
},
onLoad() {
// this.loadUser()
this.checkLoginStatus();
this.loadUserInfo();
},
onShow() {
// this.loadUser()
this.checkLoginStatus();
this.loadUserInfo();
},
methods: {
checkLoginStatus() {
this.loadUser();
this.isBindLibraryCard = !!this.token;
},
//
loadUser() {
this.token = uni.getStorageSync("token") || ""
this.userInfo = uni.getStorageSync("user-info") || {}
//
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' });
}
},
//
// +
async bindUserInfo(avatar, nickname) {
const openId = uni.getStorageSync('wx_login_code') || '';
const params = {
avatar,
libcode: "1201",
nickname,
openid: openId
};
// 1.
const res = await FetchBindRead(params);
// 2.
const userInfo = {
nickName: nickname,
avatarUrl: avatar
};
uni.setStorageSync(USER_KEY, userInfo);
// 3.
this.userInfo = userInfo;
},
//
async loadUserInfo() {
try {
const openId = uni.getStorageSync('wx_login_code');
const readerList = uni.getStorageSync(READLIST) || [];
//
if (openId) {
const res = await FetchFindAllReaderByOpenId({
libcode: '1201',
openId: openId
});
if (res.code === 200 && res.data) {
//
this.userInfo = {
nickName: res.data.nickName || res.data.nickname || '',
avatarUrl: res.data.avatarUrl || res.data.avatar || ''
};
uni.setStorageSync(USER_KEY, this.userInfo);
} else {
this.userInfo = uni.getStorageSync(USER_KEY) || {};
}
} else {
this.userInfo = uni.getStorageSync(USER_KEY) || {};
}
// ===================== =====================
//
const defaultCard = readerList.find(item => item.bindDefault === true);
this.cardNo = defaultCard ? defaultCard.bindValue : (readerList[0]?.bindValue || '');
this.isBindLibraryCard = readerList.length > 0;
} catch (err) {
//
const readerList = uni.getStorageSync(READLIST) || [];
this.userInfo = uni.getStorageSync(USER_KEY) || {};
const defaultCard = readerList.find(item => item.bindDefault === true);
this.cardNo = defaultCard ? defaultCard.bindValue : (readerList[0]?.bindValue || '');
this.isBindLibraryCard = readerList.length > 0;
}
},
//
toCheckLogin(pageName) {
this.loadUser() //
if (!this.token) {
//
this.dialogToggle()
return
const readerList = uni.getStorageSync(READLIST) || [];
//
if (readerList.length === 0) {
this.dialogToggle();
return;
}
//
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' });
}
//
// uni.showToast({
// title: `${pageName}`,
// icon: "none"
// })
//
// uni.navigateTo({
// url: `/pages/${pageName}/${pageName}`
// })
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'
});
}
},
//
dialogToggle() {
this.$refs.alertDialog.open();
},
//
dialogConfirm() {
uni.getUserProfile({
desc: "绑定读者证",
success: (res) => {
const userInfo = JSON.parse(res.rawData);
uni.setStorageSync("wxUserInfo", userInfo);
uni.setStorageSync("wxSignature", res.signature);
//
uni.navigateTo({
url: "/pages/login/login"
});
},
fail: () => {
uni.showToast({ title: "授权失败", icon: "error" });
}
});
uni.navigateTo({ url: "/pages/login/login" });
},
dialogClose() {
console.log('取消')
},
toLogOut() {
// 退
uni.showModal({
title: '确认退出',
content: '确定要退出当前账号吗?',
success: (res) => {
if (res.confirm) {
// 1.
uni.removeStorageSync("token");
uni.removeStorageSync("user-info");
uni.removeStorageSync("wxUserInfo");
uni.removeStorageSync("wxSignature");
dialogClose() {},
// 2.
this.token = "";
this.userInfo = {};
this.isBindLibraryCard = false;
// 退
toLogOut() {
uni.showModal({
title: '确认退出',
content: '确定要退出当前账号吗?',
success: (res) => {
if (res.confirm) {
//
uni.removeStorageSync(USER_KEY);
uni.removeStorageSync(READLIST);
// 3.
uni.showToast({
title: '退出成功',
icon: 'success'
});
//
this.userInfo = {};
this.cardNo = "";
this.isBindLibraryCard = false;
//
uni.switchTab({
url: "/pages/home/home"
});
//
// uni.navigateTo({
// url: "/pages/login/login"
// });
}
}
});
},
uni.showToast({ title: '退出成功', icon: 'success' });
uni.switchTab({ url: "/pages/home/home" });
}
}
});
},
}
}
</script>
@ -221,12 +267,16 @@ export default {
z-index: 99;
display: flex;
justify-content: flex-start;
.avatar{
width: 62px;
height: 62px;
border-radius: 31px;
.avatar-btn {
background: transparent;
margin-top: 19px;
margin-left: 28px;
&::after{ border: none !important; }
.avatar-img {
width: 62px;
height: 62px;
border-radius: 50%;
}
}
.user-info-text{
display: flex;
@ -280,8 +330,6 @@ export default {
}
}
}
.submenu-box{
margin-top: 80px;
background-color: #fff;

2
store/modules/user.js

@ -99,7 +99,7 @@ export default {
const { cancel, confirm } = res;
if (confirm) {
uni.navigateTo({
url: '/subpkg/pages/login-page/login-page'
url: '/pages/login/login'
});
}
return false;

11
subpkg/pages/book-detail/book-detail.vue

@ -68,7 +68,7 @@
</view>
<view class="detail-bottom">
<view class="detail-left">
<!-- <view class="detail-left"> -->
<!-- #ifdef MP-WEIXIN -->
<button open-type="share" class="handle-btn">
<uni-icons custom-prefix="iconfont" type="icon-fenxiang01" size="20"></uni-icons>
@ -81,10 +81,10 @@
<text class="share-text">{{ isCollected ? '已收藏' : '收藏' }}</text>
</button>
</view>
<button class="join-btn">
<!-- <button class="join-btn">
<text>我要借书</text>
</button>
</view>
</button> -->
<!-- </view> -->
</view>
</template>
@ -268,4 +268,7 @@ export default {
color: #333;
line-height: 1.6;
}
.detail-bottom{
justify-content: space-around;
}
</style>

74
subpkg/pages/book-list/book-list.vue

@ -19,6 +19,7 @@
<script>
import bookListItem from "@/components/book-list-item/book-list-item.vue";
import { FetchInitScreenBookRecommend } from '@/api/book';
export default {
components: {
@ -27,87 +28,38 @@ export default {
data() {
return {
bookList: [], //
pageNum: 1, //
pageSize: 10, //
loading: false, //
noMore: false //
};
},
onLoad() {
this.getList();
this.getBookRecommendList();
},
//
onPullDownRefresh() {
this.refresh();
},
//
onReachBottom() {
if (!this.loading && !this.noMore) {
this.pageNum++;
this.getList();
}
},
methods: {
//
refresh() {
this.pageNum = 1;
this.bookList = [];
this.noMore = false;
this.getList();
this.getBookRecommendList();
},
//
getList() {
//
async getBookRecommendList() {
this.loading = true;
//
setTimeout(() => {
//
const mockData = [
{
imgCover: "https://qiniu.aiyxlib.com/1606124577077",
title: "名侦探柯南",
nickname: "青山刚昌",
publish: "长春出版社"
},
{
imgCover: "https://qiniu.aiyxlib.com/1606124577077",
title: "三体",
nickname: "刘慈欣",
publish: "重庆出版社"
},
{
imgCover: "https://qiniu.aiyxlib.com/1606124577077",
title: "盗墓笔记",
nickname: "南派三叔",
publish: "中国友谊出版公司"
},
{
imgCover: "https://qiniu.aiyxlib.com/1606124577077",
title: "斗罗大陆",
nickname: "唐家三少",
publish: "太白文艺出版社"
},
{
imgCover: "https://qiniu.aiyxlib.com/1606124577077",
title: "斗破苍穹",
nickname: "天蚕土豆",
publish: "湖北少年儿童出版社"
}
];
let newList = [];
if (this.pageNum === 1) {
newList = mockData;
} else {
// 2
this.noMore = true;
}
this.bookList = [...this.bookList, ...newList];
try {
const res = await FetchInitScreenBookRecommend({ libcode: '1201' });
this.bookList = res.data || [];
this.noMore = true; //
} catch (err) {
console.error('获取推荐图书列表失败:', err);
} finally {
this.loading = false;
uni.stopPullDownRefresh();
}, 800);
}
},
//

8
subpkg/pages/feedback-list/feedback-list.vue

@ -52,7 +52,7 @@ export default {
feedbackList: [
{
nickname: "用户1",
avatar: "@/static/images/avatar.png",
avatar: "/static/images/avatar.png",
content: "这篇文章充满了激情,从字里行间能体会到作者的喜爱之情,全文层次清晰,语句流畅,叙事生动具体,趣味性强。",
createTime: "2026-04-23 10:23:01",
likeNum: 12,
@ -60,7 +60,7 @@ export default {
},
{
nickname: "热情读者",
avatar: "@/static/images/avatar.png",
avatar: "/static/images/avatar.png",
content: "写得非常棒!情感真挚,结构完整,非常有感染力,值得大家阅读学习。",
createTime: "2026-04-23 11:10:05",
likeNum: 8,
@ -68,7 +68,7 @@ export default {
},
{
nickname: "热情读者",
avatar: "@/static/images/avatar.png",
avatar: "/static/images/avatar.png",
content: "写得非常棒!情感真挚,结构完整,非常有感染力,值得大家阅读学习。",
createTime: "2026-04-23 11:10:05",
likeNum: 8,
@ -76,7 +76,7 @@ export default {
},
{
nickname: "热情读者",
avatar: "@/static/images/avatar.png",
avatar: "/static/images/avatar.png",
content: "写得非常棒!情感真挚,结构完整,非常有感染力,值得大家阅读学习。",
createTime: "2026-04-23 11:10:05",
likeNum: 8,

480
subpkg/pages/myLending/myLending-addpage.vue

@ -0,0 +1,480 @@
<template>
<view class="lending-container">
<view class="tab-sticky">
<my-tabs
:tabData="tabData"
:defaultIndex="currentIndex"
:config="{ textColor: '#333' }"
@tabClick="tabClick"
/>
</view>
<swiper
class="swiper"
:current="currentIndex"
:style="{ height: currentSwiperHeight + 'px' }"
@animationfinish="onSwiperEnd"
@change="onSwiperChange"
>
<swiper-item v-for="(tabItem, idx) in tabData" :key="idx">
<view class="list-wrapper">
<!-- 首次加载 -->
<uni-load-more status="loading" v-if="loadingMap[tabItem.status]" />
<!-- 空数据 -->
<view class="empty" v-else-if="!listData[tabItem.status] || listData[tabItem.status].length === 0">
暂无{{ tabItem.label }}记录
</view>
<!-- 列表 -->
<block v-else>
<!-- @click="goToDetail(item)" -->
<lending-list-item
:class="'list-item-' + tabItem.status"
v-for="(item, index) in listData[tabItem.status]"
:key="index"
:data="item"
:ranking="index + 1"
/>
</block>
<!-- 上拉加载更多 -->
<uni-load-more
v-if="listData[tabItem.status] && listData[tabItem.status].length > 0 && !loadingMap[tabItem.status]"
:status="loadMoreStatusMap[tabItem.status]"
/>
</view>
</swiper-item>
</swiper>
</view>
</template>
<script>
import myTabs from "@/components/my-tabs/my-tabs.vue";
import lendingListItem from "@/components/lending-list-item/lending-list-item.vue";
export default {
components: { myTabs, lendingListItem },
data() {
return {
tabData: [
{ label: "全部", status: "all", apiStatus: -1 },
{ label: "在借中", status: "lending", apiStatus: 0 },
{ label: "将过期", status: "expiring", apiStatus: 1 },
{ label: "已过期", status: "expired", apiStatus: 2 },
],
currentIndex: 0,
listData: {},
loadingMap: {}, // / loading
loadMoreStatusMap: {}, // loading / no-more / ""
pageMap: {}, //
sizeMap: {}, //
hasMoreMap: {}, //
swiperHeightData: {},
currentSwiperHeight: 400,
currentPageScrollTop: 0,
isRefreshing: false //
};
},
onLoad() {
this.initDataStructure();
// tab
const firstTab = this.getCurrentTab();
if (firstTab) {
this.loadingMap[firstTab.status] = true;
this.getListData(firstTab.status);
}
},
onShow() {
// tabIndex
const tabIndex = uni.getStorageSync('switch_tab_index');
if (tabIndex !== undefined && tabIndex !== '') {
this.currentIndex = Number(tabIndex);
// tab
const currentTab = this.getCurrentTab();
if (currentTab) {
this.loadingMap[currentTab.status] = true;
this.getListData(currentTab.status);
}
//
uni.removeStorageSync('switch_tab_index');
}
},
//
onPullDownRefresh() {
this.isRefreshing = true;
const currentTab = this.getCurrentTab();
this.refreshList(currentTab.status);
},
//
onReachBottom() {
const currentTab = this.getCurrentTab();
this.loadMoreList(currentTab.status);
},
onPageScroll(res) {
this.currentPageScrollTop = res.scrollTop;
},
methods: {
//
initDataStructure() {
this.tabData.forEach(tab => {
const key = tab.status;
this.$set(this.listData, key, []);
this.$set(this.loadingMap, key, false);
this.$set(this.loadMoreStatusMap, key, "");
this.$set(this.pageMap, key, 1);
// 4tab10
this.$set(this.sizeMap, key, key === 'lending' ? 4 : 10);
this.$set(this.hasMoreMap, key, true);
});
},
getCurrentTab() {
return this.tabData[this.currentIndex];
},
//
processBorrowData(list) {
return list.map(item => {
//
if (item.realityTime) {
if (new Date(item.realityTime) <= new Date(item.returnTime)) {
item.returnBook = 2; //
} else {
item.returnBook = 3; //
}
} else {
//
const now = new Date();
const returnDate = new Date(item.returnTime);
const diffDay = Math.ceil((returnDate - now) / (1000 * 3600 * 24));
if (diffDay < 0) {
// 1. <
item.returnBook = 3;
}else if (diffDay <= 3) {
// 2. 0~3
item.returnBook = 1;
} else {
// 3.
item.returnBook = 0;
}
}
return item;
});
},
// /
async getListData(statusKey, isRefresh = false) {
const tab = this.tabData.find(item => item.status === statusKey);
if (!tab) return;
if (!isRefresh && this.listData[statusKey]?.length > 0) {
this.loadingMap[statusKey] = false;
return;
}
this.loadingMap[statusKey] = true;
this.pageMap[statusKey] = 1;
try {
const data = await this.fetchBorrowList(tab.apiStatus, this.pageMap[statusKey], this.sizeMap[statusKey]);
console.log('data',data)
let list = data.records || [];
list = this.processBorrowData(list);
this.listData[statusKey] = list;
this.hasMoreMap[statusKey] = list.length === this.sizeMap[statusKey];
this.loadMoreStatusMap[statusKey] = this.hasMoreMap[statusKey] ? "" : "no-more";
} catch (err) {
this.listData[statusKey] = [];
} finally {
this.loadingMap[statusKey] = false;
this.isRefreshing = false;
uni.stopPullDownRefresh();
this.$nextTick(() => {
this.calcSwiperHeight(statusKey);
});
}
},
//
async loadMoreList(statusKey) {
if (this.loadingMap[statusKey] || !this.hasMoreMap[statusKey] || this.isRefreshing) return;
this.loadMoreStatusMap[statusKey] = "loading";
this.pageMap[statusKey] += 1;
const tab = this.tabData.find(item => item.status === statusKey);
try {
const data = await this.fetchBorrowList(tab.apiStatus, this.pageMap[statusKey], this.sizeMap[statusKey]);
let newList = data.records || [];
newList = this.processBorrowData(newList);
if (newList.length > 0) {
this.listData[statusKey] = [...this.listData[statusKey], ...newList];
this.hasMoreMap[statusKey] = newList.length === this.sizeMap[statusKey];
this.loadMoreStatusMap[statusKey] = this.hasMoreMap[statusKey] ? "" : "no-more";
} else {
this.hasMoreMap[statusKey] = false;
this.loadMoreStatusMap[statusKey] = "no-more";
}
} catch (err) {
this.loadMoreStatusMap[statusKey] = "";
} finally {
this.$nextTick(() => {
this.calcSwiperHeight(statusKey);
});
}
},
//
refreshList(statusKey) {
this.getListData(statusKey, true);
},
//
async fetchBorrowList(apiStatus, pageNum, pageSize) {
return new Promise((resolve) => {
setTimeout(() => {
const mock = this.getMockData(apiStatus, pageNum, pageSize);
resolve({
records: mock,
total: mock.length * 3
});
}, 500);
});
},
//
getMockData(apiStatus, pageNum, pageSize) {
const base = [
{
imgCover: "https://qiniu.aiyxlib.com/1606124577077",
title: "名侦探柯南",
nickname: "青山刚昌",
publish: "长春出版社",
isbn: "1001",
desc: '精心提炼20种GPT提问方法及指令,从入门到进阶再到精通,100个。',
startTime: "2026-03-01",
returnTime: "2026-04-30", // 10
realityTime: ""
},
{
imgCover: "https://qiniu.aiyxlib.com/1606124577077",
title: "三体",
nickname: "刘慈慈",
publish: "重庆出版社",
isbn: "1002",
desc: '精心提炼20种GPT提问方法及指令,从入门到进阶再到精通,100个。',
startTime: "2026-03-10",
returnTime: "2026-04-22", // 2
realityTime: ""
},
{
imgCover: "https://qiniu.aiyxlib.com/1606124577077",
title: "红楼梦",
nickname: "曹雪芹",
publish: "人民文学",
isbn: "1003",
desc: '精心提炼20种GPT提问方法及指令,从入门到进阶再到精通,100个。',
startTime: "2026-02-01",
returnTime: "2026-03-25", //
realityTime: ""
},
{
imgCover: "https://qiniu.aiyxlib.com/1606124577077",
title: "西游记",
nickname: "吴承恩",
publish: "中华书局",
isbn: "1004",
desc: '精心提炼20种GPT提问方法及指令,从入门到进阶再到精通,100个。',
startTime: "2026-02-10",
returnTime: "2026-04-01",
realityTime: "2026-03-31" //
},
{
imgCover: "https://qiniu.aiyxlib.com/1606124577077",
title: "水浒传",
nickname: "施耐庵",
publish: "人民文学出版社",
isbn: "1005",
desc: '精心提炼20种GPT提问方法及指令,从入门到进阶再到精通,100个。',
startTime: "2026-03-05",
returnTime: "2026-05-05",
realityTime: ""
},
{
imgCover: "https://qiniu.aiyxlib.com/1606124577077",
title: "三国演义",
nickname: "罗贯中",
publish: "人民文学出版社",
isbn: "1006",
desc: '精心提炼20种GPT提问方法及指令,从入门到进阶再到精通,100个。',
startTime: "2026-03-15",
returnTime: "2026-05-15",
realityTime: ""
},
{
imgCover: "https://qiniu.aiyxlib.com/1606124577077",
title: "活着",
nickname: "余华",
publish: "作家出版社",
isbn: "1007",
desc: '精心提炼20种GPT提问方法及指令,从入门到进阶再到精通,100个。',
startTime: "2026-03-20",
returnTime: "2026-05-20",
realityTime: ""
},
{
imgCover: "https://qiniu.aiyxlib.com/1606124577077",
title: "围城",
nickname: "钱钟书",
publish: "人民文学出版社",
isbn: "1008",
desc: '精心提炼20种GPT提问方法及指令,从入门到进阶再到精通,100个。',
startTime: "2026-03-25",
returnTime: "2026-05-25",
realityTime: ""
}
];
if (pageNum >= 4) { // 4
return [];
}
// tab
let list = [];
if (apiStatus === 0) { //
//
const start = (pageNum - 1) * pageSize;
const end = start + pageSize;
for (let i = start; i < end; i++) {
const item = base[i % base.length];
list.push({ ...item, isbn: item.isbn + pageNum + i });
}
} else {
list = [...base];
if (pageNum > 1) {
list.push(...base.map(item => ({ ...item, isbn: item.isbn + pageNum })));
}
}
switch (apiStatus) {
case -1: return list;
case 0: return list;
case 1: return [list[0], list[1]];
case 2: return [];
default: return [];
}
},
// swiper
calcSwiperHeight(statusKey) {
const selector = `.list-item-${statusKey}`;
const query = uni.createSelectorQuery().in(this);
query.selectAll(selector).boundingClientRect((res) => {
let total = 200;
if (res?.length) {
total = res.reduce((t, h) => t + h.height + 8, 0);
}
// uni-load-more
total += 80; // uni-load-more
this.swiperHeightData[statusKey] = total;
this.currentSwiperHeight = total;
}).exec();
},
// tab
tabClick(index) {
this.currentIndex = index;
const tab = this.getCurrentTab();
if (this.currentPageScrollTop > 100) {
uni.pageScrollTo({ scrollTop: 0, duration: 100 });
}
if (!this.listData[tab.status]?.length) {
this.loadingMap[tab.status] = true;
this.getListData(tab.status);
} else {
this.currentSwiperHeight = this.swiperHeightData[tab.status] || 400;
}
},
onSwiperChange(e) {
if (e.detail.source === "touch") {
this.currentIndex = e.detail.current;
}
},
onSwiperEnd() {
const tab = this.getCurrentTab();
if (!this.listData[tab.status]?.length) {
this.loadingMap[tab.status] = true;
this.getListData(tab.status);
} else {
this.currentSwiperHeight = this.swiperHeightData[tab.status] || 400;
}
},
goToDetail(item) {
uni.navigateTo({
url: `/subpkg/pages/book-detail/book-detail?isbn=${item.isbn}`
});
}
}
};
</script>
<style lang="scss" scoped>
.lending-container {
background-color: #f5f5f5;
min-height: 100vh;
.tab-sticky {
position: sticky;
top: 0;
z-index: 99;
background: #fff;
}
.swiper {
width: 100%;
min-height: 300px;
}
.swiper-item {
width: 100%;
height: 100%;
}
.list-wrapper {
padding: 10px;
box-sizing: border-box;
}
.empty {
text-align: center;
padding: 100px 0;
color: #999;
font-size: 14px;
}
}
::v-deep .uni-load-more{
height: auto !important;
}
</style>

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

@ -1,83 +1,127 @@
<template>
<view class="reader-card">
<!-- 顶部背景图 -->
<image class="card-top-bg" src="@/static/images/card-img1.png" mode="widthFix" />
<!-- 读者证列表 -->
<view class="card-list">
<radio-group v-model="selectedValue" @change="radioChange">
<view
class="card-list-item"
v-for="(item, index) in cardList"
:key="index"
@click="handleSelectItem(item.value)"
:class="{ active: selectedValue === item.value }"
>
<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.cardNum }}</text>
</view>
<radio :value="item.value" :checked="selectedValue === item.value"/>
<!-- 点击整个item触发切换 -->
<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-group>
<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>
<!-- 确定按钮 -->
<button class="submit-btn" @click="handleSubmit">确定</button>
</view>
</template>
<script>
export default {
data() {
return {
// radio
selectedValue: '1',
//
cardList: [
{
value: '1',
cardNum: 'NO.10078398329'
},
{
value: '2',
cardNum: 'NO.10078398330'
},
{
value: '3',
cardNum: 'NO.10078398331'
}
]
}
},
methods: {
// change
radioChange(e) {
console.log('radio选中值:', e.detail.value)
this.selectedValue = e.detail.value
},
// itemradio
handleSelectItem(value) {
this.selectedValue = value
},
//
handleSubmit() {
if(!this.selectedValue){
uni.showToast({
title: '请选择读者证',
icon: 'none'
})
return
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 = '';
}
console.log('提交选中的读者证:', this.selectedValue)
uni.showToast({
title: '选择成功'
})
//
} 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' });
}
}
});
},
//
radioChange() {},
toAddReaderCard() {
uni.navigateTo({ url: "/pages/login/login" });
},
}
}
</script>
<style lang="scss" scoped>
@ -116,7 +160,6 @@
cursor: pointer;
transition: all 0.2s;
//
&.active{
border-color: #01a4fe;
background: rgba(1, 164, 254, 0.1);
@ -129,38 +172,39 @@
}
.card-right-info{
flex: 1;
display: flex;
flex-direction: column;
justify-content: flex-start;
flex: 1;
.info-title{
font-size: 16px;
color: #333333;
color: #333;
font-weight: bold;
padding-bottom: 12px;
}
.info-num{
font-size: 14px;
color: #999999;
color: #999;
}
}
}
}
.submit-btn{
position: fixed;
bottom: 40px;
left: 0;
right: 0;
width: calc(100% - 40px);
padding: 5px 0;
color: #fff;
background-color: #01a4fe;
border-radius: 23px;
border: none;
font-size: 16px;
.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>

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

@ -0,0 +1,245 @@
<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>
<uni-icons
type="checkmark"
size="24"
color="#01a4fe"
v-if="selectedValue === item.bindValue"
></uni-icons>
</view>
<!-- <view class="add-card-btn" @click="toAddReaderCard">
<uni-icons type="plus" size="20" color="#01a4fe"></uni-icons>
<text>新增读者证</text>
</view> -->
</view>
<!-- 底部解绑按钮 -->
<button
class="unbind-btn"
:disabled="!selectedValue"
:class="{disabled: !selectedValue}"
@click="handleUnbind"
>
确认解绑
</button>
</view>
</template>
<script>
import {
FetchFindAllReaderBindByOpenId,
FetchUnbindReadCard
} 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) return;
const res = await FetchFindAllReaderBindByOpenId({
libcode: '1201',
openId: openId
});
if (res.code === 200) {
this.cardList = res.data;
uni.setStorageSync(READLIST, res.data);
} else {
this.cardList = [];
uni.setStorageSync(READLIST, []);
}
} catch (err) {
this.cardList = uni.getStorageSync(READLIST) || [];
}
},
//
handleSelectItem(value) {
//
if (this.selectedValue === value) {
this.selectedValue = '';
} else {
this.selectedValue = value;
}
},
//
handleUnbind() {
if (!this.selectedValue) {
uni.showToast({ title: '请选择要解绑的读者证', icon: 'none' });
return;
}
const openId = uni.getStorageSync('wx_login_code');
if (!openId) return;
uni.showModal({
title: '提示',
content: `确定要解绑【${this.selectedValue}】吗?`,
success: async (res) => {
if (res.confirm) {
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 = '';
this.getBindReaderCardList(); //
} else {
uni.showToast({ title: result.msg || '解绑失败', icon: 'none' });
}
} catch (err) {
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;
}
.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{
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;
border: none;
&.disabled{
background-color: #ccc;
}
}
}
</style>

14
utils/config.js

@ -0,0 +1,14 @@
const CONFIG = {
// 开发环境配置
development: {
// assetsPath: 'https://m.siccat.com/public/static/images/', // 静态资源路径
baseUrl: 'http://192.168.99.63:14000', // 后台接口请求地址
},
// 生产环境配置
production: {
// assetsPath: 'https://m.siccat.com/public/static/images/', // 静态资源路径
baseUrl: 'http://192.168.99.63:14000', // 后台接口请求地址
}
};
export default CONFIG[process.env.NODE_ENV];

30
utils/request.js

@ -1,20 +1,27 @@
import store from '../store';
const BASE_URL = 'https://api.imooc-blog.lgdsunday.club/api';
function request({ url, data, method }) {
import config from '@/utils/config.js'
const BASE_URL = config.baseUrl
function request({ url, data, method = 'GET' }) {
return new Promise((resolve, reject) => {
// 自动带上 token
const header = {};
if (store.state.user.token) {
header.Authorization = store.state.user.token;
}
uni.request({
url: BASE_URL + url,
data,
method,
header: {
Authorization: store.state.user.token
},
method: method.toUpperCase(),
header,
success: ({ data }) => {
if (data.success) {
if (data.code === 200) {
// 直接返回后端的 data 结构
resolve(data);
} else {
uni.showToast({
title: data.message,
title: data.message || '请求失败',
icon: 'none',
mask: true,
duration: 3000
@ -23,14 +30,17 @@ function request({ url, data, method }) {
}
},
fail: (error) => {
uni.showToast({
title: '网络异常',
icon: 'none'
});
reject(error);
},
complete: () => {
// 关闭加载
uni.hideLoading();
}
});
});
}
export default request;
export default request;
Loading…
Cancel
Save