password.vue 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. <script setup>
  2. import { onMounted, ref } from 'vue';
  3. import { useUserStore } from '@/stores/user';
  4. import { request, parseResponseJson } from '@/utils/request';
  5. const userStore = useUserStore();
  6. const oldPassword = ref('');
  7. const newPassword = ref('');
  8. const confirmPassword = ref('');
  9. const submitting = ref(false);
  10. const showOldPassword = ref(false);
  11. const showNewPassword = ref(false);
  12. const showConfirmPassword = ref(false);
  13. import { staticAssetUrl } from '@/utils/staticAsset';
  14. const ICON_HIDE_PASSWORD = staticAssetUrl('hide-passwd.svg');
  15. const ICON_SHOW_PASSWORD = staticAssetUrl('show-passwd.svg');
  16. async function handleSubmit() {
  17. if (!oldPassword.value.trim()) {
  18. uni.showToast({ title: '请输入原密码', icon: 'none' });
  19. return;
  20. }
  21. if (!newPassword.value.trim()) {
  22. uni.showToast({ title: '请输入新密码', icon: 'none' });
  23. return;
  24. }
  25. if (newPassword.value.length < 6) {
  26. uni.showToast({ title: '新密码至少6位', icon: 'none' });
  27. return;
  28. }
  29. if (newPassword.value !== confirmPassword.value) {
  30. uni.showToast({ title: '两次输入的新密码不一致', icon: 'none' });
  31. return;
  32. }
  33. if (submitting.value)
  34. return;
  35. submitting.value = true;
  36. try {
  37. const res = await request({
  38. url: '/mini/user/change-password',
  39. method: 'POST',
  40. data: {
  41. oldPassword: oldPassword.value,
  42. newPassword: newPassword.value
  43. }
  44. });
  45. const body = parseResponseJson(res);
  46. if (body.code === 200) {
  47. uni.showToast({ title: '密码已修改,请重新登录', icon: 'none' });
  48. setTimeout(() => {
  49. userStore.logout();
  50. }, 1500);
  51. }
  52. else {
  53. uni.showToast({ title: body.message || '修改失败', icon: 'none' });
  54. }
  55. }
  56. catch (e) {
  57. const msg = e instanceof Error ? e.message : '网络异常';
  58. uni.showToast({ title: msg, icon: 'none' });
  59. }
  60. finally {
  61. submitting.value = false;
  62. }
  63. }
  64. onMounted(() => {
  65. if (!userStore.isLoggedIn) {
  66. uni.reLaunch({ url: '/pages/login/login' });
  67. return;
  68. }
  69. if (!userStore.isSupplier && !userStore.isDeliverer && !userStore.isClient) {
  70. uni.showToast({ title: '当前账号无权限访问', icon: 'none' });
  71. setTimeout(() => userStore.navigateToHome(), 1500);
  72. }
  73. });
  74. </script>
  75. <template>
  76. <view class="page">
  77. <view class="card">
  78. <view class="field">
  79. <text class="field-label">原密码</text>
  80. <view class="field-input-wrap">
  81. <input
  82. v-model="oldPassword"
  83. class="field-input"
  84. type="text"
  85. :password="!showOldPassword"
  86. placeholder="请输入原密码"
  87. />
  88. <view class="eye-icon" @click="showOldPassword = !showOldPassword">
  89. <image
  90. class="eye-icon-img"
  91. :src="showOldPassword ? ICON_HIDE_PASSWORD : ICON_SHOW_PASSWORD"
  92. mode="aspectFit"
  93. />
  94. </view>
  95. </view>
  96. </view>
  97. <view class="field">
  98. <text class="field-label">新密码</text>
  99. <view class="field-input-wrap">
  100. <input
  101. v-model="newPassword"
  102. class="field-input"
  103. type="text"
  104. :password="!showNewPassword"
  105. placeholder="至少6位"
  106. />
  107. <view class="eye-icon" @click="showNewPassword = !showNewPassword">
  108. <image
  109. class="eye-icon-img"
  110. :src="showNewPassword ? ICON_HIDE_PASSWORD : ICON_SHOW_PASSWORD"
  111. mode="aspectFit"
  112. />
  113. </view>
  114. </view>
  115. </view>
  116. <view class="field">
  117. <text class="field-label">确认新密码</text>
  118. <view class="field-input-wrap">
  119. <input
  120. v-model="confirmPassword"
  121. class="field-input"
  122. type="text"
  123. :password="!showConfirmPassword"
  124. placeholder="再次输入新密码"
  125. />
  126. <view class="eye-icon" @click="showConfirmPassword = !showConfirmPassword">
  127. <image
  128. class="eye-icon-img"
  129. :src="showConfirmPassword ? ICON_HIDE_PASSWORD : ICON_SHOW_PASSWORD"
  130. mode="aspectFit"
  131. />
  132. </view>
  133. </view>
  134. </view>
  135. <button class="btn" type="default" :disabled="submitting" @click="handleSubmit">
  136. 确认修改
  137. </button>
  138. </view>
  139. </view>
  140. </template>
  141. <style lang="scss" scoped>
  142. .page {
  143. min-height: 100vh;
  144. background: #f3f7f5;
  145. padding: 16rpx;
  146. }
  147. .card {
  148. background: #ffffff;
  149. border-radius: 18rpx;
  150. padding: 22rpx 16rpx 26rpx;
  151. border: 1rpx solid #d9e9e1;
  152. box-shadow: 0 4rpx 12rpx rgba(10, 159, 109, 0.06);
  153. }
  154. .field {
  155. margin-bottom: 18rpx;
  156. }
  157. .field-label {
  158. display: block;
  159. font-size: 22rpx;
  160. color: #6f7e77;
  161. margin-bottom: 10rpx;
  162. }
  163. .field-input {
  164. flex: 1;
  165. min-width: 0;
  166. height: 76rpx;
  167. padding: 0;
  168. box-sizing: border-box;
  169. font-size: 26rpx;
  170. background: transparent;
  171. border: none;
  172. }
  173. .field-input-wrap {
  174. display: flex;
  175. align-items: center;
  176. height: 76rpx;
  177. padding: 0 10rpx 0 18rpx;
  178. box-sizing: border-box;
  179. background: #f8fcfa;
  180. border: 1rpx solid #d9e9e1;
  181. border-radius: 14rpx;
  182. }
  183. .eye-icon {
  184. width: 56rpx;
  185. height: 56rpx;
  186. display: flex;
  187. align-items: center;
  188. justify-content: center;
  189. flex-shrink: 0;
  190. }
  191. .eye-icon-img {
  192. width: 34rpx;
  193. height: 34rpx;
  194. }
  195. .btn {
  196. margin: 16rpx 0 0;
  197. background: #10b981;
  198. color: #ffffff;
  199. border: none;
  200. border-radius: 14rpx;
  201. font-size: 28rpx;
  202. height: 80rpx;
  203. line-height: 80rpx;
  204. &[disabled] {
  205. opacity: 0.68;
  206. background: #10b981;
  207. color: #ffffff;
  208. }
  209. }
  210. </style>