| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610 |
- <template>
- <wrapper
- class="c-profile"
- fill
- margin
- background
- >
- <div class="l-flex__none l-flex--col center c-profile__header has-padding">
- <div
- class="o-avatar u-pointer"
- @click="onAvatarClick"
- >
- <i
- class="o-avatar__img"
- :style="avatarStyle"
- />
- <i class="o-avatar__upload el-icon-camera" />
- <input
- ref="upload"
- type="file"
- accept="image/*"
- style="display: none;"
- @change="onUpload"
- >
- </div>
- <div class="c-profile__name has-top-padding">{{ name }}</div>
- <div class="u-relative has-top-padding">
- <i class="el-icon-user" />
- {{ role }}
- </div>
- </div>
- <div
- v-loading="loading"
- class="l-flex__fill l-flex--col center"
- >
- <warning
- v-if="error"
- @click="getUserInfo"
- />
- <div
- v-else
- class="has-padding l-flex--col"
- >
- <div class="l-flex--row">
- <UserInfoItem
- v-if="user"
- key="phone"
- v-model="phone"
- type="phone"
- :initial="user.attributes.phone[0]"
- @update="changeAttribute('phone', phone, '更新手机号')"
- />
- </div>
- <div class="l-flex--row has-padding--v">
- <UserInfoItem
- v-if="user"
- key="email"
- v-model="email"
- type="email"
- :initial="user.email"
- @update="updateUser({email}, '更新邮箱')"
- />
- </div>
- <div class="l-flex--row center has-top-padding">
- <div class="o-app">
- <i class="o-icon wechat has-bg" />
- <template v-if="wechat">
- <div class="l-flex--row">
- <div class="c-sibling-item u-color--info light">已绑定</div>
- <div
- class="c-sibling-item u-pointer"
- @click="onClickWechat"
- >
- 解绑
- </div>
- </div>
- </template>
- <div
- v-else
- class="u-pointer"
- @click="onClickWechat"
- >
- 绑定微信
- </div>
- </div>
- <div class="o-app">
- <i class="o-icon applet has-bg" />
- <template v-if="applet">
- <div class="l-flex--row">
- <div class="c-sibling-item u-color--info light">已绑定</div>
- <div
- class="c-sibling-item u-pointer"
- @click="onClickApplet"
- >
- 解绑
- </div>
- </div>
- </template>
- <div
- v-else
- class="u-pointer"
- @click="onClickApplet"
- >
- 绑定小程序
- </div>
- </div>
- </div>
- </div>
- </div>
- <el-dialog
- :visible.sync="showQr"
- custom-class="c-preview"
- width="0"
- @close="onCloseQr"
- >
- <div class="c-wechat has-padding">
- <div class="l-flex--row center has-bottom-padding">
- <i class="c-sibling-item o-icon medium wechat has-bg" />
- <span class="c-sibling-item u-color--black u-bold">请使用微信扫一扫</span>
- </div>
- <div
- v-loading="qrOptions.loading"
- class="c-wechat__wrapper"
- :class="{ retry: qrOptions.retry }"
- @click="getQr"
- >
- <img
- class="c-wechat__qr"
- :src="qrOptions.qr"
- >
- </div>
- </div>
- </el-dialog>
- </wrapper>
- </template>
- <script>
- import { mapGetters } from 'vuex'
- import UserInfoItem from './components/UserInfoItem'
- import {
- userinfo,
- updateUser,
- getTicket,
- getQrcode
- } from '@/api/user'
- import {
- validPhone,
- validEmail
- } from '@/utils/validate'
- import { GATEWAY } from '@/constant'
- export default {
- name: 'Profile',
- components: {
- UserInfoItem
- },
- data () {
- return {
- loading: true,
- error: false,
- user: {
- email: '',
- attributes: {
- phone: ['']
- }
- },
- avatar: '',
- phone: '',
- email: '',
- wechat: '',
- applet: '',
- showQr: false,
- qrType: 'wechatOptions',
- wechatOptions: {
- loading: false,
- retry: false,
- qr: null
- },
- appletOptions: {
- loading: false,
- retry: false,
- qr: null
- }
- }
- },
- computed: {
- ...mapGetters([
- 'name',
- 'isSuperAdmin',
- 'isTenantAdmin',
- 'isGroupAdmin'
- ]),
- avatarStyle () {
- const avatar = this.avatar
- return avatar ? { backgroundImage: `url("${avatar}")` } : null
- },
- qrOptions () {
- return this[this.qrType]
- },
- role () {
- if (this.isSuperAdmin) {
- return '超级管理员'
- }
- if (this.isTenantAdmin) {
- return '管理员'
- }
- if (this.isGroupAdmin) {
- return '主管'
- }
- return '员工'
- }
- },
- created () {
- this.$timer = null
- this.$checkTimer = null
- this.getUserInfo()
- },
- beforeDestroy () {
- clearTimeout(this.$timer)
- clearInterval(this.$checkTimer)
- },
- methods: {
- onAvatarClick () {
- this.$refs.upload.click()
- },
- onUpload (e) {
- const file = e.target.files[0]
- e.target.value = null
- if (file.size >= 1024 * 1024) {
- this.$message({
- type: 'warning',
- message: '请选择1M以下的图片'
- })
- return
- }
- const reader = new FileReader()
- reader.onload = () => {
- this.avatar = reader.result
- }
- reader.readAsDataURL(file)
- },
- getUserInfo () {
- this.loading = true
- this.error = false
- userinfo().then(
- this.setUserInfo,
- () => {
- this.error = true
- }
- ).finally(() => {
- this.loading = false
- })
- },
- setUserInfo (data) {
- if (!data.attributes) {
- data.attributes = {}
- }
- this.avatar = this.getOrCreateAttribute(data, 'avatar', '')
- this.phone = this.getOrCreateAttribute(data, 'phone', '')
- this.email = data.email ?? ''
- this.wechat = this.getOrCreateAttribute(data, 'wechat', '')
- this.user = data
- this.applet = this.getOrCreateAttribute(data, 'wechat-applet-openid', '')
- },
- getOrCreateAttribute (user, key, defaults = '') {
- if (!user.attributes[key]) {
- user.attributes[key] = [defaults]
- }
- return user.attributes[key][0]
- },
- updateUser (data, meesage) {
- return updateUser(this.user.id, data, meesage).then(() => {
- this.user = { ...this.user, ...data }
- })
- },
- changeAttribute (key, value, meesage) {
- if (this.user.attributes[key][0] !== value) {
- this.updateUser({
- attributes: {
- ...this.user.attributes,
- [key]: [value]
- }
- }, meesage).then(
- () => {
- this.user.attributes[key][0] = value
- },
- () => {
- this.resetAttribute(key)
- }
- )
- }
- },
- resetAttribute (key) {
- this[key] = this.user.attributes[key][0]
- },
- resetProp (key) {
- this[key] = this.user[key] ?? ''
- },
- onPhoneChange () {
- if (!this.phone) {
- this.$message({
- type: 'warning',
- message: '手机号不能为空'
- })
- this.resetAttribute('phone')
- return
- }
- if (!validPhone(this.phone)) {
- this.$message({
- type: 'warning',
- message: '手机号格式错误'
- })
- this.resetAttribute('phone')
- return
- }
- this.changeAttribute('phone', this.phone, '更新手机号')
- },
- onEmailChange () {
- if (!this.email) {
- this.$message({
- type: 'warning',
- message: '邮箱不能为空'
- })
- this.resetProp('email')
- return
- }
- if (!validEmail(this.email)) {
- this.$message({
- type: 'warning',
- message: '邮箱格式错误'
- })
- this.resetProp('email')
- return
- }
- this.updateUser({ email: this.email }, '更新邮箱').then(
- () => {
- this.user.email = this.email
- },
- () => {
- this.resetProp('email')
- }
- )
- },
- onClickWechat () {
- if (this.wechat) {
- this.$confirm(
- '解除绑定后将无法再收到消息推送',
- '解绑微信',
- { type: 'warning' }
- ).then(() => {
- this.changeAttribute('wechat', this.wechat = '', '解绑公众号')
- })
- } else {
- this.qrType = 'wechatOptions'
- this.showQr = true
- this.getQr()
- }
- },
- onClickApplet () {
- if (this.applet) {
- this.$confirm(
- '解除绑定后将无法使用小程序的功能',
- '解绑小程序',
- { type: 'warning' }
- ).then(
- () => {
- this.changeAttribute('wechat-applet-openid', this.applet = '', '解绑小程序')
- }
- )
- } else {
- this.qrType = 'appletOptions'
- this.showQr = true
- this.getQr()
- }
- },
- onCloseQr () {
- this.showQr = false
- },
- getQr () {
- const options = this.qrOptions
- if (options.loading || options.qr && !options.retry) {
- return
- }
- switch (this.qrType) {
- case 'wechatOptions':
- this.getWechatQr()
- break
- case 'appletOptions':
- this.getAppletQr()
- break
- default:
- break
- }
- },
- getWechatQr () {
- const options = this.wechatOptions
- if (!this.showQr || this.qrType !== 'wechatOptions') {
- options.qr = null
- return
- }
- options.loading = true
- options.retry = false
- clearTimeout(this.$timer)
- getTicket(this.user.id).then(
- ({ data }) => {
- if (!this.wechat) {
- try {
- const { expire_seconds, ticket } = JSON.parse(data)
- options.checking = true
- options.qr = `https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=${ticket}`
- // 提前10秒重新获取
- this.$timer = setTimeout(this.getWechatQr, (expire_seconds > 10 ? expire_seconds - 10 : expire_seconds) * 1000)
- this.checkBind()
- } catch (e) {
- console.warn(e)
- options.retry = true
- }
- }
- },
- () => {
- if (!this.wechat) {
- options.retry = true
- }
- }
- ).finally(() => {
- options.loading = false
- })
- },
- getAppletQr () {
- const options = this.appletOptions
- options.loading = true
- options.retry = false
- getQrcode({ page: 'pages/device/device', sourceUrl: GATEWAY }).then(
- ({ data }) => {
- options.checking = true
- options.qr = `data:image/png;base64,${data}`
- this.checkBind()
- },
- () => {
- options.retry = true
- }
- ).finally(() => {
- options.loading = false
- })
- },
- checkBind () {
- if (!this.$checkTimer) {
- this.$checkTimer = setInterval(this.check, 2000)
- }
- },
- check () {
- userinfo(true).then(data => {
- let bound = false
- let needCheck = false
- if (this.wechatOptions.checking) {
- const wechat = data.attributes.wechat?.[0]
- if (wechat) {
- bound = true
- this.wechatOptions.checking = false
- this.$message({
- type: 'success',
- message: '绑定公众号成功'
- })
- clearTimeout(this.$timer)
- this.wechatOptions.qr = null
- if (this.qrType === 'wechatOptions') {
- this.onCloseQr()
- }
- } else {
- needCheck = true
- }
- }
- if (this.appletOptions.checking) {
- const applet = data.attributes['wechat-applet-openid']?.[0]
- if (applet) {
- bound = true
- this.appletOptions.checking = false
- this.$message({
- type: 'success',
- message: '绑定小程序成功'
- })
- this.appletOptions.qr = null
- if (this.qrType === 'appletOptions') {
- this.onCloseQr()
- }
- } else {
- needCheck = true
- }
- }
- if (bound) {
- this.setUserInfo(data)
- }
- if (!needCheck) {
- clearInterval(this.$checkTimer)
- this.$checkTimer = null
- }
- })
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .c-profile {
- overflow: hidden;
- &__header {
- color: #fff;
- line-height: 1;
- background-color: $blue;
- }
- &__name {
- font-size: 20px;
- }
- }
- .o-avatar {
- display: inline-block;
- position: relative;
- width: 80px;
- height: 80px;
- padding: 2px;
- border-radius: 50%;
- background-color: #fff;
- &__img {
- display: inline-block;
- width: 100%;
- height: 100%;
- border-radius: 50%;
- background: url("~@/assets/icon_avatar.png") 0 0 / 100% 100% no-repeat;
- }
- &__upload {
- display: inline-flex;
- justify-content: center;
- align-items: center;
- position: absolute;
- right: 0;
- bottom: 0;
- width: 26px;
- height: 26px;
- color: $blue;
- border-radius: 50%;
- background-color: #fff;
- }
- }
- .el-icon-user {
- position: absolute;
- left: -32px;
- }
- .o-app {
- display: inline-flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- width: 128px;
- color: $blue;
- font-size: 16px;
- .o-icon {
- margin-bottom: $spacing;
- }
- }
- .o-icon {
- &.wechat {
- background-image: url("~@/assets/icon_wechat.png");
- }
- &.applet {
- background-image: url("~@/assets/icon_applet.png");
- }
- }
- .c-wechat {
- border-radius: $radius;
- background-color: #fff;
- &__wrapper {
- position: relative;
- width: 240px;
- height: 240px;
- &.retry::after {
- content: "点击重试";
- display: inline-flex;
- justify-content: center;
- align-items: center;
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- color: $black;
- font-weight: bold;
- background-color: rgba(#fff, 0.8);
- cursor: pointer;
- }
- }
- &__qr {
- display: inline-block;
- width: 100%;
- height: 100%;
- }
- }
- </style>
|