@uxda/appkit 4.3.8 → 4.3.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/.eslintrc.mjs +7 -7
  2. package/COMPONENT_USAGE.md +1523 -1523
  3. package/PROJECT_DOCS.md +142 -142
  4. package/README.md +187 -187
  5. package/babel.config.js +12 -12
  6. package/dist/appkit.css +3 -48
  7. package/dist/index.js +84 -152
  8. package/package.json +82 -79
  9. package/project.config.json +15 -15
  10. package/project.tt.json +13 -13
  11. package/rollup.config.mjs +78 -78
  12. package/src/Appkit.ts +72 -72
  13. package/src/balance/api/endpoints.ts +133 -133
  14. package/src/balance/api/index.ts +118 -118
  15. package/src/balance/components/AccountView.vue +770 -770
  16. package/src/balance/components/BalanceCard.vue +210 -210
  17. package/src/balance/components/BalanceReminder.vue +84 -84
  18. package/src/balance/components/ConsumptionFilter.vue +218 -218
  19. package/src/balance/components/ConsumptionRules.vue +68 -68
  20. package/src/balance/components/DateFilter.vue +259 -259
  21. package/src/balance/components/DateRange.vue +111 -111
  22. package/src/balance/components/ListFilter.vue +62 -62
  23. package/src/balance/components/ListFilterPicker.vue +191 -191
  24. package/src/balance/components/PromoterCard.vue +307 -307
  25. package/src/balance/components/SecondBalance.vue +77 -77
  26. package/src/balance/components/Tip.vue +45 -45
  27. package/src/balance/components/index.ts +8 -8
  28. package/src/balance/types.ts +99 -99
  29. package/src/components/bt-cropper/index.vue +730 -730
  30. package/src/components/bt-cropper/utils/calcCropper.js +42 -42
  31. package/src/components/bt-cropper/utils/calcImagePosition.js +23 -23
  32. package/src/components/bt-cropper/utils/calcImageSize.js +37 -37
  33. package/src/components/bt-cropper/utils/calcPointDistance.js +12 -12
  34. package/src/components/bt-cropper/utils/calcRightAndBottom.js +7 -7
  35. package/src/components/bt-cropper/utils/ratio.js +3 -3
  36. package/src/components/bt-cropper/utils/tools.js +25 -25
  37. package/src/components/dd-area/index.vue +225 -225
  38. package/src/components/dd-icon/doc.md +21 -21
  39. package/src/components/dd-icon/index.vue +23 -23
  40. package/src/components/dd-notice-bar/index.vue +78 -78
  41. package/src/components/dd-search/doc.md +34 -34
  42. package/src/components/dd-search/index.vue +168 -168
  43. package/src/components/dd-selector/index.vue +124 -124
  44. package/src/components/dd-skeleton/doc.md +19 -19
  45. package/src/components/dd-skeleton/index.vue +36 -36
  46. package/src/global.ts +6 -6
  47. package/src/index.ts +101 -101
  48. package/src/main.scss +1 -1
  49. package/src/notice/api/endpoints.ts +54 -54
  50. package/src/notice/api/index.ts +121 -121
  51. package/src/notice/components/NoticeBanner.vue +247 -247
  52. package/src/notice/components/NoticeEntry.vue +99 -99
  53. package/src/notice/components/NoticeList.vue +311 -311
  54. package/src/notice/components/NoticeList2.vue +240 -400
  55. package/src/notice/components/NoticePopup.vue +163 -163
  56. package/src/notice/components/index.ts +6 -6
  57. package/src/notice/components/useCommonList.ts +86 -86
  58. package/src/notice/components/useNotice.ts +35 -35
  59. package/src/notice/index.ts +1 -1
  60. package/src/notice/types.ts +25 -25
  61. package/src/payment/api/config.ts +7 -7
  62. package/src/payment/api/endpoints.ts +96 -96
  63. package/src/payment/api/index.ts +107 -107
  64. package/src/payment/components/AmountPicker.vue +90 -90
  65. package/src/payment/components/RechargeResult.vue +69 -69
  66. package/src/payment/components/RechargeView.vue +195 -191
  67. package/src/payment/components/RightsPicker.vue +105 -105
  68. package/src/payment/components/TradeView.vue +365 -363
  69. package/src/payment/components/UserAgreement.vue +234 -234
  70. package/src/payment/components/index.ts +22 -22
  71. package/src/payment/index.ts +5 -5
  72. package/src/payment/services/index.ts +16 -16
  73. package/src/payment/services/invoke-recharge.ts +25 -25
  74. package/src/payment/services/request-payment.ts +130 -130
  75. package/src/payment/types.ts +33 -33
  76. package/src/register/components/SelfRegistration.vue +233 -233
  77. package/src/register/components/index.ts +2 -2
  78. package/src/scenarios/components/SharePoster.vue +364 -364
  79. package/src/scenarios/components/index.ts +2 -2
  80. package/src/scenarios/components/poster-paste.vue +93 -93
  81. package/src/scenarios/components/share-poster.md +273 -273
  82. package/src/shared/components/AppDrawer.vue +53 -53
  83. package/src/shared/components/AppVerify.vue +128 -128
  84. package/src/shared/components/DeviceVersion.vue +78 -78
  85. package/src/shared/components/EmptyView.vue +33 -33
  86. package/src/shared/components/OcrBusinessLicense.vue +137 -137
  87. package/src/shared/components/OcrIcon.vue +229 -229
  88. package/src/shared/components/PageHeader.vue +84 -84
  89. package/src/shared/components/index.ts +8 -8
  90. package/src/shared/composables/index.ts +9 -9
  91. package/src/shared/composables/useAmount.ts +46 -46
  92. package/src/shared/composables/useCountdown.ts +46 -46
  93. package/src/shared/composables/useCrypto.ts +76 -76
  94. package/src/shared/composables/useDeviceEnv.ts +26 -26
  95. package/src/shared/composables/useDragBox.ts +97 -97
  96. package/src/shared/composables/useEncode.ts +43 -43
  97. package/src/shared/composables/useLogger.ts +144 -144
  98. package/src/shared/composables/useSafeArea.ts +46 -46
  99. package/src/shared/composables/useTabbar.ts +24 -24
  100. package/src/shared/composables/useUpload.ts +61 -61
  101. package/src/shared/composables/useValidator.ts +32 -32
  102. package/src/shared/composables/useWxAuth.ts +48 -48
  103. package/src/shared/http/Http.ts +148 -148
  104. package/src/shared/http/index.ts +1 -1
  105. package/src/shared/http/types.ts +163 -163
  106. package/src/shared/index.ts +9 -9
  107. package/src/shared/tracking/directives/index.ts +40 -40
  108. package/src/shared/tracking/examples/page-tracking-template.vue +27 -27
  109. package/src/shared/weixin/index.ts +9 -9
  110. package/src/shared/weixin/jssdk.ts +103 -103
  111. package/src/shared/weixin/payment.ts +38 -38
  112. package/src/styles/vars.scss +3 -3
  113. package/src/user/api/endpoints.ts +17 -17
  114. package/src/user/api/index.ts +123 -123
  115. package/src/user/components/LoginSetting.vue +114 -114
  116. package/src/user/components/UserAuth.vue +218 -218
  117. package/src/user/components/UserBinding.vue +277 -277
  118. package/src/user/components/UserBindingSuccess.vue +80 -80
  119. package/src/user/components/UserEntry.vue +139 -139
  120. package/src/user/components/UserFeedback.vue +427 -427
  121. package/src/user/components/UserFeedbackEntry.vue +175 -175
  122. package/src/user/components/UserHeadCrop.vue +65 -65
  123. package/src/user/components/UserInfo.vue +709 -709
  124. package/src/user/components/UserResourceEmpty.vue +75 -75
  125. package/src/user/components/index.ts +23 -23
  126. package/src/user/index.ts +1 -1
  127. package/src/utils/utils.ts +33 -33
  128. package/tsconfig.json +30 -30
  129. package/types/global.d.ts +22 -22
  130. package/types/vue.d.ts +10 -10
  131. package/dist/assets/asset-DcH8Kg-2 +0 -1
