Procházet zdrojové kódy

Merge branch 'staging' of http://pms.inspur.com/web/msr into staging

Casper Dai před 3 roky
rodič
revize
395542482f

+ 15 - 0
src/api/user.js

@@ -369,3 +369,18 @@ function addUserRoles (userId, roles) {
     data: roles
   })
 }
+export function authcodeSend (data) {
+  return request({
+    url: `/authcode/send`,
+    method: 'POST',
+    data
+  })
+}
+
+export function authcodeCheck (data) {
+  return request({
+    url: `/authcode/check`,
+    method: 'POST',
+    data
+  })
+}

+ 261 - 0
src/views/platform/profile/components/UserInfoItem.vue

@@ -0,0 +1,261 @@
+<template>
+  <div class="l-flex--col">
+    <div class="l-flex--row c-line">
+      <div class="c-grid-form__label c-line__left u-color--black u-bold">
+        绑定{{ config.label }}:
+      </div>
+      <div class="c-line__mid">
+        <el-input
+          v-model="cValue"
+          :maxlength="config.maxlength"
+          :placeholder="'请输入'+config.tipText"
+        />
+      </div>
+      <div class="c-line__right has-left-padding">
+        <button
+          v-if="expanded === false"
+          class="o-button"
+          @click="expanded = true"
+        >
+          {{ initial?'更换':'绑定' }}{{ config.label }}
+        </button>
+        <div
+          v-else
+          class="u-pointer u-color--blue"
+          @click="expanded = false"
+        >
+          收起
+        </div>
+      </div>
+    </div>
+    <div
+      v-if="expanded === true"
+      class="l-flex--row c-line"
+    >
+      <div class="c-line__left" />
+      <div class="c-line__mid l-flex--row">
+        <el-input
+          v-model="code"
+          class="c-code"
+          maxlength="6"
+          placeholder="验证码"
+          @keydown.enter="bind"
+        />
+        <el-button
+          class="o-button l-flex__fill c-btn"
+          :disabled="verification"
+          @click="sendCode"
+        >
+          {{ codeText }}
+        </el-button>
+      </div>
+      <div class="c-line__right" />
+    </div>
+    <div
+      v-if="expanded === true"
+      class="l-flex--row c-line"
+    >
+      <div class="c-line__left" />
+      <div class="c-line__mid l-flex--row">
+        <el-button
+          class="o-button l-flex__fill"
+          @click="bind"
+        >绑定</el-button>
+      </div>
+      <div class="c-line__right" />
+    </div>
+  </div>
+</template>
+
+<script>
+import {
+  validPhone, validEmail
+} from '@/utils/validate'
+import {
+  authcodeSend, authcodeCheck
+} from '@/api/user'
+const COUNTDOWN = 60
+const config = {
+  phone: {
+    label: '手机',
+    tipText: '手机号',
+    maxlength: 11,
+    valid: validPhone,
+    typeKey: 'phoneNum',
+    codeKey: 'phoneNumAuthCode',
+    checkKey: 'checkPhoneNum'
+  },
+  email: {
+    label: '邮箱',
+    maxlength: 50,
+    valid: validEmail,
+    tipText: '邮箱',
+    typeKey: 'email',
+    codeKey: 'emailAuthCode',
+    checkKey: 'checkEmail'
+  }
+}
+export default {
+  name: 'UserInfoItem',
+  props: {
+    type: {
+      type: String,
+      require: true,
+      default: 'phone'
+    },
+    value: {
+      type: String,
+      default: ''
+    },
+    initial: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      config: {},
+      code: null,
+      expanded: false,
+      verification: false,
+      countDown: COUNTDOWN
+    }
+  },
+  computed: {
+    cValue: {
+      get () {
+        return this.value
+      },
+      set (v) {
+        this.$emit('input', v)
+      }
+    },
+    codeText () {
+      return this.verification ? `${this.countDown} s` : '发送验证码'
+    }
+  },
+  watch: {
+    initial () {
+      this.reset()
+    }
+  },
+  created () {
+    this.config = config[this.type]
+  },
+  beforeDestroy () {
+    clearInterval(this.$timer)
+  },
+  methods: {
+    reset () {
+      this.expanded = false
+      this.code = ''
+      this.verification = false
+      this.countDown = COUNTDOWN
+      clearInterval(this.$timer)
+    },
+    sendCode () {
+      if (this.verification) {
+        return
+      }
+      if (!this.value) {
+        this.$message({
+          type: 'warning',
+          message: `${this.config.tipText}不能为空`
+        })
+        return
+      }
+      if (!this.config.valid(this.value)) {
+        this.$message({
+          type: 'warning',
+          message: `${this.config.tipText}格式错误`
+        })
+        return
+      }
+      authcodeSend({
+        [this.config.typeKey]: this.value
+      })
+        .then(({ success, errMessage }) => {
+          if (success) {
+            this.$message({
+              type: 'success',
+              message: '验证码已发送...'
+            })
+            this.verification = true
+            this.countDown = COUNTDOWN
+            this.$timer = setInterval(() => {
+              this.countDown--
+              if (this.countDown <= 0) {
+                this.verification = false
+                this.countDown = COUNTDOWN
+                clearInterval(this.$timer)
+              }
+            }, 1000)
+          } else {
+            console.log(errMessage)
+          }
+        })
+        .catch(err => {
+          console.log(err)
+        })
+    },
+
+    bind () {
+      if (!this.value) {
+        this.$message({
+          type: 'warning',
+          message: `${this.config.tipText}不能为空`
+        })
+        return
+      }
+      if (!this.code) {
+        this.$message({
+          type: 'warning',
+          message: `验证码不能为空`
+        })
+        return
+      }
+      authcodeCheck({
+        [this.config.typeKey]: this.value,
+        [this.config.codeKey]: this.code
+      }).then(({ success, data }) => {
+        if (success) {
+          if (data[this.config.checkKey]) {
+            this.$emit('update', () => this.reset())
+            return
+          }
+        }
+        this.$message({
+          type: 'error',
+          message: `验证码错误`
+        })
+      }).catch(err => {
+        console.log(err)
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.c-line {
+  padding-bottom: $spacing;
+  width: 420px;
+  &__left {
+    flex: 0 0 80px;
+  }
+  &__mid {
+    flex: 1
+  }
+  &__right {
+    flex: 0 0 120px;
+  }
+}
+.c-code {
+  flex: 0 0 100px;
+  margin-right: 20px;
+}
+::v-deep.el-button.is-disabled {
+  border: 1px solid $blue;
+  color: $blue;
+}
+</style>

+ 30 - 21
src/views/platform/profile/index.vue

@@ -39,29 +39,27 @@
       />
       <div
         v-else
-        class="has-padding"
+        class="has-padding l-flex--col"
       >
         <div class="l-flex--row">
-          <label class="c-grid-form__label">手机:</label>
-          <div>
-            <el-input
-              v-model="phone"
-              maxlength="11"
-              @change="onPhoneChange"
-              @keydown.enter="$event.target.blur()"
-            />
-          </div>
+          <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">
-          <label class="c-grid-form__label">邮箱:</label>
-          <div>
-            <el-input
-              v-model="email"
-              maxlength="50"
-              @change="onEmailChange"
-              @keydown.enter="$event.target.blur()"
-            />
-          </div>
+          <UserInfoItem
+            v-if="user"
+            key="email"
+            v-model="email"
+            type="email"
+            :initial="user.email"
+            @update="updateUser({email}, '更新邮箱')"
+          />
         </div>
         <div class="l-flex--row has-top-padding">
           <div class="o-app">
@@ -138,6 +136,7 @@
 
 <script>
 import { mapGetters } from 'vuex'
+import UserInfoItem from './components/UserInfoItem'
 import {
   userinfo,
   updateUser,
@@ -151,11 +150,19 @@ import {
 
 export default {
   name: 'Profile',
+  components: {
+    UserInfoItem
+  },
   data () {
     return {
       loading: true,
       error: false,
-      user: null,
+      user: {
+        email: '',
+        attributes: {
+          phone: ['']
+        }
+      },
       avatar: '',
       phone: '',
       email: '',
@@ -261,7 +268,9 @@ export default {
       return user.attributes[key][0]
     },
     updateUser (data, meesage) {
-      return updateUser(this.user.id, 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) {

+ 19 - 3
src/views/review/workflow/detail/components/ReviewDialog.vue

@@ -108,7 +108,9 @@
 
 <script>
 import { getAssetUrl } from '@/api/asset'
-import { AssetType } from '@/constant'
+import {
+  AssetType, State
+} from '@/constant'
 export default {
   name: 'ReviewDialog',
   props: {
@@ -150,7 +152,7 @@ export default {
   },
   computed: {
     showOpt () {
-      return ![2, 3].includes(this.form.status)
+      return ![State.RESOLVED, State.REJECTED].includes(this.form.status)
     },
     form () {
       return this.list[this.index] || {}
@@ -187,17 +189,31 @@ export default {
       this.$refs.previewDialog.show(this.source)
     },
     resolve () {
-      this.$emit('resolve', this.form)
+      this.$emit('resolve', this.form, () => this.nextWaiting())
     },
     reject () {
       this.$emit(
         'reject',
         () => {
           this.$message.success('驳回成功!')
+          this.nextWaiting()
         },
         { item: this.form, review: this.review }
       )
     },
+    nextWaiting () {
+      const list = this.list.map((i, index) => { return { ...i, index } }).filter(i => ![State.REJECTEDt, State.RESOLVED].includes(i.status))
+      if (!list.length) {
+        this.isReviewing = false
+      }
+      for (const item of list) {
+        if (this.index < item.index) {
+          this.next(item.index - this.index)
+          return
+        }
+      }
+      this.next(list[0].index + this.list.length - this.index)
+    },
     next (gap) {
       const position = this.index
       let index = (position + gap) % this.list.length

+ 14 - 23
src/views/review/workflow/detail/index.vue

@@ -11,7 +11,7 @@
       :error="error"
       @click="getPublishWorkflowDetail"
     />
-    <div v-if="dataMap.length">
+    <template v-if="dataMap.length">
       <div class="l-flex--row o-title has-bottom-padding u-color--black u-bold">{{ title }} <span class="applicant">{{ createBy?`申请人:${createBy}`:'' }}</span></div>
       <div class="l-flex--row has-padding">
         <el-steps
@@ -114,7 +114,7 @@
           </template>
         </div>
       </confirm-dialog>
-    </div>
+    </template>
   </wrapper>
 </template>
 
@@ -134,7 +134,6 @@ import {
 import mediaMixin from '@/views/platform/media/mixin.js'
 import {
   State,
-  ScheduleType,
   EventPriority,
   EventFreq,
   EventTarget,
@@ -242,10 +241,7 @@ export default {
       switch (this.backDataType) {
         case front2back['assets']:
           return {
-            singlePage: true,
-            condition: { status: State.REVIEW },
             list: this.getList('assets'),
-            // transform: this.transform,
             cols: [
               { prop: 'typeName', label: '类型', align: 'center', width: 80 },
               { prop: 'file', type: 'asset', on: this.onViewAsset },
@@ -267,16 +263,15 @@ export default {
               {
                 type: 'invoke',
                 width: 80,
-                render: [{ label: '审核', on: this.onView }]
+                render: [{ label: '审核', on: this.onView, render ({ status }) {
+                  return showOpt(status)
+                } }]
               }
             ]
           }
         case front2back['program']:
           return {
-            singlePage: true,
-            condition: { status: State.REVIEW },
             list: this.getList('program'),
-            // transform: this.transform,
             cols: [
               { prop: 'name', label: '节目名称', 'min-width': 100 },
               { prop: 'resolutionRatio', label: '分辨率' },
@@ -317,11 +312,6 @@ export default {
         case front2back['programRecur']:
         case front2back['schedule']:
           return {
-            singlePage: true,
-            condition: {
-              type: ScheduleType.COMPLEX,
-              status: State.REVIEW
-            },
             list: this.getList('schedule'),
             cols: [
               { prop: 'name', label: '排期名称', 'min-width': 100 },
@@ -362,10 +352,7 @@ export default {
           }
         case front2back['publish']:
           return {
-            singlePage: true,
-            condition: { status: State.REVIEW },
             list: this.getList('publish'),
-            // transform: this.transform,
             cols: [
               {
                 prop: 'expand',
@@ -488,7 +475,7 @@ export default {
       this.getPublishWorkflowDetail()
     },
     refreshStatus (item, status, review) {
-      const list = this.sourceMap[this.backDataType]
+      const list = this.tableData
       const index = list.findIndex(i => i.id === item.id)
       list[index].status = status
       this.$refs.table.onPagination()
@@ -501,7 +488,7 @@ export default {
       }
     },
     getList () {
-      return () => Promise.resolve({ data: this.tableData })
+      return () => Promise.resolve({ data: this.tableData, totalCount: 1 })
     },
     // 全部审批通过
     nextStep () {
@@ -669,9 +656,10 @@ export default {
       }
     },
     // 通过
-    onResolve (item) {
+    onResolve (item, done) {
       this.resolve(item).then(() => {
         this.refreshStatus(item, State.RESOLVED)
+        done()
       })
     },
     resolve (item) {
@@ -731,10 +719,13 @@ export default {
             type: this.review.type,
             reason: this.review.reason
           })
+          // 自动触发媒资驳回的二次确认弹窗
+          if (!this.tableData.filter(i => ![State.RESOLVED, State.REJECTED].includes(i.status)).length) {
+            this.reject()
+          }
         })
       } else {
-        // 取最新
-        done()
+        // 单数据方取最新 直接驳回接口 单数据方法不回调,确认验证在接口方法
         this.reject([rejectInfo], rejectInfo.name)
       }
     },