Procházet zdrojové kódy

feat(repair): 新增维修单转派功能

- 添加转派、转派审批通过、转派审批驳回的API接口
- 实现转派功能模块,支持选择新维修负责人和填写转派备注
- 添加转派审批页面,支持审批通过和驳回操作
- 更新字典配置,新增已拒单和转派审批中状态
- 优化派工和转派表单中的下拉选择组件为自定义搜索选择框
- 在维修单详情页面添加转派按钮,支持处理中状态的转派操作
- 调整模态框关闭逻辑,优化表单保存后的回调处理
dazhaxie před 2 týdny
rodič
revize
223565b03f

+ 42 - 0
src/api/repair/application-form.js

@@ -279,3 +279,45 @@ export function rejectRepair (parameter) {
     data: parameter
   })
 }
+
+/**
+ * 转派维修单
+ * parameter: { id, repairUserId, repairDispatchRemark }
+ * @param parameter
+ * @returns {*}
+ */
+export function transfer (parameter) {
+  return axios({
+    url: '/repair/application-forms/transfer/' + parameter.id,
+    method: 'PUT',
+    data: parameter
+  })
+}
+
+/**
+ * 转派审批通过
+ * parameter: { id, repairDispatchRemark }
+ * @param parameter
+ * @returns {*}
+ */
+export function transferApprove (parameter) {
+  return axios({
+    url: '/repair/application-forms/transfer-approve/' + parameter.id,
+    method: 'PUT',
+    data: parameter
+  })
+}
+
+/**
+ * 转派审批驳回
+ * parameter: { id, repairDispatchRemark }
+ * @param parameter
+ * @returns {*}
+ */
+export function transferReject (parameter) {
+  return axios({
+    url: '/repair/application-forms/transfer-reject/' + parameter.id,
+    method: 'PUT',
+    data: parameter
+  })
+}

+ 2 - 0
src/router/generator-platform-routers.js

