Jelajahi Sumber

feat: 待办事项

xdd 2 minggu lalu
induk
melakukan
f5ed734f87
2 mengubah file dengan 319 tambahan dan 15 penghapusan
  1. 26 0
      src/api/todo/todoItems.js
  2. 293 15
      src/views/todo/todoItems/index.vue

+ 26 - 0
src/api/todo/todoItems.js

@@ -53,3 +53,29 @@ export function delTodoItems(id) {
     data: { id: id }
   })
 }
+
+// 分配执行者
+export function assignExecutor(data) {
+  return request({
+    url: '/todoItems/assignExecutor',
+    method: 'post',
+    data: data
+  })
+}
+
+// 获取可分配的执行者列表
+export function getExecutorList() {
+  return request({
+    url: '/todoItems/getExecutorList',
+    method: 'get'
+  })
+}
+
+// 获取执行人员列表(支持分页和公司名称搜索)
+export function getUserList(param) {
+  return request({
+    url: '/todoItems/getUserList',
+    method: 'post',
+    data: param
+  })
+}

+ 293 - 15
src/views/todo/todoItems/index.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="app-container">
-    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px" >
       <el-form-item label="标题" prop="title">
         <el-input
           v-model="queryParams.title"
@@ -9,6 +9,15 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
+      <el-form-item label="公司名称" prop="companyName">
+        <el-input
+          v-model="queryParams.companyName"
+          placeholder="请输入公司名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
       <el-form-item label="状态" prop="status">
         <el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
           <el-option
@@ -61,21 +70,29 @@
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
-    <el-table v-loading="loading" :data="todoItemsList" @selection-change="handleSelectionChange">
+    <el-table
+      v-loading="loading"
+      :data="todoItemsList"
+      @selection-change="handleSelectionChange"
+    >
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="ID" align="center" prop="id" />
       <el-table-column label="标题" align="center" prop="title" />
-      <el-table-column label="分配者" align="center" prop="title" />
-      <el-table-column label="执行人" align="center" prop="title" />
+      <el-table-column label="分配者" align="center" prop="assignerName" />
+      <el-table-column label="执行人" align="center" prop="executorName" />
       <el-table-column label="描述" align="center" prop="description" show-overflow-tooltip />
       <el-table-column label="状态" align="center" prop="status">
         <template slot-scope="scope">
-          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+          <el-tag :type="getStatusType(scope.row.status)" size="small">
+            {{ getStatusLabel(scope.row.status) }}
+          </el-tag>
         </template>
       </el-table-column>
       <el-table-column label="优先级" align="center" prop="priority">
         <template slot-scope="scope">
-          <dict-tag :options="priorityOptions" :value="scope.row.priority"/>
+          <el-tag :type="getPriorityType(scope.row.priority)" size="small">
+            {{ getPriorityLabel(scope.row.priority) }}
+          </el-tag>
         </template>
       </el-table-column>
       <el-table-column label="截止时间" align="center" prop="dueDate" width="180">
@@ -88,7 +105,7 @@
           <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
         </template>
       </el-table-column>
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="220">
         <template slot-scope="scope">
           <el-button
             size="mini"
@@ -104,6 +121,14 @@
             @click="handleUpdateStatus(scope.row)"
             v-hasPermi="['todo:todoItems:edit']"
           >更新状态</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-user"
+            @click="handleAssignExecutor(scope.row)"
+            v-hasPermi="['todo:todoItems:edit']"
+            class="assign-executor-btn"
+          >分配执行者</el-button>
           <el-button
             size="mini"
             type="text"
@@ -115,13 +140,15 @@
       </el-table-column>
     </el-table>
 
-    <pagination
-      v-show="total>0"
-      :total="total"
-      :page.sync="queryParams.pageNum"
-      :limit.sync="queryParams.pageSize"
-      @pagination="getList"
-    />
+    <div class="pagination-wrapper">
+      <pagination
+        v-show="total>0"
+        :total="total"
+        :page.sync="queryParams.pageNum"
+        :limit.sync="queryParams.pageSize"
+        @pagination="getList"
+      />
+    </div>
 
     <!-- 添加或修改待办事项对话框 -->
     <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
@@ -186,11 +213,37 @@
         <el-button @click="cancelStatus">取 消</el-button>
       </div>
     </el-dialog>
