Просмотр исходного кода

feature(督办详情):如下

1.新增督办详情页面
2.全局容器高度调整
3.选择用户组件调整
4.客户管理bug修复6处
wanglj 3 лет назад
Родитель
Сommit
79f58a52cb

+ 22 - 4
src/components/select/SelectUser.vue

@@ -21,7 +21,7 @@
         </el-dropdown>
         </el-dropdown>
         <ul v-infinite-scroll="fetchData" class="options" :infinite-scroll-disabled="disabled">
         <ul v-infinite-scroll="fetchData" class="options" :infinite-scroll-disabled="disabled">
           <li v-for="(item, index) in options" :key="index" @click="transfer(index)">
           <li v-for="(item, index) in options" :key="index" @click="transfer(index)">
-            <span>{{ item.userName }}</span>
+            <span>{{ item.nickName }}</span>
             <i class="el-icon-arrow-right"></i>
             <i class="el-icon-arrow-right"></i>
           </li>
           </li>
         </ul>
         </ul>
@@ -33,7 +33,7 @@
         </header>
         </header>
         <ul class="options">
         <ul class="options">
           <li v-for="(item, index) in selected" :key="index" @click="goBack(index)">
           <li v-for="(item, index) in selected" :key="index" @click="goBack(index)">
-            <span>{{ item.userName }}</span>
+            <span>{{ item.nickName }}</span>
           </li>
           </li>
         </ul>
         </ul>
       </el-col>
       </el-col>
@@ -56,6 +56,14 @@
         default: '选择',
         default: '选择',
       },
       },
       multiple: Boolean,
       multiple: Boolean,
+      property: {
+        type: String,
+        default: '',
+      },
+      label: {
+        type: String,
+        default: '',
+      },
       queryParams: {
       queryParams: {
         type: Object,
         type: Object,
         default() {
         default() {
@@ -76,6 +84,7 @@
         list: [],
         list: [],
         options: [],
         options: [],
         selected: [],
         selected: [],
+        ids: [],
       }
       }
     },
     },
     mounted() {
     mounted() {
@@ -83,11 +92,20 @@
     },
     },
     methods: {
     methods: {
       open() {
       open() {
+        this.clear()
+        console.log(this.ids, 'ids')
+        if (this.ids.length) {
+          for (const item of this.ids) {
+            const index = this.options.findIndex((each) => each.id == item)
+            console.log(index, this.options[index])
+            if (index > -1) this.transfer(index)
+          }
+        }
         this.innerVisible = true
         this.innerVisible = true
       },
       },
       save() {
       save() {
         this.innerVisible = false
         this.innerVisible = false
-        this.$emit('save', this.selected)
+        this.$emit('save', this.selected, this.property, this.label)
       },
       },
       search() {
       search() {
         this.queryForm.pageNum = 1
         this.queryForm.pageNum = 1
@@ -142,7 +160,7 @@
       },
       },
       clear() {
       clear() {
         this.selected = []
         this.selected = []
-        this.options = this.list
+        this.options = [...this.list]
       },
       },
     },
     },
   }
   }

+ 21 - 0
src/store/modules/task.js

@@ -0,0 +1,21 @@
+/*
+ * @Author: wanglj 471442253@qq.com
+ * @Date: 2023-01-10 14:20:01
+ * @LastEditors: wanglj
+ * @LastEditTime: 2023-01-10 14:21:23
+ * @Description: file content
+ * @FilePath: \opms_frontend\src\store\modules\task.js
+ */
+/**
+ * @description 督办管理
+ */
+
+const state = () => ({
+  theTask: {},
+})
+const getters = {
+  theTask: (state) => state.theTask,
+}
+const mutations = {}
+const actions = {}
+export default { state, getters, mutations, actions }

+ 2 - 2
src/store/modules/user.js

