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

390 lines
11 KiB

2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
  1. <template>
  2. <view style="background-color: #fff; height: calc(100vh);">
  3. <view class="top-bar">
  4. <image class="top-bar-bg" src="@/static/images/mingqi-beij@2x.png" mode="aspectFill"></image>
  5. <view class="library-info">
  6. <image class="avatar" src="@/static/images/avatar.png" mode="aspectFill"></image>
  7. <view class="library-name">葛店经济技术开发区图书馆</view>
  8. </view>
  9. </view>
  10. <!-- <view class="user-info-section">
  11. <button open-type="chooseAvatar" @chooseavatar="onChooseAvatar" class="avatar-btn">
  12. <image v-if="avatarUrl" :src="avatarUrl" class="avatar-img"></image>
  13. <image v-else src="@/static/images/avatar.png" class="avatar-img"></image>
  14. <text class="tip-text">点击选择头像</text>
  15. </button>
  16. </view> -->
  17. <view class="form-box">
  18. <!-- <view class="item">
  19. <uni-icons class="form-icon" type="person" size="24"></uni-icons>
  20. <view class="uni-input-wrapper">
  21. <input
  22. class="input"
  23. type="nickname"
  24. v-model="nickName"
  25. placeholder="请输入昵称"
  26. @input="handleInput('nickName')"
  27. />
  28. <uni-icons
  29. class="clear-icon"
  30. v-if="clearIconStatus.nickName"
  31. @click="clearInput('nickName')"
  32. type="close"
  33. size="20"
  34. ></uni-icons>
  35. </view>
  36. </view> -->
  37. <view class="item">
  38. <uni-icons class="form-icon" custom-prefix="iconfont" type="icon-duzhezheng" size="24"></uni-icons>
  39. <view class="uni-input-wrapper">
  40. <input
  41. class="input"
  42. placeholder="请输入读者证号"
  43. v-model="queryvalue"
  44. @input="handleInput('queryvalue')"
  45. />
  46. <uni-icons
  47. class="clear-icon"
  48. v-if="clearIconStatus.queryvalue"
  49. @click="clearInput('queryvalue')"
  50. type="close"
  51. size="20"
  52. ></uni-icons>
  53. </view>
  54. </view>
  55. <view class="item">
  56. <uni-icons class="form-icon" type="locked" size="24"></uni-icons>
  57. <input class="input" placeholder="请输入密码" :password="!showPwd" v-model="rdpasswd" />
  58. <uni-icons class="form-right-icon" :type="showPwd ? 'eye-slash' : 'eye'" size="20"
  59. @click="togglePwd"></uni-icons>
  60. </view>
  61. <button class="login-btn" type="primary" @click="submit">绑定</button>
  62. </view>
  63. <view class="tips">
  64. 温馨提示<br />
  65. 1密码默认为 <text style="color:#e74c3c">身份证后6位</text>如果身份证号最后一位为XX需要大写;
  66. </view>
  67. </view>
  68. </template>
  69. <script>
  70. // 引入绑定接口
  71. import { FetchInitScreenSetting, FetchReaderList, FetchBindReadCard,FetchFindAllReaderBindByOpenId } from '@/api/user';
  72. import config from '@/utils/config';
  73. const READLIST = 'reader-card-list';
  74. // const USER_KEY = 'user-info';
  75. export default {
  76. data() {
  77. return {
  78. queryvalue: '',
  79. rdpasswd: '',
  80. showPwd: false,
  81. screenConfig: {},
  82. avatarUrl: '',
  83. nickName: '',
  84. // 清空按钮状态(支持多输入框)
  85. clearIconStatus: {
  86. nickName: false,
  87. queryvalue: false
  88. }
  89. };
  90. },
  91. onLoad() {
  92. this.getScreenSetting();
  93. },
  94. methods: {
  95. // 获取微信头像 + 上传到服务器
  96. onChooseAvatar(e) {
  97. console.log('获取微信头像', e)
  98. // 临时文件路径
  99. const tempFilePath = e.detail.avatarUrl;
  100. // 开始上传
  101. uni.uploadFile({
  102. url: config.baseUrl +'/api/fileRelevant/uploadWxAvatarImg', // 你的后端上传地址
  103. filePath: tempFilePath,
  104. name: 'file', // 后端接收的文件字段名,保持一致!
  105. header: {
  106. "Content-Type": "multipart/form-data"
  107. },
  108. success: (res) => {
  109. console.log("上传成功原始返回:", res);
  110. let realAvatar = '';
  111. try {
  112. const data = JSON.parse(res.data);
  113. console.log('解析成功:', data)
  114. realAvatar = data.data || data.url || ''; // 按你后端字段改
  115. } catch (e) {
  116. realAvatar = res.data; // 如果直接返回字符串URL
  117. }
  118. if (realAvatar) {
  119. console.log("永久头像URL:", realAvatar);
  120. this.avatarUrl = config.baseUrl + '/api/fileRelevant/getImg?imgType=5&imgId=' + realAvatar
  121. } else {
  122. uni.showToast({ title: '头像上传失败', icon: 'none' });
  123. }
  124. },
  125. fail: (err) => {
  126. console.log("上传失败", err);
  127. uni.showToast({ title: '头像上传失败', icon: 'none' });
  128. }
  129. });
  130. },
  131. // 统一监听输入(自动控制清空按钮显示隐藏)
  132. handleInput(field) {
  133. this.clearIconStatus[field] = this[field].trim().length > 0
  134. },
  135. // 统一清空输入框内容
  136. clearInput(field) {
  137. this[field] = ''
  138. this.clearIconStatus[field] = false
  139. },
  140. // 切换密码显隐
  141. togglePwd() {
  142. this.showPwd = !this.showPwd;
  143. },
  144. async getScreenSetting() {
  145. try {
  146. const res = await FetchInitScreenSetting({ libcode: '1201' });
  147. const data = res.data;
  148. this.screenConfig = {
  149. thirdUrl: data.open_lib_http?.context || '',
  150. thirdAppid: data.open_lib_appId?.context || '',
  151. thirdSecret: data.open_lib_secret?.context || '',
  152. sm4Key: data.sm4_key?.context || ''
  153. };
  154. } catch (err) {
  155. console.error('获取配置失败:', err);
  156. }
  157. },
  158. async submit() {
  159. // 去除首尾空格
  160. this.nickName = this.nickName.trim()
  161. this.queryvalue = this.queryvalue.trim()
  162. if (!this.queryvalue || !this.rdpasswd) {
  163. uni.showToast({ title: '请输入读者证号和密码', icon: 'none' });
  164. return;
  165. }
  166. uni.showLoading({ title: '绑定中...' });
  167. try {
  168. const params = {
  169. ...this.screenConfig,
  170. selecttype: 'rdid',
  171. queryvalue: this.queryvalue,
  172. rdpasswd: this.rdpasswd,
  173. };
  174. // {"code":200,"message":"操作成功","data":"{\"messagelist\":[{\"code\":\"R00138\",\"message\":\"未找到符合条件的读者!\"}],\"success\":false}","timestamp":1778154499544}
  175. // {"code":200,"message":"操作成功","data":"{\"success\":true,\"pagedata\":[{\"rdClusterCode\":null,\"rdlib\":\"GD\",\"rdid\":\"420105198509200438\",\"rdcfstate\":1}]}","timestamp":1778154647854}
  176. // {"code":200,"message":"操作成功","data":"{\"messageList\":[{\"R00131\":\"认证失败,系统存在该读者,密码不匹配!\"}],\"success\":true,\"pagedata\":\"\"}","timestamp":1778155520501}
  177. const res = await FetchReaderList(params);
  178. let result = {};
  179. try {
  180. result = JSON.parse(res.data);
  181. } catch (e) {
  182. uni.hideLoading();
  183. uni.showToast({ title: '数据解析失败', icon: 'none' });
  184. return;
  185. }
  186. // 统一提取错误信息
  187. let errMsg = '';
  188. if (result.messagelist?.length) {
  189. const item = result.messagelist[0];
  190. errMsg = item.message || Object.values(item)[0] || '认证失败';
  191. }
  192. if (result.messageList?.length) {
  193. const item = result.messageList[0];
  194. errMsg = item.message || Object.values(item)[0] || '认证失败';
  195. }
  196. // 成功判断
  197. const realSuccess = result.success === true && result.pagedata?.length > 0;
  198. if (realSuccess) {
  199. // 开始绑定
  200. const openId = uni.getStorageSync("wx_login_code");
  201. const bindParams = {
  202. openid: openId,
  203. bindValue: this.queryvalue,
  204. bindType: 'rdid',
  205. libcode: '1201',
  206. }
  207. // 调用绑定接口
  208. const bindRes = await FetchBindReadCard(bindParams);
  209. console.log('绑定结果', bindRes);
  210. if(bindRes.code === 200 ){
  211. uni.hideLoading();
  212. uni.showToast({
  213. title: bindRes.data || '读者证绑定成功',
  214. icon: 'success'
  215. });
  216. // const loginRes = {
  217. // token: 'reader-token-' + Date.now(),
  218. // user: {
  219. // nickName: this.nickName || '小图',
  220. // avatarUrl: this.avatarUrl
  221. // }
  222. // };
  223. // uni.setStorageSync(USER_KEY, loginRes.user);
  224. const data = {
  225. libcode: '1201',
  226. openId: openId
  227. }
  228. FetchFindAllReaderBindByOpenId(data).then(res => {
  229. console.log('获取读者证列表',res)
  230. if (res.code === 200 && res.data.length > 0) {
  231. uni.setStorageSync(READLIST, res.data);
  232. } else {
  233. uni.setStorageSync(READLIST, []);
  234. }
  235. })
  236. .catch(err => {
  237. console.error('获取读者证列表失败:', err);
  238. })
  239. // 绑定成功后返回上一页
  240. setTimeout(() => {
  241. uni.navigateBack();
  242. }, 1500);
  243. }else{
  244. // 绑定失败提示
  245. uni.hideLoading()
  246. uni.showToast({
  247. title: bindResult.message || '绑定失败,请重试',
  248. icon: 'none'
  249. })
  250. }
  251. } else {
  252. uni.hideLoading();
  253. uni.showToast({
  254. title: errMsg || '读者证或密码错误',
  255. icon: 'none'
  256. });
  257. }
  258. } catch (err) {
  259. console.error('绑定流程异常:', err)
  260. uni.hideLoading();
  261. uni.showToast({ title: '网络异常或绑定失败', icon: 'none' });
  262. }
  263. }
  264. }
  265. };
  266. </script>
  267. <style lang="scss" scoped>
  268. .user-info-section {
  269. display: flex;
  270. flex-direction: column;
  271. align-items: center;
  272. padding: 30px 0 0 0;
  273. .avatar-btn {
  274. background: transparent;
  275. display: flex;
  276. flex-direction: column;
  277. align-items: center;
  278. &::after{
  279. border: none !important;
  280. }
  281. .avatar-img {
  282. width: 60px;
  283. height: 60px;
  284. border-radius: 50%;
  285. }
  286. .tip-text {
  287. font-size: 12px;
  288. color: #999;
  289. }
  290. }
  291. }
  292. .form-box {
  293. padding: 20px 15px;
  294. .item {
  295. width: 100%;
  296. min-height: 44px;
  297. border-radius: 22px;
  298. background-color: #f7f7f7;
  299. display: flex;
  300. align-items: center;
  301. margin-bottom: 15px;
  302. .input {
  303. flex: 1;
  304. padding: 10px;
  305. font-size: 14px;
  306. }
  307. }
  308. .uni-input-wrapper{
  309. flex: 1;
  310. display: flex;
  311. align-items: center;
  312. .input {
  313. flex: 1;
  314. padding: 10px;
  315. font-size: 14px;
  316. }
  317. .clear-icon{
  318. padding: 0 12px;
  319. color: #ccc;
  320. }
  321. }
  322. }
  323. .login-btn {
  324. margin-top: 10px;
  325. background-color: #01a4fe !important;
  326. border-radius: 22px;
  327. font-size: 16px;
  328. height: 44px;
  329. line-height: 44px;
  330. }
  331. .tips {
  332. margin: 30px 20px;
  333. font-size: 12px;
  334. color: #333;
  335. line-height: 20px;
  336. }
  337. .form-icon {
  338. ::v-deep .uni-icons {
  339. margin-left: 10px;
  340. color: #01a4fe !important;
  341. }
  342. }
  343. .form-right-icon {
  344. ::v-deep .uni-icons {
  345. margin-right: 10px;
  346. }
  347. }
  348. </style>