@@ -185,6 +185,8 @@ const constantRouterComponents = {
   'RepairApplicationForm': () => import('@/views/repair/application-form/RepairApplicationForm'),
 
   'RepairOut': () => import('@/views/repair/application-form/RepairOut'),
+  // 转派审批
+  'TransferApproval': () => import('@/views/repair/application-form/TransferApproval'),
   // 验收单
   'RepairCheckForm': () => import('@/views/repair/application-form/RepairCheckForm'),
   // 维修单

+ 6 - 2
src/utils/dict.js

@@ -811,7 +811,9 @@ DictCache.VALUE = {
     WAIT_SUBMIT: 3, // 待审核
     NOT_ACCEPTANCE: 4, // 审核中
     REBACK: 5, // 已驳回
-    FINISHED: 6// 已完成
+    FINISHED: 6, // 已完成
+    REFUSED: 7, // 已拒单
+    TRANSFER_APPROVAL: 8 // 转派审批中
   },
   /**
    * 维修状态
@@ -1357,7 +1359,9 @@ DictCache.COLOR = {
     3: 'yellow', // 待提交审核
     4: 'error', // 审核中
     5: 'success', // 已驳回
-    6: 'default' // 已完成
+    6: 'default', // 已完成
+    7: 'error', // 已拒单
+    8: 'warning' // 转派审批中
   },
   /**
    * 维修状态

+ 191 - 0
src/views/repair/application-form/TransferApproval.vue

@@ -0,0 +1,191 @@
+<template>
+  <a-card :bordered="false">
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline">
+        <a-row :gutter="48">
+          <a-col :md="6" :sm="24">
+            <a-form-item label="关键字">
+              <a-input v-model="queryParam.keyword" placeholder="设备名称/编号/问题描述"/>
+            </a-form-item>
+          </a-col>
+          <a-col :md="6" :sm="24">
+            <a-form-item label="报修起始日期">
+              <a-date-picker
+                v-model="queryParam.searchStartTime"
+                style="width: 100%"
+                :format="BaseTool.Date.PICKER_NORM_DATETIME_PATTERN"
+              />
+            </a-form-item>
+          </a-col>
+          <a-col :md="6" :sm="24">
+            <a-form-item label="报修结束日期">
+              <a-date-picker
+                v-model="queryParam.searchEndTime"
+                style="width: 100%"
+                :format="BaseTool.Date.PICKER_NORM_DATETIME_PATTERN"
+              />
+            </a-form-item>
+          </a-col>
+          <a-col :md="8 || 24" :sm="24">
+            <span class="table-page-search-submitButtons">
+              <a-button type="primary" @click="handleOk()">查询</a-button>
+              <a-button style="margin-left: 8px" @click="resetSearchForm">重置</a-button>
+            </span>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+
+    <s-table
+      ref="table"
+      size="default"
+      rowKey="id"
+      :columns="columns"
+      :data="loadData"
+      :scroll="{x: 1000, y: BaseTool.Constant.scrollY }"
+      showPagination="auto"
+    >
+      <span slot="action" slot-scope="record">
+        <template>
+          <a @click="handleView(record)">查看</a>
+          <a-divider type="vertical" />
+          <a-popconfirm title="确认通过该转派申请?" @confirm="handleApprove(record)">
+            <a>通过</a>
+          </a-popconfirm>
+          <a-divider type="vertical" />
+          <a @click="handleReject(record)">驳回</a>
+        </template>
+      </span>
+      <span slot="status" slot-scope="text">
+        <badge :text="BaseTool.Object.getField(statusMap,text)" :status="DictCache.COLOR.REPAIR_APPLICATION_FORM_STATUS[text]"/>
+      </span>
+    </s-table>
+
+    <detail ref="detailModal" @ok="handleOk"/>
+    <transfer-approve-form ref="approveForm" @ok="handleOk"/>
+  </a-card>
+</template>
+
+<script>
+import { STable, Ellipsis } from '@/components'
+import Detail from './modules/DetailRepair'
+import TransferApproveForm from './modules/TransferApproveForm'
+import { getRepairApplicationFormPage, fetchRepairApplicationForm, transferApprove, transferReject } from '@/api/repair/application-form'
+
+export default {
+  name: 'TransferApproval',
+  components: {
+    STable,
+    Ellipsis,
+    Detail,
+    TransferApproveForm
+  },
+  data () {
+    return {
+      queryParam: {
+        status: 8
+      },
+      statusMap: {},
+      columns: [
+        {
+          title: '序号',
+          dataIndex: 'index',
+          width: '70px',
+          customRender: (text, record, index) => {
+            return `${(this.$refs.table.localPagination.current - 1) * this.$refs.table.localPagination.pageSize + index + 1}`
+          }
+        },
+        {
+          title: '报修单号',
+          width: '150px',
+          dataIndex: 'no'
+        },
+        {
+          title: '设备编号',
+          width: '120px',
+          dataIndex: 'sbNo'
+        },
+        {
+          title: '设备名称',
+          width: '150px',
+          dataIndex: 'sbName'
+        },
+        {
+          title: '报修人',
+          width: '100px',
+          dataIndex: 'actualUser'
+        },
+        {
+          title: '当前维修人',
+          width: '120px',
+          dataIndex: 'repairUserName'
+        },
+        {
+          title: '报修时间',
+          width: '180px',
+          dataIndex: 'applyTime'
+        },
+        {
+          title: '状态',
+          width: '120px',
+          fixed: 'right',
+          dataIndex: 'status',
+          scopedSlots: { customRender: 'status' }
+        },
+        {
+          title: '操作',
+          fixed: 'right',
+          key: 'action',
+          width: '180px',
+          align: 'center',
+          scopedSlots: { customRender: 'action' }
+        }
+      ],
+      loadData: parameter => {
+        parameter = {
+          ...parameter,
+          ...this.queryParam,
+          type: 1,
+          dataScope: {
+            sortBy: 'desc',
+            sortName: 'apply_time'
+          }
+        }
+        return getRepairApplicationFormPage(parameter)
+          .then(res => {
+            return res.data
+          })
+      }
+    }
+  },
+  created () {
+    this.statusMap = this.DictCache.getLabelByValueMapByType(this.DictCache.TYPE.REPAIR_APPLICATION_FORM_STATUS)
+  },
+  methods: {
+    handleOk () {
+      this.$refs.table.refresh()
+    },
+    resetSearchForm () {
+      this.queryParam = { status: 8 }
+      this.$refs.table.refresh()
+    },
+    handleView (record) {
+      fetchRepairApplicationForm({ id: record.id }).then(res => {
+        const modal = this.$refs.detailModal
+        modal.base(res.data)
+      })
+    },
+    handleApprove (record) {
+      transferApprove({ id: record.id, repairDispatchRemark: '审批通过' })
+        .then(() => {
+          this.$message.success('转派审批通过')
+          this.handleOk()
+        })
+    },
+    handleReject (record) {
+      const modal = this.$refs.approveForm
+      modal.base(record, 'reject')
+    }
+  }
+}
+</script>

+ 107 - 14
src/views/repair/application-form/modules/AssignForm.vue

@@ -14,14 +14,64 @@
             :labelCol="BaseTool.Constant.labelCol"
             :wrapperCol="BaseTool.Constant.wrapperCol"
           >
-            <a-select v-decorator="['repairUserId', {rules: [{required: true, message: '维修人负责人不能为空'}]}]" placeholder="请选择">
-              <a-select-option
-                v-for="item in deptUserList"
-                :key="item.userId"
-                :label="item.realName"
-                :value="item.userId">{{ item.realName }}
-              </a-select-option>
-            </a-select>
+            <div style="position: relative;">
+              <a-input
+                v-model="searchKeyword"
+                placeholder="点击选择维修负责人"
+                readonly
+                @click="showDropdown = !showDropdown"
+              >
+                <a-icon
+                  slot="suffix"
+                  type="down"
+                  @click="showDropdown = !showDropdown"
+                />
+              </a-input>
+              <div
+                v-if="showDropdown"
+                style="
+                  position: absolute;
+                  top: 100%;
+                  left: 0;
+                  right: 0;
+                  background: #fff;
+                  border: 1px solid #d9d9d9;
+                  border-radius: 4px;
+                  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+                  max-height: 300px;
+                  overflow-y: auto;
+                  z-index: 1000;
+                  margin-top: 4px;
+                "
+                @mouseleave="onDropdownMouseLeave"
+              >
+                <div style="padding: 8px; border-bottom: 1px solid #f0f0f0; position: sticky; top: 0; background: #fff; z-index: 1;">
+                  <a-input
+                    v-model="filterKeyword"
+                    placeholder="搜索姓名"
+                    size="small"
+                    @click.stop
+                  />
+                </div>
+                <div
+                  v-for="item in filteredDeptUserList"
+                  :key="item.userId"
+                  @click="selectUser(item)"
+                  :style="{
+                    padding: '8px 12px',
+                    cursor: 'pointer',
+                    background: selectedUserId === item.userId ? '#e6f7ff' : 'transparent'
+                  }"
+                  @mouseenter="($event.target.style.background = selectedUserId === item.userId ? '#e6f7ff' : '#f5f5f5')"
+                  @mouseleave="($event.target.style.background = selectedUserId === item.userId ? '#e6f7ff' : 'transparent')"
+                >
+                  {{ item.realName }}
+                </div>
+                <div v-if="filteredDeptUserList.length === 0" style="padding: 16px; text-align: center; color: #999;">
+                  无匹配结果
+                </div>
+              </div>
+            </div>
           </a-form-item>
         </row-item>
       </row-list>
@@ -51,38 +101,76 @@ import { queryUserDept } from '@/api/upms/user-dept'
 import { queryUser } from '@/api/upms/user'
 
 export default {
-  name: 'DispatchBaseForm',
+  name: 'AssignForm',
   data () {
     return {
       confirmLoading: false,
       modalTitle: null,
       form: this.$form.createForm(this),
       visible: false,
-      // 下拉框map
       sourceMap: {},
       levelMap: {},
       statusMap: {},
       record: {},
       userList: [],
-      deptUserList: []
+      deptUserList: [],
+      showDropdown: false,
+      searchKeyword: '',
+      filterKeyword: '',
+      selectedUserId: null,
+      selectedUserName: ''
     }
   },
-  props: {
+  computed: {
+    filteredDeptUserList () {
+      if (!this.filterKeyword) {
+        return this.deptUserList
+      }
+      return this.deptUserList.filter(item =>
+        item.realName.toLowerCase().includes(this.filterKeyword.toLowerCase())
+      )
+    }
   },
   created () {
-    // 下拉框map
     this.sourceMap = this.DictCache.getLabelByValueMapByType(this.DictCache.TYPE.REPAIR_APPLICATION_FORM_SOURCE)
     this.levelMap = this.DictCache.getLabelByValueMapByType(this.DictCache.TYPE.REPAIR_APPLICATION_FORM_LEVEL)
     this.statusMap = this.DictCache.getLabelByValueMapByType(this.DictCache.TYPE.REPAIR_APPLICATION_FORM_STATUS)
     this.getUsers()
     this.getDeptUsers()
   },
+  mounted () {
+    document.addEventListener('click', this.handleDocumentClick)
+  },
+  beforeDestroy () {
+    document.removeEventListener('click', this.handleDocumentClick)
+  },
   methods: {
+    handleDocumentClick (e) {
+      if (this.showDropdown && !e.target.closest('.ant-input-affix-wrapper')) {
+        this.showDropdown = false
+      }
+    },
+    onDropdownMouseLeave () {
+    },
+    selectUser (item) {
+      this.selectedUserId = item.userId
+      this.selectedUserName = item.realName
+      this.searchKeyword = item.realName
+      this.showDropdown = false
+      this.form.setFieldsValue({ repairUserId: item.userId })
+    },
     base (record) {
       this.visible = true
-      // 如果是空标识添加
       this.modalTitle = '派工'
       this.record = record
+      this.$nextTick(() => {
+        this.form.resetFields()
+        this.selectedUserId = null
+        this.selectedUserName = ''
+        this.searchKeyword = ''
+        this.filterKeyword = ''
+        this.showDropdown = false
+      })
     },
     getDeptUsers () {
       queryUserDept({ deptCode: this.DictCache.VALUE.SYS_DEPT_CODE.XIAN_CHANG_WEI_XIU_ZU, userStatus: 1 }).then(res => {
@@ -97,6 +185,10 @@ export default {
       })
     },
     save () {
+      if (!this.selectedUserId) {
+        this.$message.warning('请选择维修负责人')
+        return
+      }
       const { form: { validateFieldsAndScroll } } = this
       this.confirmLoading = true
       validateFieldsAndScroll((errors, values) => {
@@ -105,6 +197,7 @@ export default {
           return
         }
         values.id = this.record.id
+        values.repairUserId = this.selectedUserId
         dispatchModelByDTO(values)
           .then(() => {
             this.handleCancel(values)

+ 5 - 5
src/views/repair/application-form/modules/BaseOutForm.vue

@@ -5,7 +5,7 @@
     :visible="visible"
     :confirmLoading="confirmLoading"
     class="ant-modal2"
-    @cancel="handleCancel"
+    @cancel="handleCancel(false)"
   >
     <a-form :form="form">
 
@@ -174,25 +174,25 @@ export default {
         if (this.BaseTool.String.isBlank(values.id)) {
           addRepairApplicationForm(values)
             .then(() => {
-              this.handleCancel(values)
+              this.handleCancel(true, values)
             }).catch(() => {
               this.confirmLoading = false
             })
         } else {
           updateRepairApplicationForm(values)
             .then(() => {
-              this.handleCancel(values)
+              this.handleCancel(true, values)
             }).catch(() => {
               this.confirmLoading = false
             })
         }
       })
     },
-    handleCancel (values) {
+    handleCancel (isSave, values) {
       this.visible = false
       this.confirmLoading = false
       this.form.resetFields()
-      if (this.BaseTool.Object.isNotBlank(values)) {
+      if (isSave && this.BaseTool.Object.isNotBlank(values)) {
         this.$emit('ok', values)
       }
     }

+ 8 - 0
src/views/repair/application-form/modules/DetailRepair.vue

@@ -13,6 +13,7 @@
             <a-button v-if="$auth('repair-application-forms-deal') && (DictCache.VALUE.REPAIR_APPLICATION_FORM_STATUS.NOT_ALLOCATED === model.status || DictCache.VALUE.REPAIR_APPLICATION_FORM_STATUS.REBACK === model.status)" style="margin-left: 8px" @click="handleReject">拒单</a-button>
             <a-button v-if="$auth('repair-application-forms-out') && (DictCache.VALUE.REPAIR_APPLICATION_FORM_STATUS.PROCESSING >= model.status) && model.type != 2" style="margin-left: 8px" type="default" @click="handleOut">委外</a-button>
             <a-button v-if="$auth('repair-application-forms-dispatch') && DictCache.VALUE.REPAIR_APPLICATION_FORM_STATUS.REBACK === model.status" style="margin-left: 8px" type="default" @click="handleDispatch">转派</a-button>
+            <a-button v-if="$auth('repair-application-forms-transfer') && DictCache.VALUE.REPAIR_APPLICATION_FORM_STATUS.PROCESSING === model.status" style="margin-left: 8px" type="default" @click="handleTransfer">转派</a-button>
             <a-button v-if="$auth('repair-application-forms-finish') && DictCache.VALUE.REPAIR_APPLICATION_FORM_STATUS.PROCESSING === model.status" style="margin-left: 8px" type="default" @click="handleFinish()">完成</a-button>
             <a-button v-if="$auth('repair-application-forms-edit')" style="margin-left: 8px" type="default" @click="handleEdit()">修改</a-button>
             <a-popconfirm v-if="DictCache.VALUE.REPAIR_APPLICATION_FORM_STATUS.WAIT_SUBMIT === model.status" title="是否要提交审核该条数据?" @confirm="handleExamine">
@@ -202,6 +203,7 @@
     <detail ref="detailRepairProjectModal" />
     <edit-form ref="editForm" @ok="handleOk" />
     <RejectForm ref="rejectForm" @ok="handleOk" />
+    <transfer-form ref="transferForm" @ok="handleOk" />
   </div>
 </template>
 
@@ -214,6 +216,7 @@ import BaseOutForm from './BaseOutForm'
 import FinishForm from './FinishForm'
 import EditForm from './EditForm'
 import DispatchForm from './DispatchForm'
+import TransferForm from './TransferForm'
 import AssignForm from './AssignForm'
 import SparePickBaseForm from '../../../store/sparepickform/modules/BaseForm'
 import SparePartUsedSelectTable from '@/views/sqarepartmanage/sparepartused/modules/SparePartUsedSelectTable'
@@ -253,6 +256,7 @@ export default {
     ReasonBaseForm,
     ReasonDetail,
     DetailListItem,
+    TransferForm,
     FinishForm,
     BaseOutForm,
     DispatchForm,
@@ -676,6 +680,10 @@ export default {
       const modal = this.$refs.dispatchForm
       modal.base(this.model)
     },
+    handleTransfer() {
+      const modal = this.$refs.transferForm
+      modal.base(this.model)
+    },
     handleAssign() {
       const modal = this.$refs.assignForm
       modal.base(this.model)

+ 107 - 14
src/views/repair/application-form/modules/DispatchForm.vue

@@ -14,14 +14,64 @@
             :labelCol="BaseTool.Constant.labelCol"
             :wrapperCol="BaseTool.Constant.wrapperCol"
           >
-            <a-select v-decorator="['repairUserId', {rules: [{required: true, message: '维修人负责人不能为空'}]}]" placeholder="请选择">
-              <a-select-option
-                v-for="item in deptUserList"
-                :key="item.userId"
-                :label="item.realName"
-                :value="item.userId">{{ item.realName }}
-              </a-select-option>
-            </a-select>
+            <div style="position: relative;">
+              <a-input
+                v-model="searchKeyword"
+                placeholder="点击选择维修负责人"
+                readonly
+                @click="showDropdown = !showDropdown"
+              >
+                <a-icon
+                  slot="suffix"
+                  type="down"
+                  @click="showDropdown = !showDropdown"
+                />
+              </a-input>
+              <div
+                v-if="showDropdown"
+                style="
+                  position: absolute;
+                  top: 100%;
+                  left: 0;
+                  right: 0;
+                  background: #fff;
+                  border: 1px solid #d9d9d9;
+                  border-radius: 4px;
+                  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+                  max-height: 300px;
+                  overflow-y: auto;
+                  z-index: 1000;
+                  margin-top: 4px;
+                "
+                @mouseleave="onDropdownMouseLeave"
+              >
+                <div style="padding: 8px; border-bottom: 1px solid #f0f0f0; position: sticky; top: 0; background: #fff; z-index: 1;">
+                  <a-input
+                    v-model="filterKeyword"
+                    placeholder="搜索姓名"
+                    size="small"
+                    @click.stop
+                  />
+                </div>
+                <div
+                  v-for="item in filteredDeptUserList"
+                  :key="item.userId"
+                  @click="selectUser(item)"
+                  :style="{
+                    padding: '8px 12px',
+                    cursor: 'pointer',
+                    background: selectedUserId === item.userId ? '#e6f7ff' : 'transparent'
+                  }"
+                  @mouseenter="($event.target.style.background = selectedUserId === item.userId ? '#e6f7ff' : '#f5f5f5')"
+                  @mouseleave="($event.target.style.background = selectedUserId === item.userId ? '#e6f7ff' : 'transparent')"
+                >
+                  {{ item.realName }}
+                </div>
+                <div v-if="filteredDeptUserList.length === 0" style="padding: 16px; text-align: center; color: #999;">
+                  无匹配结果
+                </div>
+              </div>
+            </div>
           </a-form-item>
         </row-item>
       </row-list>
@@ -51,38 +101,76 @@ import { queryUserDept } from '@/api/upms/user-dept'
 import { queryUser } from '@/api/upms/user'
 
 export default {
-  name: 'DispatchBaseForm',
+  name: 'DispatchForm',
   data () {
     return {
       confirmLoading: false,
       modalTitle: null,
       form: this.$form.createForm(this),
       visible: false,
-      // 下拉框map
       sourceMap: {},
       levelMap: {},
       statusMap: {},
       record: {},
       userList: [],
-      deptUserList: []
+      deptUserList: [],
+      showDropdown: false,
+      searchKeyword: '',
+      filterKeyword: '',
+      selectedUserId: null,
+      selectedUserName: ''
     }
   },
-  props: {
+  computed: {
+    filteredDeptUserList () {
+      if (!this.filterKeyword) {
+        return this.deptUserList
+      }
+      return this.deptUserList.filter(item =>
+        item.realName.toLowerCase().includes(this.filterKeyword.toLowerCase())
+      )
+    }
   },
   created () {
-    // 下拉框map
     this.sourceMap = this.DictCache.getLabelByValueMapByType(this.DictCache.TYPE.REPAIR_APPLICATION_FORM_SOURCE)
     this.levelMap = this.DictCache.getLabelByValueMapByType(this.DictCache.TYPE.REPAIR_APPLICATION_FORM_LEVEL)
     this.statusMap = this.DictCache.getLabelByValueMapByType(this.DictCache.TYPE.REPAIR_APPLICATION_FORM_STATUS)
     this.getUsers()
     this.getDeptUsers()
   },
+  mounted () {
+    document.addEventListener('click', this.handleDocumentClick)
+  },
+  beforeDestroy () {
+    document.removeEventListener('click', this.handleDocumentClick)
+  },
   methods: {
+    handleDocumentClick (e) {
+      if (this.showDropdown && !e.target.closest('.ant-input-affix-wrapper')) {
+        this.showDropdown = false
+      }
+    },
+    onDropdownMouseLeave () {
+    },
+    selectUser (item) {
+      this.selectedUserId = item.userId
+      this.selectedUserName = item.realName
+      this.searchKeyword = item.realName
+      this.showDropdown = false
+      this.form.setFieldsValue({ repairUserId: item.userId })
+    },
     base (record) {
       this.visible = true
-      // 如果是空标识添加
       this.modalTitle = '派工'
       this.record = record
+      this.$nextTick(() => {
+        this.form.resetFields()
+        this.selectedUserId = null
+        this.selectedUserName = ''
+        this.searchKeyword = ''
+        this.filterKeyword = ''
+        this.showDropdown = false
+      })
     },
     getDeptUsers () {
       queryUserDept({ deptCode: this.DictCache.VALUE.SYS_DEPT_CODE.XIAN_CHANG_WEI_XIU_ZU, userStatus: 1 }).then(res => {
@@ -97,6 +185,10 @@ export default {
       })
     },
     save () {
+      if (!this.selectedUserId) {
+        this.$message.warning('请选择维修负责人')
+        return
+      }
       const { form: { validateFieldsAndScroll } } = this
       this.confirmLoading = true
       validateFieldsAndScroll((errors, values) => {
@@ -105,6 +197,7 @@ export default {
           return
         }
         values.id = this.record.id
+        values.repairUserId = this.selectedUserId
         dispatchModelByDTO(values)
           .then(() => {
             this.handleCancel(values)

+ 82 - 0
src/views/repair/application-form/modules/TransferApproveForm.vue

@@ -0,0 +1,82 @@
+<template>
+  <a-modal
+    :title="modalTitle"
+    :width="600"
+    :visible="visible"
+    :confirmLoading="confirmLoading"
+    @cancel="handleCancel"
+  >
+    <a-form :form="form">
+      <row-list :col="1">
+        <row-item>
+          <a-form-item
+            label="驳回原因"
+            :labelCol="BaseTool.Constant.labelCol2"
+            :wrapperCol="BaseTool.Constant.wrapperCol2"
+          >
+            <a-textarea
+              :rows="4"
+              v-decorator="['repairDispatchRemark', {rules: [{required: true, message: '驳回原因不能为空'}]}]"
+              placeholder="请填写驳回原因"/>
+          </a-form-item>
+        </row-item>
+      </row-list>
+    </a-form>
+    <template slot="footer">
+      <a-button :loading="confirmLoading" type="primary" @click="save()">确认驳回</a-button>
+    </template>
+  </a-modal>
+</template>
+
+<script>
+import { transferReject } from '@/api/repair/application-form'
+
+export default {
+  name: 'TransferApproveForm',
+  data () {
+    return {
+      confirmLoading: false,
+      modalTitle: null,
+      form: this.$form.createForm(this),
+      visible: false,
+      record: {}
+    }
+  },
+  methods: {
+    base (record, type) {
+      this.visible = true
+      this.modalTitle = '转派审批驳回'
+      this.record = record
+      this.$nextTick(() => {
+        this.form.resetFields()
+      })
+    },
+    save () {
+      const { form: { validateFieldsAndScroll } } = this
+      this.confirmLoading = true
+      validateFieldsAndScroll((errors, values) => {
+        if (errors) {
+          this.confirmLoading = false
+          return
+        }
+        values.id = this.record.id
+        transferReject(values)
+          .then(() => {
+            this.$message.success('已驳回转派申请')
+            this.handleCancel(values)
+          }).catch(() => {
+            this.confirmLoading = false
+          })
+      })
+    },
+    handleCancel (values) {
+      this.visible = false
+      this.confirmLoading = false
+      this.form.resetFields()
+      if (this.BaseTool.Object.isNotBlank(values)) {
+        this.$emit('ok')
+      }
+    }
+  }
+}
+</script>

+ 213 - 0
src/views/repair/application-form/modules/TransferForm.vue

@@ -0,0 +1,213 @@
+<template>
+  <a-modal
+    :title="modalTitle"
+    :width="800"
+    :visible="visible"
+    :confirmLoading="confirmLoading"
+    @cancel="handleCancel"
+  >
+    <a-form :form="form">
+      <a-alert
+        v-if="record.repairUserName"
+        message=""
+        type="info"
+        style="margin-bottom: 16px"
+      >
+        <template slot="description">
+          当前维修人:<b>{{ record.repairUserName }}</b>,转派后将进入<b>转派审批中</b>状态,审批通过后更换维修人。
+        </template>
+      </a-alert>
+      <row-list :col="2">
+        <row-item>
+          <a-form-item
+            label="新维修负责人"
+            :labelCol="BaseTool.Constant.labelCol"
+            :wrapperCol="BaseTool.Constant.wrapperCol"
+          >
+            <div style="position: relative;">
+              <a-input
+                v-model="searchKeyword"
+                placeholder="点击选择新维修负责人"
+                readonly
+                @click="showDropdown = !showDropdown"
+              >
+                <a-icon
+                  slot="suffix"
+                  type="down"
+                  @click="showDropdown = !showDropdown"
+                />
+              </a-input>
+              <div
+                v-if="showDropdown"
+                style="
+                  position: absolute;
+                  top: 100%;
+                  left: 0;
+                  right: 0;
+                  background: #fff;
+                  border: 1px solid #d9d9d9;
+                  border-radius: 4px;
+                  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+                  max-height: 300px;
+                  overflow-y: auto;
+                  z-index: 1000;
+                  margin-top: 4px;
+                "
+                @mouseleave="onDropdownMouseLeave"
+              >
+                <div style="padding: 8px; border-bottom: 1px solid #f0f0f0; position: sticky; top: 0; background: #fff; z-index: 1;">
+                  <a-input
+                    v-model="filterKeyword"
+                    placeholder="搜索姓名"
+                    size="small"
+                    @click.stop
+                  />
+                </div>
+                <div
+                  v-for="item in filteredDeptUserList"
+                  :key="item.userId"
+                  @click="selectUser(item)"
+                  :style="{
+                    padding: '8px 12px',
+                    cursor: 'pointer',
+                    background: selectedUserId === item.userId ? '#e6f7ff' : 'transparent'
+                  }"
+                  @mouseenter="($event.target.style.background = selectedUserId === item.userId ? '#e6f7ff' : '#f5f5f5')"
+                  @mouseleave="($event.target.style.background = selectedUserId === item.userId ? '#e6f7ff' : 'transparent')"
+                >
+                  {{ item.realName }}
+                </div>
+                <div v-if="filteredDeptUserList.length === 0" style="padding: 16px; text-align: center; color: #999;">
+                  无匹配结果
+                </div>
+              </div>
+            </div>
+          </a-form-item>
+        </row-item>
+      </row-list>
+      <row-list :col="1">
+        <row-item>
+          <a-form-item
+            label="转派备注"
+            :labelCol="BaseTool.Constant.labelCol2"
+            :wrapperCol="BaseTool.Constant.wrapperCol2"
+          >
+            <a-textarea
+              :rows="4"
+              v-decorator="['repairDispatchRemark', {rules: [{required: true, message: '转派备注不能为空'}]}]"
+              placeholder="请填写转派原因"/>
+          </a-form-item>
+        </row-item>
+      </row-list>
+    </a-form>
+    <template slot="footer">
+      <a-button :loading="confirmLoading" type="primary" @click="save()">提交转派</a-button>
+    </template>
+  </a-modal>
+</template>
+
+<script>
+import { transfer } from '@/api/repair/application-form'
+import { queryUserDept } from '@/api/upms/user-dept'
+
+export default {
+  name: 'TransferForm',
+  data () {
+    return {
+      confirmLoading: false,
+      modalTitle: null,
+      form: this.$form.createForm(this),
+      visible: false,
+      record: {},
+      deptUserList: [],
+      showDropdown: false,
+      searchKeyword: '',
+      filterKeyword: '',
+      selectedUserId: null,
+      selectedUserName: ''
+    }
+  },
+  computed: {
+    filteredDeptUserList () {
+      if (!this.filterKeyword) {
+        return this.deptUserList
+      }
+      return this.deptUserList.filter(item =>
+        item.realName.toLowerCase().includes(this.filterKeyword.toLowerCase())
+      )
+    }
+  },
+  created () {
+    this.getDeptUsers()
+  },
+  mounted () {
+    document.addEventListener('click', this.handleDocumentClick)
+  },
+  beforeDestroy () {
+    document.removeEventListener('click', this.handleDocumentClick)
+  },
+  methods: {
+    handleDocumentClick (e) {
+      if (this.showDropdown && !e.target.closest('.ant-input-affix-wrapper')) {
+        this.showDropdown = false
+      }
+    },
+    onDropdownMouseLeave () {
+    },
+    selectUser (item) {
+      this.selectedUserId = item.userId
+      this.selectedUserName = item.realName
+      this.searchKeyword = item.realName
+      this.showDropdown = false
+      this.form.setFieldsValue({ repairUserId: item.userId })
+    },
+    base (record) {
+      this.visible = true
+      this.modalTitle = '转派维修单'
+      this.record = record
+      this.$nextTick(() => {
+        this.form.resetFields()
+        this.selectedUserId = null
+        this.selectedUserName = ''
+        this.searchKeyword = ''
+        this.filterKeyword = ''
+        this.showDropdown = false
+      })
+    },
+    getDeptUsers () {
+      queryUserDept({ deptCode: this.DictCache.VALUE.SYS_DEPT_CODE.XIAN_CHANG_WEI_XIU_ZU, userStatus: 1 }).then(res => {
+        queryUserDept({ deptCode: this.DictCache.VALUE.SYS_DEPT_CODE.CHANG_NEI_WEI_XIU_ZU, userStatus: 1 }).then(res2 => {
+          this.deptUserList = res.data.concat(res2.data)
+        })
+      })
+    },
+    save () {
+      if (!this.selectedUserId) {
+        this.$message.warning('请选择新维修负责人')
+        return
+      }
+      const values = {
+        id: this.record.id,
+        repairUserId: this.selectedUserId,
+        repairDispatchRemark: this.form.getFieldValue('repairDispatchRemark')
+      }
+      this.confirmLoading = true
+      transfer(values)
+        .then(() => {
+          this.$message.success('转派已提交,等待审批')
+          this.handleCancel(values)
+        }).catch(() => {
+          this.confirmLoading = false
+        })
+    },
+    handleCancel (values) {
+      this.visible = false
+      this.confirmLoading = false
+      this.form.resetFields()
+      if (this.BaseTool.Object.isNotBlank(values)) {
+        this.$emit('ok')
+      }
+    }
+  }
+}
+</script>