Răsfoiți Sursa

feature:工单增加交付工单模块

liuzl 2 ani în urmă
părinte
comite
dea90385af

+ 29 - 0
src/api/work/deliver.js

@@ -0,0 +1,29 @@
+/*
+ * @Author: liuzhenlin 461480418@qq.ocm
+ * @Date: 2023-03-21 16:33:47
+ * @LastEditors: liuzhenlin
+ * @LastEditTime: 2023-06-20 11:09:40
+ * @Description: file content
+ * @FilePath: \订单全流程管理系统\src\api\work\index.js
+ */
+import micro_request from '@/utils/micro_request'
+
+const basePath = process.env.VUE_APP_ParentPath
+export default {
+  // 工单列表
+  addDeliverOrder(query) {
+    return micro_request.postRequest(basePath, 'DeliverOrder', 'Add', query)
+  },
+  getDeliverOrderList(query) {
+    return micro_request.postRequest(basePath, 'DeliverOrder', 'List', query)
+  },
+  updateDeliverOrder(query) {
+    return micro_request.postRequest(basePath, 'DeliverOrder', 'Update', query)
+  },
+  getDeliverOrder(query) {
+    return micro_request.postRequest(basePath, 'DeliverOrder', 'Get', query)
+  },
+  finish(query) {
+    return micro_request.postRequest(basePath, 'DeliverOrder', 'Finish', query)
+  },
+}

+ 31 - 0
src/api/work/deliverPlan.js

@@ -0,0 +1,31 @@
+/*
+ * @Author: liuzhenlin 461480418@qq.ocm
+ * @Date: 2023-03-21 16:33:47
+ * @LastEditors: liuzhenlin
+ * @LastEditTime: 2023-06-20 11:09:40
+ * @Description: file content
+ * @FilePath: \订单全流程管理系统\src\api\work\index.js
+ */
+import micro_request from '@/utils/micro_request'
+
+const basePath = process.env.VUE_APP_ParentPath
+export default {
+  addPlan(query) {
+    return micro_request.postRequest(basePath, 'DeliverOrderPlan', 'Add', query)
+  },
+  getList(query) {
+    return micro_request.postRequest(basePath, 'DeliverOrderPlan', 'List', query)
+  },
+  updatePlan(query) {
+    return micro_request.postRequest(basePath, 'DeliverOrderPlan', 'Update', query)
+  },
+  getPlan(query) {
+    return micro_request.postRequest(basePath, 'DeliverOrderPlan', 'Get', query)
+  },
+  startPlan(query) {
+    return micro_request.postRequest(basePath, 'DeliverOrderPlan', 'Start', query)
+  },
+  finishPlan(query) {
+    return micro_request.postRequest(basePath, 'DeliverOrderPlan', 'Finish', query)
+  },
+}

+ 34 - 0
src/api/work/deliverWork.js

@@ -0,0 +1,34 @@
+/*
+ * @Author: liuzhenlin 461480418@qq.ocm
+ * @Date: 2023-03-21 16:33:47
+ * @LastEditors: liuzhenlin
+ * @LastEditTime: 2023-06-20 11:09:40
+ * @Description: file content
+ * @FilePath: \订单全流程管理系统\src\api\work\index.js
+ */
+import micro_request from '@/utils/micro_request'
+
+const basePath = process.env.VUE_APP_ParentPath
+export default {
+  add(query) {
+    return micro_request.postRequest(basePath, 'DeliverOrderProgress', 'Add', query)
+  },
+  list(query) {
+    return micro_request.postRequest(basePath, 'DeliverOrderProgress', 'List', query)
+  },
+  update(query) {
+    return micro_request.postRequest(basePath, 'DeliverOrderProgress', 'Update', query)
+  },
+  get(query) {
+    return micro_request.postRequest(basePath, 'DeliverOrderProgress', 'Get', query)
+  },
+  delete(query) {
+    return micro_request.postRequest(basePath, 'DeliverOrderProgress', 'Delete', query)
+  },
+  startWork(query) {
+    return micro_request.postRequest(basePath, 'DeliverOrderProgress', 'Start', query)
+  },
+  finishWork(query) {
+    return micro_request.postRequest(basePath, 'DeliverOrderProgress', 'Finish', query)
+  },
+}

+ 113 - 0
src/views/work/order/deliver/components/editPlan.vue

