PersonalCenter.vue 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150
  1. <template>
  2. <div class="personal">
  3. <Breadcrumb />
  4. <div class="personal-head">
  5. <el-avatar :size="100"
  6. :src="appStore?.userInfo?.userAvatar ? appStore.userInfo.userAvatar : appStore.avatarDefault" />
  7. <div class="personal-head-box">
  8. <div class="personal-head-top">
  9. <div class="personal-head-left">
  10. <div class="personal-user-info">
  11. <div class="personal-username">
  12. <div class="">{{ appStore?.userInfo?.nickName }}</div>
  13. <template v-if="['0', '1', '2'].includes(appStore?.userInfo?.memberType)"></template>
  14. <img :src="`${ getImgUrl(`vip${appStore?.userInfo?.memberType}@2x.png`) }`" alt="">
  15. <!-- memberType 会员类型memberType 会员类型分为企业会员(2)和个人会员(1)、免费会员(0) -->
  16. </div>
  17. <div class="personal-user-phone mt4">{{ $t('personalCenter.phoneNumber') }}:{{
  18. appStore?.userInfo?.userPhone
  19. }}
  20. </div>
  21. <div class="" v-if="['1', '2'].includes(appStore?.userInfo?.memberType)">{{
  22. $t('personalCenter.vipEndTime')
  23. }}: {{
  24. appStore?.userInfo?.memberExpire }}</div>
  25. <div class="mt4" v-if="appStore?.userInfo?.skillTags">
  26. <el-button v-for="(item, index) in appStore.userInfo.skillTags.split(',')" type="primary" plain>{{ item
  27. }}</el-button>
  28. </div>
  29. </div>
  30. </div>
  31. <div class="personal-head-right">
  32. <div @click="changeSHow" class="personal-head-right-li">
  33. <img src="/src/assets/imgs/my/bianji@2x.png" alt="">
  34. <div class="">{{ $t('personalCenter.editProfile') }}</div>
  35. </div>
  36. <div @click="router.push({ path: '/member' })" class="personal-head-right-li">
  37. <img src="/src/assets/imgs/my/huiyuan@2x.png" alt="">
  38. <div class="">{{ $t('personalCenter.openMembership') }}</div>
  39. </div>
  40. <div @click="signIn" class="personal-head-right-li gradient">
  41. <img src="/src/assets/imgs/my/qiandao@2x.png" alt="">
  42. <div class="">{{ $t('personalCenter.checkIn') }}</div>
  43. </div>
  44. </div>
  45. </div>
  46. <div class="personal-head-bot">
  47. <div class="personal-user-list">
  48. <div class="personal-user-li">
  49. <span>{{ appStore?.userInfo?.pointsBalance || 0 }}</span>
  50. <span>{{ $t('common.mibi') }}</span>
  51. </div>
  52. <div class="personal-user-line"></div>
  53. <div class="personal-user-li">
  54. <span>{{ appStore?.userInfo?.baoMiBalance || 0 }}</span>
  55. <span>{{ $t('common.baomibi') }}</span>
  56. </div>
  57. <div class="btn">
  58. <el-button type="primary" @click="router.push({
  59. path: `/order-confirm`,
  60. })">{{ $t('route.recharge') }}</el-button>
  61. </div>
  62. <!-- <div class="personal-user-line"></div> -->
  63. </div>
  64. <div class="personal-user-list">
  65. <div class="personal-user-li">
  66. <span>{{ collectCount }}</span>
  67. <span>{{ $t('common.collect') }}</span>
  68. </div>
  69. </div>
  70. </div>
  71. </div>
  72. </div>
  73. <div class="personal-main">
  74. <div class="personal-left">
  75. <div class="personal-left-list">
  76. <template v-for="(item, index) in navList" :key="index">
  77. <div v-if="item.show" @click="toPath(item, index)" :class="{ active: index == navIndex }"
  78. class="personal-left-li">
  79. <img v-if="index == navIndex" :src="item.iconActive" alt="">
  80. <img v-else :src="item.icon" alt="">
  81. <div class="">{{ $t(item.name) }}</div>
  82. </div>
  83. </template>
  84. </div>
  85. </div>
  86. <div class="personal-right">
  87. <div class="personal-right-main">
  88. <router-view />
  89. </div>
  90. </div>
  91. </div>
  92. <!-- 工单 -->
  93. <div class="workOrder-dot" @click="show = true">
  94. <img src="/src/assets/imgs/my/icon9a@2x.png" alt="">
  95. <div class="">{{ $t('personalCenter.gongdan') }}</div>
  96. </div>
  97. <el-dialog v-model="show" :title="`${$t('personalCenter.gongdan')}`" width="784">
  98. <el-tabs v-model="activeName" @tab-click="handleClick">
  99. <el-tab-pane v-for="tab in tabs" :key="tab.name" :label="`${$t(tab.label)}`" :name="tab.name">
  100. <template v-if="activeName == 0">
  101. <el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="auto">
  102. <el-form-item :label="`${$t('personalCenter.gongdanleixing')}`" prop="issueCategory">
  103. <el-select v-model="ruleForm.issueCategory"
  104. :placeholder="`${$t('personalCenter.gongdanleixing_placeholder')}`" style="width: 100%">
  105. <el-option v-for="item in workTypeList" :key="item.value" :label="`${$t(item.label)}`"
  106. :value="item.value" />
  107. </el-select>
  108. </el-form-item>
  109. <el-form-item :label="`${$t('personalCenter.gongdanbiaoti')}`" prop="issueTitle">
  110. <el-input v-model="ruleForm.issueTitle"
  111. :placeholder="`${$t('personalCenter.gongdanbiaoti_placeholder')}`" />
  112. </el-form-item>
  113. <el-form-item :label="`${$t('personalCenter.gongdanneirong')}`" prop="issueContent">
  114. <el-input v-model="ruleForm.issueContent"
  115. :placeholder="`${$t('personalCenter.gongdanneirong_placeholder')}`" :rows="10" type="textarea" />
  116. </el-form-item>
  117. </el-form>
  118. </template>
  119. <template v-else>
  120. <el-collapse v-model="workName" accordion>
  121. <el-collapse-item :title="item.issueTitle || `${index + 1}、${item.question}`" :name="item.id"
  122. v-for="(item, index) in workList" :key="index">
  123. <template #title>
  124. <div class="work-head">
  125. <div class="work-head-left">
  126. <img v-if="activeName == 2" src="/src/assets/imgs/my/Q@2x.png" alt="">
  127. <div class="">{{ `${activeName == 2 ? (index + 1) + '、' : ''}` }}{{ item.issueTitle ||
  128. item.question }}</div>
  129. </div>
  130. <el-tag v-if="activeName == 1" :type="item.issueStatus == 2 ? 'success' : 'primary'">{{ item.issueStatus == 0 ?
  131. $t('personalCenter.daijiejue') : item.issueStatus == 2 ? $t('personalCenter.yijiejue') : ''
  132. }}</el-tag>
  133. </div>
  134. </template>
  135. <div class="work-content">
  136. <template v-if="activeName == 2">
  137. <img src="/src/assets/imgs/my/A@2x.png" alt="">
  138. <div class="">{{ item.issueContent || item.answer }}</div>
  139. </template>
  140. <el-descriptions style="width: 100%;" class="margin-top" :column="2" border v-else :label-width="langStore.currentLang == 'en' ? 180 : 80">
  141. <el-descriptions-item>
  142. <template #label>
  143. <div class="cell-item">{{ $t('personalCenter.gongdanbianhao') }}</div>
  144. </template>
  145. {{ item.issueNo }}
  146. </el-descriptions-item>
  147. <el-descriptions-item>
  148. <template #label>
  149. <div class="cell-item">{{ $t('personalCenter.gongdanzhuangtai') }}</div>
  150. </template>
  151. <el-tag :type="item.issueStatus == 2 ? 'success' : 'primary'">{{ item.issueStatus == 0 ?
  152. $t('personalCenter.daijiejue') : item.issueStatus == 2 ? $t('personalCenter.yijiejue') : ''
  153. }}</el-tag>
  154. </el-descriptions-item>
  155. <el-descriptions-item>
  156. <template #label>
  157. <div class="cell-item">{{ $t('personalCenter.gongdanleixing') }}</div>
  158. </template>
  159. {{ $t(getName(item.issueCategory)) }}
  160. </el-descriptions-item>
  161. <el-descriptions-item>
  162. <template #label>
  163. <div class="cell-item">{{ $t('personalCenter.gongdanbiaoti') }}</div>
  164. </template>
  165. {{ item.issueTitle }}
  166. </el-descriptions-item>
  167. <el-descriptions-item :span="2">
  168. <template #label>
  169. <div class="cell-item">{{ $t('personalCenter.gongdanneirong') }}</div>
  170. </template>
  171. {{ item.issueContent }}
  172. </el-descriptions-item>
  173. <el-descriptions-item :span="2" v-if="item.issueStatus == 2">
  174. <template #label>
  175. <div class="cell-item">{{ $t('personalCenter.gongdanhuifu') }}</div>
  176. </template>
  177. {{ item.remark }}
  178. </el-descriptions-item>
  179. </el-descriptions>
  180. </div>
  181. </el-collapse-item>
  182. </el-collapse>
  183. <template v-if="workList && workList.length">
  184. <Pagination :total="workForm.total" :page-size="workForm.pageSize" :current-page="workForm.pageNum"
  185. @page-change="handlePageChange" />
  186. </template>
  187. <el-empty v-else :description="$t('common.empty')" />
  188. </template>
  189. </el-tab-pane>
  190. </el-tabs>
  191. <template #footer v-if="activeName == 0">
  192. <div class="dialog-footer flex-center">
  193. <el-button @click="resetForm">{{ $t('common.cancel') }}</el-button>
  194. <el-button class="gradient" type="primary" @click="submitForm(ruleFormRef)">{{ $t('common.confirm')
  195. }}</el-button>
  196. </div>
  197. </template>
  198. </el-dialog>
  199. <el-dialog v-model="dialogVisible" :title="$t('personalCenter.editProfile')" width="784" :destroy-on-close="true">
  200. <el-form ref="userFormRef" :model="userInfo" label-width="auto" label-position="top" :rules="rules">
  201. <el-row :gutter="16">
  202. <el-col :span="12">
  203. <el-form-item :label="$t('personalCenter.nickName')" prop="nickName">
  204. <el-input v-model="userInfo.nickName" :placeholder="$t('personalCenter.pinickName')" class="inputStyle"
  205. :input-style="{
  206. backgroundColor: 'transparent',
  207. }" maxlength="15" />
  208. </el-form-item>
  209. </el-col>
  210. <el-col :span="12">
  211. <el-form-item :label="$t('personalCenter.uploadAvatar')">
  212. <!-- 图片类型 -->
  213. <FileUploader ref="fileUploader" accept="image/*" :multiple="false" :limit="1" :auto-upload="true"
  214. list-type="picture-card" :data="{ directory: 'workflow' }" buttonText="" v-model="coverImage" tip="" />
  215. </el-form-item>
  216. </el-col>
  217. </el-row>
  218. <el-row :gutter="16">
  219. <el-col :span="12">
  220. <el-form-item :label="$t('personalCenter.loginPhone')">
  221. <el-input :disabled="appStore?.userInfo?.userPhone ? true : false" v-model="userInfo.userPhone"
  222. :placeholder="$t('workflowTradeAdd.placeholderPhoneNumber')" class="inputStyle" :input-style="{
  223. backgroundColor: 'transparent',
  224. }" />
  225. </el-form-item>
  226. </el-col>
  227. <el-col :span="12" v-if="!appStore?.userInfo?.userPhone">
  228. <el-form-item :label="$t('personalCenter.phoneCode')" prop="verifyCode">
  229. <el-input v-model="userInfo.verifyCode" maxlength="6" :placeholder="$t('login.placeholderCaptcha')"
  230. class="inputStyle" :input-style="{
  231. backgroundColor: 'transparent',
  232. }">
  233. <template #append>
  234. <el-button :disabled="smsCountdown > 0" @click="sendSmsCode" style="width:120px"
  235. :class="{ 'countdown-btn': smsCountdown > 0 }" size="small">
  236. {{ smsCountdown > 0 ? `${smsCountdown}s` : $t('login.sendCaptcha') }}
  237. </el-button>
  238. </template>
  239. </el-input>
  240. </el-form-item>
  241. </el-col>
  242. </el-row>
  243. <el-row :gutter="16">
  244. <el-col :span="12">
  245. <el-form-item :label="$t('personalCenter.loginEmail')">
  246. <el-input v-model="userInfo.email" :placeholder="$t('workflowTradeAdd.placeholderEmail')"
  247. class="inputStyle" :input-style="{
  248. backgroundColor: 'transparent',
  249. }" :disabled="appStore?.userInfo?.email ? true : false" />
  250. </el-form-item>
  251. </el-col>
  252. <el-col :span="12" v-if="!appStore?.userInfo?.email">
  253. <el-form-item :label="$t('personalCenter.emailCode')" prop="verifyCode">
  254. <el-input v-model="userInfo.verifyCode" maxlength="6" :placeholder="$t('login.placeholderCaptcha')"
  255. class="inputStyle" :input-style="{
  256. backgroundColor: 'transparent',
  257. }">
  258. <template #append>
  259. <el-button :disabled="smsCountdown > 0" @click="sendSmsCode" style="width:120px"
  260. :class="{ 'countdown-btn': smsCountdown > 0 }" size="small">
  261. {{ smsCountdown > 0 ? `${smsCountdown}s` : $t('login.sendCaptcha') }}
  262. </el-button>
  263. </template>
  264. </el-input>
  265. </el-form-item>
  266. </el-col>
  267. </el-row>
  268. <el-row :gutter="16">
  269. <el-col :span="12">
  270. <el-form-item :label="$t('personalCenter.n8nAccout')">
  271. <el-input disabled v-model="userInfo.n8nAccount" :placeholder="$t(!appStore?.userInfo?.email ? 'personalCenter.bdyxjcjzh' : 'personalCenter.createN8n')"
  272. class="inputStyle" :input-style="{
  273. backgroundColor: 'transparent',
  274. }">
  275. <template #append v-if="appStore?.userInfo?.email && !appStore?.userInfo?.n8nAccount">
  276. <el-tooltip class="box-item" effect="dark" :content="$t('personalCenter.ceraten8n')" placement="top">
  277. <el-button @click="createAi('0')" :icon="Refresh" />
  278. </el-tooltip>
  279. </template>
  280. </el-input>
  281. </el-form-item>
  282. </el-col>
  283. <el-col :span="12">
  284. <el-form-item :label="$t('personalCenter.n8nPassword')">
  285. <el-input v-model="userInfo.n8nPassword" :placeholder="$t('personalCenter.createN8n')" class="inputStyle"
  286. :input-style="{
  287. backgroundColor: 'transparent',
  288. }" readonly type="password" show-password />
  289. </el-form-item>
  290. </el-col>
  291. </el-row>
  292. <el-row :gutter="16">
  293. <el-col :span="12">
  294. <el-form-item :label="$t('personalCenter.cozeAccout')">
  295. <el-input disabled v-model="userInfo.cozeAccount" :placeholder="$t(!appStore?.userInfo?.email ? 'personalCenter.bdyxjcjzh' :'personalCenter.createCoze')"
  296. class="inputStyle" :input-style="{
  297. backgroundColor: 'transparent',
  298. }">
  299. <template #append v-if="appStore?.userInfo?.email && !appStore?.userInfo?.cozeAccount">
  300. <el-tooltip class="box-item" effect="dark" :content="$t('personalCenter.ceratenCoze')"
  301. placement="top">
  302. <el-button @click="createAi('1')" :icon="Refresh" />
  303. </el-tooltip>
  304. </template>
  305. </el-input>
  306. </el-form-item>
  307. </el-col>
  308. <el-col :span="12">
  309. <el-form-item :label="$t('personalCenter.cozePassword')">
  310. <el-input v-model="userInfo.cozePassword" :placeholder="$t('personalCenter.createCoze')"
  311. class="inputStyle" :input-style="{
  312. backgroundColor: 'transparent',
  313. }" readonly type="password" show-password />
  314. </el-form-item>
  315. </el-col>
  316. </el-row>
  317. <el-row :gutter="16">
  318. <el-col :span="12">
  319. <el-form-item :label="$t('personalCenter.difyAccout')">
  320. <el-input disabled v-model="userInfo.difyAccount" :placeholder="$t(!appStore?.userInfo?.email ? 'personalCenter.bdyxjcjzh' :'personalCenter.createDify')"
  321. class="inputStyle" :input-style="{
  322. backgroundColor: 'transparent',
  323. }">
  324. <template #append v-if="appStore?.userInfo?.email && !appStore?.userInfo?.difyAccount">
  325. <el-tooltip class="box-item" effect="dark" :content="$t('personalCenter.ceratenDify')"
  326. placement="top">
  327. <el-button @click="createAi('2')" :icon="Refresh" />
  328. </el-tooltip>
  329. </template>
  330. </el-input>
  331. </el-form-item>
  332. </el-col>
  333. <el-col :span="12">
  334. <el-form-item :label="$t('personalCenter.difyPassword')">
  335. <el-input v-model="userInfo.difyPassword" :placeholder="$t('personalCenter.createDify')"
  336. class="inputStyle" :input-style="{
  337. backgroundColor: 'transparent',
  338. }" readonly type="password" show-password />
  339. </el-form-item>
  340. </el-col>
  341. </el-row>
  342. <el-row :gutter="16">
  343. <el-col :span="12">
  344. <el-form-item :label="$t('personalCenter.fastGptAccout')">
  345. <el-input disabled v-model="userInfo.fastGptAccount" :placeholder="$t(!appStore?.userInfo?.email ? 'personalCenter.bdyxjcjzh' :'personalCenter.createFastGpt')"
  346. class="inputStyle" :input-style="{
  347. backgroundColor: 'transparent',
  348. }">
  349. <template #append v-if="appStore?.userInfo?.email && !appStore?.userInfo?.fastGptAccount">
  350. <el-tooltip class="box-item" effect="dark" :content="$t('personalCenter.ceratenFastGpt')"
  351. placement="top">
  352. <el-button @click="createAi('3')" :icon="Refresh" />
  353. </el-tooltip>
  354. </template>
  355. </el-input>
  356. </el-form-item>
  357. </el-col>
  358. <el-col :span="12">
  359. <el-form-item :label="$t('personalCenter.fastGptPassword')">
  360. <el-input v-model="userInfo.fastGptPassword" :placeholder="$t('personalCenter.createFastGpt')"
  361. class="inputStyle" :input-style="{
  362. backgroundColor: 'transparent',
  363. }" readonly type="password" show-password />
  364. </el-form-item>
  365. </el-col>
  366. </el-row>
  367. <el-row>
  368. <el-col :span="24">
  369. <el-form-item :label="`${$t('personalCenter.skillTag')}(${ $t('personalCenter.zdtjwg') })`">
  370. <div class="flex tags flex_1">
  371. <el-tag v-for="tag in dynamicTags" :key="tag" closable @close="handleClose(tag)">
  372. {{ tag }}
  373. </el-tag>
  374. <template v-if="dynamicTags.length < 5">
  375. <el-input v-if="inputVisible" ref="InputRef" v-model="inputValue" class="w-20" size="small"
  376. @keyup.enter="handleInputConfirm" @blur="handleInputConfirm" maxlength="5" :placeholder="
  377. $t('personalCenter.psrjnbq')
  378. ">
  379. <template #append>
  380. <el-button :icon="Plus" />
  381. </template></el-input>
  382. <el-button v-else class="button-new-tag" size="small" @click="showInput">
  383. + {{ $t('common.addTags') }}
  384. </el-button>
  385. </template>
  386. </div>
  387. </el-form-item>
  388. </el-col>
  389. </el-row>
  390. </el-form>
  391. <template #footer>
  392. <div class="dialog-footer flex-center">
  393. <el-button @click="userInfo = {}, dialogVisible = false">{{ $t('common.cancel') }}</el-button>
  394. <el-button class="gradient" type="primary" @click="handleConfirm(userFormRef)">
  395. {{ $t('common.confirm') }}
  396. </el-button>
  397. </div>
  398. </template>
  399. </el-dialog>
  400. </div>
  401. </template>
  402. <script setup lang="ts">
  403. import { Plus, Refresh } from '@element-plus/icons-vue'
  404. import { useAppStore } from '@/pinia/appStore'
  405. import { ref, onMounted, computed, nextTick } from 'vue';
  406. import type { InputInstance } from 'element-plus'
  407. import { useRoute, useRouter } from 'vue-router'
  408. import { getUserInfo, updateUserInfo, getSmsCode, getEmailCode,sendBindCode } from '@/api/auth.js'
  409. import { checkIn, queryCollectCount, issue, issueList, faqList, getfaq, createAiAccount } from '@/api/my.js'
  410. import DGTMessage from '@/utils/message'
  411. import { useI18n } from 'vue-i18n'
  412. import FileUploader from '@/components/FileUploader.vue'
  413. import Pagination from '@/components/Pagination.vue'
  414. import type { FormInstance, FormRules } from 'element-plus'
  415. import { useLangStore } from '@/pinia/langStore'
  416. const langStore = useLangStore();
  417. interface RuleForm {
  418. issueCategory: string
  419. issueTitle: string
  420. issueContent: string
  421. }
  422. const ruleFormRef = ref(null);
  423. const userFormRef = ref();
  424. const { t } = useI18n()
  425. const appStore = useAppStore();
  426. const route = useRoute()
  427. const router = useRouter()
  428. const getImgUrl = (path) => {
  429. return new URL(`/src/assets/imgs/my/${path}`, import.meta.url).href
  430. }
  431. const navList = ref([
  432. {
  433. name: 'personalCenter.myWallet',
  434. path: '/personal-center/wallet',
  435. icon: getImgUrl('icon1@2x.png'),
  436. iconActive: getImgUrl('icon1a@2x.png'),
  437. show: true
  438. },
  439. {
  440. name: 'personalCenter.membershipInfo',
  441. path: '/personal-center/member-details',
  442. icon: getImgUrl('icon2@2x.png'),
  443. iconActive: getImgUrl('icon2a@2x.png'),
  444. show: true
  445. },
  446. {
  447. name: 'personalCenter.myCollection',
  448. path: '/personal-center/collection',
  449. icon: getImgUrl('icon3@2x.png'),
  450. iconActive: getImgUrl('icon3a@2x.png'),
  451. show: true
  452. },
  453. {
  454. name: 'personalCenter.myDemand',
  455. path: '/personal-center/demand',
  456. icon: getImgUrl('icon4@2x.png'),
  457. iconActive: getImgUrl('icon4a@2x.png'),
  458. show: true
  459. },
  460. {
  461. name: 'personalCenter.myOrders',
  462. path: '/personal-center/orders',
  463. icon: getImgUrl('icon5@2x.png'),
  464. iconActive: getImgUrl('icon5a@2x.png'),
  465. show: true
  466. },
  467. {
  468. name: 'personalCenter.myInvoice',
  469. path: '/personal-center/invoice',
  470. icon: getImgUrl('icon6@2x.png'),
  471. iconActive: getImgUrl('icon6a@2x.png'),
  472. show: true
  473. },
  474. {
  475. name: 'personalCenter.myWorkflow',
  476. path: '/personal-center/workflow',
  477. icon: getImgUrl('icon7@2x.png'),
  478. iconActive: getImgUrl('icon7a@2x.png'),
  479. show: true
  480. },
  481. {
  482. name: 'personalCenter.businessManagement',
  483. path: '/personal-center/business-management',
  484. icon: getImgUrl('icon8@2x.png'),
  485. iconActive: getImgUrl('icon8a@2x.png'),
  486. show: false
  487. },
  488. // {
  489. // name: 'personalCenter.serviceManagement',
  490. // path: '/personal-center/business-management',
  491. // icon: '/src/assets/imgs/my/icon9@2x.png',
  492. // iconActive: '/src/assets/imgs/my/icon9a@2x.png'
  493. // }
  494. ])
  495. const dialogVisible = ref(false)
  496. const show = ref(false)
  497. const tabs = ref([
  498. { label: 'personalCenter.tijiaogongdan', name: 0 },
  499. { label: 'personalCenter.lishigongdan', name: 1 },
  500. { label: 'personalCenter.changjianwenti', name: 2 }
  501. ])
  502. const workList = ref([])
  503. const workForm = ref({
  504. pageNum: 1,
  505. pageSize: 10,
  506. total: 0,
  507. })
  508. const activeName = ref(0)
  509. const workName = ref(null)
  510. const workTypeList = ref([
  511. {
  512. value: 'account',
  513. label: 'personalCenter.zhanghaowenti'
  514. },
  515. {
  516. value: 'payment',
  517. label: 'personalCenter.zhifuwenti'
  518. },
  519. {
  520. value: 'course',
  521. label: 'personalCenter.kechengwenti'
  522. },
  523. {
  524. value: 'workflow',
  525. label: 'personalCenter.gongzuoliuwenti'
  526. },
  527. {
  528. value: 'other',
  529. label: 'personalCenter.qitawenti'
  530. }
  531. ])
  532. // 获取工单分类
  533. const getName = (value) => {
  534. let txt = ''
  535. workTypeList.value.forEach(item => {
  536. if (item.value == value) {
  537. txt = item.label
  538. }
  539. })
  540. return txt
  541. }
  542. const ruleForm = ref<RuleForm>({
  543. issueCategory: '',
  544. issueTitle: '',
  545. issueContent: ''
  546. })
  547. const rules = ref<FormRules<RuleForm>>({
  548. issueCategory: [
  549. {
  550. required: true,
  551. message: t('personalCenter.gongdanleixing_placeholder'),
  552. trigger: 'change',
  553. },
  554. ],
  555. issueTitle: [
  556. { required: true, message: t('personalCenter.gongdanbiaoti_placeholder'), trigger: 'blur' },
  557. ],
  558. issueContent: [
  559. { required: true, message: t('personalCenter.gongdanneirong_placeholder'), trigger: 'blur' },
  560. ],
  561. nickName: [
  562. {
  563. required: true, message: t('personalCenter.pinickName'), trigger: 'blur'
  564. }
  565. ]
  566. })
  567. const navIndex = computed(() => {
  568. switch (route.name) {
  569. case 'Wallet':
  570. return 0
  571. break;
  572. case 'MemberDetails':
  573. return 1
  574. break;
  575. case 'Wallet':
  576. return 0
  577. break;
  578. case 'Collection':
  579. return 2
  580. break;
  581. case 'Demand':
  582. return 3
  583. break;
  584. case 'Orders':
  585. return 4
  586. break;
  587. case 'Invoice':
  588. return 5
  589. break;
  590. case 'Workflow':
  591. return 6
  592. break;
  593. case 'BusinessManagement':
  594. return 7
  595. break;
  596. default:
  597. break;
  598. }
  599. return null;
  600. })
  601. const userInfo = ref({})//用户信息
  602. const coverImage = ref([]);
  603. // 验证码倒计时
  604. const smsCountdown = ref(0)
  605. const passwordresetCountdown = ref(0)
  606. const emailCountdown = ref(0)
  607. // 正则表达式
  608. const PHONE_REGEX = /^1[3-9]\d{9}$/;
  609. // 优化后的邮箱正则(兼顾准确性和实用性)
  610. const EMAIL_REGEX = /^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/;
  611. const isPasswordPhone = computed(() => {
  612. return PHONE_REGEX.test(passwordForm.account);
  613. });
  614. const isPasswordEmail = computed(() => {
  615. return EMAIL_REGEX.test(passwordForm.account);
  616. });
  617. // 创建ai相关账号
  618. const createAi = async (creatFlag) => {
  619. let res = await createAiAccount({ creatFlag });
  620. if (res.code === 200) {
  621. DGTMessage.success(`${t('common.success')}`)
  622. }
  623. }
  624. // 发送短信验证码
  625. const sendSmsCode = async () => {
  626. let account = appStore?.userInfo?.userPhone ? userInfo.value.email : userInfo.value.userPhone
  627. if (!account) {
  628. DGTMessage.warning(appStore?.userInfo?.userPhone ? t('workflowTradeAdd.placeholderEmail') : t('workflowTradeAdd.placeholderPhoneNumber'))
  629. return
  630. }
  631. // 验证手机号格式
  632. if ((!PHONE_REGEX.test(account) && appStore?.userInfo?.email) || (!EMAIL_REGEX.test(account) && appStore?.userInfo?.userPhone)) {
  633. DGTMessage.warning(appStore?.userInfo?.userPhone ? t('common.pleaseInputRightEmail') : t('common.pleaseInputRightPhoneNumber'))
  634. return
  635. }
  636. let res = await sendBindCode({
  637. account: account,
  638. type: appStore?.userInfo?.userPhone ? 'email' : 'phone'
  639. });
  640. if (res.code !== 200) {
  641. return
  642. }
  643. // 模拟发送验证码
  644. DGTMessage.success(t('login.captchaSendSuccess'))
  645. // 开始倒计时
  646. smsCountdown.value = 60
  647. const timer = setInterval(() => {
  648. smsCountdown.value--
  649. if (smsCountdown.value <= 0) {
  650. clearInterval(timer)
  651. }
  652. }, 1000)
  653. }
  654. const handlePageChange = (page) => {
  655. workForm.value.pageNum = page;
  656. getList()
  657. }
  658. const handleClick = async (tab) => {
  659. activeName.value = tab.props.name
  660. workForm.value.pageNum = 1;
  661. getList()
  662. }
  663. const getList = async () => {
  664. if (activeName.value == 0) return;
  665. let api = activeName.value == 1 ? issueList(workForm.value) : faqList(workForm.value);
  666. let res = await api;
  667. workList.value = res.rows;
  668. workForm.value.total = res.total;
  669. }
  670. const resetForm = () => {
  671. show.value = false;
  672. for (const key in ruleForm.value) {
  673. ruleForm.value[key] = ''
  674. }
  675. }
  676. const submitForm = async (formEl) => {
  677. if (!formEl) return;
  678. await formEl[0].validate(async (valid, fields) => {
  679. if (valid) {
  680. let res = await issue(ruleForm.value);
  681. if (res.code === 200) {
  682. resetForm();
  683. DGTMessage.success(`${t('common.submitSuccess')}`)
  684. }
  685. }
  686. })
  687. }
  688. // 更新用户信息
  689. const handleConfirm = async (formEl) => {
  690. if (!formEl) return
  691. await formEl.validate(async (valid, fields) => {
  692. if (valid) {
  693. if (!appStore.userInfo.userPhone || !appStore.userInfo.email) {
  694. userInfo.value.bindType = appStore.userInfo.userPhone ? 'email' : 'phone'
  695. }
  696. let obj = !appStore.userInfo.userPhone && userInfo.value.userPhone || !appStore.userInfo.email && userInfo.value.email ? { email: userInfo.value.email, bindType: userInfo.value.bindType, userPhone: userInfo.value.userPhone, verifyCode: userInfo.value.verifyCode } : {}
  697. let res = await updateUserInfo({
  698. nickName: userInfo.value.nickName,
  699. userAvatar: coverImage.value.map(item => item.url).join(';'),
  700. skillTags: dynamicTags.value.join(','),
  701. ...obj
  702. })
  703. if (res.code === 200) {
  704. appStore.USERINFO();
  705. DGTMessage.success(`${t('common.modify')}${t('common.success')}`)
  706. dialogVisible.value = false;
  707. }
  708. }
  709. })
  710. }
  711. const toPath = (item: any, index: number) => {
  712. if (item.path) {
  713. router.push(item.path);
  714. }
  715. };
  716. // 签到
  717. const signIn = async () => {
  718. let res = await checkIn({ actionType: 1 });
  719. if (res.code === 200) {
  720. appStore.USERINFO();
  721. DGTMessage.success(`${t('personalCenter.checkIn')}${t('common.success')}`)
  722. }
  723. }
  724. // 获取用户信息
  725. const getInfo = async () => {
  726. let res = await getUserInfo();
  727. if (res?.user?.userAvatar) {
  728. coverImage.value = [{ url: res.user.userAvatar }]
  729. }
  730. if (res?.user?.skillTags) {
  731. dynamicTags.value = res.user.skillTags.split(',')
  732. } else {
  733. dynamicTags.value = []
  734. }
  735. userInfo.value = res.user;
  736. navList.value.forEach(item => {
  737. if (item.name === 'personalCenter.businessManagement' && res?.user?.isCompanyAuth == 1) {
  738. item.show = true;
  739. }
  740. })
  741. }
  742. const collectCount = ref(0)
  743. const inputValue = ref('')
  744. const dynamicTags = ref([])
  745. const inputVisible = ref(false)
  746. const InputRef = ref<InputInstance>()
  747. const handleClose = (tag: string) => {
  748. dynamicTags.value.splice(dynamicTags.value.indexOf(tag), 1)
  749. }
  750. const showInput = () => {
  751. inputVisible.value = true
  752. nextTick(() => {
  753. InputRef.value!.input!.focus()
  754. })
  755. }
  756. const handleInputConfirm = () => {
  757. if (inputValue.value) {
  758. dynamicTags.value.push(inputValue.value)
  759. }
  760. inputVisible.value = false
  761. inputValue.value = ''
  762. }
  763. const getCount = async () => {
  764. let res = await queryCollectCount();
  765. collectCount.value = res?.data?.collectCount;
  766. }
  767. const changeSHow = () => {
  768. getInfo()
  769. dialogVisible.value = true;
  770. }
  771. onMounted(() => {
  772. getInfo()
  773. getCount()
  774. })
  775. </script>
  776. <style lang="scss" scoped>
  777. div {
  778. -webkit-user-select: none;
  779. /* Safari, Chrome */
  780. -moz-user-select: none;
  781. /* Firefox */
  782. -ms-user-select: none;
  783. /* IE 10+ */
  784. user-select: none;
  785. /* 标准语法 */
  786. }
  787. .personal-head {
  788. border-radius: 16px;
  789. padding: 24px 16px;
  790. background: #FFFFFF;
  791. display: flex;
  792. .personal-head-box {
  793. flex: 1;
  794. margin-left: 16px;
  795. }
  796. .personal-head-top {
  797. display: flex;
  798. align-items: center;
  799. justify-content: space-between;
  800. }
  801. .personal-head-bot {
  802. margin-top: 16px;
  803. display: flex;
  804. align-items: center;
  805. justify-content: space-between;
  806. .personal-user-list {
  807. display: flex;
  808. align-items: center;
  809. .btn {
  810. margin-left: 16px;
  811. }
  812. .personal-user-li {
  813. span {
  814. color: #333333;
  815. font-size: 14px;
  816. &:first-child {
  817. font-size: 28px;
  818. font-weight: bold;
  819. margin-right: 10px;
  820. }
  821. }
  822. }
  823. .personal-user-line {
  824. margin: 0 16px;
  825. height: 20px;
  826. width: 2px;
  827. background: #EBEEF5;
  828. }
  829. }
  830. }
  831. .personal-head-left {
  832. display: flex;
  833. .personal-user-info {
  834. .personal-username {
  835. display: flex;
  836. align-items: center;
  837. font-size: 18px;
  838. font-weight: bold;
  839. color: #333333;
  840. img {
  841. width: 68px;
  842. height: 21px;
  843. margin-left: 8px;
  844. }
  845. }
  846. }
  847. }
  848. .personal-head-right {
  849. display: flex;
  850. align-items: center;
  851. .personal-head-right-li {
  852. display: flex;
  853. padding: 9px 16px;
  854. align-items: center;
  855. margin-left: 8px;
  856. // height: 32px;
  857. background: #EAF0FF;
  858. border-radius: 4px;
  859. cursor: pointer;
  860. &:first-child {
  861. margin-left: 0;
  862. }
  863. &:last-child {
  864. background: linear-gradient(270deg, #0055FE 0%, #C832FA 100%);
  865. div {
  866. color: #FFFFFF;
  867. }
  868. }
  869. img {
  870. width: 14px;
  871. height: 14px;
  872. margin-right: 4px;
  873. }
  874. div {
  875. color: #2D71FF;
  876. font-size: 14px;
  877. }
  878. &:hover {
  879. opacity: 0.7;
  880. }
  881. }
  882. }
  883. }
  884. .personal-main {
  885. margin-top: 16px;
  886. display: flex;
  887. justify-content: space-between;
  888. .personal-left {
  889. width: 300px;
  890. .personal-left-list {
  891. background: #FFFFFF;
  892. border-radius: 16px;
  893. padding: 8px;
  894. .personal-left-li {
  895. height: 56px;
  896. display: flex;
  897. align-items: center;
  898. padding: 0 8px;
  899. font-size: 16px;
  900. color: #333333;
  901. cursor: pointer;
  902. border-radius: 8px;
  903. img {
  904. width: 20px;
  905. height: 20px;
  906. margin-right: 4px;
  907. }
  908. &:hover {
  909. background: #F5F7FF;
  910. }
  911. }
  912. .active {
  913. position: relative;
  914. background: #EAF0FF;
  915. &::after {
  916. top: 50%;
  917. transform: translateY(-50%);
  918. content: '';
  919. position: absolute;
  920. right: 8px;
  921. width: 4px;
  922. height: 24px;
  923. background: #2D71FF;
  924. border-radius: 2px;
  925. }
  926. div {
  927. color: #2D71FF;
  928. }
  929. }
  930. }
  931. }
  932. .personal-right {
  933. flex: 1;
  934. margin-left: 16px;
  935. .personal-right-main {
  936. padding: 0 16px;
  937. border-radius: 16px;
  938. background: #FFFFFF;
  939. }
  940. }
  941. }
  942. .tags {
  943. flex-wrap: wrap;
  944. gap: 16px;
  945. }
  946. .inputStyle {
  947. width: 368px;
  948. height: 36px;
  949. background: #F5F7FA;
  950. border-radius: 4px;
  951. border: 1px solid #F2F6FC;
  952. }
  953. .workOrder-dot {
  954. display: flex;
  955. cursor: pointer;
  956. align-items: center;
  957. justify-content: center;
  958. flex-direction: column;
  959. right: 80px;
  960. bottom: 70px;
  961. width: 84px;
  962. height: 84px;
  963. position: fixed;
  964. color: #2D71FF;
  965. font-size: 14px;
  966. background: #FFFFFF;
  967. box-shadow: 2px 2px 10px 0px rgba(45, 113, 255, 0.15);
  968. border-radius: 50px;
  969. img {
  970. width: 24px;
  971. height: 24px;
  972. }
  973. }
  974. .work-head {
  975. display: flex;
  976. color: #333333;
  977. font-size: 18px;
  978. font-weight: bold;
  979. align-items: center;
  980. justify-content: space-between;
  981. .work-head-left {
  982. display: flex;
  983. align-items: center;
  984. }
  985. img {
  986. width: 24px;
  987. height: 24px;
  988. margin-right: 8px;
  989. }
  990. }
  991. .work-content {
  992. padding: 16px;
  993. background: #F5F7FA;
  994. border-radius: 16px;
  995. color: #333333;
  996. line-height: 24px;
  997. font-size: 16px;
  998. display: flex;
  999. img {
  1000. width: 24px;
  1001. height: 24px;
  1002. margin-right: 16px;
  1003. }
  1004. }
  1005. :deep(.el-collapse-item__header) {
  1006. padding: 0 8px;
  1007. background-color: transparent;
  1008. }
  1009. :deep(.el-collapse-item__content) {
  1010. padding: 0 16px 16px;
  1011. }
  1012. </style>