PersonalCenter.vue 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164
  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. if (creatFlag == '0') {
  622. userInfo.value.n8nAccount = res.data.n8nAccount;
  623. userInfo.value.n8nPassword = res.data.n8nPassword;
  624. } else if (creatFlag == '1') {
  625. userInfo.value.cozeAccount = res.data.cozeAccount;
  626. userInfo.value.cozePassword = res.data.cozePassword;
  627. } else if (creatFlag == '2') {
  628. userInfo.value.difyAccount = res.data.difyAccount;
  629. userInfo.value.difyPassword = res.data.difyPassword;
  630. } else if (creatFlag == '3') {
  631. userInfo.value.fastGptAccount = res.data.fastGptAccount;
  632. userInfo.value.fastGptPassword = res.data.fastGptPassword;
  633. }
  634. appStore.USERINFO();
  635. DGTMessage.success(`${t('common.success')}`)
  636. }
  637. }
  638. // 发送短信验证码
  639. const sendSmsCode = async () => {
  640. let account = appStore?.userInfo?.userPhone ? userInfo.value.email : userInfo.value.userPhone
  641. if (!account) {
  642. DGTMessage.warning(appStore?.userInfo?.userPhone ? t('workflowTradeAdd.placeholderEmail') : t('workflowTradeAdd.placeholderPhoneNumber'))
  643. return
  644. }
  645. // 验证手机号格式
  646. if ((!PHONE_REGEX.test(account) && appStore?.userInfo?.email) || (!EMAIL_REGEX.test(account) && appStore?.userInfo?.userPhone)) {
  647. DGTMessage.warning(appStore?.userInfo?.userPhone ? t('common.pleaseInputRightEmail') : t('common.pleaseInputRightPhoneNumber'))
  648. return
  649. }
  650. let res = await sendBindCode({
  651. account: account,
  652. type: appStore?.userInfo?.userPhone ? 'email' : 'phone'
  653. });
  654. if (res.code !== 200) {
  655. return
  656. }
  657. // 模拟发送验证码
  658. DGTMessage.success(t('login.captchaSendSuccess'))
  659. // 开始倒计时
  660. smsCountdown.value = 60
  661. const timer = setInterval(() => {
  662. smsCountdown.value--
  663. if (smsCountdown.value <= 0) {
  664. clearInterval(timer)
  665. }
  666. }, 1000)
  667. }
  668. const handlePageChange = (page) => {
  669. workForm.value.pageNum = page;
  670. getList()
  671. }
  672. const handleClick = async (tab) => {
  673. activeName.value = tab.props.name
  674. workForm.value.pageNum = 1;
  675. getList()
  676. }
  677. const getList = async () => {
  678. if (activeName.value == 0) return;
  679. let api = activeName.value == 1 ? issueList(workForm.value) : faqList(workForm.value);
  680. let res = await api;
  681. workList.value = res.rows;
  682. workForm.value.total = res.total;
  683. }
  684. const resetForm = () => {
  685. show.value = false;
  686. for (const key in ruleForm.value) {
  687. ruleForm.value[key] = ''
  688. }
  689. }
  690. const submitForm = async (formEl) => {
  691. if (!formEl) return;
  692. await formEl[0].validate(async (valid, fields) => {
  693. if (valid) {
  694. let res = await issue(ruleForm.value);
  695. if (res.code === 200) {
  696. resetForm();
  697. DGTMessage.success(`${t('common.submitSuccess')}`)
  698. }
  699. }
  700. })
  701. }
  702. // 更新用户信息
  703. const handleConfirm = async (formEl) => {
  704. if (!formEl) return
  705. await formEl.validate(async (valid, fields) => {
  706. if (valid) {
  707. if (!appStore.userInfo.userPhone || !appStore.userInfo.email) {
  708. userInfo.value.bindType = appStore.userInfo.userPhone ? 'email' : 'phone'
  709. }
  710. 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 } : {}
  711. let res = await updateUserInfo({
  712. nickName: userInfo.value.nickName,
  713. userAvatar: coverImage.value.map(item => item.url).join(';'),
  714. skillTags: dynamicTags.value.join(','),
  715. ...obj
  716. })
  717. if (res.code === 200) {
  718. appStore.USERINFO();
  719. DGTMessage.success(`${t('common.modify')}${t('common.success')}`)
  720. dialogVisible.value = false;
  721. }
  722. }
  723. })
  724. }
  725. const toPath = (item: any, index: number) => {
  726. if (item.path) {
  727. router.push(item.path);
  728. }
  729. };
  730. // 签到
  731. const signIn = async () => {
  732. let res = await checkIn({ actionType: 1 });
  733. if (res.code === 200) {
  734. appStore.USERINFO();
  735. DGTMessage.success(`${t('personalCenter.checkIn')}${t('common.success')}`)
  736. }
  737. }
  738. // 获取用户信息
  739. const getInfo = async () => {
  740. let res = await getUserInfo();
  741. if (res?.user?.userAvatar) {
  742. coverImage.value = [{ url: res.user.userAvatar }]
  743. }
  744. if (res?.user?.skillTags) {
  745. dynamicTags.value = res.user.skillTags.split(',')
  746. } else {
  747. dynamicTags.value = []
  748. }
  749. userInfo.value = res.user;
  750. navList.value.forEach(item => {
  751. if (item.name === 'personalCenter.businessManagement' && res?.user?.isCompanyAuth == 1) {
  752. item.show = true;
  753. }
  754. })
  755. }
  756. const collectCount = ref(0)
  757. const inputValue = ref('')
  758. const dynamicTags = ref([])
  759. const inputVisible = ref(false)
  760. const InputRef = ref<InputInstance>()
  761. const handleClose = (tag: string) => {
  762. dynamicTags.value.splice(dynamicTags.value.indexOf(tag), 1)
  763. }
  764. const showInput = () => {
  765. inputVisible.value = true
  766. nextTick(() => {
  767. InputRef.value!.input!.focus()
  768. })
  769. }
  770. const handleInputConfirm = () => {
  771. if (inputValue.value) {
  772. dynamicTags.value.push(inputValue.value)
  773. }
  774. inputVisible.value = false
  775. inputValue.value = ''
  776. }
  777. const getCount = async () => {
  778. let res = await queryCollectCount();
  779. collectCount.value = res?.data?.collectCount;
  780. }
  781. const changeSHow = () => {
  782. getInfo()
  783. dialogVisible.value = true;
  784. }
  785. onMounted(() => {
  786. getInfo()
  787. getCount()
  788. })
  789. </script>
  790. <style lang="scss" scoped>
  791. div {
  792. -webkit-user-select: none;
  793. /* Safari, Chrome */
  794. -moz-user-select: none;
  795. /* Firefox */
  796. -ms-user-select: none;
  797. /* IE 10+ */
  798. user-select: none;
  799. /* 标准语法 */
  800. }
  801. .personal-head {
  802. border-radius: 16px;
  803. padding: 24px 16px;
  804. background: #FFFFFF;
  805. display: flex;
  806. .personal-head-box {
  807. flex: 1;
  808. margin-left: 16px;
  809. }
  810. .personal-head-top {
  811. display: flex;
  812. align-items: center;
  813. justify-content: space-between;
  814. }
  815. .personal-head-bot {
  816. margin-top: 16px;
  817. display: flex;
  818. align-items: center;
  819. justify-content: space-between;
  820. .personal-user-list {
  821. display: flex;
  822. align-items: center;
  823. .btn {
  824. margin-left: 16px;
  825. }
  826. .personal-user-li {
  827. span {
  828. color: #333333;
  829. font-size: 14px;
  830. &:first-child {
  831. font-size: 28px;
  832. font-weight: bold;
  833. margin-right: 10px;
  834. }
  835. }
  836. }
  837. .personal-user-line {
  838. margin: 0 16px;
  839. height: 20px;
  840. width: 2px;
  841. background: #EBEEF5;
  842. }
  843. }
  844. }
  845. .personal-head-left {
  846. display: flex;
  847. .personal-user-info {
  848. .personal-username {
  849. display: flex;
  850. align-items: center;
  851. font-size: 18px;
  852. font-weight: bold;
  853. color: #333333;
  854. img {
  855. width: 68px;
  856. height: 21px;
  857. margin-left: 8px;
  858. }
  859. }
  860. }
  861. }
  862. .personal-head-right {
  863. display: flex;
  864. align-items: center;
  865. .personal-head-right-li {
  866. display: flex;
  867. padding: 9px 16px;
  868. align-items: center;
  869. margin-left: 8px;
  870. // height: 32px;
  871. background: #EAF0FF;
  872. border-radius: 4px;
  873. cursor: pointer;
  874. &:first-child {
  875. margin-left: 0;
  876. }
  877. &:last-child {
  878. background: linear-gradient(270deg, #0055FE 0%, #C832FA 100%);
  879. div {
  880. color: #FFFFFF;
  881. }
  882. }
  883. img {
  884. width: 14px;
  885. height: 14px;
  886. margin-right: 4px;
  887. }
  888. div {
  889. color: #2D71FF;
  890. font-size: 14px;
  891. }
  892. &:hover {
  893. opacity: 0.7;
  894. }
  895. }
  896. }
  897. }
  898. .personal-main {
  899. margin-top: 16px;
  900. display: flex;
  901. justify-content: space-between;
  902. .personal-left {
  903. width: 300px;
  904. .personal-left-list {
  905. background: #FFFFFF;
  906. border-radius: 16px;
  907. padding: 8px;
  908. .personal-left-li {
  909. height: 56px;
  910. display: flex;
  911. align-items: center;
  912. padding: 0 8px;
  913. font-size: 16px;
  914. color: #333333;
  915. cursor: pointer;
  916. border-radius: 8px;
  917. img {
  918. width: 20px;
  919. height: 20px;
  920. margin-right: 4px;
  921. }
  922. &:hover {
  923. background: #F5F7FF;
  924. }
  925. }
  926. .active {
  927. position: relative;
  928. background: #EAF0FF;
  929. &::after {
  930. top: 50%;
  931. transform: translateY(-50%);
  932. content: '';
  933. position: absolute;
  934. right: 8px;
  935. width: 4px;
  936. height: 24px;
  937. background: #2D71FF;
  938. border-radius: 2px;
  939. }
  940. div {
  941. color: #2D71FF;
  942. }
  943. }
  944. }
  945. }
  946. .personal-right {
  947. flex: 1;
  948. margin-left: 16px;
  949. .personal-right-main {
  950. padding: 0 16px;
  951. border-radius: 16px;
  952. background: #FFFFFF;
  953. }
  954. }
  955. }
  956. .tags {
  957. flex-wrap: wrap;
  958. gap: 16px;
  959. }
  960. .inputStyle {
  961. width: 368px;
  962. height: 36px;
  963. background: #F5F7FA;
  964. border-radius: 4px;
  965. border: 1px solid #F2F6FC;
  966. }
  967. .workOrder-dot {
  968. display: flex;
  969. cursor: pointer;
  970. align-items: center;
  971. justify-content: center;
  972. flex-direction: column;
  973. right: 80px;
  974. bottom: 70px;
  975. width: 84px;
  976. height: 84px;
  977. position: fixed;
  978. color: #2D71FF;
  979. font-size: 14px;
  980. background: #FFFFFF;
  981. box-shadow: 2px 2px 10px 0px rgba(45, 113, 255, 0.15);
  982. border-radius: 50px;
  983. img {
  984. width: 24px;
  985. height: 24px;
  986. }
  987. }
  988. .work-head {
  989. display: flex;
  990. color: #333333;
  991. font-size: 18px;
  992. font-weight: bold;
  993. align-items: center;
  994. justify-content: space-between;
  995. .work-head-left {
  996. display: flex;
  997. align-items: center;
  998. }
  999. img {
  1000. width: 24px;
  1001. height: 24px;
  1002. margin-right: 8px;
  1003. }
  1004. }
  1005. .work-content {
  1006. padding: 16px;
  1007. background: #F5F7FA;
  1008. border-radius: 16px;
  1009. color: #333333;
  1010. line-height: 24px;
  1011. font-size: 16px;
  1012. display: flex;
  1013. img {
  1014. width: 24px;
  1015. height: 24px;
  1016. margin-right: 16px;
  1017. }
  1018. }
  1019. :deep(.el-collapse-item__header) {
  1020. padding: 0 8px;
  1021. background-color: transparent;
  1022. }
  1023. :deep(.el-collapse-item__content) {
  1024. padding: 0 16px 16px;
  1025. }
  1026. </style>