personal_info.vue 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. <template>
  2. <view class="personal-info">
  3. <view class="personal-info-box">
  4. <!-- 上传 -->
  5. <view class="upload">
  6. <view class="upload-box">
  7. <up-upload @afterRead="
  8. async (e) => {
  9. await afterRead(e);
  10. getImage();
  11. }
  12. " name="1" :maxCount="1" :previewImage="false" :deletable="false" :multiple="false">
  13. <view class="upload-block">
  14. <up-avatar size="144rpx" shape="circle" :src="userInfo.avatar" mode="aspectFill"></up-avatar>
  15. <view class="upload-block-edit flex-center">
  16. <image src="@/static/images/edit@2x.png" mode=""></image>
  17. </view>
  18. </view>
  19. </up-upload>
  20. </view>
  21. </view>
  22. <view class="personal-list">
  23. <view class="flex-center-between border-bottom personal-info-item">
  24. <text class="label_width">昵称</text>
  25. <up-input class="title-input" placeholder="请输入" type="text" confirmType="完成" maxlength="10"
  26. :adjustPosition="false" border="none" :showWordLimit="true" v-model="userInfo.nickname" inputAlign="right"></up-input>
  27. </view>
  28. <view class="flex-center-between border-bottom personal-info-item">
  29. <text class="label_width">手机号</text>
  30. <text class="gray">{{telEncrypt(userInfo.phone)}}</text>
  31. </view>
  32. </view>
  33. <view class="personal-list">
  34. <view class="flex-center-between border-bottom personal-info-item" @click="pickerSexShow = true">
  35. <text class="label_width">性别</text>
  36. <view class="flex-center-between">
  37. <text>{{sexText}}</text>
  38. <image style="width: 32rpx;height: 32rpx;" src="/static/images/right.png" mode=""></image>
  39. </view>
  40. </view>
  41. <view class="flex-center-between border-bottom personal-info-item">
  42. <text class="label_width">地址</text>
  43. <picker mode="multiSelector" @change="bindRegionChange" @columnchange="bindMultiPickerColumnChange"
  44. :value="valueRegion" :range="multiArray">
  45. <view class='flex-center-between'>
  46. <view class="picker line1">{{ region[0] }},{{ region[1] }},{{ region[2] }}</view>
  47. <image style="width: 32rpx;height: 32rpx;" src="/static/images/right.png" mode=""></image>
  48. </view>
  49. </picker>
  50. </view>
  51. <view class="flex-center-between border-bottom personal-info-item">
  52. <text class="label_width">年龄</text>
  53. <up-input class="title-input" placeholder="请输入年龄" fontSize="28rpx" type="text" confirmType="完成" maxlength="3"
  54. :adjustPosition="false" border="none" :showWordLimit="true" v-model="userInfo.age" inputAlign="right"></up-input>
  55. </view>
  56. </view>
  57. <view class="personal-list">
  58. <view class="flex-center-between border-bottom personal-info-item">
  59. <text class="label_width">个人简介</text>
  60. <up-input class="title-input" placeholder="请输入个人简介" fontSize="28rpx" type="text" confirmType="完成" maxlength="50"
  61. :adjustPosition="false" border="none" :showWordLimit="true" v-model="userInfo.mark" inputAlign="right"></up-input>
  62. </view>
  63. <!-- <view class="flex-center-between border-bottom personal-info-item" @tap.stop="setPayword">
  64. <text class="label_width">支付密码</text>
  65. <text>* * * * * *</text>
  66. </view> -->
  67. </view>
  68. </view>
  69. <view class="footer">
  70. <view @click="submitFn" class="submit-btn">提交</view>
  71. </view>
  72. <up-picker @confirm="changeSex" @cancel="pickerSexShow = false" :show="pickerSexShow" :columns="[
  73. [
  74. { label: '男', id: 1 },
  75. { label: '女', id: 2 },
  76. { label: '保密', id: 3 },
  77. ],
  78. ]" keyName="label" valueName="id"></up-picker>
  79. <!-- 页面内 容结束 -->
  80. </view>
  81. </template>
  82. <script setup>
  83. import {
  84. ref,
  85. computed,
  86. nextTick
  87. } from "vue";
  88. import {
  89. useImageUpload
  90. } from "@/hooks/useImageUpload";
  91. import {
  92. useAppStore
  93. } from "@/stores/app";
  94. import {
  95. onLoad
  96. } from "@dcloudio/uni-app";
  97. import {
  98. useToast
  99. } from "@/hooks/useToast";
  100. import {
  101. getUserInfo,
  102. userEdit,
  103. registerpayPasswordAPI
  104. } from "@/api/user";
  105. import {
  106. getCity
  107. } from "@/api/api.js";
  108. import Cache from "@/utils/cache";
  109. import {
  110. telEncrypt
  111. } from "@/utils/util.js";
  112. const paypopRef = ref(null);
  113. const {
  114. Toast
  115. } = useToast();
  116. const {
  117. imageList,
  118. afterRead,
  119. deletePic,
  120. uploadLoading
  121. } = useImageUpload({
  122. pid: 5,
  123. model: "book",
  124. });
  125. const appStore = useAppStore();
  126. const userInfo = ref({
  127. avatar: "",
  128. nickname: "",
  129. addres: "",
  130. mark: "",
  131. sex: "",
  132. age: "",
  133. });
  134. const pickerSexShow = ref(false);
  135. const sexText = computed(() => {
  136. return userInfo.value.sex == 1 ?
  137. "男" :
  138. userInfo.value.sex == 2 ?
  139. "女" :
  140. userInfo.value.sex == 3 ?
  141. "保密" :
  142. "未知";
  143. });
  144. //省市区选择
  145. const district = ref([]);
  146. const multiArray = ref([
  147. [],
  148. [],
  149. []
  150. ]);
  151. const multiIndex = ref([0, 0, 0]);
  152. const region = ref(["省", "市", "区"]);
  153. const valueRegion = ref([0, 0, 0]);
  154. onLoad(() => {
  155. fetchUserInfo();
  156. getCityList();
  157. });
  158. const changeSex = (e) => {
  159. userInfo.value.sex = e.value[0].id;
  160. pickerSexShow.value = false;
  161. };
  162. // 设置支付密码
  163. const setPayword = () => {
  164. nextTick(() => {
  165. paypopRef.value.Open();
  166. });
  167. };
  168. const handlerPwd = async (e) => {
  169. const res = await registerpayPasswordAPI({
  170. account: appStore.userInfo.phone,
  171. payPassword: e,
  172. });
  173. uni.showToast({
  174. title: "修改成功",
  175. duration: 2000,
  176. });
  177. };
  178. // 获取用户头像
  179. async function getImage() {
  180. if (imageList.value.length > 0) {
  181. if (imageList.value[0].status == "success") {
  182. userInfo.value.avatar = imageList.value[0].info.url;
  183. } else {
  184. Toast({
  185. title: "上传失败"
  186. });
  187. }
  188. }
  189. imageList.value = [];
  190. }
  191. function submitFn() {
  192. change();
  193. }
  194. const change = async () => {
  195. await userEdit(userInfo.value);
  196. Toast({
  197. title: "修改成功",
  198. endtime: 1500
  199. });
  200. appStore.USERINFO();
  201. setTimeout(() => {
  202. uni.navigateBack();
  203. }, 1600);
  204. };
  205. // 获取用户信息
  206. async function fetchUserInfo() {
  207. try {
  208. const {
  209. data
  210. } = await getUserInfo(appStore.uid);
  211. userInfo.value = data;
  212. userInfo.value.addres = userInfo.value.addres || "";
  213. const list = userInfo.value.addres.split("-");
  214. if (list.length > 0) {
  215. region.value = [list[0], list[1], list[2]];
  216. }
  217. } catch (error) {
  218. console.error("otherUserinfo", error);
  219. Toast({
  220. title: "获取用户信息失败"
  221. });
  222. }
  223. }
  224. function bindRegionChange(e) {
  225. const mi = multiIndex.value;
  226. const province = district.value[mi[0]] || {
  227. child: []
  228. };
  229. const ma = multiArray.value;
  230. const value = e.detail.value;
  231. region.value = [ma[0][value[0]], ma[1][value[1]], ma[2][value[2]]];
  232. userInfo.value.addres = region.value.join("-");
  233. valueRegion.value = [0, 0, 0];
  234. // change();
  235. initialize();
  236. }
  237. function getCityList() {
  238. getCity().then((res) => {
  239. district.value = res.data;
  240. let oneDay = 24 * 3600 * 1000;
  241. Cache.setItem({
  242. name: "cityList",
  243. value: res.data,
  244. expires: oneDay * 7
  245. }); //设置七天过期时间
  246. initialize();
  247. });
  248. }
  249. function initialize() {
  250. if (district.value.length) {
  251. let province = [],
  252. city = [],
  253. area = [];
  254. let cityChildren = district.value[0].child || [];
  255. let areaChildren = cityChildren.length ? cityChildren[0].child || [] : [];
  256. district.value.forEach((item) => province.push(item.name));
  257. cityChildren.forEach((item) => city.push(item.name));
  258. areaChildren.forEach((item) => area.push(item.name));
  259. multiArray.value = [province, city, area];
  260. }
  261. }
  262. function bindMultiPickerColumnChange(e) {
  263. const column = e.detail.column;
  264. const value = e.detail.value;
  265. const ma = multiArray.value;
  266. const mi = multiIndex.value;
  267. mi[column] = value;
  268. switch (column) {
  269. case 0:
  270. const currentCity = district.value[value] || {
  271. child: []
  272. };
  273. const areaList = currentCity.child[0] || {
  274. child: []
  275. };
  276. ma[1] = currentCity.child.map((item) => item.name);
  277. ma[2] = areaList.child.map((item) => item.name);
  278. break;
  279. case 1:
  280. const cityList = district.value[mi[0]].child[mi[1]].child || [];
  281. ma[2] = cityList.map((item) => item.name);
  282. break;
  283. case 2:
  284. break;
  285. }
  286. multiArray.value = [...ma];
  287. multiIndex.value = [...mi];
  288. }
  289. </script>
  290. <style>
  291. page {
  292. background: #F9F7F0;
  293. }
  294. </style>
  295. <style lang="scss" scoped>
  296. page{
  297. height: 100%;
  298. }
  299. .personal-info {
  300. .personal-info-box {
  301. padding: 0 16rpx;
  302. .upload {
  303. padding: 16rpx 0;
  304. display: flex;
  305. align-items: center;
  306. justify-content: center;
  307. }
  308. .upload-box {
  309. width: 145rpx;
  310. height: 145rpx;
  311. border-radius: 50%;
  312. border: 1rpx solid #CCCCCC;
  313. }
  314. }
  315. .upload-block {
  316. display: flex;
  317. align-items: center;
  318. justify-content: center;
  319. position: relative;
  320. .upload-block-edit {
  321. bottom: 0;
  322. right: 12rpx;
  323. position: absolute;
  324. width: 40rpx;
  325. height: 40rpx;
  326. background: #F8C008;
  327. border-radius: 20rpx;
  328. image {
  329. width: 24rpx;
  330. height: 24rpx;
  331. }
  332. }
  333. }
  334. .personal-list {
  335. margin-bottom: 16rpx;
  336. padding: 0 16rpx;
  337. background: #FFFFFF;
  338. border-radius: 16rpx;
  339. &:last-child {
  340. margin-bottom: 0;
  341. }
  342. }
  343. .personal-info-item {
  344. min-height: 100rpx;
  345. border-bottom: 1rpx solid #F1F3F8;
  346. &:last-child {
  347. border-bottom: none;
  348. }
  349. .label_width {
  350. width: 200rpx;
  351. display: inline-block;
  352. }
  353. }
  354. }
  355. .footer {
  356. width: 100%;
  357. bottom: 0;
  358. position: fixed;
  359. padding: 22rpx 32rpx 56rpx;
  360. background: #FFFFFF;
  361. .submit-btn {
  362. font-weight: bold;
  363. font-size: 32rpx;
  364. text-align: center;
  365. line-height: 88rpx;
  366. background: #F8C008;
  367. border-radius: 16rpx;
  368. }
  369. }
  370. </style>