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

403 lines
12 KiB

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