@@ -0,0 +1,113 @@
+<template>
+  <el-dialog :title="title" :visible.sync="dialogFormVisible" width="500px" @close="close">
+    <el-form ref="form" label-position="top" :model="form" :rules="rules">
+      <el-row :gutter="20">
+        <el-col :span="24">
+          <el-form-item label="计划标题" prop="planTitle">
+            <el-input v-model="form.planTitle" placeholder="请输入计划标题" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20">
+        <el-col :span="24">
+          <el-form-item label="时间范围" prop="date">
+            <el-date-picker
+              v-model="form.date"
+              end-placeholder="结束日期"
+              range-separator="至"
+              start-placeholder="开始日期"
+              style="width: 100%"
+              type="datetimerange"
+              value-format="yyyy-MM-dd HH:mm:ss" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+    <template #footer>
+      <el-button @click="close">取 消</el-button>
+      <el-button type="primary" @click="save">确 定</el-button>
+    </template>
+  </el-dialog>
+</template>
+
+<script>
+  import planApi from '@/api/work/deliverPlan'
+
+  export default {
+    name: 'WorkOrderFeedback',
+    components: {},
+    props: {
+      // orderStatusOptions: {
+      //   type: Array,
+      //   default: () => [],
+      // },
+    },
+    data() {
+      return {
+        form: {
+          deliverOrderId: 0,
+          planTitle: undefined,
+          date: [],
+        },
+        rules: {
+          planTitle: [{ required: true, message: '不能为空', trigger: ['blur', 'change'] }],
+          date: [{ required: true, message: '不能为空', trigger: ['blur', 'change'] }],
+        },
+        dialogFormVisible: false,
+        planId: 0,
+        title: '',
+      }
+    },
+    mounted() {},
+    methods: {
+      open(planId) {
+        console.log('planId', planId)
+        if (planId) {
+          this.planId = planId
+          this.title = '编辑'
+          this.getPlanDetail()
+        } else {
+          this.title = '新建计划'
+          this.planId = 0
+        }
+        this.form.deliverOrderId = parseInt(this.$route.query.id)
+        this.dialogFormVisible = true
+      },
+      close() {
+        this.$refs['form'].resetFields()
+        this.form = this.$options.data().form
+        this.dialogFormVisible = false
+      },
+      async getPlanDetail() {
+        const { data, code } = await planApi.getPlan({ id: this.planId })
+        if (code == 200) {
+          this.form.date = [data.planStartDate, data.planEndDate]
+          this.form.planTitle = data.planTitle
+        }
+      },
+      save() {
+        this.$refs['form'].validate(async (valid) => {
+          if (valid) {
+            console.log(this.form.date)
+            const params = {
+              deliverOrderId: this.form.deliverOrderId,
+              planTitle: this.form.planTitle,
+              planStartDate: this.form.date[0],
+              planEndDate: this.form.date[1],
+            }
+            if (this.planId) {
+              params.id = this.planId
+              const { msg } = await planApi.updatePlan(params)
+              this.$baseMessage(msg, 'success', 'vab-hey-message-success')
+            } else {
+              const { msg } = await planApi.addPlan(params)
+              this.$baseMessage(msg, 'success', 'vab-hey-message-success')
+            }
+            this.$emit('fetch-data')
+            this.close()
+          }
+        })
+      },
+    },
+  }
+</script>

+ 128 - 0
src/views/work/order/deliver/components/editWork.vue

@@ -0,0 +1,128 @@
+<template>
+  <el-dialog :title="title" :visible.sync="dialogFormVisible" @close="close">
+    <el-form ref="form" label-position="top" :model="form" :rules="rules">
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="任务标题" prop="progressTitle">
+            <el-input v-model="form.progressTitle" placeholder="请输入任务标题" />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="任务内容" prop="progressContext">
+            <el-input v-model="form.progressContext" placeholder="请输入任务内容" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="优先级" prop="progressLevel">
+            <el-select v-model="form.progressLevel" clearable placeholder="优先级" style="width: 100%">
+              <el-option label="最高" value="10" />
+              <el-option label="普通" value="20" />
+              <el-option label="较低" value="30" />
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="时间范围" prop="date">
+            <el-date-picker
+              v-model="form.date"
+              end-placeholder="结束日期"
+              range-separator="至"
+              start-placeholder="开始日期"
+              style="width: 100%"
+              type="datetimerange"
+              value-format="yyyy-MM-dd HH:mm:ss" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20">
+        <el-col :span="24">
+          <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" placeholder="请输入备注信息" :rows="5" show-word-limit type="textarea" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+    <template #footer>
+      <el-button @click="close">取 消</el-button>
+      <el-button type="primary" @click="save">确 定</el-button>
+    </template>
+
+    <!-- 选择分派人员弹窗 -->
+  </el-dialog>
+</template>
+
+<script>
+  import deliverWorkApi from '@/api/work/deliverWork'
+  export default {
+    name: 'WorkOrderFeedback',
+    components: {},
+    data() {
+      return {
+        form: {
+          progressTitle: undefined,
+          progressContext: '',
+          date: [],
+          progressLevel: '10',
+          remark: undefined,
+        },
+        rules: {
+          progressTitle: [{ required: true, message: '不能为空', trigger: ['blur', 'change'] }],
+          progressContext: [{ required: true, message: '不能为空', trigger: ['blur', 'change'] }],
+          date: [{ required: true, message: '不能为空', trigger: ['blur', 'change'] }],
+        },
+        dialogFormVisible: false,
+        planId: 0,
+        workId: 0,
+        title: '',
+      }
+    },
+    mounted() {},
+    methods: {
+      open(planId, row) {
+        this.planId = planId
+        if (row) {
+          this.workId = row.id
+          this.title = '编辑'
+          this.form = {
+            progressTitle: row.progressTitle,
+            progressContext: row.progressContext,
+            date: [row.startDate, row.endDate],
+            progressLevel: row.progressLevel,
+            remark: row.remark,
+          }
+        } else {
+          this.title = '新建工作项'
+          this.workId = 0
+        }
+        this.dialogFormVisible = true
+      },
+      close() {
+        this.$refs['form'].resetFields()
+        this.form = this.$options.data().form
+        this.dialogFormVisible = false
+      },
+      save() {
+        this.$refs['form'].validate(async (valid) => {
+          if (valid) {
+            let params = Object.assign(this.form, { planId: this.planId })
+            params.startDate = this.form.date[0]
+            params.endDate = this.form.date[1]
+            if (this.workId) {
+              params.id = this.workId
+              const { msg } = await deliverWorkApi.update(params)
+              this.$baseMessage(msg, 'success', 'vab-hey-message-success')
+            } else {
+              const { msg } = await deliverWorkApi.add(params)
+              this.$baseMessage(msg, 'success', 'vab-hey-message-success')
+            }
+
+            this.$emit('fetch-data')
+            this.close()
+          }
+        })
+      },
+    },
+  }
+</script>