@@ -1,709 +1,709 @@
1
- <template>
2
- <ScrollView :scroll-y="!userState.visible && !avatarVisible" class="user-info">
3
- <DdSkeleton v-if="firstLoading" :row="3"></DdSkeleton>
4
- <div v-else class="user-info-wrap">
5
- <div class="user-info-tit">账号信息</div>
6
- <div class="user-info-head">
7
- <div class="user-info-head-avatar" v-track-click="'用户信息-头像'" @click="avatarVisible = true">
8
- <img class="user-info-head-img" mode="aspectFit" v-if="userInfo.avatar" :src="userInfo.avatar" alt="" />
9
- <img class="user-info-head-img" mode="aspectFit" v-else
10
- src="https://cdn.ddjf.com/static/images/wx-yunservice/account-head.png" alt="" />
11
- <div class="user-info-head-upload">
12
- <img class="user-info-head-upload-icon" mode="aspectFit"
13
- src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzQiIGhlaWdodD0iMzQiIHZpZXdCb3g9IjAgMCAzNCAzNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yMi4wOTk5IDE4LjQyMjRDMjIuMDk5OSAxNS41ODMyIDE5LjgxNjYgMTMuMjgxNiAxNi45OTk5IDEzLjI4MTZDMTQuMTgzMyAxMy4yODE2IDExLjg5OTkgMTUuNTgzMiAxMS44OTk5IDE4LjQyMjRDMTEuODk5OSAyMS4yNjE2IDE0LjE4MzMgMjMuNTYzMiAxNi45OTk5IDIzLjU2MzJDMTkuODE2NiAyMy41NjMyIDIyLjA5OTkgMjEuMjYxNiAyMi4wOTk5IDE4LjQyMjRWMTguNDIyNFoiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMi41NSIgc3Ryb2tlLWxpbmVjYXA9InNxdWFyZSIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTIzLjc5OTkgNS45OTg4QzIzLjc5OTkgNi4yMzUzOSAyMy45OTAyIDYuNDI3MiAyNC4yMjQ5IDYuNDI3MkgyNS45MjVDMjkuNDQ1OCA2LjQyNzIgMzIuMyA5LjMwNDIxIDMyLjMgMTIuODUzMlYyMy45OTE2QzMyLjMgMjcuNTQwNiAyOS40NDU4IDMwLjQxNzYgMjUuOTI1IDMwLjQxNzZIOC4wNzQ5NEM0LjU1NDE0IDMwLjQxNzYgMS42OTk5NSAyNy41NDA2IDEuNjk5OTUgMjMuOTkxNlYxMi44NTMyQzEuNjk5OTUgOS4zMDQyMSA0LjU1NDE0IDYuNDI3MiA4LjA3NDk0IDYuNDI3Mkg5Ljc3NDk1QzEwLjAwOTcgNi40MjcyIDEwLjIgNi4yMzUzOSAxMC4yIDUuOTk4OEMxMC4yIDUuNzA5NDkgMTAuMjQwNiA1LjQyOTc1IDEwLjMxNjUgNS4xNjUwNkMxMC42NzQ4IDMuOTE0NTEgMTEuODE4OSAzIDEzLjE3NSAzSDIwLjgyNUMyMi40NjggMyAyMy43OTk5IDQuMzQyNjEgMjMuNzk5OSA1Ljk5ODhWNS45OTg4WiIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIyLjU1IiBzdHJva2UtbGluZWNhcD0ic3F1YXJlIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNy42NDk5IDEwLjI4MjhDOC44MjM1MSAxMC4yODI4IDkuNzc0OSAxMS4yNDE4IDkuNzc0OSAxMi40MjQ4QzkuNzc0OSAxMy42MDc4IDguODIzNTEgMTQuNTY2OCA3LjY0OTkgMTQuNTY2OEM2LjQ3NjMgMTQuNTY2OCA1LjUyNDkgMTMuNjA3OCA1LjUyNDkgMTIuNDI0OEM1LjUyNDkgMTEuMjQxOCA2LjQ3NjMgMTAuMjgyOCA3LjY0OTkgMTAuMjgyOFoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo="
14
- alt="" />
15
- </div>
16
- </div>
17
- <nut-cell title="登录手机号" is-link :desc="encodePhone(userInfo.mobile || '')" v-track-click="'用户信息-登录手机号'" @click="toBinding" />
18
- <nut-cell v-if="props.isPersonal" title="昵称" is-link v-track-click="'用户信息-昵称'" @click="onNickNameChange"
19
- :desc="userInfo?.nickName || '--'" />
20
- <nut-cell v-else title="昵称" :desc="userInfo?.nickName || '--'" />
21
- <nut-cell title="认证信息" is-link v-track-click="'用户信息-认证信息'" @click="toAuth">
22
- <template #desc>
23
- <span v-if="userInfo?.verifyResult === 1">已认证</span>
24
- <span v-if="userInfo?.verifyResult === 0" style="color: #e8523f">已失效,重新认证</span>
25
- <span v-if="userInfo?.verifyResult != 0 && userInfo?.verifyResult != 1"
26
- style="color: #017fff">未认证,去认证</span>
27
- </template>
28
- </nut-cell>
29
- </div>
30
- <div v-if="hasQiyezuhu" class="user-info-tit">企业/团队</div>
31
- <div class="user-info-team">
32
- <div v-if="hasQiyezuhu" v-for="(item, key) in userInfo.tenantInfoList" :key="key" class="user-info-team-item">
33
- <div class="user-info-team-item-avatar">
34
- <img v-if="item.tenantLogo" class="user-info-team-item-avatar-img" mode="aspectFit" :src="item.tenantLogo"
35
- alt="" />
36
- <img v-else class="user-info-team-item-avatar-img empty" mode="aspectFit"
37
- src="https://cdn.ddjf.com/static/images/customer-center/tenant-logo.png" alt="" />
38
- </div>
39
- <div class="user-info-team-item-bd">
40
- <div class="user-info-team-item-title">{{ item.tenantName }}</div>
41
- <div class="user-info-team-item-app" v-if="item.appRoleInfo">
42
- <div class="user-info-team-item-app-tag" v-for="(aitem, akey) in item.appRoleInfo || []" :key="akey">
43
- {{ aitem.appAbbr }}
44
- </div>
45
- <div class="user-info-team-item-role-btn" v-track-click="'用户信息-角色详情'" @click="toShowRole(item)">
46
- 角色详情
47
- <img :class="{ showRole: item.showRole }" class="user-info-team-item-role-btn-icon"
48
- src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTE4IDlMMTIgMTVMNiA5IiBzdHJva2U9IiMwMTdGRkYiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+Cjwvc3ZnPgo="
49
- alt="" />
50
- </div>
51
- </div>
52
- <div class="user-info-team-item-role" v-if="item.showRole">
53
- <div class="user-info-team-item-role-item" v-for="(aitem, akey) in item.appRoleInfo || []" :key="akey">
54
- <div class="user-info-team-item-role-item-name">
55
- {{ aitem.appAbbr }}
56
- </div>
57
- <div class="user-info-team-item-role-item-info">
58
- {{ aitem.roleName }}
59
- </div>
60
- </div>
61
- </div>
62
- <div class="user-info-team-item-user">
63
- {{ item.fullName }}
64
- <img v-track-click="'用户信息-用户名'" @click="toUserNameChange(item)" class="user-info-team-item-user-icon"
65
- src="https://cdn.ddjf.com/static/images/appkit/edit.png" alt="" />
66
- </div>
67
- <div class="user-info-team-item-dept">
68
- <div v-for="(ditem, dkey) in item.deptNames" :key="dkey" class="user-info-team-item-dept-item">
69
- {{ ditem }}
70
- </div>
71
- </div>
72
- </div>
73
- </div>
74
- </div>
75
-
76
- <div class="user-info-ft">
77
- <nut-button v-if="!isApp()" class="user-info-ft-btn" style="width: 100%; margin-top: 12px" v-track-click="'用户信息-退出登录'" @click="toLogout" plain
78
- type="primary">退出登录</nut-button>
79
- </div>
80
- </div>
81
- </ScrollView>
82
-
83
- <!-- 修改用户名弹框 -->
84
- <nut-dialog title="输入新的用户名" :border="false" pop-class="change-username-popup" v-model:visible="userState.visible"
85
- @cancel="onUserNameCancel">
86
- <nut-input :max-length="20" placeholder="请输入新的用户名" v-model="userState.value" />
87
- <template #footer>
88
- <nut-button class="change-username-popup-cancel" type="default" v-track-click="'用户信息-修改用户名-取消'" @click="onUserNameCancel">
89
- 取消
90
- </nut-button>
91
- <nut-button class="change-username-popup-ok" type="primary" v-track-click="'用户信息-修改用户名-确定'" @click="onUserNameOk">
92
- 确定
93
- </nut-button>
94
- </template>
95
- </nut-dialog>
96
-
97
- <!-- 修改昵称弹框 -->
98
- <nut-dialog title="输入新的昵称" :border="false" pop-class="change-username-popup" v-model:visible="nickNameState.visible"
99
- @cancel="onNickNameCancel">
100
- <input v-model="nickNameState.value" style="
101
- background: #f5f5f5;
102
- border-radius: 6px;
103
- line-height: 40px;
104
- padding: 10px 25px;
105
- font-size: 16px;
106
- " :max-length="20" placeholder="请输入新的昵称" type="nickname" />
107
-
108
- <template #footer>
109
- <nut-button class="change-username-popup-cancel" type="default" v-track-click="'用户信息-修改昵称-取消'" @click="onNickNameCancel">
110
- 取消
111
- </nut-button>
112
- <nut-button class="change-username-popup-ok" type="primary" v-track-click="'用户信息-修改昵称-确定'" @click="onNickNameOk">
113
- 确定
114
- </nut-button>
115
- </template>
116
- </nut-dialog>
117
-
118
- <!-- 修改头像弹框 -->
119
- <nut-popup pop-class="upload-avatar-popup" style="background: transparent" v-model:visible="avatarVisible"
120
- :overlay-style="{ background: 'rgba(0, 0, 0, 0.9)' }">
121
- <div class="upload-avatar-popup-box">
122
- <img class="upload-avatar-popup-avatar" mode="aspectFit" v-if="userInfo.avatar" :src="userInfo.avatar" alt="" />
123
- <img class="upload-avatar-popup-avatar" mode="aspectFit" v-else
124
- src="https://cdn.ddjf.com/static/images/wx-yunservice/account-head.png" alt="" />
125
- <div class="upload-avatar-popup-btn" v-track-click="'用户信息-更换头像'" @click="toUpload">更换头像</div>
126
- </div>
127
- </nut-popup>
128
- </template>
129
-
130
- <script lang="ts" setup>
131
- import Taro, { useDidShow, showToast, showLoading, hideLoading, uploadFile, showModal, chooseMedia } from "@tarojs/taro";
132
- import { ref, onMounted, reactive, onUnmounted } from "vue";
133
- import { useAppKitOptions } from "../../Appkit";
134
- import { useEncode } from "../../shared/composables/useEncode";
135
- import DdSkeleton from "../../components/dd-skeleton/index.vue";
136
- import { useHttp } from "../api";
137
- import { ScrollView } from '@tarojs/components'
138
- import { isApp } from '../../utils/utils'
139
-
140
- const props = withDefaults(
141
- defineProps<{
142
- miniType?: string;
143
- app?: string;
144
- userId: string;
145
- hasQiyezuhu: number;
146
- isPersonal: number;
147
- }>(),
148
- {
149
- miniType: "05",
150
- app: "",
151
- userId: "",
152
- hasQiyezuhu: 0,
153
- isPersonal: 0,
154
- }
155
- );
156
-
157
- const { encodePhone } = useEncode();
158
-
159
- useDidShow(() => {
160
- getUserInfoByUserId();
161
- });
162
- onMounted(() => {
163
- Taro.eventCenter.on("USER-HEAD-CROP-OK", updateImage);
164
- });
165
- onUnmounted(() => {
166
- Taro.eventCenter.off("USER-HEAD-CROP-OK");
167
- });
168
-
169
- const firstLoading = ref(true);
170
- const userInfo = ref<any>({});
171
- // 根据用户id,查询用户所在租户列表
172
- function getUserInfoByUserId() {
173
- const $http = useHttp();
174
-
175
- $http
176
- .get(`/cas/sysAccount/getAccountInfo/${props.userId}`)
177
- .then((result: any) => {
178
- userInfo.value = result;
179
- firstLoading.value = false;
180
- })
181
- .catch(() => {
182
- firstLoading.value = false;
183
- });
184
- }
185
-
186
- // 修改头像弹框
187
- const avatarVisible = ref(false);
188
-
189
- // 去上传头像
190
- async function toUpload() {
191
- if (!userInfo.value.avatar && Taro.getEnv() !== "WEB") {
192
- const profile = await Taro.getUserProfile({
193
- desc: "头像用于改变默认头像",
194
- });
195
-
196
- const res = await Taro.downloadFile({
197
- url: profile.userInfo.avatarUrl,
198
- });
199
-
200
- updateImage(res.tempFilePath);
201
- } else {
202
- let res = await chooseMedia({
203
- count: 1,
204
- sourceType: ['album'], // "camera" | "album"
205
- });
206
- if (res.tempFiles) {
207
- const { tempFilePath } = res.tempFiles[0];
208
-
209
- if (Taro.getEnv() === "WEB") {
210
- updateImage(tempFilePath);
211
- return
212
- }
213
-
214
- emits("crop", tempFilePath);
215
- }
216
- }
217
- }
218
-
219
- // 上传图片
220
- async function updateImage(filePath: string) {
221
- showLoading({
222
- title: "上传中...",
223
- });
224
- const appkitOptions = useAppKitOptions();
225
- const $http = useHttp();
226
-
227
- let Res: any = await uploadFile({
228
- url: `${appkitOptions.baseUrl()}/cas/file/uploadImg`,
229
- filePath: filePath,
230
- name: "file",
231
- formData: {
232
- objectNo: `${userInfo.value.mobile}${Date.now()}`,
233
- objectTypeCode: `MINI_HEADIMAGE${props.miniType}`,
234
- },
235
- header: {
236
- token: appkitOptions.tempToken() || appkitOptions.token(),
237
- },
238
- });
239
- avatarVisible.value = false;
240
-
241
- const res = JSON.parse(Res.data);
242
- if (res.success) {
243
- $http
244
- .post("/cas/sysUser/update", {
245
- appCode: props.app,
246
- avatar: res.result,
247
- userId: props.userId,
248
- })
249
- .then(() => {
250
- hideLoading();
251
- showToast({ title: "头像上传成功", icon: "none" });
252
- getUserInfoByUserId();
253
- emits("avatar-success", res.result);
254
- })
255
- .catch(() => {
256
- hideLoading();
257
- });
258
- } else {
259
- hideLoading();
260
- }
261
- }
262
-
263
- // 查看角色详情
264
- function toShowRole(item: any) {
265
- item.showRole = !item.showRole;
266
- }
267
-
268
- const nickNameState = reactive({
269
- visible: false,
270
- value: "",
271
- });
272
- // 更换用户名
273
- const userState = reactive({
274
- visible: false,
275
- value: "",
276
- oldName: "",
277
- tenantId: "",
278
- });
279
- function toUserNameChange(item: any) {
280
- userState.visible = true;
281
- userState.oldName = item.fullName;
282
- userState.tenantId = item.tenantId;
283
- }
284
- function onUserNameCancel() {
285
- userState.visible = false;
286
- userState.value = "";
287
- userState.oldName = "";
288
- userState.tenantId = "";
289
- }
290
-
291
- function onNickNameCancel() {
292
- nickNameState.visible = false;
293
- nickNameState.value = "";
294
- }
295
- function onNickNameChange() {
296
- nickNameState.visible = true;
297
- nickNameState.value = "";
298
- }
299
- function onUserNameOk() {
300
- if (!userState.value) {
301
- return showToast({
302
- title: "请输入用户名",
303
- icon: "none",
304
- });
305
- }
306
- if (userState.value === userState.oldName) {
307
- return showToast({
308
- title: "用户名不能与原用户名相同",
309
- icon: "none",
310
- });
311
- }
312
-
313
- const $http = useHttp();
314
-
315
- $http
316
- .post("/cas/sysUser/updateUserInfoByTenantId", {
317
- fullName: userState.value,
318
- tenantId: userState.tenantId,
319
- userId: props.userId,
320
- })
321
- .then(() => {
322
- showToast({ title: "用户名修改成功", icon: "none" });
323
- getUserInfoByUserId();
324
- onUserNameCancel();
325
- emits("username-success");
326
- });
327
- }
328
-
329
- function onNickNameOk() {
330
- if (!nickNameState.value) {
331
- return showToast({
332
- title: "请输入昵称",
333
- icon: "none",
334
- });
335
- }
336
- // if (userState.value === userState.oldName) {
337
- // return showToast({
338
- // title: "用户名不能与原用户名相同",
339
- // icon: "none",
340
- // });
341
- // }
342
-
343
- const $http = useHttp();
344
-
345
- $http
346
- .post("/cas/sysAccount/updateAccountInfo", {
347
- nickName: nickNameState.value,
348
- })
349
- .then(() => {
350
- showToast({ title: "昵称修改成功", icon: "none" });
351
- getUserInfoByUserId();
352
- onNickNameCancel();
353
- // emits("username-success");
354
- });
355
- }
356
- // 退出登录
357
- function toLogout() {
358
- showModal({
359
- title: "提示",
360
- content: "确定要退出登录吗?",
361
- confirmText: "确定",
362
- success: async (e: any) => {
363
- if (e.confirm) {
364
- emits("logout");
365
- }
366
- },
367
- });
368
- }
369
-
370
- // 去绑定手机号
371
- function toBinding() {
372
- emits("binding", userInfo.value.mobile || "");
373
- }
374
-
375
- // 去认证页
376
- function toAuth() {
377
- emits(
378
- "auth",
379
- props.userId,
380
- userInfo.value?.verifyResult,
381
- userInfo.value?.mobile
382
- );
383
- }
384
-
385
- // 父组件事件
386
- const emits = defineEmits([
387
- "avatar-success",
388
- "logout",
389
- "crop",
390
- "binding",
391
- "username-success",
392
- "auth",
393
- ]);
394
-
395
- // 外部访问
396
- defineExpose({
397
- updateImage,
398
- });
399
- </script>
400
-
401
- <style lang="scss">
402
- .user-info {
403
- height: 100vh;
404
-
405
- .nut-cell {
406
- border-radius: 0px;
407
- }
408
-
409
- &-wrap {
410
- padding: 0 12px;
411
- padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
412
- box-sizing: border-box;
413
- min-height: 100%;
414
- }
415
-
416
- &-tit {
417
- height: 38px;
418
- display: flex;
419
- align-items: center;
420
- color: #666666;
421
- font-size: 12px;
422
- padding-left: 10px;
423
- }
424
-
425
- &-head {
426
- border-radius: 5px;
427
- background: #fff;
428
- padding: 30px 11px 0;
429
-
430
- &-avatar {
431
- position: relative;
432
- width: 80px;
433
- height: 80px;
434
- margin: 0 auto 25px;
435
- }
436
-
437
- &-img {
438
- width: 100%;
439
- height: 100%;
440
- overflow: hidden;
441
- border-radius: 50%;
442
- }
443
-
444
- &-upload {
445
- position: absolute;
446
- bottom: -2px;
447
- left: 52px;
448
- width: 29px;
449
- height: 29px;
450
- background: #333333;
451
- overflow: hidden;
452
- border-radius: 50%;
453
- display: flex;
454
- align-items: center;
455
- justify-content: center;
456
-
457
- &-icon {
458
- width: 17px;
459
- height: 17px;
460
- }
461
- }
462
- }
463
-
464
- &-team {
465
- &-item {
466
- border-radius: 5px;
467
- background: #fff;
468
- display: flex;
469
- padding: 15px;
470
- margin-bottom: 10px;
471
-
472
- &-avatar {
473
- width: 38px;
474
- height: 38px;
475
- margin-right: 15px;
476
- border-radius: 5px;
477
- background: rgba(1, 127, 255, 0.3);
478
- display: flex;
479
- align-items: center;
480
- justify-content: center;
481
-
482
- &-img {
483
- width: 100%;
484
- height: 100%;
485
- }
486
-
487
- .empty {
488
- width: 20px;
489
- height: 40px;
490
- }
491
- }
492
-
493
- &-title {
494
- font-size: 16px;
495
- font-weight: 500;
496
- margin-bottom: 5px;
497
- }
498
-
499
- &-app {
500
- display: flex;
501
- align-items: center;
502
- flex-wrap: wrap;
503
-
504
- &-tag {
505
- border: 1px solid rgba(53, 53, 53, 0.2);
506
- font-size: 10px;
507
- height: 18px;
508
- display: inline-flex;
509
- align-items: center;
510
- justify-content: center;
511
- padding: 0 6px;
512
- border-radius: 2px;
513
- margin: 0 10px 6px 0;
514
- }
515
- }
516
-
517
- &-bd {
518
- flex: 1;
519
- }
520
-
521
- &-role {
522
- padding: 10px;
523
- background: rgba(245, 245, 245, 0.5);
524
- border-radius: 5px;
525
- margin-bottom: 10px;
526
-
527
- &-btn {
528
- color: var(--app-primary-color, #017fff);
529
- font-size: 10px;
530
- display: inline-flex;
531
- align-items: center;
532
- margin-bottom: 6px;
533
-
534
- &-icon {
535
- width: 12px;
536
- height: 12px;
537
- position: relative;
538
- top: 1px;
539
-
540
- &.showRole {
541
- transform: rotate(180deg);
542
- }
543
- }
544
- }
545
-
546
- &-item {
547
- display: flex;
548
- font-size: 10px;
549
- margin-bottom: 10px;
550
-
551
- &:last-child {
552
- margin-bottom: 0;
553
- }
554
-
555
- &-name {
556
- opacity: 0.5;
557
- white-space: nowrap;
558
- margin-right: 10px;
559
- min-width: 40px;
560
- }
561
-
562
- &-info {
563
- flex: 1;
564
- color: #1a1a1a;
565
- }
566
- }
567
- }
568
-
569
- &-user {
570
- margin-bottom: 4px;
571
- font-size: 12px;
572
- display: flex;
573
- align-items: center;
574
-
575
- &-icon {
576
- width: 10px;
577
- height: 10px;
578
- margin-left: 4px;
579
- }
580
- }
581
-
582
- &-dept {
583
- display: flex;
584
- flex-wrap: wrap;
585
- font-size: 10px;
586
- color: rgba(26, 26, 26, 0.8);
587
-
588
- &-item {
589
- font-size: 10px;
590
- color: rgba(26, 26, 26, 0.5);
591
- margin: 4px 10px 4px 0;
592
-
593
- &:first-child {
594
- color: rgba(26, 26, 26, 0.8);
595
- }
596
- }
597
- }
598
- }
599
- }
600
-
601
- &-ft {
602
- &-btn {
603
- width: 100%;
604
- border-color: transparent !important;
605
- color: rgba(27, 63, 107, 0.8) !important;
606
- }
607
- }
608
-
609
- .nut-cell {
610
- padding: 11px 0;
611
- margin: 0;
612
- box-shadow: none;
613
- border-bottom: 1px solid #f0f0f0;
614
- font-size: 16px;
615
-
616
- .nut-cell__value {
617
- font-size: 16px;
618
- color: #000;
619
- }
620
-
621
- .nut-cell__link {
622
- color: #ccc;
623
- margin-left: 8px;
624
- }
625
- }
626
- }
627
-
628
- .upload-avatar-popup {
629
- &-box {
630
- display: flex;
631
- flex-direction: column;
632
- align-items: center;
633
- justify-content: center;
634
- }
635
-
636
- &-avatar {
637
- width: 320px;
638
- height: 320px;
639
- overflow: hidden;
640
- border-radius: 50%;
641
- margin-bottom: 50px;
642
- }
643
-
644
- &-btn {
645
- width: 106px;
646
- height: 37px;
647
- border-radius: 50px;
648
- border: 1px solid #ffffff;
649
- display: flex;
650
- justify-content: center;
651
- align-items: center;
652
- color: #ffffff;
653
- font-size: 16px;
654
- }
655
- }
656
-
657
- .change-username-popup {
658
- .nut-dialog {
659
- min-height: auto;
660
- }
661
-
662
- .nut-input {
663
- height: 40px;
664
- padding: 0;
665
- display: flex;
666
- align-items: center;
667
- font-size: 16px;
668
- border: none;
669
-
670
- .input-text {
671
- width: 100%;
672
- height: 100%;
673
- font-size: 14px;
674
- }
675
-
676
- .nut-input-value,
677
- .nut-input-inner,
678
- .nut-input-box {
679
- height: 100%;
680
- overflow: hidden;
681
- background: #f5f5f5;
682
- border-radius: 6px;
683
- }
684
-
685
- .nut-placeholder {
686
- color: #cccccc;
687
- line-height: 38px;
688
- height: 38px;
689
- }
690
-
691
- .nut-input-box {
692
- padding: 0 15px;
693
- }
694
- }
695
-
696
- &-cancel.nut-button {
697
- border-radius: 15px;
698
- font-size: 14px;
699
- height: 30px;
700
- }
701
-
702
- &-ok.nut-button {
703
- background: var(--app-primary-color, #017fff);
704
- height: 30px;
705
- font-size: 14px;
706
- border-radius: 15px;
707
- }
708
- }
709
- </style>
1
+ <template>
2
+ <ScrollView :scroll-y="!userState.visible && !avatarVisible" class="user-info">
3
+ <DdSkeleton v-if="firstLoading" :row="3"></DdSkeleton>
4
+ <div v-else class="user-info-wrap">
5
+ <div class="user-info-tit">账号信息</div>
6
+ <div class="user-info-head">
7
+ <div class="user-info-head-avatar" v-track-click="'用户信息-头像'" @click="avatarVisible = true">
8
+ <img class="user-info-head-img" mode="aspectFit" v-if="userInfo.avatar" :src="userInfo.avatar" alt="" />
9
+ <img class="user-info-head-img" mode="aspectFit" v-else
10
+ src="https://cdn.ddjf.com/static/images/wx-yunservice/account-head.png" alt="" />
11
+ <div class="user-info-head-upload">
12
+ <img class="user-info-head-upload-icon" mode="aspectFit"
13
+ src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzQiIGhlaWdodD0iMzQiIHZpZXdCb3g9IjAgMCAzNCAzNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yMi4wOTk5IDE4LjQyMjRDMjIuMDk5OSAxNS41ODMyIDE5LjgxNjYgMTMuMjgxNiAxNi45OTk5IDEzLjI4MTZDMTQuMTgzMyAxMy4yODE2IDExLjg5OTkgMTUuNTgzMiAxMS44OTk5IDE4LjQyMjRDMTEuODk5OSAyMS4yNjE2IDE0LjE4MzMgMjMuNTYzMiAxNi45OTk5IDIzLjU2MzJDMTkuODE2NiAyMy41NjMyIDIyLjA5OTkgMjEuMjYxNiAyMi4wOTk5IDE4LjQyMjRWMTguNDIyNFoiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMi41NSIgc3Ryb2tlLWxpbmVjYXA9InNxdWFyZSIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTIzLjc5OTkgNS45OTg4QzIzLjc5OTkgNi4yMzUzOSAyMy45OTAyIDYuNDI3MiAyNC4yMjQ5IDYuNDI3MkgyNS45MjVDMjkuNDQ1OCA2LjQyNzIgMzIuMyA5LjMwNDIxIDMyLjMgMTIuODUzMlYyMy45OTE2QzMyLjMgMjcuNTQwNiAyOS40NDU4IDMwLjQxNzYgMjUuOTI1IDMwLjQxNzZIOC4wNzQ5NEM0LjU1NDE0IDMwLjQxNzYgMS42OTk5NSAyNy41NDA2IDEuNjk5OTUgMjMuOTkxNlYxMi44NTMyQzEuNjk5OTUgOS4zMDQyMSA0LjU1NDE0IDYuNDI3MiA4LjA3NDk0IDYuNDI3Mkg5Ljc3NDk1QzEwLjAwOTcgNi40MjcyIDEwLjIgNi4yMzUzOSAxMC4yIDUuOTk4OEMxMC4yIDUuNzA5NDkgMTAuMjQwNiA1LjQyOTc1IDEwLjMxNjUgNS4xNjUwNkMxMC42NzQ4IDMuOTE0NTEgMTEuODE4OSAzIDEzLjE3NSAzSDIwLjgyNUMyMi40NjggMyAyMy43OTk5IDQuMzQyNjEgMjMuNzk5OSA1Ljk5ODhWNS45OTg4WiIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIyLjU1IiBzdHJva2UtbGluZWNhcD0ic3F1YXJlIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNy42NDk5IDEwLjI4MjhDOC44MjM1MSAxMC4yODI4IDkuNzc0OSAxMS4yNDE4IDkuNzc0OSAxMi40MjQ4QzkuNzc0OSAxMy42MDc4IDguODIzNTEgMTQuNTY2OCA3LjY0OTkgMTQuNTY2OEM2LjQ3NjMgMTQuNTY2OCA1LjUyNDkgMTMuNjA3OCA1LjUyNDkgMTIuNDI0OEM1LjUyNDkgMTEuMjQxOCA2LjQ3NjMgMTAuMjgyOCA3LjY0OTkgMTAuMjgyOFoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo="
14
+ alt="" />
15
+ </div>
16
+ </div>
17
+ <nut-cell title="登录手机号" is-link :desc="encodePhone(userInfo.mobile || '')" v-track-click="'用户信息-登录手机号'" @click="toBinding" />
18
+ <nut-cell v-if="props.isPersonal" title="昵称" is-link v-track-click="'用户信息-昵称'" @click="onNickNameChange"
19
+ :desc="userInfo?.nickName || '--'" />
20
+ <nut-cell v-else title="昵称" :desc="userInfo?.nickName || '--'" />
21
+ <nut-cell title="认证信息" is-link v-track-click="'用户信息-认证信息'" @click="toAuth">
22
+ <template #desc>
23
+ <span v-if="userInfo?.verifyResult === 1">已认证</span>
24
+ <span v-if="userInfo?.verifyResult === 0" style="color: #e8523f">已失效,重新认证</span>
25
+ <span v-if="userInfo?.verifyResult != 0 && userInfo?.verifyResult != 1"
26
+ style="color: #017fff">未认证,去认证</span>
27
+ </template>
28
+ </nut-cell>
29
+ </div>
30
+ <div v-if="hasQiyezuhu" class="user-info-tit">企业/团队</div>
31
+ <div class="user-info-team">
32
+ <div v-if="hasQiyezuhu" v-for="(item, key) in userInfo.tenantInfoList" :key="key" class="user-info-team-item">
33
+ <div class="user-info-team-item-avatar">
34
+ <img v-if="item.tenantLogo" class="user-info-team-item-avatar-img" mode="aspectFit" :src="item.tenantLogo"
35
+ alt="" />
36
+ <img v-else class="user-info-team-item-avatar-img empty" mode="aspectFit"
37
+ src="https://cdn.ddjf.com/static/images/customer-center/tenant-logo.png" alt="" />
38
+ </div>
39
+ <div class="user-info-team-item-bd">
40
+ <div class="user-info-team-item-title">{{ item.tenantName }}</div>
41
+ <div class="user-info-team-item-app" v-if="item.appRoleInfo">
42
+ <div class="user-info-team-item-app-tag" v-for="(aitem, akey) in item.appRoleInfo || []" :key="akey">
43
+ {{ aitem.appAbbr }}
44
+ </div>
45
+ <div class="user-info-team-item-role-btn" v-track-click="'用户信息-角色详情'" @click="toShowRole(item)">
46
+ 角色详情
47
+ <img :class="{ showRole: item.showRole }" class="user-info-team-item-role-btn-icon"
48
+ src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTE4IDlMMTIgMTVMNiA5IiBzdHJva2U9IiMwMTdGRkYiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+Cjwvc3ZnPgo="
49
+ alt="" />
50
+ </div>
51
+ </div>
52
+ <div class="user-info-team-item-role" v-if="item.showRole">
53
+ <div class="user-info-team-item-role-item" v-for="(aitem, akey) in item.appRoleInfo || []" :key="akey">
54
+ <div class="user-info-team-item-role-item-name">
55
+ {{ aitem.appAbbr }}
56
+ </div>
57
+ <div class="user-info-team-item-role-item-info">
58
+ {{ aitem.roleName }}
59
+ </div>
60
+ </div>
61
+ </div>
62
+ <div class="user-info-team-item-user">
63
+ {{ item.fullName }}
64
+ <img v-track-click="'用户信息-用户名'" @click="toUserNameChange(item)" class="user-info-team-item-user-icon"
65
+ src="https://cdn.ddjf.com/static/images/appkit/edit.png" alt="" />
66
+ </div>
67
+ <div class="user-info-team-item-dept">
68
+ <div v-for="(ditem, dkey) in item.deptNames" :key="dkey" class="user-info-team-item-dept-item">
69
+ {{ ditem }}
70
+ </div>
71
+ </div>
72
+ </div>
73
+ </div>
74
+ </div>
75
+
76
+ <div class="user-info-ft">
77
+ <nut-button v-if="!isApp()" class="user-info-ft-btn" style="width: 100%; margin-top: 12px" v-track-click="'用户信息-退出登录'" @click="toLogout" plain
78
+ type="primary">退出登录</nut-button>
79
+ </div>
80
+ </div>
81
+ </ScrollView>
82
+
83
+ <!-- 修改用户名弹框 -->
84
+ <nut-dialog title="输入新的用户名" :border="false" pop-class="change-username-popup" v-model:visible="userState.visible"
85
+ @cancel="onUserNameCancel">
86
+ <nut-input :max-length="20" placeholder="请输入新的用户名" v-model="userState.value" />
87
+ <template #footer>
88
+ <nut-button class="change-username-popup-cancel" type="default" v-track-click="'用户信息-修改用户名-取消'" @click="onUserNameCancel">
89
+ 取消
90
+ </nut-button>
91
+ <nut-button class="change-username-popup-ok" type="primary" v-track-click="'用户信息-修改用户名-确定'" @click="onUserNameOk">
92
+ 确定
93
+ </nut-button>
94
+ </template>
95
+ </nut-dialog>
96
+
97
+ <!-- 修改昵称弹框 -->
98
+ <nut-dialog title="输入新的昵称" :border="false" pop-class="change-username-popup" v-model:visible="nickNameState.visible"
99
+ @cancel="onNickNameCancel">
100
+ <input v-model="nickNameState.value" style="
101
+ background: #f5f5f5;
102
+ border-radius: 6px;
103
+ line-height: 40px;
104
+ padding: 10px 25px;
105
+ font-size: 16px;
106
+ " :max-length="20" placeholder="请输入新的昵称" type="nickname" />
107
+
108
+ <template #footer>
109
+ <nut-button class="change-username-popup-cancel" type="default" v-track-click="'用户信息-修改昵称-取消'" @click="onNickNameCancel">
110
+ 取消
111
+ </nut-button>
112
+ <nut-button class="change-username-popup-ok" type="primary" v-track-click="'用户信息-修改昵称-确定'" @click="onNickNameOk">
113
+ 确定
114
+ </nut-button>
115
+ </template>
116
+ </nut-dialog>
117
+
118
+ <!-- 修改头像弹框 -->
119
+ <nut-popup pop-class="upload-avatar-popup" style="background: transparent" v-model:visible="avatarVisible"
120
+ :overlay-style="{ background: 'rgba(0, 0, 0, 0.9)' }">
121
+ <div class="upload-avatar-popup-box">
122
+ <img class="upload-avatar-popup-avatar" mode="aspectFit" v-if="userInfo.avatar" :src="userInfo.avatar" alt="" />
123
+ <img class="upload-avatar-popup-avatar" mode="aspectFit" v-else
124
+ src="https://cdn.ddjf.com/static/images/wx-yunservice/account-head.png" alt="" />
125
+ <div class="upload-avatar-popup-btn" v-track-click="'用户信息-更换头像'" @click="toUpload">更换头像</div>
126
+ </div>
127
+ </nut-popup>
128
+ </template>
129
+
130
+ <script lang="ts" setup>
131
+ import Taro, { useDidShow, showToast, showLoading, hideLoading, uploadFile, showModal, chooseMedia } from "@tarojs/taro";
132
+ import { ref, onMounted, reactive, onUnmounted } from "vue";
133
+ import { useAppKitOptions } from "../../Appkit";
134
+ import { useEncode } from "../../shared/composables/useEncode";
135
+ import DdSkeleton from "../../components/dd-skeleton/index.vue";
136
+ import { useHttp } from "../api";
137
+ import { ScrollView } from '@tarojs/components'
138
+ import { isApp } from '../../utils/utils'
139
+
140
+ const props = withDefaults(
141
+ defineProps<{
142
+ miniType?: string;
143
+ app?: string;
144
+ userId: string;
145
+ hasQiyezuhu: number;
146
+ isPersonal: number;
147
+ }>(),
148
+ {
149
+ miniType: "05",
150
+ app: "",
151
+ userId: "",
152
+ hasQiyezuhu: 0,
153
+ isPersonal: 0,
154
+ }
155
+ );
156
+
157
+ const { encodePhone } = useEncode();
158
+
159
+ useDidShow(() => {
160
+ getUserInfoByUserId();
161
+ });
162
+ onMounted(() => {
163
+ Taro.eventCenter.on("USER-HEAD-CROP-OK", updateImage);
164
+ });
165
+ onUnmounted(() => {
166
+ Taro.eventCenter.off("USER-HEAD-CROP-OK");
167
+ });
168
+
169
+ const firstLoading = ref(true);
170
+ const userInfo = ref<any>({});
171
+ // 根据用户id,查询用户所在租户列表
172
+ function getUserInfoByUserId() {
173
+ const $http = useHttp();
174
+
175
+ $http
176
+ .get(`/cas/sysAccount/getAccountInfo/${props.userId}`)
177
+ .then((result: any) => {
178
+ userInfo.value = result;
179
+ firstLoading.value = false;
180
+ })
181
+ .catch(() => {
182
+ firstLoading.value = false;
183
+ });
184
+ }
185
+
186
+ // 修改头像弹框
187
+ const avatarVisible = ref(false);
188
+
189
+ // 去上传头像
190
+ async function toUpload() {
191
+ if (!userInfo.value.avatar && Taro.getEnv() !== "WEB") {
192
+ const profile = await Taro.getUserProfile({
193
+ desc: "头像用于改变默认头像",
194
+ });
195
+
196
+ const res = await Taro.downloadFile({
197
+ url: profile.userInfo.avatarUrl,
198
+ });
199
+
200
+ updateImage(res.tempFilePath);
201
+ } else {
202
+ let res = await chooseMedia({
203
+ count: 1,
204
+ sourceType: ['album'], // "camera" | "album"
205
+ });
206
+ if (res.tempFiles) {
207
+ const { tempFilePath } = res.tempFiles[0];
208
+
209
+ if (Taro.getEnv() === "WEB") {
210
+ updateImage(tempFilePath);
211
+ return
212
+ }
213
+
214
+ emits("crop", tempFilePath);
215
+ }
216
+ }
217
+ }
218
+
219
+ // 上传图片
220
+ async function updateImage(filePath: string) {
221
+ showLoading({
222
+ title: "上传中...",
223
+ });
224
+ const appkitOptions = useAppKitOptions();
225
+ const $http = useHttp();
226
+
227
+ let Res: any = await uploadFile({
228
+ url: `${appkitOptions.baseUrl()}/cas/file/uploadImg`,
229
+ filePath: filePath,
230
+ name: "file",
231
+ formData: {
232
+ objectNo: `${userInfo.value.mobile}${Date.now()}`,
233
+ objectTypeCode: `MINI_HEADIMAGE${props.miniType}`,
234
+ },
235
+ header: {
236
+ token: appkitOptions.tempToken() || appkitOptions.token(),
237
+ },
238
+ });
239
+ avatarVisible.value = false;
240
+
241
+ const res = JSON.parse(Res.data);
242
+ if (res.success) {
243
+ $http
244
+ .post("/cas/sysUser/update", {
245
+ appCode: props.app,
246
+ avatar: res.result,
247
+ userId: props.userId,
248
+ })
249
+ .then(() => {
250
+ hideLoading();
251
+ showToast({ title: "头像上传成功", icon: "none" });
252
+ getUserInfoByUserId();
253
+ emits("avatar-success", res.result);
254
+ })
255
+ .catch(() => {
256
+ hideLoading();
257
+ });
258
+ } else {
259
+ hideLoading();
260
+ }
261
+ }
262
+
263
+ // 查看角色详情
264
+ function toShowRole(item: any) {
265
+ item.showRole = !item.showRole;
266
+ }
267
+
268
+ const nickNameState = reactive({
269
+ visible: false,
270
+ value: "",
271
+ });
272
+ // 更换用户名
273
+ const userState = reactive({
274
+ visible: false,
275
+ value: "",
276
+ oldName: "",
277
+ tenantId: "",
278
+ });
279
+ function toUserNameChange(item: any) {
280
+ userState.visible = true;
281
+ userState.oldName = item.fullName;
282
+ userState.tenantId = item.tenantId;
283
+ }
284
+ function onUserNameCancel() {
285
+ userState.visible = false;
286
+ userState.value = "";
287
+ userState.oldName = "";
288
+ userState.tenantId = "";
289
+ }
290
+
291
+ function onNickNameCancel() {
292
+ nickNameState.visible = false;
293
+ nickNameState.value = "";
294
+ }
295
+ function onNickNameChange() {
296
+ nickNameState.visible = true;
297
+ nickNameState.value = "";
298
+ }
299
+ function onUserNameOk() {
300
+ if (!userState.value) {
301
+ return showToast({
302
+ title: "请输入用户名",
303
+ icon: "none",
304
+ });
305
+ }
306
+ if (userState.value === userState.oldName) {
307
+ return showToast({
308
+ title: "用户名不能与原用户名相同",
309
+ icon: "none",
310
+ });
311
+ }
312
+
313
+ const $http = useHttp();
314
+
315
+ $http
316
+ .post("/cas/sysUser/updateUserInfoByTenantId", {
317
+ fullName: userState.value,
318
+ tenantId: userState.tenantId,
319
+ userId: props.userId,
320
+ })
321
+ .then(() => {
322
+ showToast({ title: "用户名修改成功", icon: "none" });
323
+ getUserInfoByUserId();
324
+ onUserNameCancel();
325
+ emits("username-success");
326
+ });
327
+ }
328
+
329
+ function onNickNameOk() {
330
+ if (!nickNameState.value) {
331
+ return showToast({
332
+ title: "请输入昵称",
333
+ icon: "none",
334
+ });
335
+ }
336
+ // if (userState.value === userState.oldName) {
337
+ // return showToast({
338
+ // title: "用户名不能与原用户名相同",
339
+ // icon: "none",
340
+ // });
341
+ // }
342
+
343
+ const $http = useHttp();
344
+
345
+ $http
346
+ .post("/cas/sysAccount/updateAccountInfo", {
347
+ nickName: nickNameState.value,
348
+ })
349
+ .then(() => {
350
+ showToast({ title: "昵称修改成功", icon: "none" });
351
+ getUserInfoByUserId();
352
+ onNickNameCancel();
353
+ // emits("username-success");
354
+ });
355
+ }
356
+ // 退出登录
357
+ function toLogout() {
358
+ showModal({
359
+ title: "提示",
360
+ content: "确定要退出登录吗?",
361
+ confirmText: "确定",
362
+ success: async (e: any) => {
363
+ if (e.confirm) {
364
+ emits("logout");
365
+ }
366
+ },
367
+ });
368
+ }
369
+
370
+ // 去绑定手机号
371
+ function toBinding() {
372
+ emits("binding", userInfo.value.mobile || "");
373
+ }
374
+
375
+ // 去认证页
376
+ function toAuth() {
377
+ emits(
378
+ "auth",
379
+ props.userId,
380
+ userInfo.value?.verifyResult,
381
+ userInfo.value?.mobile
382
+ );
383
+ }
384
+
385
+ // 父组件事件
386
+ const emits = defineEmits([
387
+ "avatar-success",
388
+ "logout",
389
+ "crop",
390
+ "binding",
391
+ "username-success",
392
+ "auth",
393
+ ]);
394
+
395
+ // 外部访问
396
+ defineExpose({
397
+ updateImage,
398
+ });
399
+ </script>
400
+
401
+ <style lang="scss">
402
+ .user-info {
403
+ height: 100vh;
404
+
405
+ .nut-cell {
406
+ border-radius: 0px;
407
+ }
408
+
409
+ &-wrap {
410
+ padding: 0 12px;
411
+ padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
412
+ box-sizing: border-box;
413
+ min-height: 100%;
414
+ }
415
+
416
+ &-tit {
417
+ height: 38px;
418
+ display: flex;
419
+ align-items: center;
420
+ color: #666666;
421
+ font-size: 12px;
422
+ padding-left: 10px;
423
+ }
424
+
425
+ &-head {
426
+ border-radius: 5px;
427
+ background: #fff;
428
+ padding: 30px 11px 0;
429
+
430
+ &-avatar {
431
+ position: relative;
432
+ width: 80px;
433
+ height: 80px;
434
+ margin: 0 auto 25px;
435
+ }
436
+
437
+ &-img {
438
+ width: 100%;
439
+ height: 100%;
440
+ overflow: hidden;
441
+ border-radius: 50%;
442
+ }
443
+
444
+ &-upload {
445
+ position: absolute;
446
+ bottom: -2px;
447
+ left: 52px;
448
+ width: 29px;
449
+ height: 29px;
450
+ background: #333333;
451
+ overflow: hidden;
452
+ border-radius: 50%;
453
+ display: flex;
454
+ align-items: center;
455
+ justify-content: center;
456
+
457
+ &-icon {
458
+ width: 17px;
459
+ height: 17px;
460
+ }
461
+ }
462
+ }
463
+
464
+ &-team {
465
+ &-item {
466
+ border-radius: 5px;
467
+ background: #fff;
468
+ display: flex;
469
+ padding: 15px;
470
+ margin-bottom: 10px;
471
+
472
+ &-avatar {
473
+ width: 38px;
474
+ height: 38px;
475
+ margin-right: 15px;
476
+ border-radius: 5px;
477
+ background: rgba(1, 127, 255, 0.3);
478
+ display: flex;
479
+ align-items: center;
480
+ justify-content: center;
481
+
482
+ &-img {
483
+ width: 100%;
484
+ height: 100%;
485
+ }
486
+
487
+ .empty {
488
+ width: 20px;
489
+ height: 40px;
490
+ }
491
+ }
492
+
493
+ &-title {
494
+ font-size: 16px;
495
+ font-weight: 500;
496
+ margin-bottom: 5px;
497
+ }
498
+
499
+ &-app {
500
+ display: flex;
501
+ align-items: center;
502
+ flex-wrap: wrap;
503
+
504
+ &-tag {
505
+ border: 1px solid rgba(53, 53, 53, 0.2);
506
+ font-size: 10px;
507
+ height: 18px;
508
+ display: inline-flex;
509
+ align-items: center;
510
+ justify-content: center;
511
+ padding: 0 6px;
512
+ border-radius: 2px;
513
+ margin: 0 10px 6px 0;
514
+ }
515
+ }
516
+
517
+ &-bd {
518
+ flex: 1;
519
+ }
520
+
521
+ &-role {
522
+ padding: 10px;
523
+ background: rgba(245, 245, 245, 0.5);
524
+ border-radius: 5px;
525
+ margin-bottom: 10px;
526
+
527
+ &-btn {
528
+ color: var(--app-primary-color, #017fff);
529
+ font-size: 10px;
530
+ display: inline-flex;
531
+ align-items: center;
532
+ margin-bottom: 6px;
533
+
534
+ &-icon {
535
+ width: 12px;
536
+ height: 12px;
537
+ position: relative;
538
+ top: 1px;
539
+
540
+ &.showRole {
541
+ transform: rotate(180deg);
542
+ }
543
+ }
544
+ }
545
+
546
+ &-item {
547
+ display: flex;
548
+ font-size: 10px;
549
+ margin-bottom: 10px;
550
+
551
+ &:last-child {
552
+ margin-bottom: 0;
553
+ }
554
+
555
+ &-name {
556
+ opacity: 0.5;
557
+ white-space: nowrap;
558
+ margin-right: 10px;
559
+ min-width: 40px;
560
+ }
561
+
562
+ &-info {
563
+ flex: 1;
564
+ color: #1a1a1a;
565
+ }
566
+ }
567
+ }
568
+
569
+ &-user {
570
+ margin-bottom: 4px;
571
+ font-size: 12px;
572
+ display: flex;
573
+ align-items: center;
574
+
575
+ &-icon {
576
+ width: 10px;
577
+ height: 10px;
578
+ margin-left: 4px;
579
+ }
580
+ }
581
+
582
+ &-dept {
583
+ display: flex;
584
+ flex-wrap: wrap;
585
+ font-size: 10px;
586
+ color: rgba(26, 26, 26, 0.8);
587
+
588
+ &-item {
589
+ font-size: 10px;
590
+ color: rgba(26, 26, 26, 0.5);
591
+ margin: 4px 10px 4px 0;
592
+
593
+ &:first-child {
594
+ color: rgba(26, 26, 26, 0.8);
595
+ }
596
+ }
597
+ }
598
+ }
599
+ }
600
+
601
+ &-ft {
602
+ &-btn {
603
+ width: 100%;
604
+ border-color: transparent !important;
605
+ color: rgba(27, 63, 107, 0.8) !important;
606
+ }
607
+ }
608
+
609
+ .nut-cell {
610
+ padding: 11px 0;
611
+ margin: 0;
612
+ box-shadow: none;
613
+ border-bottom: 1px solid #f0f0f0;
614
+ font-size: 16px;
615
+
616
+ .nut-cell__value {
617
+ font-size: 16px;
618
+ color: #000;
619
+ }
620
+
621
+ .nut-cell__link {
622
+ color: #ccc;
623
+ margin-left: 8px;
624
+ }
625
+ }
626
+ }
627
+
628
+ .upload-avatar-popup {
629
+ &-box {
630
+ display: flex;
631
+ flex-direction: column;
632
+ align-items: center;
633
+ justify-content: center;
634
+ }
635
+
636
+ &-avatar {
637
+ width: 320px;
638
+ height: 320px;
639
+ overflow: hidden;
640
+ border-radius: 50%;
641
+ margin-bottom: 50px;
642
+ }
643
+
644
+ &-btn {
645
+ width: 106px;
646
+ height: 37px;
647
+ border-radius: 50px;
648
+ border: 1px solid #ffffff;
649
+ display: flex;
650
+ justify-content: center;
651
+ align-items: center;
652
+ color: #ffffff;
653
+ font-size: 16px;
654
+ }
655
+ }
656
+
657
+ .change-username-popup {
658
+ .nut-dialog {
659
+ min-height: auto;
660
+ }
661
+
662
+ .nut-input {
663
+ height: 40px;
664
+ padding: 0;
665
+ display: flex;
666
+ align-items: center;
667
+ font-size: 16px;
668
+ border: none;
669
+
670
+ .input-text {
671
+ width: 100%;
672
+ height: 100%;
673
+ font-size: 14px;
674
+ }
675
+
676
+ .nut-input-value,
677
+ .nut-input-inner,
678
+ .nut-input-box {
679
+ height: 100%;
680
+ overflow: hidden;
681
+ background: #f5f5f5;
682
+ border-radius: 6px;
683
+ }
684
+
685
+ .nut-placeholder {
686
+ color: #cccccc;
687
+ line-height: 38px;
688
+ height: 38px;
689
+ }
690
+
691
+ .nut-input-box {
692
+ padding: 0 15px;
693
+ }
694
+ }
695
+
696
+ &-cancel.nut-button {
697
+ border-radius: 15px;
698
+ font-size: 14px;
699
+ height: 30px;
700
+ }
701
+
702
+ &-ok.nut-button {
703
+ background: var(--app-primary-color, #017fff);
704
+ height: 30px;
705
+ font-size: 14px;
706
+ border-radius: 15px;
707
+ }
708
+ }
709
+ </style>