+
+    <!-- 分配执行者对话框 -->
+    <el-dialog title="分配执行者" :visible.sync="assignOpen" width="500px" append-to-body>
+      <el-form ref="assignForm" :model="assignForm" :rules="assignRules" label-width="80px">
+        <el-form-item label="待办事项" prop="title">
+          <el-input v-model="assignForm.title" disabled />
+        </el-form-item>
+        <el-form-item label="执行者" prop="executorId">
+          <el-select v-model="assignForm.executorId" placeholder="请选择执行者" filterable class="executor-select">
+            <el-option
+              v-for="executor in executorList"
+              :key="executor.userId"
+              :label="executor.userName"
+              :value="executor.userId"
+            ></el-option>
+          </el-select>
+          <div class="el-form-item__tip">
+            <small>执行者列表会根据搜索条件中的公司名称进行过滤</small>
+          </div>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitAssignForm">确 定</el-button>
+        <el-button @click="cancelAssign">取 消</el-button>
+      </div>
+    </el-dialog>
   </div>
 </template>
 
 <script>
-import { listTodoItems, getTodoItems, delTodoItems, addTodoItems, updateTodoItems, updateTodoItemsStatus } from "@/api/todo/todoItems";
+import { listTodoItems, getTodoItems, delTodoItems, addTodoItems, updateTodoItems, updateTodoItemsStatus, assignExecutor, getExecutorList, getUserList } from "@/api/todo/todoItems";
 import {parseTime} from "../../../utils/common";
 
 export default {
@@ -217,16 +270,21 @@ export default {
       open: false,
       // 是否显示状态更新弹出层
       statusOpen: false,
+      // 是否显示分配执行者弹出层
+      assignOpen: false,
       // 状态选项
       statusOptions: [],
       // 优先级选项
       priorityOptions: [],
       todoItemTypeOptions: [],
+      // 执行者列表
+      executorList: [],
       // 查询参数
       queryParams: {
         pageNum: 1,
         pageSize: 10,
         title: null,
+        companyName: null,
         status: null
       },
       // 表单参数
@@ -235,6 +293,13 @@ export default {
       },
       // 状态表单参数
       statusForm: {},
+      // 分配执行者表单参数
+      assignForm: {
+        id: null,
+        title: '',
+        executorId: null,
+        remark: ''
+      },
       // 表单校验
       rules: {
         title: [
@@ -243,6 +308,12 @@ export default {
         status: [
           { required: true, message: "状态不能为空", trigger: "change" }
         ]
+      },
+      // 分配执行者表单校验
+      assignRules: {
+        executorId: [
+          { required: true, message: "请选择执行者", trigger: "change" }
+        ]
       }
     };
   },
@@ -257,6 +328,8 @@ export default {
     this.getDicts("todo_item_type").then(response => {
       this.todoItemTypeOptions = response.data;
     });
+    // 获取执行者列表
+    this.getExecutorList();
   },
   methods: {
     parseTime,
@@ -269,6 +342,60 @@ export default {
         this.loading = false;
       });
     },
+    /** 获取执行者列表 */
+    getExecutorList() {
+      const params = {
+        companyName: this.queryParams.companyName,
+        companyId: null,
+        pageNum: 1,
+        pageSize: 10 // 获取足够多的执行者供选择
+      };
+      getUserList(params).then(response => {
+        if (response.code === 200) {
+          this.executorList = response.data || [];
+        }
+      });
+    },
+    /** 获取状态标签 */
+    getStatusLabel(status) {
+      const statusOption = this.statusOptions.find(option => option.dictValue === String(status));
+      return statusOption ? statusOption.dictLabel : '未知';
+    },
+    /** 获取状态标签类型(颜色) */
+    getStatusType(status) {
+      const statusMap = {
+        '0': 'info',      // 待处理 - 蓝色
+        '1': 'warning',   // 进行中 - 橙色
+        '2': 'success',   // 已完成 - 绿色
+        '3': 'danger'     // 已取消 - 红色
+      };
+      return statusMap[String(status)] || 'info';
+    },
+    /** 获取优先级标签 */
+    getPriorityLabel(priority) {
+      const priorityOption = this.priorityOptions.find(option => option.dictValue === String(priority));
+      return priorityOption ? priorityOption.dictLabel : '未知';
+    },
+    /** 获取优先级标签类型(颜色) */
+    getPriorityType(priority) {
+      const priorityMap = {
+        '0': 'info',      // 低 - 蓝色
+        '1': 'success',   // 中 - 绿色
+        '2': 'warning',   // 高 - 橙色
+        '3': 'danger'     // 紧急 - 红色
+      };
+      return priorityMap[String(priority)] || 'info';
+    },
+    /** 表格行样式类 */
+    tableRowClassName({ row, rowIndex }) {
+      // 根据优先级设置行样式
+      if (row.priority === '3' || row.priority === 3) {
+        return 'priority-urgent-row';
+      } else if (row.priority === '2' || row.priority === 2) {
+        return 'priority-high-row';
+      }
+      return '';
+    },
     // 取消按钮
     cancel() {
       this.open = false;
@@ -295,11 +422,15 @@ export default {
     handleQuery() {
       this.queryParams.pageNum = 1;
       this.getList();
+      // 更新执行者列表
+      this.getExecutorList();
     },
     /** 重置按钮操作 */
     resetQuery() {
       this.resetForm("queryForm");
       this.handleQuery();
+      // 重置后更新执行者列表
+      this.getExecutorList();
     },
     // 多选框选中数据
     handleSelectionChange(selection) {
@@ -338,6 +469,16 @@ export default {
       };
       this.statusOpen = true;
     },
+    /** 分配执行者按钮操作 */
+    handleAssignExecutor(row) {
+      this.assignForm = {
+        id: row.id,
+        title: row.title,
+        executorId: row.executorId || null,
+        remark: ''
+      };
+      this.assignOpen = true;
+    },
     /** 提交按钮 */
     submitForm() {
       this.$refs["form"].validate(valid => {
@@ -366,6 +507,28 @@ export default {
         this.getList();
       });
     },
+    /** 提交分配执行者 */
+    submitAssignForm() {
+      this.$refs["assignForm"].validate(valid => {
+        if (valid) {
+          assignExecutor(this.assignForm).then(response => {
+            this.$message.success("执行者分配成功");
+            this.assignOpen = false;
+            this.getList();
+          });
+        }
+      });
+    },
+    /** 取消分配执行者 */
+    cancelAssign() {
+      this.assignOpen = false;
+      this.assignForm = {
+        id: null,
+        title: '',
+        executorId: null,
+        remark: ''
+      };
+    },
     /** 删除按钮操作 */
     handleDelete(row) {
       const ids = row.id || this.ids;
@@ -384,7 +547,122 @@ export default {
 .mb8 {
   margin-bottom: 8px;
 }
+
 .fixed-width {
   width: 100px;
 }
+
+/* 搜索表单样式 */
+.search-form {
+  background: #f8f9fa;
+  padding: 20px;
+  border-radius: 8px;
+  margin-bottom: 20px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+/* 操作按钮行样式 */
+.operation-row {
+  background: #fff;
+  padding: 15px;
+  border-radius: 8px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+  margin-bottom: 20px;
+}
+
+/* 操作按钮样式 */
+.action-btn {
+  margin-right: 8px;
+  border-radius: 6px;
+  font-weight: 500;
+  transition: all 0.3s ease;
+}
+
+.action-btn:hover {
+  transform: translateY(-2px);
+  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
+}
+
+.assign-executor-btn {
+  margin-left: 5px;
+}
+
+.executor-select {
+  width: 100%;
+}
+
+.el-form-item__tip {
+  margin-top: 5px;
+  color: #909399;
+  font-size: 12px;
+}
+
+
+/* 优先级行样式 */
+.priority-urgent-row {
+  background: linear-gradient(135deg, #fff5f5 0%, #ffe8e8 100%);
+}
+
+.priority-urgent-row:hover {
+  background: linear-gradient(135deg, #ffe8e8 0%, #ffd6d6 100%);
+}
+
+.priority-high-row {
+  background: linear-gradient(135deg, #fffbf0 0%, #fff2d9 100%);
+}
+
+.priority-high-row:hover {
+  background: linear-gradient(135deg, #fff2d9 0%, #ffe7ba 100%);
+}
+
+/* 标签样式优化 */
+.el-tag {
+  border-radius: 12px;
+  font-weight: 500;
+  padding: 4px 12px;
+  border: none;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+/* 分页样式 */
+.pagination-wrapper {
+  margin-top: 20px;
+}
+
+.el-pagination {
+  text-align: center;
+  padding: 20px;
+  background: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+/* 对话框样式 */
+.el-dialog {
+  border-radius: 12px;
+  overflow: hidden;
+}
+
+.el-dialog__header {
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  color: white;
+  padding: 20px;
+}
+
+.el-dialog__title {
+  color: white;
+  font-weight: 600;
+}
+
+.el-dialog__body {
+  padding: 30px;
+}
+
+.el-dialog__footer {
+  padding: 20px;
+  border-top: 1px solid #ebeef5;
+  background: #f8f9fa;
+}
+
+
 </style>