+ 59 - 0
src/views/work/order/deliver/components/finish.vue

@@ -0,0 +1,59 @@
+<template>
+  <el-dialog title="完成" :visible.sync="dialogFormVisible" @close="close">
+    <el-form ref="form" label-position="top" :model="form" :rules="rules">
+      <el-row :gutter="20">
+        <el-col :span="24">
+          <el-form-item label="完成信息" prop="finishRemark">
+            <el-input v-model="form.finishRemark" placeholder="完成信息" :rows="5" show-word-limit type="textarea" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+    <template #footer>
+      <el-button @click="close">取 消</el-button>
+      <el-button type="primary" @click="save">确 定</el-button>
+    </template>
+  </el-dialog>
+</template>
+
+<script>
+  import deliverApi from '@/api/work/deliver'
+
+  export default {
+    name: 'WorkOrderFeedback',
+    data() {
+      return {
+        form: {
+          orderId: undefined,
+          finishRemark: undefined,
+        },
+        rules: {
+          orderId: [{ required: true, message: '不能为空', trigger: ['blur', 'change'] }],
+        },
+        dialogFormVisible: false,
+      }
+    },
+    mounted() {},
+    methods: {
+      showEdit(row) {
+        this.form.orderId = row.id
+        this.dialogFormVisible = true
+      },
+      close() {
+        this.$refs['form'].resetFields()
+        this.form = this.$options.data().form
+        this.dialogFormVisible = false
+      },
+      save() {
+        this.$refs['form'].validate(async (valid) => {
+          if (valid) {
+            const { msg } = await deliverApi.finish(this.form)
+            this.$baseMessage(msg, 'success', 'vab-hey-message-success')
+            this.$emit('fetch-data')
+            this.close()
+          }
+        })
+      },
+    },
+  }
+</script>

+ 72 - 0
src/views/work/order/deliver/components/selectStatus.vue

@@ -0,0 +1,72 @@
+<template>
+  <el-dialog title="修改状态" :visible.sync="dialogFormVisible" width="300px" @close="close">
+    <el-form ref="form" label-position="top" :model="form">
+      <el-row :gutter="20">
+        <el-col :span="24">
+          <el-form-item label="状态" prop="planTitle">
+            <el-select v-model="form.planStatus" placeholder="请选择">
+              <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+    <template #footer>
+      <el-button @click="close">取 消</el-button>
+      <el-button :disabled="!form.planStatus" type="primary" @click="save">确 定</el-button>
+    </template>
+  </el-dialog>
+</template>
+
+<script>
+  import planApi from '@/api/work/deliverPlan'
+
+  export default {
+    name: 'WorkOrderFeedback',
+    components: {},
+    props: {},
+    data() {
+      return {
+        options: [
+          {
+            value: '20',
+            label: '开始计划',
+          },
+          {
+            value: '30',
+            label: '关闭计划',
+          },
+        ],
+        form: {
+          id: 0,
+          planStatus: null,
+        },
+        dialogFormVisible: false,
+      }
+    },
+    mounted() {},
+    methods: {
+      open(planId) {
+        this.form.id = planId
+        this.dialogFormVisible = true
+      },
+      close() {
+        this.$refs['form'].resetFields()
+        this.form = this.$options.data().form
+        this.dialogFormVisible = false
+      },
+
+      async save() {
+        if (this.form.planStatus == 20) {
+          const { msg } = await planApi.startPlan(this.form)
+          this.$baseMessage(msg, 'success', 'vab-hey-message-success')
+        } else {
+          const { msg } = await planApi.finishPlan(this.form)
+          this.$baseMessage(msg, 'success', 'vab-hey-message-success')
+        }
+        this.$emit('fetch-data')
+        this.close()
+      },
+    },
+  }
+</script>

+ 105 - 0
src/views/work/order/deliver/components/updateUser.vue