@@ -96,8 +96,8 @@ const actions = {
     const userId = res.data.entity.id
     const userId = res.data.entity.id
     const username = res.data.entity.userName
     const username = res.data.entity.userName
     const avatar = res.data.entity.avatar
     const avatar = res.data.entity.avatar
-    let roles
-    let permissions
+    let roles = res.data.roleIds
+    let permissions = res.data.permissions
     /**
     /**
      * 检验返回数据是否正常,无对应参数,将使用默认用户名,头像,Roles和Permissions
      * 检验返回数据是否正常,无对应参数,将使用默认用户名,头像,Roles和Permissions
      * username {String}
      * username {String}

+ 1 - 1
src/vab/styles/variables/variables.scss

@@ -75,7 +75,7 @@ $base-tag-item-height: 34px;
 $base-menu-item-height: 50px;
 $base-menu-item-height: 50px;
 //app-main的高度
 //app-main的高度
 $base-keep-alive-height: calc(
 $base-keep-alive-height: calc(
-  100vh - #{$base-nav-height} - #{$base-tabs-height} - #{$base-padding} * 2 - 40px
+  100vh - #{$base-nav-height} - #{$base-padding} * 2 - 40px
 );
 );
 //纵向左侧导航未折叠的宽度
 //纵向左侧导航未折叠的宽度
 $base-left-menu-width: 266px;
 $base-left-menu-width: 266px;

+ 2 - 1
src/views/customer/components/Allocate.vue

@@ -2,7 +2,7 @@
  * @Author: wanglj 471442253@qq.com
  * @Author: wanglj 471442253@qq.com
  * @Date: 2022-12-26 14:34:34
  * @Date: 2022-12-26 14:34:34
  * @LastEditors: wanglj
  * @LastEditors: wanglj
- * @LastEditTime: 2023-01-05 18:17:04
+ * @LastEditTime: 2023-01-10 11:08:34
  * @Description: file content
  * @Description: file content
  * @FilePath: \opms_frontend\src\views\customer\components\allocate.vue
  * @FilePath: \opms_frontend\src\views\customer\components\allocate.vue
 -->
 -->
@@ -72,6 +72,7 @@
         this.form.allocate = userList.map((item) => item.userName).join()
         this.form.allocate = userList.map((item) => item.userName).join()
       },
       },
       async handleSubmit() {
       async handleSubmit() {
+        if (!this.userList.length) return this.$message.warning('请选择销售代表')
         let params = {
         let params = {
           salesId: this.userList[0].id,
           salesId: this.userList[0].id,
           ids: this.ids,
           ids: this.ids,

+ 35 - 8
src/views/customer/components/Contact.vue

@@ -91,6 +91,16 @@
           callback()
           callback()
         }
         }
       }
       }
+      var validateEmail = (rule, value, callback) => {
+        const reg = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$/
+        if (!value) {
+          callback()
+        } else if (!reg.test(value)) {
+          callback(new Error('请输入正确邮箱'))
+        } else {
+          callback()
+        }
+      }
       return {
       return {
         title: '新增联系人',
         title: '新增联系人',
         contactVisible: false,
         contactVisible: false,
@@ -110,18 +120,24 @@
           cuctName: [{ required: true, trigger: 'blur', message: '请输入联系人姓名' }],
           cuctName: [{ required: true, trigger: 'blur', message: '请输入联系人姓名' }],
           custName: [{ required: true, trigger: 'blur', message: '请输入客户名称' }],
           custName: [{ required: true, trigger: 'blur', message: '请输入客户名称' }],
           telephone: [{ required: true, trigger: 'blur', validator: validateTel }],
           telephone: [{ required: true, trigger: 'blur', validator: validateTel }],
+          postion: [{ required: true, trigger: 'blur', message: '请输入职位' }],
+          email: [{ trigger: 'blur', validator: validateEmail }],
         },
         },
       }
       }
     },
     },
     methods: {
     methods: {
       // 联系人新建
       // 联系人新建
       async contactSave() {
       async contactSave() {
-        let params = { ...this.contactForm }
-        const [err, res] = await to(api.createContact(params))
-        if (err) return
-        this.$message.success(res.msg)
-        this.contactVisible = false
-        this.$emit('contactSave')
+        this.$refs.contactForm.validate(async (valid) => {
+          if (valid) {
+            let params = { ...this.contactForm }
+            const [err, res] = await to(api.createContact(params))
+            if (err) return
+            this.$message.success(res.msg)
+            this.contactVisible = false
+            this.$emit('contactSave')
+          }
+        })
       },
       },
       // 联系人编辑
       // 联系人编辑
       async contactEdit() {
       async contactEdit() {
@@ -133,8 +149,19 @@
         this.$emit('contactSave')
         this.$emit('contactSave')
       },
       },
       contactClose() {
       contactClose() {
-        this.$refs.contactForm.resetFields()
-        this.contactForm.custId = ''
+        this.contactForm = {
+          custId: '', //客户ID  (必传)
+          custName: '', //客户名称
+          cuctName: '', //联系人名字
+          cuctGender: '10', //性别(10男20女)
+          postion: '', //职位
+          telephone: '', //电话
+          wechat: '', //微信
+          email: '', //邮箱
+          remark: '', //备注
+          policy: 0, //是否决策人 0 不是  1 是
+        }
+        this.$refs.contactForm.clearValidate()
       },
       },
     },
     },
   }
   }

+ 2 - 1
src/views/customer/components/Shift.vue

@@ -2,7 +2,7 @@
  * @Author: wanglj 471442253@qq.com
  * @Author: wanglj 471442253@qq.com
  * @Date: 2022-12-26 17:21:07
  * @Date: 2022-12-26 17:21:07
  * @LastEditors: wanglj
  * @LastEditors: wanglj
- * @LastEditTime: 2023-01-04 18:06:08
+ * @LastEditTime: 2023-01-10 11:10:14
  * @Description: file content
  * @Description: file content
  * @FilePath: \opms_frontend\src\views\customer\components\Shift.vue
  * @FilePath: \opms_frontend\src\views\customer\components\Shift.vue
 -->
 -->
@@ -66,6 +66,7 @@
         this.form.SalesName = userList[0].userName
         this.form.SalesName = userList[0].userName
       },
       },
       async handleSubmit() {
       async handleSubmit() {
+        if (!this.userList.length) return this.$message.warning('请选择销售代表')
         let params = { ...this.form }
         let params = { ...this.form }
         params.SalesId = this.userList[0].id
         params.SalesId = this.userList[0].id
         const [err, res] = await to(api.updateBytransfer(params))
         const [err, res] = await to(api.updateBytransfer(params))

+ 2 - 2
src/views/customer/components/ToOpen.vue

@@ -2,12 +2,12 @@
  * @Author: wanglj 471442253@qq.com
  * @Author: wanglj 471442253@qq.com
  * @Date: 2022-12-26 17:21:07
  * @Date: 2022-12-26 17:21:07
  * @LastEditors: wanglj
  * @LastEditors: wanglj
- * @LastEditTime: 2022-12-28 14:10:30
+ * @LastEditTime: 2023-01-10 10:48:11
  * @Description: file content
  * @Description: file content
  * @FilePath: \opms_frontend\src\views\customer\components\ToOpen.vue
  * @FilePath: \opms_frontend\src\views\customer\components\ToOpen.vue
 -->
 -->
 <template>
 <template>
-  <el-dialog title="转移客户" :visible.sync="visible" width="30%" @close="handleClose">
+  <el-dialog title="移入公海" :visible.sync="visible" width="30%" @close="handleClose">
     <el-form ref="form" label-width="100px" :model="form">
     <el-form ref="form" label-width="100px" :model="form">
       <el-form-item label="移入公海原因" prop="remark">
       <el-form-item label="移入公海原因" prop="remark">
         <el-input v-model="form.remark" maxlength="300" resize="none" :rows="5" show-word-limit type="textarea" />
         <el-input v-model="form.remark" maxlength="300" resize="none" :rows="5" show-word-limit type="textarea" />

+ 5 - 7
src/views/customer/detail.vue

@@ -2,7 +2,7 @@
  * @Author: wanglj 471442253@qq.com
  * @Author: wanglj 471442253@qq.com
  * @Date: 2022-12-26 09:30:47
  * @Date: 2022-12-26 09:30:47
  * @LastEditors: wanglj
  * @LastEditors: wanglj
- * @LastEditTime: 2023-01-05 11:50:51
+ * @LastEditTime: 2023-01-10 15:25:50
  * @Description: file content
  * @Description: file content
  * @FilePath: \opms_frontend\src\views\customer\detail.vue
  * @FilePath: \opms_frontend\src\views\customer\detail.vue
 -->
 -->
@@ -22,7 +22,7 @@
               </template>
               </template>
               <template v-else>
               <template v-else>
                 <el-button @click="handleReceive">领取客户</el-button>
                 <el-button @click="handleReceive">领取客户</el-button>
-                <el-button @click="handleAllocate">分配客户</el-button>
+                <el-button v-permissions="['customer:allocate']" @click="handleAllocate">分配客户</el-button>
               </template>
               </template>
             </span>
             </span>
           </h3>
           </h3>
@@ -345,14 +345,13 @@
       async getDynamics() {
       async getDynamics() {
         const [err, res] = await to(api.dynamicsList({ custId: parseInt(this.id) }))
         const [err, res] = await to(api.dynamicsList({ custId: parseInt(this.id) }))
         if (err) return
         if (err) return
-        if (res.data.list[0]) {
+        if (res.data.list && res.data.list[0]) {
           let obj = res.data.list[0]
           let obj = res.data.list[0]
           const keys = Object.keys(obj).reverse()
           const keys = Object.keys(obj).reverse()
           let records = {}
           let records = {}
           for (const item of keys) {
           for (const item of keys) {
             records[item] = obj[item]
             records[item] = obj[item]
           }
           }
-
           this.records = records
           this.records = records
         }
         }
       },
       },
@@ -400,6 +399,7 @@
       // 编辑联系人
       // 编辑联系人
       contactEdit(row) {
       contactEdit(row) {
         this.$refs.contact.contactForm = { ...row }
         this.$refs.contact.contactForm = { ...row }
+        this.$refs.contact.contactForm.custName = this.detail.custName
         this.$refs.contact.contactVisible = true
         this.$refs.contact.contactVisible = true
       },
       },
       // 删除联系人
       // 删除联系人
@@ -517,10 +517,9 @@
 <style lang="scss" scoped>
 <style lang="scss" scoped>
   $base: '.detail';
   $base: '.detail';
   #{$base} {
   #{$base} {
-    height: calc(100vh - 60px - 50px - 12px * 2 - 40px);
+    height: calc(100vh - 60px - 12px * 2 - 40px);
     display: flex;
     display: flex;
     padding: 20px 40px;
     padding: 20px 40px;
-
     > .el-row {
     > .el-row {
       flex: 1;
       flex: 1;
 
 
@@ -528,7 +527,6 @@
         height: 100%;
         height: 100%;
       }
       }
     }
     }
-
     .title {
     .title {
       p,
       p,
       h3 {
       h3 {

+ 18 - 3
src/views/customer/list.vue

@@ -2,7 +2,7 @@
  * @Author: wanglj 471442253@qq.com
  * @Author: wanglj 471442253@qq.com
  * @Date: 2022-12-26 16:34:37
  * @Date: 2022-12-26 16:34:37
  * @LastEditors: wanglj
  * @LastEditors: wanglj
- * @LastEditTime: 2023-01-09 11:39:29
+ * @LastEditTime: 2023-01-10 11:41:59
  * @Description: file content
  * @Description: file content
  * @FilePath: \opms_frontend\src\views\customer\list.vue
  * @FilePath: \opms_frontend\src\views\customer\list.vue
 -->
 -->
@@ -45,7 +45,14 @@
     </el-row>
     </el-row>
     <vab-query-form>
     <vab-query-form>
       <vab-query-form-left-panel :span="12">
       <vab-query-form-left-panel :span="12">
-        <el-button icon="el-icon-plus" size="mini" type="primary" @click="$refs.edit.init()">新建</el-button>
+        <el-button
+          v-permissions="['customer:add']"
+          icon="el-icon-plus"
+          size="mini"
+          type="primary"
+          @click="$refs.edit.init()">
+          新建
+        </el-button>
         <el-button icon="el-icon-plus" size="mini" type="primary" @click="handleShift">转移客户</el-button>
         <el-button icon="el-icon-plus" size="mini" type="primary" @click="handleShift">转移客户</el-button>
         <el-button icon="el-icon-plus" size="mini" type="primary" @click="handleToOpen">移入公海</el-button>
         <el-button icon="el-icon-plus" size="mini" type="primary" @click="handleToOpen">移入公海</el-button>
         <el-button icon="el-icon-plus" size="mini" type="primary" @click="handleMerge">合并客户</el-button>
         <el-button icon="el-icon-plus" size="mini" type="primary" @click="handleMerge">合并客户</el-button>
@@ -84,7 +91,7 @@
       <el-table-column align="center" label="操作">
       <el-table-column align="center" label="操作">
         <template slot-scope="scope">
         <template slot-scope="scope">
           <el-button type="text" @click="handleEdit(scope.row)">编辑</el-button>
           <el-button type="text" @click="handleEdit(scope.row)">编辑</el-button>
-          <el-button type="text" @click="handleDelete(scope.row)">删除</el-button>
+          <el-button v-permissions="['customer:delete']" type="text" @click="handleDelete(scope.row)">删除</el-button>
         </template>
         </template>
       </el-table-column>
       </el-table-column>
     </el-table>
     </el-table>
@@ -205,6 +212,13 @@
             sortable: false,
             sortable: false,
             disableCheck: false,
             disableCheck: false,
           },
           },
+          {
+            label: '创建人',
+            width: '140px',
+            prop: 'createdName',
+            sortable: false,
+            disableCheck: false,
+          },
           {
           {
             label: '创建时间',
             label: '创建时间',
             width: '140px',
             width: '140px',
@@ -306,6 +320,7 @@
                 type: 'success',
                 type: 'success',
                 message: '删除成功!',
                 message: '删除成功!',
               })
               })
+              this.fetchData()
             }
             }
           })
           })
           .catch(() => {})
           .catch(() => {})

+ 15 - 4
src/views/customer/openSea.vue

@@ -2,7 +2,7 @@
  * @Author: wanglj 471442253@qq.com
  * @Author: wanglj 471442253@qq.com
  * @Date: 2022-12-15 15:38:21
  * @Date: 2022-12-15 15:38:21
  * @LastEditors: wanglj
  * @LastEditors: wanglj
- * @LastEditTime: 2023-01-09 11:42:18
+ * @LastEditTime: 2023-01-10 11:37:48
  * @Description: file content
  * @Description: file content
  * @FilePath: \opms_frontend\src\views\customer\openSea.vue
  * @FilePath: \opms_frontend\src\views\customer\openSea.vue
 -->
 -->
@@ -40,8 +40,12 @@
     </el-row>
     </el-row>
     <vab-query-form>
     <vab-query-form>
       <vab-query-form-left-panel :span="12">
       <vab-query-form-left-panel :span="12">
-        <el-button icon="el-icon-plus" type="primary" @click="$refs.edit.init()">新建</el-button>
-        <el-button icon="el-icon-plus" type="primary" @click="handleAllocate">分配</el-button>
+        <el-button v-permissions="['customer:add']" icon="el-icon-plus" type="primary" @click="$refs.edit.init()">
+          新建
+        </el-button>
+        <el-button v-permissions="['customer:allocate']" icon="el-icon-plus" type="primary" @click="handleAllocate">
+          分配
+        </el-button>
         <el-button icon="el-icon-plus" type="primary" @click="handleReceive">领取</el-button>
         <el-button icon="el-icon-plus" type="primary" @click="handleReceive">领取</el-button>
       </vab-query-form-left-panel>
       </vab-query-form-left-panel>
       <vab-query-form-right-panel :span="12">
       <vab-query-form-right-panel :span="12">
@@ -117,7 +121,7 @@
       <el-table-column align="center" label="操作">
       <el-table-column align="center" label="操作">
         <template slot-scope="scope">
         <template slot-scope="scope">
           <el-button type="text" @click="handleEdit(scope.row)">编辑</el-button>
           <el-button type="text" @click="handleEdit(scope.row)">编辑</el-button>
-          <el-button type="text" @click="handleDelete(scope.row)">删除</el-button>
+          <el-button v-permissions="['customer:delete']" type="text" @click="handleDelete(scope.row)">删除</el-button>
         </template>
         </template>
       </el-table-column>
       </el-table-column>
     </el-table>
     </el-table>
@@ -232,6 +236,13 @@
             sortable: false,
             sortable: false,
             disableCheck: false,
             disableCheck: false,
           },
           },
+          {
+            label: '创建人',
+            width: '140px',
+            prop: 'createdName',
+            sortable: false,
+            disableCheck: false,
+          },
           {
           {
             label: '创建时间',
             label: '创建时间',
             width: '140px',
             width: '140px',

+ 592 - 4
src/views/index/index.vue

@@ -1,15 +1,603 @@
+<!--
+ * @Author: wanglj 471442253@qq.com
+ * @Date: 2022-12-13 10:28:33
+ * @LastEditors: wanglj
+ * @LastEditTime: 2023-01-10 11:05:36
+ * @Description: file content
+ * @FilePath: \opms_frontend\src\views\index\index.vue
+-->
 <template>
 <template>
-  <div class="index-container"></div>
+  <div class="index">
+    <div class="left">
+      <el-card class="board">
+        <div slot="header" class="card-title">
+          <span>个人看板</span>
+          <vab-icon icon="question-line" />
+        </div>
+        <ul>
+          <li>
+            <vab-icon icon="account-circle-line" />
+            <div class="text">
+              <p class="num">124</p>
+              <p>当前客户数(个)</p>
+            </div>
+          </li>
+          <li>
+            <vab-icon icon="user-add-line" />
+            <div class="text">
+              <p class="num">124</p>
+              <p>新增客户数(个)</p>
+            </div>
+          </li>
+          <li>
+            <vab-icon icon="account-pin-box-line" />
+            <div class="text">
+              <p class="num">124</p>
+              <p>跟进客户数(个)</p>
+            </div>
+          </li>
+          <li>
+            <vab-icon icon="account-circle-line" />
+            <div class="text">
+              <p class="num">124</p>
+              <p>合同订单数(个)</p>
+            </div>
+          </li>
+        </ul>
+        <ul>
+          <li>
+            <vab-icon icon="exchange-cny-fill" />
+            <div class="text">
+              <p class="num">{{ parseFloat(123).toFixed(2) }}</p>
+              <p>合同订单金额(元)</p>
+            </div>
+          </li>
+          <li>
+            <vab-icon icon="mail-add-line" />
+            <div class="text">
+              <p class="num">124</p>
+              <p>新增机会数(个)</p>
+            </div>
+          </li>
+          <li>
+            <vab-icon icon="exchange-cny-fill" />
+            <div class="text">
+              <p class="num">{{ parseFloat(123).toFixed(2) }}</p>
+              <p>新增机会金额(元)</p>
+            </div>
+          </li>
+          <li>
+            <vab-icon icon="account-circle-line" />
+            <div class="text">
+              <p class="num">124</p>
+              <p>采购合同数(个)</p>
+            </div>
+          </li>
+        </ul>
+        <ul>
+          <li>
+            <vab-icon icon="money-cny-circle-line" />
+            <div class="text">
+              <p class="num">{{ parseFloat(123).toFixed(2) }}</p>
+              <p>采购金额(元)</p>
+            </div>
+          </li>
+          <li>
+            <vab-icon icon="money-cny-circle-line" />
+            <div class="text">
+              <p class="num">{{ parseFloat(123).toFixed(2) }}</p>
+              <p>应收未收(元)</p>
+            </div>
+          </li>
+          <li>
+            <vab-icon icon="money-cny-circle-line" />
+            <div class="text">
+              <p class="num">{{ parseFloat(123).toFixed(2) }}</p>
+              <p>计划付款(元)</p>
+            </div>
+          </li>
+          <li>
+            <vab-icon icon="money-cny-circle-line" />
+            <div class="text">
+              <p class="num">{{ parseFloat(123).toFixed(2) }}</p>
+              <p>当前库存成本(元)</p>
+            </div>
+          </li>
+        </ul>
+      </el-card>
+      <el-row class="chart-row" :gutter="12" type="flex">
+        <el-col :span="12">
+          <el-card class="chart">
+            <div slot="header" class="card-title">
+              <span>销售预测</span>
+              <div class="buttons">
+                <el-select v-model="forecast" style="width: 120px">
+                  <el-option label="公司数据" value="1" />
+                </el-select>
+              </div>
+            </div>
+            <div id="bar"></div>
+          </el-card>
+        </el-col>
+        <el-col :span="12">
+          <el-card class="chart">
+            <div slot="header" class="card-title">
+              <span>销售漏斗</span>
+              <div class="buttons">
+                <el-select v-model="forecast" style="width: 120px">
+                  <el-option label="公司数据" value="1" />
+                </el-select>
+                <el-date-picker
+                  v-model="date"
+                  :clearable="false"
+                  style="width: 120px; margin-left: 10px"
+                  value-format="yyyy-MM-dd" />
+              </div>
+            </div>
+            <div id="funnel"></div>
+          </el-card>
+        </el-col>
+      </el-row>
+    </div>
+    <div class="right">
+      <el-card class="calendar">
+        <div slot="header" class="card-title">
+          <span>日程安排</span>
+          <el-button style="padding: 0" type="text">添加</el-button>
+        </div>
+        <div class="week">
+          <vab-icon icon="arrow-left-s-line" />
+          <ul>
+            <li v-for="item in list" :key="item.date" :class="{ active: item.day == '日' }">
+              <span>{{ item.day }}</span>
+              <span>{{ item.date }}</span>
+            </li>
+          </ul>
+          <vab-icon icon="arrow-right-s-line" />
+        </div>
+        <el-timeline>
+          <el-timeline-item v-for="(activity, index) in activities" :key="index">
+            <div class="detail" :class="{ active: index > 2 }">
+              <p class="time">
+                {{ activity.timestamp }}
+                <el-button type="text">详情</el-button>
+              </p>
+              <p>{{ activity.content }}</p>
+            </div>
+          </el-timeline-item>
+        </el-timeline>
+      </el-card>
+      <el-card class="notice">
+        <div slot="header" class="card-title">
+          <span>公告</span>
+          <div class="buttons">
+            <el-button icon="el-icon-plus" size="mini">发布</el-button>
+            <el-button size="mini">
+              更多
+              <i class="el-icon-arrow-right el-icon--right"></i>
+            </el-button>
+          </div>
+        </div>
+        <ul>
+          <li v-for="(activity, index) in activities" :key="index" class="notice-list">
+            <p>
+              <span>【{{ activity.type }}】</span>
+              {{ activity.content }}
+            </p>
+            <p class="time">
+              <vab-icon icon="time-line" />
+              {{ activity.timestamp }}
+            </p>
+          </li>
+        </ul>
+      </el-card>
+    </div>
+  </div>
 </template>
 </template>
 
 
 <script>
 <script>
+  import * as echarts from 'echarts'
   export default {
   export default {
     name: 'Index',
     name: 'Index',
     data() {
     data() {
-      return {}
+      return {
+        list: [
+          {
+            day: '日',
+            date: '09',
+          },
+          {
+            day: '一',
+            date: '10',
+          },
+          {
+            day: '二',
+            date: '11',
+          },
+          {
+            day: '三',
+            date: '12',
+          },
+          {
+            day: '四',
+            date: '13',
+          },
+          {
+            day: '五',
+            date: '14',
+          },
+          {
+            day: '六',
+            date: '15',
+          },
+        ],
+        activities: [
+          {
+            type: '内部分享',
+            content: '活动按期开始',
+            timestamp: '2018-04-15',
+          },
+          {
+            type: '内部分享',
+            content: '如何建立良好的客户关系',
+            timestamp: '2018-04-13',
+          },
+          {
+            type: '内部分享',
+            content: '创建成功',
+            timestamp: '2018-04-11',
+          },
+          {
+            type: '内部分享',
+            content: '创建成功',
+            timestamp: '2018-04-11',
+          },
+          {
+            type: '内部分享',
+            content: '创建成功',
+            timestamp: '2018-04-11',
+          },
+        ],
+        chartBar: {},
+        chartFunnel: {},
+        forecast: '1',
+        date: '2023-01-10',
+      }
+    },
+    mounted() {
+      this.initBar()
+      this.initFunnel()
+      window.addEventListener('resize', this.handleResize)
+    },
+    methods: {
+      initBar() {
+        this.chartBar = echarts.init(document.getElementById('bar'))
+        const option = {
+          grid: {
+            bottom: 20,
+            top: 20,
+            right: 0,
+          },
+          tooltip: {
+            trigger: 'axis',
+          },
+          xAxis: [
+            {
+              type: 'category',
+              // prettier-ignore
+              data: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
+            },
+          ],
+          yAxis: [
+            {
+              type: 'value',
+            },
+          ],
+          series: [
+            {
+              name: 'Rainfall',
+              type: 'bar',
+              data: [2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3],
+            },
+            {
+              name: 'Evaporation',
+              type: 'bar',
+              data: [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3],
+            },
+          ],
+        }
+        this.chartBar.setOption(option)
+      },
+      initFunnel() {
+        this.chartFunnel = echarts.init(document.getElementById('funnel'))
+        const option = {
+          grid: {
+            top: 0,
+            bottom: 0,
+          },
+          tooltip: {
+            trigger: 'item',
+            formatter: '{b} : {d}%',
+          },
+          label: {
+            formatter: '{b} {c}',
+          },
+          labelLine: {
+            show: true,
+          },
+          series: [
+            {
+              name: '销售漏斗',
+              type: 'funnel',
+              top: 0,
+              bottom: 0,
+              minSize: '20%',
+              maxSize: '100%',
+              label: {
+                position: 'inside',
+                formatter: '{c}%',
+                color: '#fff',
+              },
+              data: [
+                { value: 500, name: '初步洽谈' },
+                { value: 300, name: '深入沟通' },
+                { value: 250, name: '产品报价' },
+                { value: 150, name: '成交商机' },
+                { value: 120, name: '流失商机' },
+              ],
+            },
+            {
+              name: '销售漏斗',
+              type: 'funnel',
+              top: 0,
+              bottom: 0,
+              minSize: '20%',
+              maxSize: '100%',
+              z: 1,
+              data: [
+                { value: 500, name: '初步洽谈' },
+                { value: 300, name: '深入沟通' },
+                { value: 250, name: '产品报价' },
+                { value: 150, name: '成交商机' },
+                { value: 120, name: '流失商机' },
+              ],
+            },
+          ],
+        }
+        this.chartFunnel.setOption(option)
+      },
+      handleResize() {
+        this.$nextTick(() => {
+          this.chartBar.resize()
+          this.chartFunnel.resize()
+        })
+      },
     },
     },
-    created() {},
   }
   }
 </script>
 </script>
 
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+  $base: '.index';
+  #{$base} {
+    display: flex;
+    background: #f6f8f9;
+    height: calc(100vh - 60px - 12px * 2 - 40px);
+    .el-card {
+      margin-bottom: 12px;
+      border-radius: 4px;
+    }
+    .card-title {
+      font-size: 16px;
+      font-weight: 700;
+      line-height: 22px;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      i {
+        font-weight: normal;
+        cursor: pointer;
+        &:hover {
+          color: #1d66dc;
+        }
+      }
+    }
+    .left {
+      flex: 1;
+      margin-right: 10px;
+      overflow-x: hidden;
+      overflow-y: auto;
+      .board {
+        height: 60%;
+        display: flex;
+        flex-direction: column;
+        ::v-deep .el-card__body {
+          flex: 1;
+          display: flex;
+          flex-direction: column;
+          justify-content: space-around;
+        }
+        ul {
+          height: 60px;
+          display: flex;
+          li {
+            flex: 1;
+            height: 60px;
+            display: flex;
+            align-items: center;
+            padding: 0 20px;
+            user-select: none;
+            cursor: pointer;
+            + li {
+              border-left: 1px solid #eee;
+            }
+            i {
+              font-size: 32px;
+              border-radius: 4px;
+              width: 40px;
+              height: 40px;
+              color: #1d66dc;
+              background: #ecf5ff;
+              &.ri-money-cny-circle-line {
+                color: #e6a23c;
+                background: #fdf6ec;
+              }
+              &.ri-exchange-cny-fill {
+                color: #f56c6c;
+                background: #fef0f0;
+              }
+            }
+            .text {
+              padding-left: 10px;
+              color: #9499a0;
+              .num {
+                font-size: 22px;
+                font-weight: bold;
+                color: #333;
+              }
+            }
+          }
+        }
+      }
+      .chart-row {
+        height: calc(40% - 12px);
+        .el-card {
+          height: 100%;
+          display: flex;
+          flex-direction: column;
+          ::v-deep .el-card__body {
+            flex: 1;
+            > div {
+              height: 100%;
+              width: 100%;
+            }
+          }
+        }
+      }
+    }
+    .right {
+      width: 400px;
+      .detail {
+        height: 64px;
+        border: 1px solid rgb(235, 237, 240);
+        border-radius: 4px;
+        &.active {
+          border: 1px solid #d7e8f4;
+          background: #f7fbfe;
+          p:last-child {
+            font-weight: bold;
+          }
+        }
+        p {
+          height: 32px;
+          line-height: 32px;
+          padding: 0 10px;
+          white-space: nowrap;
+          overflow: hidden;
+          text-overflow: ellipsis;
+        }
+        .time {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+        }
+      }
+      .calendar {
+        height: 60%;
+        border-radius: 4px;
+        display: flex;
+        flex-direction: column;
+        ::v-deep .el-card__body {
+          flex: 1;
+          overflow: hidden;
+        }
+        .week {
+          height: 48px;
+          display: flex;
+          align-items: center;
+          ul {
+            flex: 1;
+            display: flex;
+            height: 48px;
+            li {
+              flex: 1;
+              display: flex;
+              flex-direction: column;
+              align-items: center;
+              justify-content: center;
+              &.active span:last-child {
+                background: rgb(34, 76, 218);
+                color: #fff;
+              }
+              span {
+                flex: 1;
+                height: 24px;
+                width: 24px;
+                text-align: center;
+                line-height: 24px;
+              }
+              span:first-child {
+                color: rgb(150, 151, 153);
+              }
+              span:last-child {
+                color: rgb(50, 50, 51);
+                border-radius: 4px;
+              }
+            }
+          }
+          i {
+            height: 24px;
+            width: 24px;
+            font-size: 24px;
+            color: rgb(100, 101, 102);
+            background: rgb(247, 248, 250);
+            border-radius: 4px;
+            cursor: pointer;
+            transition: 0.3s all;
+            &:hover {
+              color: #fff;
+              background: rgb(100, 101, 102);
+            }
+          }
+        }
+        .el-timeline {
+          margin-top: 20px;
+          padding-top: 4px;
+          height: calc(100% - 72px);
+          overflow: auto;
+          .el-timeline-item {
+            padding-bottom: 10px;
+          }
+        }
+      }
+      .notice {
+        height: calc(40% - 12px);
+        display: flex;
+        flex-direction: column;
+        ::v-deep .el-card__body {
+          flex: 1;
+          overflow: auto;
+        }
+        .notice-list {
+          display: flex;
+          justify-content: space-between;
+          height: 40px;
+          line-height: 40px;
+          border-bottom: 1px solid #ebeef5;
+          p:first-child {
+            flex: 1;
+            min-width: 0;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+          }
+          span {
+            font-weight: bold;
+          }
+        }
+      }
+    }
+  }
+  ::v-deep .el-timeline-item__tail {
+    border-left: 2px dashed #e4e7ed;
+  }
+</style>

+ 72 - 16
src/views/plat/task/components/TaskAdd.vue

@@ -42,30 +42,45 @@
         </el-col>
         </el-col>
         <el-col :span="12">
         <el-col :span="12">
           <el-form-item label="督办人" prop="supervisorUserId">
           <el-form-item label="督办人" prop="supervisorUserId">
-            <el-select v-model="form.supervisorUserId" placeholder="请选择督办人" style="width: 100%">
+            <!-- <el-select v-model="form.supervisorUserId" placeholder="请选择督办人" style="width: 100%">
               <el-option v-for="item in users" :key="item.id" :label="item.userName" :value="item.id" />
               <el-option v-for="item in users" :key="item.id" :label="item.userName" :value="item.id" />
-            </el-select>
+            </el-select> -->
+            <el-input v-model="form.supervisorUserName" readonly>
+              <el-button
+                slot="append"
+                icon="el-icon-search"
+                @click="choose(false, 'supervisorUserId', 'supervisorUserName')" />
+            </el-input>
           </el-form-item>
           </el-form-item>
         </el-col>
         </el-col>
         <el-col :span="12">
         <el-col :span="12">
           <el-form-item label="监办人" prop="watchUserId">
           <el-form-item label="监办人" prop="watchUserId">
-            <el-select v-model="form.watchUserId" clear placeholder="请选择监办人" style="width: 100%">
+            <!-- <el-select v-model="form.watchUserId" clear placeholder="请选择监办人" style="width: 100%">
               <el-option v-for="item in users" :key="item.id" :label="item.userName" :value="item.id" />
               <el-option v-for="item in users" :key="item.id" :label="item.userName" :value="item.id" />
-            </el-select>
+            </el-select> -->
+            <el-input v-model="form.watchUserName" placeholder="监办人" readonly>
+              <el-button slot="append" icon="el-icon-search" @click="choose(false, 'watchUserId', 'watchUserName')" />
+            </el-input>
           </el-form-item>
           </el-form-item>
         </el-col>
         </el-col>
         <el-col :span="12">
         <el-col :span="12">
           <el-form-item label="负责人" prop="mainUserId">
           <el-form-item label="负责人" prop="mainUserId">
-            <el-select v-model="form.mainUserId" placeholder="请选择负责人" style="width: 100%">
+            <!-- <el-select v-model="form.mainUserId" placeholder="请选择负责人" style="width: 100%">
               <el-option v-for="item in users" :key="item.id" :label="item.userName" :value="item.id" />
               <el-option v-for="item in users" :key="item.id" :label="item.userName" :value="item.id" />
-            </el-select>
+            </el-select> -->
+            <el-input v-model="form.mainUserName" placeholder="负责人" readonly>
+              <el-button slot="append" icon="el-icon-search" @click="choose(false, 'mainUserId', 'mainUserName')" />
+            </el-input>
           </el-form-item>
           </el-form-item>
         </el-col>
         </el-col>
         <el-col :span="12">
         <el-col :span="12">
           <el-form-item label="团队成员">
           <el-form-item label="团队成员">
-            <el-select v-model="teamIds" clear multiple placeholder="请选择团队成员" style="width: 100%">
+            <!-- <el-select v-model="teamIds" clear multiple placeholder="请选择团队成员" style="width: 100%">
               <el-option v-for="item in users" :key="item.id" :label="item.userName" :value="item.id" />
               <el-option v-for="item in users" :key="item.id" :label="item.userName" :value="item.id" />
-            </el-select>
+            </el-select> -->
+            <el-input v-model="form.teamNames" placeholder="团队成员" readonly>
+              <el-button slot="append" icon="el-icon-search" @click="choose(true, 'teamIds', 'teamNames')" />
+            </el-input>
           </el-form-item>
           </el-form-item>
         </el-col>
         </el-col>
         <el-col :span="12">
         <el-col :span="12">
@@ -101,29 +116,38 @@
       <el-button @click="selfVisible = false">取 消</el-button>
       <el-button @click="selfVisible = false">取 消</el-button>
       <el-button type="primary" @click="save">确 定</el-button>
       <el-button type="primary" @click="save">确 定</el-button>
     </template>
     </template>
+    <SelectUser
+      ref="selectUser"
+      :ids="ids"
+      :label="label"
+      :multiple="multiple"
+      :property="property"
+      @save="selectUser" />
   </el-dialog>
   </el-dialog>
 </template>
 </template>
 
 
 <script>
 <script>
+  import SelectUser from '@/components/select/SelectUser.vue'
   import taskApi from '@/api/plat/task'
   import taskApi from '@/api/plat/task'
   import custApi from '@/api/customer/index'
   import custApi from '@/api/customer/index'
 
 
   export default {
   export default {
     name: 'TaskAdd',
     name: 'TaskAdd',
+    components: {
+      SelectUser,
+    },
     props: {
     props: {
-      selfVisible: {
-        type: Boolean,
-        default: false,
-      },
       users: {
       users: {
         type: Array,
         type: Array,
-        // eslint-disable-next-line vue/require-valid-default-prop
-        default: [],
+        default() {
+          return []
+        },
       },
       },
       types: {
       types: {
         type: Array,
         type: Array,
-        // eslint-disable-next-line vue/require-valid-default-prop
-        default: [],
+        default() {
+          return []
+        },
       },
       },
       doRefresh: {
       doRefresh: {
         type: Function,
         type: Function,
@@ -132,6 +156,7 @@
     },
     },
     data() {
     data() {
       return {
       return {
+        selfVisible: false,
         // 团队成员
         // 团队成员
         teamIds: [],
         teamIds: [],
         // 客户数据
         // 客户数据
@@ -156,6 +181,7 @@
           targetType: '',
           targetType: '',
           targetName: '',
           targetName: '',
           remark: '',
           remark: '',
+          teamIds: [],
         },
         },
         // 校验规则
         // 校验规则
         rules: {
         rules: {
@@ -166,6 +192,10 @@
           supervisorUserId: [{ required: true, message: '督办人不能为空', trigger: 'change' }],
           supervisorUserId: [{ required: true, message: '督办人不能为空', trigger: 'change' }],
           mainUserId: [{ required: true, message: '负责人不能为空', trigger: 'change' }],
           mainUserId: [{ required: true, message: '负责人不能为空', trigger: 'change' }],
         },
         },
+        multiple: false,
+        property: '',
+        label: '',
+        ids: [],
       }
       }
     },
     },
     watch: {
     watch: {
@@ -265,6 +295,32 @@
           }
           }
         })
         })
       },
       },
+      choose(multiple, property, label) {
+        this.multiple = multiple
+        this.property = property
+        this.label = label
+        console.log(this.form[property], Boolean(this.form[property]), 'this.form[property]')
+        if (this.form[property].length) {
+          this.$refs.selectUser.ids = this.form[property]
+        } else if (this.form[property]) {
+          console.log(123)
+          this.$refs.selectUser.ids = [this.form[property]]
+          console.log(this.ids)
+        } else {
+          this.$refs.selectUser.ids = []
+        }
+        this.$refs.selectUser.open()
+      },
+      selectUser(userList, property, label) {
+        console.log(userList, 'userList')
+        this.form[label] = userList.map((item) => item.nickName).join()
+        if (this.multiple) {
+          this.form[property] = userList.map((item) => item.id)
+        } else {
+          this.form[property] = userList[0] ? userList[0].id : ''
+        }
+        this.$forceUpdate()
+      },
     },
     },
   }
   }
 </script>
 </script>

+ 405 - 0
src/views/plat/task/detail.vue

@@ -0,0 +1,405 @@
+<!--
+ * @Author: wanglj 471442253@qq.com
+ * @Date: 2023-01-10 13:41:07
+ * @LastEditors: wanglj
+ * @LastEditTime: 2023-01-10 18:00:55
+ * @Description: file content
+ * @FilePath: \opms_frontend\src\views\plat\task\detail.vue
+-->
+<template>
+  <div class="detail">
+    <el-row :gutter="10">
+      <el-col :span="16">
+        <div class="title">
+          <p>督办详情</p>
+          <h3>
+            {{ theTask.taskTitle }}
+            <span></span>
+          </h3>
+        </div>
+        <header>
+          <el-descriptions :colon="false" :column="6" direction="vertical">
+            <el-descriptions-item content-class-name="my-content" label="督办类型" label-class-name="my-label">
+              {{ typeMap[theTask.taskType] }}
+            </el-descriptions-item>
+            <el-descriptions-item content-class-name="my-content" label="状态" label-class-name="my-label">
+              <span v-if="theTask.taskStatus === '10'">发起</span>
+              <span v-else-if="theTask.taskStatus === '20'">进行中</span>
+              <span v-else-if="theTask.taskStatus === '30'">流程完成</span>
+            </el-descriptions-item>
+            <el-descriptions-item content-class-name="my-content" label="超期" label-class-name="my-label">
+              {{ theTask.isOverdue === '10' ? '否' : '是' }}
+            </el-descriptions-item>
+            <el-descriptions-item content-class-name="my-content" label="开始时间" label-class-name="my-label">
+              {{ parseTime(theTask.taskStartDate) }}
+            </el-descriptions-item>
+            <el-descriptions-item content-class-name="my-content" label="结束时间" label-class-name="my-label">
+              {{ parseTime(theTask.taskEndDate) }}
+            </el-descriptions-item>
+            <el-descriptions-item content-class-name="my-content" label="说明" label-class-name="my-label">
+              {{ theTask.taskDesc }}
+            </el-descriptions-item>
+          </el-descriptions>
+          <el-descriptions :colon="false" :column="6" direction="vertical">
+            <el-descriptions-item content-class-name="my-content" label="督办人" label-class-name="my-label">
+              {{ userMap[theTask.supervisorUserId] }}
+            </el-descriptions-item>
+            <el-descriptions-item content-class-name="my-content" label="监办人" label-class-name="my-label">
+              {{ userMap[theTask.watchUserId] }}
+            </el-descriptions-item>
+            <el-descriptions-item content-class-name="my-content" label="负责人" label-class-name="my-label">
+              {{ userMap[theTask.mainUserId] }}
+            </el-descriptions-item>
+            <el-descriptions-item content-class-name="my-content" label="团队成员" label-class-name="my-label">
+              {{ teamNames }}
+            </el-descriptions-item>
+            <el-descriptions-item content-class-name="my-content" label="关联类型" label-class-name="my-label">
+              <span v-show="theTask.targetType == '10'">客户</span>
+              <span v-show="theTask.targetType == '20'">项目</span>
+              <span v-show="theTask.targetType == '30'">合同</span>
+              <span v-show="theTask.targetType == '40'">回款</span>
+            </el-descriptions-item>
+            <el-descriptions-item content-class-name="my-content" label="关联对象" label-class-name="my-label">
+              {{ theTask.targetName }}
+            </el-descriptions-item>
+          </el-descriptions>
+        </header>
+        <el-form label-width="80px" :model="form" style="margin-top: 10px">
+          <el-form-item label="进展情况">
+            <el-button v-show="theTask.step === 20 && type == '1'" circle icon="el-icon-plus" @click="addProgress" />
+          </el-form-item>
+          <el-form-item label-width="0">
+            <el-table border :data="progressList" max-height="300px">
+              <el-table-column align="center" label="进展说明" prop="progDesc">
+                <template #default="{ row }">
+                  <span v-if="row.id">{{ row.progDesc }}</span>
+                  <el-input v-else v-model="row.progDesc" placeholder="进展说明" style="width: 100%" />
+                </template>
+              </el-table-column>
+              <el-table-column align="center" label="时间" prop="progDate">
+                <template #default="{ row }">
+                  <span v-if="row.id">{{ parseTime(row.progDate) }}</span>
+                  <el-date-picker
+                    v-else
+                    v-model="row.progDate"
+                    style="width: 100%"
+                    value-format="yyyy-MM-dd HH:mm:ss" />
+                </template>
+              </el-table-column>
+              <el-table-column align="center" label="附件" prop="progFile">
+                <template #default="{ row }">
+                  <el-link v-show="row.progFile" @click="showFile(row.progFile)">查看附件</el-link>
+                </template>
+              </el-table-column>
+              <el-table-column align="center" label="备注" prop="remark">
+                <template #default="{ row }">
+                  <span v-if="row.id">{{ row.remark }}</span>
+                  <el-input v-else v-model="row.remark" placeholder="备注" style="width: 100%" />
+                </template>
+              </el-table-column>
+              <el-table-column v-if="theTask.step < 30 && type == 1" align="center" label="操作">
+                <template #default="{ row }">
+                  <el-button type="text" @click="handleDel(row.$index)">删除</el-button>
+                </template>
+              </el-table-column>
+            </el-table>
+          </el-form-item>
+          <el-form-item v-if="theTask.approDate || theTask.step === 30" label="审批意见">
+            <el-input v-if="theTask.step === 30" v-model="form.approDesc" placeholder="审批意见" />
+            <span v-else>{{ theTask.approDesc }}</span>
+          </el-form-item>
+          <el-form-item v-if="theTask.approDate || theTask.step === 40" label="督办评价">
+            <el-input v-if="theTask.step === 40" v-model="form.evaluateDesc" placeholder="督办评价" />
+            <span v-else>{{ theTask.evaluateDesc }}</span>
+          </el-form-item>
+        </el-form>
+      </el-col>
+      <el-col :span="8">
+        <div class="buttons">
+          <el-button v-show="theTask.taskStatus === '10' && type == 1" type="primary" @click="changeStatus(10, '10')">
+            接收
+          </el-button>
+          <el-button
+            v-show="theTask.taskStatus === '20' && theTask.step === 20 && type == 1"
+            type="success"
+            @click="changeStatus(15)">
+            暂存
+          </el-button>
+          <el-button
+            v-show="theTask.taskStatus === '20' && theTask.step === 20 && type == 1"
+            type="primary"
+            @click="changeStatus(20, '20')">
+            提交
+          </el-button>
+          <el-button v-show="theTask.step === 30 && type == 1" type="primary" @click="changeStatus(30, '30')">
+            审批通过
+          </el-button>
+          <el-button v-show="theTask.step === 30 && type == 1" type="danger" @click="changeStatus(30, '40')">
+            审批退回
+          </el-button>
+          <el-button v-show="theTask.step === 40 && type == 1" type="primary" @click="changeStatus(40, '30')">
+            审批通过
+          </el-button>
+          <el-button v-show="theTask.step === 40 && type == 1" type="danger" @click="changeStatus(40, '40')">
+            审批退回
+          </el-button>
+          <el-button @click="$router.go(-1)">返回</el-button>
+        </div>
+        <ul class="records">
+          <li v-for="log in logList" :key="log.id">
+            <vab-icon icon="record-circle-line" />
+            <div class="text">
+              <p class="action">
+                <span>{{ log.nodeName }}</span>
+                <span>{{ log.desc }}</span>
+              </p>
+              <p>
+                <span>开始处理</span>
+                <span>完成处理</span>
+              </p>
+              <p>
+                <span>{{ log.startTime }}</span>
+                <span>{{ log.endTime }}</span>
+              </p>
+            </div>
+          </li>
+        </ul>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+<script>
+  import to from 'await-to-js'
+  import taskApi from '@/api/plat/task'
+  import userApi from '@/api/system/user'
+  import dictApi from '@/api/system/dict'
+  export default {
+    name: 'TaskDetail',
+    data() {
+      return {
+        detail: {},
+        // 督办进展
+        progressList: [],
+        // 日志
+        logList: [],
+        theTask: {},
+        typeMap: {},
+        userMap: {},
+        teamNames: '',
+        form: {
+          comment: '',
+        },
+        type: '',
+      }
+    },
+    async mounted() {
+      this.type = this.$route.query.type
+      await this.initData()
+      this.theTask = this.$store.state.task.theTask
+      this.open()
+    },
+    methods: {
+      // 打开弹窗
+      open() {
+        // 获取数据信息
+        this.getProgressList()
+        this.getLogList()
+        this.teamNames = ''
+        if (this.theTask.ownerUserId != '') {
+          let ids = this.theTask.ownerUserId.split(',')
+          for (let id of ids) {
+            if (this.teamNames == '') {
+              this.teamNames = this.userMap[parseInt(id)]
+            } else {
+              this.teamNames += ',' + this.userMap[parseInt(id)]
+            }
+          }
+        }
+      },
+      // 初始化数据
+      async initData() {
+        const [err, [type, user]] = await to(
+          Promise.all([dictApi.getDictDataList({ dictType: 'TaskType' }), userApi.getList()])
+        )
+        if (err) return
+        this.types = type.data.list
+        for (let type of this.types) {
+          this.typeMap[type.dictValue] = type.dictLabel
+        }
+        this.users = user.data.list
+        for (let user of this.users) {
+          this.userMap[user.id] = user.userName
+        }
+      },
+      // 获取进展信息
+      getProgressList() {
+        this.progressList = []
+        taskApi
+          .getTaskProgressList({ taskId: this.theTask.id + '' })
+          .then((res) => {
+            if (res.data.list) {
+              this.progressList = res.data.list
+            }
+          })
+          .catch((err) => {
+            console.error(err)
+          })
+      },
+      // 获取日志信息
+      getLogList() {
+        this.logList = []
+        taskApi
+          .getTaskLogList({ taskId: this.theTask.id + '' })
+          .then((res) => {
+            if (res.data.list) {
+              this.logList = res.data.list
+            }
+          })
+          .catch((err) => {
+            console.error(err)
+          })
+      },
+      // 改变督办状态
+      changeStatus(step, status) {
+        if (step == 30 && !this.form.approDesc) return this.$message.warning('请填写审批意见')
+        else if (step == 40 && !this.form.evaluateDesc) return this.$message.warning('请填写督办意见')
+        this.$confirm('确定修改督办状态?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning',
+        }).then(async () => {
+          // eslint-disable-next-line vue/no-mutating-props
+          this.selfVisible = false
+          let data = {
+            taskId: this.theTask.id,
+            step,
+            handleStatus: status,
+            handleDesc: '',
+            progressList: this.progressList,
+          }
+          if (this.theTask.step == 30) data.handleDesc = this.form.approDesc
+          else if (this.theTask.step == 40) data.handleDesc = this.form.evaluateDesc
+          const { msg } = await taskApi.handleTask(data)
+          this.$baseMessage(msg, 'success', 'vab-hey-message-success')
+          this.$router.go(-1)
+        })
+      },
+      // 查看附件
+      showFile(path) {
+        const a = document.createElement('a')
+        a.href = path // 文件链接
+        a.download = path // 文件名,跨域资源download无效
+        a.click()
+        a.remove()
+      },
+      // 添加进展
+      addProgress() {
+        this.progressList.push({})
+      },
+      handleDel(index) {
+        this.progressList.splice(index, 1)
+      },
+    },
+  }
+</script>
+<style lang="scss" scoped>
+  $base: '.detail';
+  #{$base} {
+    height: calc(100vh - 60px - 12px * 2 - 40px);
+    display: flex;
+    padding: 20px 40px;
+    > .el-row {
+      flex: 1;
+      > .el-col {
+        height: 100%;
+      }
+    }
+    .title {
+      p,
+      h3 {
+        margin: 0;
+      }
+
+      p {
+        font-size: 14px;
+        font-weight: 400;
+        line-height: 22px;
+      }
+
+      h3 {
+        font-size: 24px;
+        font-weight: 500;
+        line-height: 36px;
+        color: #333;
+        display: flex;
+        justify-content: space-between;
+      }
+    }
+    header {
+      min-height: 134px;
+      background: rgba(196, 196, 196, 0.5);
+      border-radius: 4px;
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      padding: 7px 20px;
+      margin-top: 16px;
+      ::v-deep .el-descriptions__body {
+        background: transparent;
+      }
+
+      ::v-deep .my-label {
+        font-size: 14px;
+        font-weight: 600;
+        color: #1d66dc;
+      }
+
+      ::v-deep .my-content {
+        font-size: 14px;
+        font-weight: 600;
+        color: #333;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+      }
+    }
+    .buttons {
+      height: 60px;
+      padding-top: 28px;
+      text-align: right;
+    }
+    .add-pro {
+      text-align: right;
+      margin: 10px 0;
+    }
+    .records {
+      padding: 10px 20px;
+      height: calc(100% - 60px);
+      overflow-y: auto;
+      li {
+        display: flex;
+        align-items: center;
+        i {
+          font-size: 40px;
+          margin-right: 10px;
+        }
+        .text {
+          flex: 1;
+        }
+        p {
+          height: 20px;
+          line-height: 20px;
+          display: flex;
+          justify-content: space-between;
+          font-weight: 500;
+          &:first-child {
+            font-weight: bold;
+          }
+        }
+        & + li {
+          margin-top: 10px;
+        }
+      }
+    }
+  }
+</style>

+ 35 - 27
src/views/plat/task/index.vue

@@ -95,7 +95,7 @@
               </span>
               </span>
               <span
               <span
                 v-else-if="item.prop === 'taskStartDate' || item.prop === 'taskEndDate' || item.prop === 'createdTime'">
                 v-else-if="item.prop === 'taskStartDate' || item.prop === 'taskEndDate' || item.prop === 'createdTime'">
-                {{ parseTime(row[item.prop]) }}
+                {{ parseTime(row[item.prop], '{y}-{m}-{d} {h}:{i}') }}
               </span>
               </span>
               <span v-else>{{ row[item.prop] }}</span>
               <span v-else>{{ row[item.prop] }}</span>
             </template>
             </template>
@@ -120,7 +120,7 @@
       </el-col>
       </el-col>
     </el-row>
     </el-row>
     <!-- 新建督办 -->
     <!-- 新建督办 -->
-    <taskAdd :do-refresh="doRefresh" :self-visible.sync="addDialogVisible" :types="types" :users="users" />
+    <taskAdd ref="taskAdd" :do-refresh="doRefresh" :types="types" :users="users" />
     <!-- 查看详情 -->
     <!-- 查看详情 -->
     <taskDetail
     <taskDetail
       :do-refresh="doRefresh"
       :do-refresh="doRefresh"
@@ -179,70 +179,70 @@
         columns: [
         columns: [
           {
           {
             label: '督办标题',
             label: '督办标题',
-            width: 'auto',
+            width: '280px',
             prop: 'taskTitle',
             prop: 'taskTitle',
-            sortable: true,
+            sortable: false,
             disableCheck: true,
             disableCheck: true,
           },
           },
           {
           {
             label: '督办类型',
             label: '督办类型',
-            width: 'auto',
+            width: '120px',
             prop: 'taskType',
             prop: 'taskType',
-            sortable: true,
+            sortable: false,
           },
           },
           {
           {
             label: '状态',
             label: '状态',
-            width: 'auto',
+            width: '120px',
             prop: 'taskStatus',
             prop: 'taskStatus',
-            sortable: true,
+            sortable: false,
           },
           },
           {
           {
             label: '超期',
             label: '超期',
-            width: 'auto',
+            width: '120px',
             prop: 'isOverdue',
             prop: 'isOverdue',
-            sortable: true,
+            sortable: false,
           },
           },
           {
           {
             label: '督办说明',
             label: '督办说明',
-            width: 'auto',
+            width: '120px',
             prop: 'taskDesc',
             prop: 'taskDesc',
-            sortable: true,
+            sortable: false,
           },
           },
           {
           {
             label: '关联对象',
             label: '关联对象',
-            width: 'auto',
+            width: '120px',
             prop: 'targetName',
             prop: 'targetName',
-            sortable: true,
+            sortable: false,
           },
           },
           {
           {
             label: '负责人',
             label: '负责人',
-            width: 'auto',
+            width: '120px',
             prop: 'mainUserId',
             prop: 'mainUserId',
-            sortable: true,
+            sortable: false,
           },
           },
           {
           {
             label: '督办人',
             label: '督办人',
-            width: 'auto',
+            width: '120px',
             prop: 'supervisorUserId',
             prop: 'supervisorUserId',
-            sortable: true,
+            sortable: false,
           },
           },
           {
           {
             label: '开始时间',
             label: '开始时间',
-            width: 'auto',
+            width: '160px',
             prop: 'taskStartDate',
             prop: 'taskStartDate',
-            sortable: true,
+            sortable: false,
           },
           },
           {
           {
             label: '结束时间',
             label: '结束时间',
-            width: 'auto',
+            width: '160px',
             prop: 'taskEndDate',
             prop: 'taskEndDate',
-            sortable: true,
+            sortable: false,
           },
           },
           {
           {
             label: '创建时间',
             label: '创建时间',
-            width: 'auto',
+            width: '160px',
             prop: 'createdTime',
             prop: 'createdTime',
-            sortable: true,
+            sortable: false,
           },
           },
         ],
         ],
       }
       }
@@ -344,12 +344,20 @@
       },
       },
       // 显示详情数据
       // 显示详情数据
       showDetail(row) {
       showDetail(row) {
-        this.theTask = JSON.parse(JSON.stringify(row))
-        this.detailDialogVisible = true
+        // this.theTask = JSON.parse(JSON.stringify(row))
+        // this.detailDialogVisible = true
+        this.$store.state.task.theTask = { ...row }
+        this.$router.push({
+          path: '/customer/plat/task/detail',
+          query: {
+            type: this.queryForm.operateType,
+          },
+        })
       },
       },
       // 处理新增
       // 处理新增
       handleAdd() {
       handleAdd() {
-        this.addDialogVisible = true
+        // this.addDialogVisible = true
+        this.$refs.taskAdd.selfVisible = true
       },
       },
       // 更换页数据大小
       // 更换页数据大小
       handleSizeChange(val) {
       handleSizeChange(val) {