information.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. <template>
  2. <div class="info-layout">
  3. <edit
  4. :name="langAccount.info"
  5. @clickOper="handleOper('infoStatus')"
  6. :oper="infoStatus?langAccount.edit:langAccount.show"
  7. :isActive="infoStatus"
  8. class="container"
  9. >
  10. <div class="info" :class="{'info-en':language==='en'}" slot="show">
  11. <div class="s-tx">
  12. <p>{{langAccount.avatar}}</p>
  13. <div class="card-img avatar" :style="{backgroundImage: info.head? `url(${info.head})`:`#e6e6e6`}"></div>
  14. </div>
  15. <p><span>{{langAccount.account}}</span><span>{{info.userName||'--'}}</span></p>
  16. <p><span>{{langAccount.nickname}}</span><span>{{info.nickName||'--'}}</span></p>
  17. <p><span>{{langAccount.email}}</span><span>{{info.email||'--'}}</span></p>
  18. </div>
  19. <div class="info edit-info" :class="{'edit-en':language==='en','info-en':language==='en'}" slot="edit">
  20. <div class="info-left">
  21. <div class="i-tx">
  22. <p>{{langAccount.avatar}}</p>
  23. <div class="itx-con">
  24. <div class="card-img avatar" :style="{backgroundImage: info.head?`url(${info.head})`:'#e6e6e6'}"></div>
  25. <div class="btn choose">
  26. <input class="el-upload" ref="uploadInput" name="file" type="file" @change="update" alt="sadasdasd">
  27. <span>{{langAccount.select}}</span>
  28. </div>
  29. <p class="p-desc" v-for="(item,i) in langAccount.sinfo" :key="i">{{item}}</p>
  30. </div>
  31. </div>
  32. <p><span>{{langAccount.account}}</span><span>{{info.userName}}</span></p>
  33. <p>
  34. <span>{{langAccount.nickname}}</span>
  35. <input
  36. autofocus
  37. v-model="editinfo.nickName"
  38. :placeholder="langAccount.placeholder.nickname"
  39. class="nickname"
  40. maxlength="10"
  41. type="text"
  42. >
  43. </p>
  44. <p>
  45. <span>{{langAccount.email}}</span>
  46. <input
  47. autofocus
  48. v-model="editinfo.email"
  49. :placeholder="langAccount.placeholder.email"
  50. class="nickname"
  51. maxlength="40"
  52. type="text"
  53. >
  54. </p>
  55. <label class="check-con" @click="isReceive=!isReceive">
  56. <span class="check-box">
  57. <span class="checkbox-inner" :class="{'checkbox-inner-checked':isReceive}"></span>
  58. </span>
  59. <span style="font-size:14px;color:#000;" v-html="langAccount.isReceive"></span>
  60. </label>
  61. <div @click="saveNickName" class="btn parmary">{{langAccount.save}}</div>
  62. </div>
  63. </div>
  64. </edit>
  65. <edit
  66. :name="langAccount.address"
  67. @clickOper="handleOper('addressStatus')"
  68. :oper="addressStatus?langAccount.edit:langAccount.show"
  69. :isActive="addressStatus"
  70. >
  71. <div class="address" slot="show">
  72. <template v-if="address.shipName">
  73. <p>
  74. <span>{{address.shipName}}</span>
  75. <span>{{address.shipMobile}}</span>
  76. </p>
  77. <p class="p-desc">{{`${address.shipAreaPath}${address.shipAddress}`}}</p>
  78. </template>
  79. <template v-else>
  80. <p class="p-desc">{{language==='en'?'Not filled':'暂无信息'}}</p>
  81. </template>
  82. </div>
  83. <div class="address edit-address" slot="edit">
  84. <div class="input-con">
  85. <input type="text" maxlength="10" v-model="editAdd.shipName" :placeholder="langAccount.placeholder.name">
  86. <input type="text" oninput="value=value.replace(/[^\d\-]/g,'')" maxlength='11' v-model="editAdd.shipMobile" :placeholder="langAccount.placeholder.phone">
  87. </div>
  88. <div class="input-con">
  89. <citySelect :areaPath="editAdd.shipAreaPath" @currentVal="getCurrentSelect"/>
  90. </div>
  91. <div class="input-con address-input">
  92. <input
  93. type="text"
  94. v-model="editAdd.shipAddress"
  95. maxlength="50"
  96. :placeholder="langAccount.placeholder.address"
  97. >
  98. </div>
  99. <div class="btn parmary" @click="uAddress">{{langAccount.save}}</div>
  100. </div>
  101. </edit>
  102. </div>
  103. </template>
  104. <script>
  105. import { mapState } from 'vuex'
  106. import edit from '@/components/edit'
  107. import { reg } from '@/util'
  108. import citySelect from '@/components/citySelect'
  109. var cloneObj = function (obj) {
  110. var newObj = {}
  111. if (obj instanceof Array) {
  112. newObj = []
  113. }
  114. for (var key in obj) {
  115. var val = obj[key] || ''
  116. newObj[key] = typeof val === 'object' ? cloneObj(val) : val
  117. }
  118. return newObj
  119. }
  120. export default {
  121. components: { edit, citySelect },
  122. computed: {
  123. ...mapState({
  124. info: state => state.user.info,
  125. langAccount: state => state.language.home.manage.account,
  126. language: state => state.language.current,
  127. langToast: state => state.language.home.toast,
  128. editinfo: state => cloneObj(state.user.info),
  129. token: state => state.user.token,
  130. invoice2: state => {
  131. let type = Object.prototype.toString.call(state.user.invoice2)
  132. if (type === '[object Object]') {
  133. return state.user.invoice2
  134. }
  135. let condition = state.user.invoice2 && state.user.invoice2 !== 'null' && type !== '[object Array]'
  136. return (condition ? JSON.parse(state.user.invoice2) : {})
  137. },
  138. editInvoice2: state => {
  139. let type = Object.prototype.toString.call(state.user.invoice2)
  140. if (type === '[object Object]') {
  141. return state.user.invoice2
  142. }
  143. let condition = state.user.invoice2 && state.user.invoice2 !== 'null' && type !== '[object Array]'
  144. return cloneObj(condition ? JSON.parse(state.user.invoice2) : {})
  145. },
  146. invoice3: state => {
  147. let type = Object.prototype.toString.call(state.user.invoice3)
  148. if (type === '[object Object]') {
  149. return state.user.invoice3
  150. }
  151. let condition = state.user.invoice3 && state.user.invoice3 !== 'null' && type !== '[object Array]'
  152. return (condition ? JSON.parse(state.user.invoice3) : {})
  153. },
  154. editInvoice3: state => {
  155. let type = Object.prototype.toString.call(state.user.invoice3)
  156. if (type === '[object Object]') {
  157. return state.user.invoice3
  158. }
  159. let condition = state.user.invoice3 && state.user.invoice3 !== 'null' && type !== '[object Array]'
  160. return cloneObj(condition ? JSON.parse(state.user.invoice3) : {})
  161. },
  162. address: state => state.user.address || {},
  163. editAdd: state => cloneObj(state.user.address) || {}
  164. })
  165. },
  166. data () {
  167. return {
  168. infoStatus: true,
  169. addressStatus: true,
  170. invoiceStatus: true,
  171. cInvoice: 'normal',
  172. tempSelect: '',
  173. isReceive: true,
  174. addre: []
  175. }
  176. },
  177. methods: {
  178. handleOper (type) {
  179. this[type] = !this[type]
  180. },
  181. getCurrentSelect (data) {
  182. this.tempSelect = data
  183. },
  184. async saveNickName () {
  185. if (!this.editinfo.nickName.trim()) {
  186. return this.$toast.show('warn', this.langToast['35'])
  187. }
  188. if (this.editinfo.email.trim() && !reg.email.test(this.editinfo.email)) {
  189. return this.$toast.show('warn', this.langToast['8'])
  190. }
  191. let res = await this.$http
  192. .post(
  193. '/user/updateUserDetail',
  194. {
  195. nickName: this.editinfo.nickName,
  196. email: this.editinfo.email || null,
  197. isNotice: Number(this.isReceive)
  198. },
  199. {
  200. headers: {
  201. token: this.token
  202. }
  203. }
  204. )
  205. let data = res.data
  206. if (data.code === 0) {
  207. this.infoStatus = true
  208. this.$store.dispatch('getInfo', {url: '/user/getUserInfo', name: 'info'})
  209. } else {
  210. this.$toast.show('warn', this.langToast[data.code], async () => {
  211. if (data.code === 3004) {
  212. await this.$store.dispatch('logout')
  213. this.$router.push({name: 'home'})
  214. }
  215. })
  216. }
  217. },
  218. saveInvoice (cInvoice) {
  219. let isObject = function (obj) {
  220. return JSON.stringify(obj) === '{}' ? '' : obj
  221. }
  222. let params = {}
  223. let invoiceType = ''
  224. let check = value => {
  225. for (let i = 0, len = value.length; i < len; i++) {
  226. if (!value[i].val) {
  227. return this.$toast.show('warn', (this.language === 'en' ? value[i].En : value[i].name) + this.langToast['7'])
  228. }
  229. }
  230. return true
  231. }
  232. if (cInvoice === 'normal') {
  233. invoiceType = 2
  234. let title = isObject(this.editInvoice2.title)
  235. let code = isObject(this.editInvoice2.code)
  236. params = {
  237. invoiceType,
  238. title,
  239. code
  240. }
  241. let checkStr = [
  242. {
  243. name: '发票抬头',
  244. En: 'Title',
  245. val: title
  246. },
  247. {
  248. name: '税务登记号',
  249. En: 'Code',
  250. val: code
  251. }
  252. ]
  253. if (!check(checkStr)) {
  254. return
  255. }
  256. } else {
  257. let {title: title1, code: code1, organizedAddress: organizedAddress1, registerPhone: registerPhone1, bankName: bankName1, bankAccount: bankAccount1} = this.editInvoice3
  258. invoiceType = 3
  259. let title = isObject(title1)
  260. let code = isObject(code1)
  261. let organizedAddress = isObject(organizedAddress1)
  262. let registerPhone = isObject(registerPhone1)
  263. let bankName = isObject(bankName1)
  264. let bankAccount = isObject(bankAccount1)
  265. params = {
  266. invoiceType,
  267. title,
  268. code,
  269. organizedAddress,
  270. registerPhone,
  271. bankName,
  272. bankAccount
  273. }
  274. let checkStr = [
  275. {
  276. name: '发票抬头',
  277. En: 'Title',
  278. val: title
  279. },
  280. {
  281. name: '税务登记号',
  282. En: 'Code',
  283. val: code
  284. },
  285. {
  286. name: '注册地址',
  287. En: 'Organized address',
  288. val: organizedAddress
  289. },
  290. {
  291. name: '注册电话',
  292. En: 'Register phone',
  293. val: registerPhone
  294. },
  295. {
  296. name: '开户银行',
  297. En: 'Bank name',
  298. val: bankName
  299. },
  300. {
  301. name: '银行账号',
  302. En: 'Bank account',
  303. val: bankAccount
  304. }
  305. ]
  306. if (!check(checkStr)) {
  307. return
  308. }
  309. }
  310. this.$http
  311. .post('user/invoice/save', params, {
  312. headers: {
  313. token: this.token
  314. }
  315. })
  316. .then(data => {
  317. this.invoiceStatus = true
  318. this.$store.dispatch('getInvoice', {
  319. type: invoiceType,
  320. params: {
  321. invoiceType: invoiceType
  322. }
  323. })
  324. })
  325. },
  326. uAddress () {
  327. this.editAdd.province = this.tempSelect[0]
  328. this.editAdd.city = this.tempSelect[1]
  329. this.editAdd.shipAreaPath = this.tempSelect.join(',')
  330. let {
  331. shipAddress,
  332. shipAreaPath,
  333. province,
  334. city,
  335. shipMobile,
  336. shipName,
  337. id
  338. } = this.editAdd
  339. let check = value => {
  340. for (let i = 0, len = value.length; i < len; i++) {
  341. if (!value[i].val) {
  342. return this.$toast.show('warn', (this.language === 'en' ? value[i].En : value[i].name) + this.langToast['7'])
  343. }
  344. }
  345. return true
  346. }
  347. let checkStr = [
  348. {
  349. name: '详细地址',
  350. En: 'Detailed address',
  351. val: shipAddress
  352. },
  353. {
  354. name: '电话',
  355. En: 'Phone number',
  356. val: shipMobile
  357. },
  358. {
  359. name: '姓名',
  360. En: 'Name',
  361. val: shipName
  362. }
  363. ]
  364. if (!check(checkStr)) {
  365. return
  366. }
  367. let params = {
  368. shipAddress,
  369. shipAreaPath,
  370. province,
  371. city,
  372. shipMobile,
  373. shipName,
  374. id
  375. }
  376. this.$http
  377. .post('/user/updateAddress', params, {
  378. headers: {
  379. token: this.token
  380. }
  381. })
  382. .then(data => {
  383. this.addressStatus = true
  384. this.$store.dispatch('getInfo', {
  385. url: '/user/getReceiverInfo',
  386. name: 'address'
  387. })
  388. })
  389. },
  390. update (e) {
  391. let file = e.target.files[0]
  392. let type = file.type.toLowerCase()
  393. if (type !== 'image/jpeg' && type !== 'image/png') {
  394. return this.$toast.show('warn', this.langToast['36'])
  395. }
  396. let token = this.token
  397. let config = {
  398. headers: {
  399. token
  400. }
  401. } // 添加请求头
  402. var reader = new FileReader()
  403. reader.onload = async e => {
  404. let imgdata = e.target.result
  405. this.$http.post('/user/uploadHead', { imgdata }, config).then(data => {
  406. this.info.head = data.data.msg
  407. localStorage.setItem('info', JSON.stringify(this.info))
  408. })
  409. }
  410. reader.readAsDataURL(file)
  411. }
  412. },
  413. watch: {},
  414. mounted () {
  415. this.$store.dispatch('getInfo', {
  416. url: '/user/getReceiverInfo',
  417. name: 'address'
  418. })
  419. Object.keys(this.invoice2).length === 0 && this.$store.dispatch('getInvoice', {
  420. type: 2,
  421. params: {
  422. invoiceType: 2
  423. }
  424. })
  425. Object.keys(this.invoice3).length === 0 && this.$store.dispatch('getInvoice', {
  426. type: 3,
  427. params: {
  428. invoiceType: 3
  429. }
  430. })
  431. }
  432. }
  433. </script>
  434. <style lang="scss" scoped>
  435. .info-layout {
  436. $theme-color: #1fe4dc;
  437. $border-color: #e7e7e7;
  438. $info-width: 120px;
  439. width: 90%;
  440. padding-bottom: 100px;
  441. input {
  442. appearance: none;
  443. line-height: 36px;
  444. height: 36px;
  445. border: solid 1px $border-color;
  446. padding-left: 10px;
  447. &:focus {
  448. border: solid 1px $theme-color;
  449. }
  450. }
  451. .btn {
  452. text-align: center;
  453. cursor: pointer;
  454. }
  455. .parmary {
  456. background-color: $theme-color;
  457. width: 126px;
  458. height: 36px;
  459. line-height: 36px;
  460. margin-top: 20px;
  461. }
  462. .choose {
  463. background-color: #ddd;
  464. color: #2d2d2d;
  465. width: 100px;
  466. line-height: 26px;
  467. height: 26px;
  468. font-size: 12px;
  469. margin: 12px 0 20px;
  470. &:hover{
  471. background: #1fe4dc;
  472. }
  473. }
  474. .info,
  475. .address,
  476. .invoice {
  477. margin-top: 20px;
  478. p {
  479. line-height: 36px;
  480. span {
  481. padding-right: 10px;
  482. }
  483. }
  484. .p-desc {
  485. color: #a0a0a0;
  486. line-height: 24px;
  487. }
  488. .card-img{
  489. font-size: 0;
  490. display: inline-block;
  491. cursor: pointer;
  492. background-position: center;
  493. background-size: auto 100%;
  494. }
  495. .avatar {
  496. width: 68px;
  497. height: 68px;
  498. box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.4);
  499. margin: 5px 0;
  500. background-size: cover;
  501. background-repeat: no-repeat;
  502. }
  503. .nickname {
  504. width: 250px;
  505. }
  506. }
  507. .info{
  508. .s-tx{
  509. position: relative;
  510. &>p{
  511. position: absolute;
  512. left: 0;
  513. top: 0;
  514. }
  515. .avatar{
  516. margin-left: 80px
  517. }
  518. }
  519. p{
  520. span{
  521. display: inline-block;
  522. &:first-of-type{
  523. width: 80px;
  524. }
  525. }
  526. }
  527. }
  528. .info-en{
  529. .s-tx{
  530. .avatar{
  531. margin-left: $info-width;
  532. }
  533. }
  534. p{
  535. span{
  536. &:first-of-type{
  537. width: $info-width;
  538. }
  539. }
  540. }
  541. }
  542. .edit-info {
  543. display: flex;
  544. .info-left {
  545. &>p{
  546. margin: 10px 0;
  547. }
  548. min-width: 210px;
  549. .i-tx{
  550. position: relative;
  551. &>p{
  552. position: absolute;
  553. left: 0;
  554. top: 0;
  555. }
  556. .itx-con{
  557. margin-left: 80px;
  558. font-size: 14px;
  559. }
  560. }
  561. }
  562. .choose {
  563. cursor: pointer;
  564. position: relative;
  565. .el-upload {
  566. position: absolute;
  567. top: 0;
  568. left: 0;
  569. opacity: 0;
  570. line-height: 1;
  571. cursor: pointer;
  572. height: 100%;
  573. z-index: 10;
  574. width: 100%;
  575. padding: 0;
  576. margin: 0;
  577. font-size: 0;
  578. display: inline-block;
  579. }
  580. span {
  581. cursor: pointer;
  582. }
  583. }
  584. }
  585. .edit-en{
  586. .info-left {
  587. .i-tx{
  588. .itx-con{
  589. margin-left: $info-width;
  590. }
  591. }
  592. }
  593. }
  594. .edit-address {
  595. .input-con {
  596. input {
  597. width: 200px;
  598. line-height: 36px;
  599. height: 36px;
  600. margin: 10px 25px 10px 0;
  601. }
  602. }
  603. .address-input {
  604. input {
  605. width: 660px;
  606. }
  607. }
  608. }
  609. .edit-invoice {
  610. .select-con {
  611. div {
  612. position: relative;
  613. cursor: pointer;
  614. min-width: 230px;
  615. line-height: 36px;
  616. height: 36px;
  617. margin: 10px 25px 10px 0;
  618. border: solid 1px $border-color;
  619. color: #a0a0a0;
  620. padding: 0 10px;
  621. display: inline-block;
  622. img {
  623. display: none;
  624. position: absolute;
  625. bottom: 0;
  626. right: 0;
  627. }
  628. }
  629. .tag-active {
  630. border: solid 1px $theme-color;
  631. color: #000;
  632. img {
  633. display: inline-block;
  634. }
  635. }
  636. }
  637. .input-con {
  638. input {
  639. width: 316px;
  640. line-height: 36px;
  641. height: 36px;
  642. margin: 10px 25px 10px 0;
  643. }
  644. }
  645. }
  646. }
  647. @media screen and (min-width: 2000px) {
  648. .edit-layout {
  649. max-width: 75%!important;
  650. }
  651. }
  652. </style>