@@ -0,0 +1,105 @@
+<template>
+  <el-dialog title="更新成员信息" :visible.sync="dialogFormVisible" @close="close">
+    <el-form ref="form" label-position="top" :model="form" :rules="rules">
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="项目经理" prop="projectManId">
+            <el-input
+              v-model="form.projectManName"
+              readonly
+              suffix-icon="el-icon-search"
+              @focus="handleSelectUser('projectManId', 'projectManName')" />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="交付经理" prop="deliverManId">
+            <el-input
+              v-model="form.deliverManName"
+              readonly
+              suffix-icon="el-icon-search"
+              @focus="handleSelectUser('deliverManId', 'deliverManName')" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+    <template #footer>
+      <el-button @click="close">取 消</el-button>
+      <el-button :disabled="!form.deliverManId && !form.projectManId" type="primary" @click="save">确 定</el-button>
+    </template>
+
+    <!-- 选择分派人员弹窗 -->
+    <select-user ref="selectUser" @save="selectUser" />
+  </el-dialog>
+</template>
+
+<script>
+  import deliverApi from '@/api/work/deliver'
+  import SelectUser from '@/components/select/SelectUser'
+
+  export default {
+    name: 'WorkOrderFeedback',
+    components: {
+      SelectUser,
+    },
+    props: {},
+    data() {
+      return {
+        form: {
+          deliverManId: undefined,
+          deliverManName: undefined,
+          projectManId: undefined,
+          projectManName: undefined,
+          id: 0,
+        },
+        rules: {
+          // deliverManId: [{ required: true, message: '不能为空', trigger: ['blur', 'change'] }],
+          // deliverManName: [{ required: true, message: '不能为空', trigger: ['blur', 'change'] }],
+        },
+        dialogFormVisible: false,
+        orderTypeList: [],
+        dingtalkForm: undefined,
+        curKey: '',
+        curName: '',
+      }
+    },
+    mounted() {},
+    methods: {
+      handleSelectUser(key, name) {
+        this.curKey = key
+        this.curName = name
+        this.$refs.selectUser.open()
+      },
+      selectUser(val) {
+        if (val && val.length > 0) {
+          this.form[this.curKey] = val[0].id
+          this.form[this.curName] = val.map((item) => item.nickName).join()
+        }
+      },
+      open(row) {
+        this.form = {
+          deliverManId: row.deliverManId,
+          deliverManName: row.deliverManName,
+          projectManId: row.projectManId,
+          projectManName: row.projectManName,
+          id: row.id,
+        }
+        this.dialogFormVisible = true
+      },
+      close() {
+        this.$refs['form'].resetFields()
+        this.form = this.$options.data().form
+        this.dialogFormVisible = false
+      },
+      save() {
+        this.$refs['form'].validate(async (valid) => {
+          if (valid) {
+            const { msg } = await deliverApi.updateDeliverOrder(this.form)
+            this.$baseMessage(msg, 'success', 'vab-hey-message-success')
+            this.$emit('fetch-data')
+            this.close()
+          }
+        })
+      },
+    },
+  }
+</script>

+ 273 - 0
src/views/work/order/deliver/index.vue

@@ -0,0 +1,273 @@
+<template>
+  <div class="list-container">
+    <vab-query-form>
+      <vab-query-form-top-panel>
+        <el-form ref="queryForm" :inline="true" :model="queryForm" @submit.native.prevent>
+          <el-form-item prop="contractCode">
+            <el-input v-model="queryForm.contractCode" placeholder="合同编号" @keyup.enter.native="restFetchData" />
+          </el-form-item>
+          <el-form-item prop="custName">
+            <el-input v-model="queryForm.custName" placeholder="客户名称" @keyup.enter.native="restFetchData" />
+          </el-form-item>
+          <el-form-item prop="orderType">
+            <el-select
+              v-model="queryForm.orderType"
+              clearable
+              placeholder="交付类型"
+              style="width: 100%"
+              @keyup.enter.native="restFetchData">
+              <el-option label="软件" value="10" />
+              <el-option label="硬件" value="20" />
+            </el-select>
+          </el-form-item>
+          <el-form-item prop="projectManName">
+            <el-input v-model="queryForm.projectManName" placeholder="项目经理" @keyup.enter.native="restFetchData" />
+          </el-form-item>
+
+          <el-form-item>
+            <el-button icon="el-icon-search" type="primary" @click="restFetchData">查询</el-button>
+            <el-button icon="el-icon-refresh-right" @click="reset">重置</el-button>
+          </el-form-item>
+        </el-form>
+      </vab-query-form-top-panel>
+      <vab-query-form-left-panel :span="12" />
+      <vab-query-form-right-panel :span="12">
+        <table-tool :columns="columns" :show-columns.sync="showColumns" table-type="deliverWorkOrderTable" />
+      </vab-query-form-right-panel>
+    </vab-query-form>
+
+    <el-table ref="table" v-loading="listLoading" border :data="list" :height="$baseTableHeight(2)">
+      <el-table-column align="center" label="序号" show-overflow-tooltip width="80">
+        <template #default="{ $index }">
+          {{ $index + 1 }}
+        </template>
+      </el-table-column>
+      <el-table-column
+        v-for="(item, index) in showColumns"
+        :key="index"
+        align="center"
+        :label="item.label"
+        :prop="item.prop"
+        show-overflow-tooltip
+        :sortable="item.sortable"
+        :width="item.width">
+        <template #default="{ row }">
+          <el-button v-if="item.prop === 'orderCode'" style="font-size: 14px" type="text" @click="handleDetail(row)">
+            {{ row.orderCode }}
+          </el-button>
+          <span v-else-if="item.prop === 'orderType'">
+            {{ row.orderType == '10' ? '软件' : '硬件' }}
+          </span>
+          <span v-else-if="item.prop === 'product'">
+            {{ selectDictLabel(productLineOptions, row.product) }}
+          </span>
+          <span v-else-if="item.prop === 'orderStatus'">
+            {{ selectDictLabel(deliveryStatusOptions, row.orderStatus) }}
+          </span>
+          <span v-else-if="item.prop === 'createdTime'">
+            {{ parseTime(row.createdTime, '{y}-{m}-{d}') }}
+          </span>
+          <span v-else>{{ row[item.prop] }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column align="center" label="操作" width="90">
+        <template #default="{ row }">
+          <el-button type="text" @click="handleUpdateUser(row)">成员</el-button>
+          <el-button v-if="row.orderStatus != 20" type="text" @click="handleFinish(row)">完成</el-button>
+        </template>
+      </el-table-column>
+      <template #empty>
+        <el-image class="vab-data-empty" :src="require('@/assets/empty_images/data_empty.png')" />
+      </template>
+    </el-table>
+
+    <el-pagination
+      background
+      :current-page="queryForm.pageNum"
+      :layout="layout"
+      :page-size="queryForm.pageSize"
+      :total="total"
+      @current-change="handleCurrentChange"
+      @size-change="handleSizeChange" />
+    <!--创建工单-->
+    <!-- <edit ref="edit" @fetch-data="fetchData" /> -->
+    <!--反馈-->
+    <finish ref="finish" @fetch-data="restFetchData" />
+    <!-- 更新项目经理交付经理 -->
+    <update-user ref="updateUser" @fetch-data="restFetchData" />
+  </div>
+</template>
+
+<script>
+  import to from 'await-to-js'
+  import deliverApi from '@/api/work/deliver'
+  import TableTool from '@/components/table/TableTool'
+  import Finish from './components/finish'
+  import UpdateUser from './components/updateUser'
+
+  export default {
+    name: 'WorkOrder',
+    components: { TableTool, Finish, UpdateUser },
+    data() {
+      return {
+        activeName: 'first',
+        layout: 'total, sizes, prev, pager, next, jumper',
+        queryForm: {
+          contractCode: '',
+          custName: '',
+          orderType: '',
+          projectManName: '',
+          pageNum: 1,
+          pageSize: 10,
+        },
+        total: 0,
+        listLoading: false,
+        list: [],
+        selectRows: [],
+        showColumns: [],
+        columns: [
+          {
+            label: '交付工单号',
+            width: '160px',
+            prop: 'orderCode',
+          },
+          {
+            label: '关联合同',
+            width: 'auto',
+            prop: 'contractCode',
+          },
+          {
+            label: '交付状态',
+            width: '160px',
+            prop: 'orderStatus',
+            disableCheck: true,
+          },
+          {
+            label: '交付类型',
+            width: '160px',
+            prop: 'orderType',
+          },
+          {
+            label: '关联客户',
+            width: 'auto',
+            prop: 'custName',
+          },
+          {
+            label: '关联项目',
+            width: 'auto',
+            prop: 'projectName',
+          },
+          {
+            label: '项目经理',
+            width: '160px',
+            prop: 'projectManName',
+          },
+          {
+            label: '交付经理',
+            width: '160px',
+            prop: 'deliverManName',
+          },
+          {
+            label: '产品线',
+            width: 'auto',
+            prop: 'product',
+          },
+          {
+            label: '完成信息',
+            width: '160px',
+            prop: 'finishRemark',
+          },
+          {
+            label: '创建时间',
+            width: 'auto',
+            prop: 'createdTime',
+          },
+        ],
+        deliveryStatusOptions: [],
+        productLineOptions: [],
+      }
+    },
+    watch: {
+      showColumns: function () {
+        this.$nextTick(() => this.$refs.table.doLayout())
+      },
+    },
+    activated() {
+      this.fetchData()
+    },
+    mounted() {
+      this.getOptions()
+      this.fetchData()
+      // deliverApi.addDeliverOrder({ contractId: 47 })
+    },
+
+    methods: {
+      getOptions() {
+        Promise.all([this.getDicts('delivery_status'), this.getDicts('sys_product_line')])
+          .then(([deliveryStatus, productLine]) => {
+            this.deliveryStatusOptions = deliveryStatus.data.values || []
+            this.productLineOptions = productLine.data.values || []
+          })
+          .catch((err) => console.log(err))
+      },
+      restFetchData() {
+        this.queryForm.pageNum = 1
+        this.fetchData()
+      },
+      async fetchData() {
+        this.listLoading = true
+        const params = { ...this.queryForm }
+        const [err, res] = await to(deliverApi.getDeliverOrderList({ ...params }))
+        this.listLoading = false
+        if (err) return (this.listLoading = false)
+        if (res.code == 200 && res.data) {
+          this.list = res.data.list || []
+          this.total = res.data.total
+        }
+        this.$nextTick(() => this.$refs.table.doLayout())
+      },
+      handleFinish(row) {
+        this.$refs['finish'].showEdit(row)
+      },
+      handleUpdateUser(row) {
+        this.$refs['updateUser'].open(row)
+      },
+      //详情
+      handleDetail(row) {
+        this.$router.push({
+          name: 'DeliveryPlan',
+          query: {
+            id: row.id,
+          },
+        })
+      },
+      reset() {
+        this.queryForm = {
+          pageNum: 1,
+          pageSize: 10,
+          name: '',
+          orderTypeName: '',
+          orderStatus: '',
+          assignUserName: '',
+        }
+        this.fetchData()
+      },
+
+      handleSizeChange(val) {
+        this.queryForm.pageSize = val
+        this.fetchData()
+      },
+      handleCurrentChange(val) {
+        this.queryForm.pageNum = val
+        this.fetchData()
+      },
+      setSelectRows(val) {
+        this.selectRows = val
+      },
+    },
+  }
+</script>
+
+<style lang="scss" scoped>
+  $base: '.list';
+</style>

+ 512 - 0
src/views/work/order/deliver/plan.vue

@@ -0,0 +1,512 @@
+<template>
+  <div class="user-management-container">
+    <div class="side-layout">
+      <div class="tree-side">
+        <div class="head-container">
+          <el-button
+            v-show="workOrderStatus != 20"
+            v-permissions="['order:delivery:plan:add']"
+            class="add-btn"
+            icon="el-icon-plus"
+            type="text"
+            @click="openAddPlan()">
+            新建计划
+          </el-button>
+        </div>
+        <div class="left-scroll">
+          <ul class="plan-wrap">
+            <li
+              v-for="(v, i) in planList"
+              :key="i"
+              class="plan-item"
+              :class="v.id == curPlanId ? 'actived' : ''"
+              @click="selectPlanItem(v)">
+              <div class="flex-between" style="margin-bottom: 20px">
+                <span>{{ v.planTitle }}</span>
+                <div class="plan-status" :class="'plan-status-' + v.planStatus" @click="openChangeStatus(v)">
+                  {{ plasnStatusObj[v.planStatus] }}
+                </div>
+              </div>
+              <div class="flex-between">
+                <div>{{ parseTime(v.planStartDate, '{m}-{d}') }} ~ {{ parseTime(v.planEndDate, '{m}-{d}') }}</div>
+                <el-button
+                  v-show="workOrderStatus != 20 && v.planStatus != 30"
+                  style="padding: 0"
+                  type="text"
+                  @click="openAddPlan(v.id)">
+                  编辑
+                </el-button>
+              </div>
+            </li>
+          </ul>
+        </div>
+      </div>
+      <div class="tree-table">
+        <vab-query-form>
+          <vab-query-form-top-panel>
+            <el-form :inline="true" :model="queryForm" @submit.native.prevent>
+              <el-form-item>
+                <el-input
+                  v-model.trim="queryForm.progressTitle"
+                  clearable
+                  placeholder="任务标题"
+                  @keyup.enter.native="fetchWorkListPage1" />
+              </el-form-item>
+              <el-form-item>
+                <el-select
+                  v-model="queryForm.progressStatus"
+                  clearable
+                  placeholder="状态"
+                  style="width: 100%"
+                  @change="fetchWorkListPage1">
+                  <el-option label="未开始" value="10" />
+                  <el-option label="已开始" value="20" />
+                  <el-option label="已完成" value="30" />
+                </el-select>
+              </el-form-item>
+              <el-form-item>
+                <el-select
+                  v-model="queryForm.progressLevel"
+                  clearable
+                  placeholder="级别"
+                  style="width: 100%"
+                  @change="fetchWorkListPage1">
+                  <el-option label="最高" value="10" />
+                  <el-option label="普通" value="20" />
+                  <el-option label="较低" value="30" />
+                </el-select>
+              </el-form-item>
+              <el-form-item>
+                <el-button icon="el-icon-search" type="primary" @click="fetchWorkList">查询</el-button>
+                <el-button icon="el-icon-refresh-right" @click="reset">重置</el-button>
+              </el-form-item>
+            </el-form>
+          </vab-query-form-top-panel>
+          <vab-query-form-left-panel>
+            <el-button
+              v-show="workOrderStatus != 20 && curPlanStatus != 30"
+              v-permissions="['order:delivery:work:add']"
+              icon="el-icon-plus"
+              type="primary"
+              @click="openAddWork">
+              新建工作项
+            </el-button>
+          </vab-query-form-left-panel>
+          <vab-query-form-right-panel>
+            <table-tool :columns="columns" :show-columns.sync="showColumns" table-type="productTable" />
+          </vab-query-form-right-panel>
+        </vab-query-form>
+
+        <el-table ref="table" v-loading="listLoading" border :data="tabaleList" :height="$baseTableHeight(2)">
+          <el-table-column align="center" label="序号" show-overflow-tooltip width="80">
+            <template #default="{ $index }">
+              {{ $index + 1 }}
+            </template>
+          </el-table-column>
+          <el-table-column
+            v-for="(item, index) in showColumns"
+            :key="index"
+            align="center"
+            :label="item.label"
+            :min-width="item.minWidth"
+            :prop="item.prop"
+            show-overflow-tooltip
+            :sortable="item.sortable"
+            :width="item.width">
+            <template #default="{ row }">
+              <el-button
+                v-if="item.prop === 'progressTitle'"
+                style="font-size: 14px"
+                type="text"
+                @click="handleWorkDetail(row)">
+                {{ row.progressTitle }}
+              </el-button>
+              <span v-else-if="item.prop === 'progressLevel'">
+                <el-select
+                  v-model="row.progressLevel"
+                  :disabled="workOrderStatus == 20 || curPlanStatus == 30 || row.progressStatus == 30"
+                  placeholder="请选择"
+                  @change="changeprogressLevel($event, row)">
+                  <el-option label="最高" value="10" />
+                  <el-option label="普通" value="20" />
+                  <el-option label="较低" value="30" />
+                </el-select>
+              </span>
+              <span v-else-if="item.prop === 'progressStatus'">
+                {{ plasnStatusObj[row.progressStatus] }}
+              </span>
+              <span v-else-if="item.prop === 'startDate'">
+                {{ parseTime(row.startDate, '{y}-{m}-{d}') }}
+              </span>
+              <span v-else-if="item.prop === 'endDate'">
+                {{ parseTime(row.endDate, '{y}-{m}-{d}') }}
+              </span>
+              <span v-else-if="item.prop === 'reaStartDate'">
+                {{ parseTime(row.reaStartDate, '{y}-{m}-{d}') }}
+              </span>
+              <span v-else-if="item.prop === 'reaEndDate'">
+                {{ parseTime(row.reaEndDate, '{y}-{m}-{d}') }}
+              </span>
+              <span v-else>{{ row[item.prop] }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column align="center" fixed="right" label="操作" show-overflow-tooltip width="120">
+            <template #default="{ row }">
+              <el-button
+                v-if="row.progressStatus == 10 && workOrderStatus != 20 && curPlanStatus != 30"
+                type="text"
+                @click="handleStartWork(row)">
+                开始
+              </el-button>
+              <el-button
+                v-if="row.progressStatus == 20 && workOrderStatus != 20 && curPlanStatus != 30"
+                type="text"
+                @click="handleFinishWork(row)">
+                完成
+              </el-button>
+              <el-button v-show="workOrderStatus != 20 && curPlanStatus != 30" type="text" @click="handleDelete(row)">
+                删除
+              </el-button>
+            </template>
+          </el-table-column>
+          <template #empty>
+            <el-image class="vab-data-empty" :src="require('@/assets/empty_images/data_empty.png')" />
+          </template>
+        </el-table>
+        <el-pagination
+          background
+          :current-page="queryForm.pageNum"
+          :layout="layout"
+          :page-size="queryForm.pageSize"
+          :total="total"
+          @current-change="handleCurrentChange"
+          @size-change="handleSizeChange" />
+      </div>
+      <edit-plan ref="plan" @fetch-data="fetchPlanList" />
+      <edit-work ref="work" @fetch-data="fetchWorkListPage1" />
+      <select-status ref="status" @fetch-data="fetchPlanList" />
+    </div>
+  </div>
+</template>
+
+<script>
+  import orderWorkApi from '@/api/work/deliver'
+  import planApi from '@/api/work/deliverPlan'
+  import deliverWorkApi from '@/api/work/deliverWork'
+  import TableTool from '@/components/table/TableTool'
+  import EditPlan from '@/views/work/order/deliver/components/editPlan'
+  import EditWork from '@/views/work/order/deliver/components/editWork'
+  import selectStatus from './components/selectStatus'
+  import to from 'await-to-js'
+  export default {
+    name: 'Product',
+    components: { EditPlan, EditWork, TableTool, selectStatus },
+    data() {
+      return {
+        planList: [], //左侧工单列表
+        curPlanId: -1,
+        tabaleList: [],
+        plasnStatusObj: {
+          10: '未开始',
+          20: '已开始',
+          30: '已关闭',
+        },
+        progressLevelOptions: {
+          10: '最高',
+          20: '普通',
+          30: '较低',
+        },
+        listLoading: true,
+        layout: 'total, sizes, prev, pager, next, jumper',
+        total: 0,
+        selectRows: '',
+        queryForm: {
+          pageNum: 1,
+          pageSize: 10,
+          progressStatus: '',
+          progressLevel: '',
+          progressTitle: '',
+        },
+        showColumns: [],
+        columns: [
+          {
+            label: '任务标题',
+            width: '160px',
+            prop: 'progressTitle',
+            sortable: false,
+            disableCheck: true,
+          },
+          {
+            label: '任务内容',
+            prop: 'progressContext',
+            minWidth: '160px',
+            sortable: false,
+            disableCheck: true,
+          },
+          {
+            label: '优先级',
+            width: '120px',
+            prop: 'progressLevel',
+            sortable: false,
+          },
+          {
+            label: '状态',
+            width: '120px',
+            prop: 'progressStatus',
+            sortable: false,
+          },
+          {
+            label: '计划开始时间',
+            width: '120px',
+            prop: 'startDate',
+            sortable: false,
+            disableCheck: true,
+          },
+
+          {
+            label: '计划结束时间',
+            width: '120px',
+            prop: 'endDate',
+            sortable: false,
+          },
+          {
+            label: '实际开始时间',
+            width: '120px',
+            prop: 'reaStartDate',
+            sortable: false,
+            disableCheck: true,
+          },
+
+          {
+            label: '实际结束时间',
+            width: '120px',
+            prop: 'reaEndDate',
+            sortable: false,
+          },
+          {
+            label: '备注',
+            width: '120px',
+            prop: 'remark',
+            sortable: false,
+          },
+        ],
+        defaultProps: {
+          key: 'key',
+          label: 'value',
+        },
+        prodClassOptions: [], //产品分类
+        id: 0,
+        curPlanStatus: 0,
+        workOrderStatus: 0,
+      }
+    },
+    watch: {
+      showColumns: function () {
+        this.$nextTick(() => this.$refs.table.doLayout())
+      },
+    },
+    mounted() {
+      this.id = parseInt(this.$route.query.id)
+      this.getOrderDetails()
+      this.fetchPlanList()
+    },
+    methods: {
+      openChangeStatus(v) {
+        if (this.workOrderStatus == 20 || v.planStatus == 30) return
+        this.$refs.status.open(v.id)
+      },
+      selectPlanItem(row) {
+        if (this.curPlanId != row.id) {
+          this.curPlanId = row.id
+          this.curPlanStatus = row.planStatus
+
+          this.queryForm.pageNum = 1
+          this.fetchWorkListPage1()
+        }
+      },
+      reset() {
+        this.queryForm = {
+          pageNum: 1,
+          pageSize: 10,
+          progressStatus: '',
+          progressLevel: '',
+          progressTitle: '',
+        }
+        this.fetchWorkListPage1()
+      },
+      async changeprogressLevel(val, row) {
+        console.log(val, row)
+        const params = {
+          id: row.id,
+          progressLevel: val,
+        }
+        const [err, res] = await to(deliverWorkApi.update(params))
+        if (err) return
+        if (res.code == 200) {
+          this.$baseMessage(res.msg, 'success', 'vab-hey-message-success')
+        }
+        this.fetchWorkList()
+      },
+      // 新建计划
+      openAddPlan(id = null) {
+        this.$refs.plan.open(id)
+      },
+      // 新增工作项
+      openAddWork() {
+        this.$refs.work.open(this.curPlanId)
+      },
+      //工作项详情
+      handleWorkDetail(row) {
+        if (this.workOrderStatus == 20 || this.curPlanStatus == 30 || row.progressStatus == 30) return
+        this.$refs['work'].open(this.planId, row)
+      },
+      // 开始工作项
+      async handleStartWork(row) {
+        this.$prompt('你确定要开始当前任务吗', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+        })
+          .then(async ({ value }) => {
+            // 当用户点击确定按钮时,执行的逻辑
+            await this.fetchWorkList()
+            console.log('输入的值为:', value)
+            const [err, res] = await to(deliverWorkApi.startWork({ id: row.id, remark: value }))
+            if (err) return
+            if (res.code == 200) {
+              this.$baseMessage(res.msg, 'success', 'vab-hey-message-success')
+              this.fetchWorkList()
+            }
+          })
+          .catch(() => {
+            // 当用户点击取消按钮时,执行的逻辑
+            console.log('取消输入')
+          })
+      },
+      // 完成工作项
+      async handleFinishWork(row) {
+        this.$prompt('你确定要完成当前任务吗', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+        })
+          .then(async ({ value }) => {
+            // 当用户点击确定按钮时,执行的逻辑
+            await this.fetchWorkList()
+            console.log('输入的值为:', value)
+            const [err, res] = await to(deliverWorkApi.finishWork({ id: row.id, remark: value }))
+            if (err) return
+            if (res.code == 200) {
+              this.$baseMessage(res.msg, 'success', 'vab-hey-message-success')
+              this.fetchWorkList()
+            }
+          })
+          .catch(() => {
+            // 当用户点击取消按钮时,执行的逻辑
+            console.log('取消输入')
+          })
+      },
+      handleDelete(row) {
+        this.$baseConfirm('你确定要删除当前项吗', null, async () => {
+          const { msg } = await deliverWorkApi.delete({ id: [row.id] })
+          this.$baseMessage(msg, 'success', 'vab-hey-message-success')
+          await this.fetchWorkList()
+        })
+      },
+      handleSizeChange(val) {
+        this.queryForm.pageSize = val
+        this.fetchWorkList()
+      },
+      handleCurrentChange(val) {
+        this.queryForm.pageNum = val
+        this.fetchWorkList()
+      },
+      fetchWorkListPage1() {
+        this.queryForm.pageNum = 1
+        this.fetchWorkList()
+      },
+      // 查询计划
+      async fetchPlanList() {
+        this.listLoading = true
+        const [err, res] = await to(planApi.getList({ deliverOrderId: this.id }))
+        this.listLoading = false
+        if (err) return
+        if (res.code == 200 && res.data) {
+          this.planList = res.data.list
+          if (this.curPlanId === -1 && this.planList.length > 0) {
+            this.curPlanId = this.planList[0].id
+            // this.workOrderStatus = this.planList[0].orderStatus || 10
+            this.curPlanStatus = this.planList[0].planStatus
+          }
+          this.fetchWorkList()
+        }
+      },
+      async getOrderDetails() {
+        const [err, res] = await to(orderWorkApi.getDeliverOrder({ id: this.id }))
+        if (err) return
+        if (res.code == 200 && res.data) {
+          this.workOrderStatus = res.data.orderStatus || 10
+        }
+      },
+      // 查询工作项
+      async fetchWorkList() {
+        this.listLoading = true
+        const params = Object.assign(this.queryForm, { planId: this.curPlanId })
+        const [err, res] = await to(deliverWorkApi.list(params))
+        this.listLoading = false
+        if (err) return
+        if (res.code == 200 && res.data) {
+          this.tabaleList = res.data.list
+          this.total = res.data.total
+        }
+      },
+    },
+  }
+</script>
+<style lang="scss" scoped>
+  .el-form-item--small {
+    margin: 0 0 10px 0 !important;
+  }
+  .left-scroll {
+    height: 100%;
+    overflow: auto;
+  }
+  .tree-side {
+    border-right: 0;
+    .plan-item {
+      cursor: pointer;
+      padding: 10px 10px 10px 10px;
+      border-radius: 4px;
+      .flex-between {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 10px;
+      }
+    }
+    .actived {
+      background: rgb(135 206 235 / 40%);
+    }
+    .plan-status {
+      border: 1px solid;
+      border-radius: 30px;
+      padding: 5px 10px;
+      line-height: 1;
+      font-size: 12px;
+    }
+    .plan-status-10 {
+      color: #409eff;
+      border-color: #409eff;
+    }
+    .plan-status-20 {
+      color: #67c23a;
+      border-color: #67c23a;
+    }
+    .plan-status-30 {
+      color: #f56c6c;
+      border-color: #f56c6c;
+    }
+    .add-btn {
+      font-size: 14px;
+      font-weight: bold;
+    }
+  }
+</style>

+ 5 - 0
src/views/work/order/index.vue

@@ -38,6 +38,11 @@
     </vab-query-form>
 
     <el-table ref="table" v-loading="listLoading" border :data="list" :height="$baseTableHeight(2)">
+      <el-table-column align="center" label="序号" show-overflow-tooltip width="80">
+        <template #default="{ $index }">
+          {{ $index + 1 }}
+        </template>
+      </el-table-column>
       <el-table-column
         v-for="(item, index) in showColumns"
         :key="index"