hejianhao
2025-04-03 44444c07223ebd9f12922b86c870919a73901666
Merge branch 'main' of http://120.76.84.145:10101/gitblit/r/H5/leshan-laboratory
10个文件已添加
10个文件已修改
3429 ■■■■■ 已修改文件
src/assets/public/notice.png 补丁 | 查看 | 原始文档 | blame | 历史
src/components/SignatureCanvas.vue 216 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.js 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dataManagement/approvalPlan/addPlan.vue 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dataManagement/approvalPlan/list.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dataManagement/confirmation-sheet/components/add.vue 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dataManagement/confirmation-sheet/components/experimental-scheduling.vue 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dataManagement/confirmation-sheet/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dataManagement/dispatching/addDispatch.vue 503 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dataManagement/dispatching/components/AddGroupDialog.vue 206 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dataManagement/dispatching/components/AddTaskDialog.vue 236 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dataManagement/dispatching/list.vue 325 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportLibrary/feasibilityReport/components/approval/index.vue 393 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportLibrary/feasibilityReport/index.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportLibrary/feasibilityStudy/add.vue 173 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportLibrary/feasibilityStudy/components/approval/index.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportLibrary/feasibilityStudy/index.vue 96 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportLibrary/processDevelopment/components/approval/index.vue 393 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportLibrary/projectProposalLibrary/components/approval/index.vue 393 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportLibrary/verificationRelease/components/approval/index.vue 393 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/public/notice.png
src/components/SignatureCanvas.vue
New file
@@ -0,0 +1,216 @@
<template>
  <el-dialog
    title="确认签字"
    :visible.sync="visible"
    :width="dialogWidth"
    :close-on-click-modal="false"
    custom-class="signature-dialog"
    @close="$emit('update:visible', false)"
  >
    <div class="signature-container">
      <div class="signature-content">
        <canvas
          ref="signatureCanvas"
          :width="canvasWidth"
          :height="canvasHeight"
          @mousedown="startDrawing"
          @mousemove="draw"
          @mouseup="stopDrawing"
          @mouseleave="stopDrawing"
          @touchstart="handleTouchStart"
          @touchmove="handleTouchMove"
          @touchend="stopDrawing"
        ></canvas>
      </div>
      <div class="signature-footer">
        <el-button type="default" @click="clearCanvas">重置</el-button>
        <el-button type="primary" @click="confirmSignature">确认</el-button>
      </div>
    </div>
  </el-dialog>
</template>
<script>
export default {
  name: 'SignatureCanvas',
  props: {
    visible: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      isDrawing: false,
      context: null,
      lastX: 0,
      lastY: 0
    }
  },
  computed: {
    dialogWidth() {
      // 获取屏幕宽度的80%
      return window.innerWidth * 0.8 + 'px'
    },
    canvasWidth() {
      // 获取弹窗宽度的90%
      return window.innerWidth * 0.8 * 0.9
    },
    canvasHeight() {
      // 设置画布高度为宽度的1/3
      return this.canvasWidth / 3
    }
  },
  watch: {
    visible(val) {
      if (val) {
        this.$nextTick(() => {
          this.initCanvas()
          // 添加窗口大小改变的监听
          window.addEventListener('resize', this.handleResize)
        })
      } else {
        // 移除监听
        window.removeEventListener('resize', this.handleResize)
      }
    }
  },
  methods: {
    handleResize() {
      // 窗口大小改变时重新初始化画布
      this.$nextTick(() => {
        this.initCanvas()
      })
    },
    initCanvas() {
      const canvas = this.$refs.signatureCanvas
      this.context = canvas.getContext('2d')
      this.context.strokeStyle = 'rgba(4, 156, 154, 1)'
      this.context.lineWidth = 2
      this.context.lineCap = 'round'
      this.context.lineJoin = 'round'
      // 清空画布并绘制虚线边框
      this.clearCanvas()
    },
    drawDashedBorder() {
      const ctx = this.context
      ctx.setLineDash([5, 5])
      ctx.strokeStyle = '#dcdfe6'
      ctx.strokeRect(0, 0, this.canvasWidth, this.canvasHeight)
      ctx.setLineDash([])
      ctx.strokeStyle = 'rgba(4, 156, 154, 1)'
    },
    startDrawing(event) {
      this.isDrawing = true
      const rect = this.$refs.signatureCanvas.getBoundingClientRect()
      this.lastX = event.clientX - rect.left
      this.lastY = event.clientY - rect.top
    },
    draw(event) {
      if (!this.isDrawing) return
      const rect = this.$refs.signatureCanvas.getBoundingClientRect()
      const x = event.clientX - rect.left
      const y = event.clientY - rect.top
      this.context.beginPath()
      this.context.moveTo(this.lastX, this.lastY)
      this.context.lineTo(x, y)
      this.context.stroke()
      this.lastX = x
      this.lastY = y
    },
    handleTouchStart(event) {
      event.preventDefault()
      const touch = event.touches[0]
      const rect = this.$refs.signatureCanvas.getBoundingClientRect()
      this.lastX = touch.clientX - rect.left
      this.lastY = touch.clientY - rect.top
      this.isDrawing = true
    },
    handleTouchMove(event) {
      event.preventDefault()
      if (!this.isDrawing) return
      const touch = event.touches[0]
      const rect = this.$refs.signatureCanvas.getBoundingClientRect()
      const x = touch.clientX - rect.left
      const y = touch.clientY - rect.top
      this.context.beginPath()
      this.context.moveTo(this.lastX, this.lastY)
      this.context.lineTo(x, y)
      this.context.stroke()
      this.lastX = x
      this.lastY = y
    },
    stopDrawing() {
      this.isDrawing = false
    },
    clearCanvas() {
      this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
      this.drawDashedBorder()
    },
    confirmSignature() {
      const canvas = this.$refs.signatureCanvas
      const imageData = canvas.toDataURL('image/png')
      this.$emit('confirm', imageData)
    }
  },
  beforeDestroy() {
    // 组件销毁前移除监听
    window.removeEventListener('resize', this.handleResize)
  }
}
</script>
<style lang="less" scoped>
.signature-dialog {
  :deep(.el-dialog__body) {
    padding: 0;
  }
  :deep(.el-dialog) {
    margin-top: 10vh !important;
  }
}
.signature-container {
  background: #fff;
  border-radius: 4px;
  .signature-content {
    padding: 20px;
    display: flex;
    justify-content: center;
    canvas {
      border-radius: 4px;
      background: rgba(239, 248, 250, 1);
      width: 100%;
      height: 100%;
    }
  }
  .signature-footer {
    padding: 20px;
    border-top: 1px solid #dcdfe6;
    display: flex;
    justify-content: flex-end;
    gap: 12px;
    button{
      width: 150px;
    }
  }
}
</style>
src/router/index.js
@@ -157,6 +157,15 @@
                component: () => import("../views/dataManagement/dispatching/list.vue"),
            },
            {
                path: "addDispatch",
                meta: {
                    title: "新增实验调度",
                    hide: true,
                    keepAlive: true,
                },
                component: () => import("../views/dataManagement/dispatching/addDispatch"),
            },
            {
                path: "confirmation-sheet",
                name: "ConfirmationSheet",
                meta: {
@@ -190,6 +199,15 @@
                component: () => import("../views/reportLibrary/feasibilityStudy/index.vue"),
            },
            {
                path: "add",
                meta: {
                    title: "新增可行报告",
                    hide: true,
                    keepAlive: true,
                },
                component: () => import("../views/reportLibrary/feasibilityStudy/add.vue"),
            },
            {
                path: "feasibilityReport",
                meta: {
                    title: "可行报告库",
src/views/dataManagement/approvalPlan/addPlan.vue
@@ -1,6 +1,6 @@
<template>
  <Card>
    <template style="position: relative;">
    <template style="position: relative">
      <div class="header-title">
        <div class="header-title-left">
          <img src="@/assets/public/headercard.png" />
@@ -76,7 +76,7 @@
      </div>
      <div class="add-project-footer">
        <el-button type="primary" class="save-btn">保存</el-button>
        <el-button >存草稿</el-button>
        <el-button>存草稿</el-button>
      </div>
    </template>
    <SelectMember ref="selectMember" />
@@ -177,9 +177,10 @@
    margin-top: 0;
  }
}
.item-title {
  padding-left: 25px;
  span {
    flex-shrink: 0;
    font-weight: bold;
@@ -196,6 +197,11 @@
    }
  }
}
.header-title:first-child {
  .header-title-left {
    margin-top: 0;
  }
}
.add-project-footer {
  margin-top: 43px;
src/views/dataManagement/approvalPlan/list.vue
@@ -46,7 +46,7 @@
            >草稿箱</div>
          </div>
          <el-button @click="handleAddPlan" class="el-icon-plus" type="primary">
            新增实验调度</el-button
            新增项目课题方案</el-button
          >
        </div>
      </template>
src/views/dataManagement/confirmation-sheet/components/add.vue
@@ -21,7 +21,7 @@
    <div class="header-title-left" style="margin-top: 60px;">
      <img src="@/assets/public/headercard.png" />
      <div>检测明细</div>
      <el-button @click="handleAddPlan" type="primary" class="el-icon-plus">
      <el-button  type="primary" class="el-icon-plus">
        新增检测项</el-button>
      <span>【注意:这里有多少个检测项 系统就会自动创建对应数量的《检测项的检验方法及数据记录》】</span>
    </div>
@@ -78,20 +78,7 @@
  },
  watch: {},
  created() {
    roleInfoFromUserId({ userId: 1 }).then(res => {
      if (this.$route.query.roleId) {
        getRoleInfo({ roleId: this.$route.query.roleId }).then(resp => {
          this.menu = this.setSelectedIds(res.data.data, resp.data.data.menus || []);
          this.form = {
            roleName: resp.data.data.roleName,
            remark: resp.data.data.remark,
            roleId: resp.data.data.roleId
          }
        })
      } else {
        this.menu = res.data.data
      }
    })
  },
  mounted() { },
  methods: {
src/views/dataManagement/confirmation-sheet/components/experimental-scheduling.vue
@@ -24,7 +24,7 @@
                                <el-option label="已确认" value="已确认"></el-option>
                            </el-select>
                        </el-form-item>
                        <el-form-item label="">
                        <el-form-item label="" class="search-btn-box">
                            <el-button type="default" @click="resetForm">重置</el-button>
                            <el-button type="primary" @click="handleSearch">查询</el-button>
                        </el-form-item>
@@ -35,17 +35,11 @@
                    <el-table-column prop="planCode" label="所属项目课题方案"></el-table-column>
                    <el-table-column prop="planName" label="实验编号"></el-table-column>
                    <el-table-column prop="planName" label="实验名称"></el-table-column>
                    <el-table-column prop="stage" label="提交时间"></el-table-column>
                    <el-table-column prop="stage" label="通知时间"></el-table-column>
                    <el-table-column prop="stage" label="实验开始时间"></el-table-column>
                    <el-table-column prop="stage" label="试验结束时间"></el-table-column>
                    <el-table-column prop="stage" label="参加人员"></el-table-column>
                    <el-table-column prop="creator" label="状态"></el-table-column>
                    <el-table-column label="操作" width="150">
                        <!-- 撤销、详情、编辑、删除 -->
                        <template slot-scope="scope">
                            <el-button type="text" @click="handleDetail(scope.row)">撤销</el-button>
                            <el-button type="text" @click="handleDetail(scope.row)">详情</el-button>
                            <el-button type="text" @click="handleDetail(scope.row)">编辑</el-button>
                            <el-button type="text" @click="handleDetail(scope.row)">删除</el-button>
                        </template>
                    </el-table-column>
                </template>
            </TableCustom>
            <span slot="footer" class="dialog-footer">
@@ -63,10 +57,25 @@
        return {
            form: {},
            tableData: [],
            totol: 0
            total: 0
        }
    },
    methods: {
        resetForm() {
        },
        handleSearch() {
        }
    }
}
</script>
<style></style>
<style lang="less" scoped>
.dialog-footer {
    display: flex
;
    justify-content: center;
    gap: 10px;
}
</style>
src/views/dataManagement/confirmation-sheet/index.vue
@@ -22,7 +22,7 @@
                            <el-option label="已确认" value="已确认"></el-option>
                        </el-select>
                    </el-form-item>
                    <el-form-item label="">
                    <el-form-item label="" class="search-btn-box">
                        <el-button type="default" @click="resetForm">重置</el-button>
                        <el-button type="primary" @click="handleSearch">查询</el-button>
                    </el-form-item>
src/views/dataManagement/dispatching/addDispatch.vue
New file
@@ -0,0 +1,503 @@
<template>
  <Card>
    <template style="position: relative">
      <el-form
        ref="form"
        :model="form"
        :rules="rules"
        inline
        label-position="top"
      >
        <div class="header-title" style="margin-bottom: 38px">
          <div class="header-title-left">
            <img src="@/assets/public/headercard.png" />
            <span>一、项目课题方案信息</span>
          </div>
        </div>
        <div style="padding-left: 25px">
          <el-form-item prop="name" label="项目课题方案名称">
            <el-input v-model="form.name" placeholder="请输入" />
          </el-form-item>
          <el-form-item prop="description" label="项目课题方案编号">
            <el-input v-model="form.description" placeholder="请输入" />
          </el-form-item>
          <el-form-item prop="description" label="项目阶段">
            <el-input v-model="form.description" placeholder="请输入" />
          </el-form-item>
        </div>
        <div class="header-title" style="margin-bottom: 38px">
          <div class="header-title-left">
            <img src="@/assets/public/headercard.png" />
            <span>二 、实验信息</span>
          </div>
        </div>
        <div style="padding-left: 25px">
          <el-form-item prop="name" label="试验日期">
            <el-input v-model="form.name" placeholder="请输入" />
          </el-form-item>
          <el-form-item prop="description" label="实验名称">
            <el-input v-model="form.description" placeholder="请输入" />
          </el-form-item>
          <el-form-item prop="description" label="实验编号">
            <el-input v-model="form.description" placeholder="请输入" />
          </el-form-item>
        </div>
        <div class="add-group">
          <span>实验分组</span>
          <el-button type="primary" class="el-icon-plus" @click="handleAddGroup">添加组别</el-button>
        </div>
        <Table
          :data="groupTableData"
          :total="0"
          :height="null"
          class="groupTable"
        >
          <el-table-column type="index" label="序号" width="80"></el-table-column>
          <el-table-column prop="groupName" label="组别"></el-table-column>
          <el-table-column prop="remark" label="备注"></el-table-column>
          <el-table-column label="操作" width="200">
            <template slot-scope="scope">
              <el-button type="text" @click="handleEditGroup(scope.row)">编辑</el-button>
              <el-button type="text" @click="handleDeleteGroup(scope.row)">移除</el-button>
            </template>
          </el-table-column>
        </Table>
        <div class="header-title" style="margin-bottom: 38px">
          <div class="header-title-left">
            <img src="@/assets/public/headercard.png" />
            <span>三 、计划时间及人员</span>
          </div>
        </div>
        <div style="padding-left: 25px">
          <el-form-item prop="name" label="试验时间">
            <el-input v-model="form.name" placeholder="请输入" />
          </el-form-item>
        </div>
        <div class="add-group">
          <div>*</div>
          <span>参加人员</span>
          <el-button type="primary" class="el-icon-plus" @click="addMember">选择参加人员</el-button>
        </div>
        <div class="member-list">
          <div v-for="item in 3" :key="item" class="member-list-card">
            <div class="member-item">
              <div class="member-title">
                {{ ["工艺工程师", "实验员", "化验师"][item - 1] }}
              </div>
              <div
                :class="item == 1 || item == 2 ? 'member-name-box' : 'flex1'"
              >
                <div
                  :class="
                    item == 1 || item == 2
                      ? 'member-name-box'
                      : 'member-name-box-2'
                  "
                >
                  <div
                    v-for="i in memberList(item)"
                    :key="i"
                    class="member-name"
                  >
                    张三
                  </div>
                </div>
              </div>
              <div class="member-change">
                <div class="member-change-btn">修改</div>
              </div>
            </div>
          </div>
        </div>
        <div class="header-title" style="margin-bottom: 38px">
          <div class="header-title-left">
            <img src="@/assets/public/headercard.png" />
            <span>四 、任务分解</span>
          </div>
          <el-button type="primary" class="el-icon-plus" @click="handleAddTask">新增任务</el-button>
        </div>
        <Table
          :data="taskTableData"
          :total="0"
          :height="null"
          class="rwuTable"
        >
          <el-table-column type="index" label="序号" width="80"></el-table-column>
          <el-table-column prop="taskName" label="任务名称"></el-table-column>
          <el-table-column prop="leader" label="负责人"></el-table-column>
          <el-table-column prop="startTime" label="开始时间"></el-table-column>
          <el-table-column label="操作" width="200">
            <template slot-scope="scope">
              <el-button type="text" @click="handleEditTask(scope.row)">编辑</el-button>
              <el-button type="text" @click="handleDeleteTask(scope.row)">移除</el-button>
            </template>
          </el-table-column>
        </Table>
        <div class="header-title">
          <div class="header-title-left">
            <img src="@/assets/public/headercard.png" />
            <span>五 、关键节点</span>
          </div>
        </div>
        <div class="add-project-footer">
          <el-button type="primary" class="save-btn">发送</el-button>
          <el-button>存草稿</el-button>
        </div>
      </el-form>
    </template>
    <SelectMember ref="selectMember" />
    <AddGroupDialog ref="addGroupDialog" @submit="handleGroupSubmit" />
    <AddTaskDialog ref="addTaskDialog" @submit="handleTaskSubmit" />
  </Card>
</template>
<script>
import SelectMember from '@/components/SelectMember'
import AddGroupDialog from './components/AddGroupDialog'
import AddTaskDialog from './components/AddTaskDialog'
export default {
  name: "AddProject",
  components: {
    SelectMember,
    AddGroupDialog,
    AddTaskDialog
  },
  data() {
    return {
      form: {},
      rules: {
        name: [
          { required: true, message: "请输入项目组名称", trigger: "blur" },
        ],
        description: [
          { required: true, message: "请输入项目组描述", trigger: "blur" },
        ],
      },
      groupTableData: [],
      taskTableData: []
    };
  },
  methods: {
    submitForm() {
      this.$refs.form.validate((valid) => {
        if (valid) {
          console.log("submit!");
        }
      });
    },
    addMember() {
      this.$refs.selectMember.open();
    },
    memberList(i) {
      switch (i) {
        case 1:
          return [1];
        case 2:
          return [1];
        case 3:
          return [1, 2, 3, 4, 5, 6, 7, 8];
        case 4:
          return [1, 2, 3, 4, 5, 6, 7, 8];
        default:
          break;
      }
    },
    handleAddGroup() {
      this.$refs.addGroupDialog.open()
    },
    handleEditGroup(row) {
      this.$refs.addGroupDialog.open(row)
    },
    handleDeleteGroup(row) {
      this.$confirm('确认删除该组别吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        const index = this.groupTableData.findIndex(item => item === row)
        if (index > -1) {
          this.groupTableData.splice(index, 1)
          this.$message.success('删除成功')
        }
      }).catch(() => {})
    },
    handleGroupSubmit(form) {
      const index = this.groupTableData.findIndex(item => item.groupName === form.groupName)
      if (index > -1) {
        this.groupTableData.splice(index, 1, form)
      } else {
        this.groupTableData.push(form)
      }
    },
    handleAddTask() {
      this.$refs.addTaskDialog.open()
    },
    handleEditTask(row) {
      this.$refs.addTaskDialog.open(row)
    },
    handleDeleteTask(row) {
      this.$confirm('确认删除该任务吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        const index = this.taskTableData.findIndex(item => item === row)
        if (index > -1) {
          this.taskTableData.splice(index, 1)
          this.$message.success('删除成功')
        }
      }).catch(() => {})
    },
    handleTaskSubmit(form) {
      const index = this.taskTableData.findIndex(item => item.taskName === form.taskName)
      if (index > -1) {
        this.taskTableData.splice(index, 1, form)
      } else {
        this.taskTableData.push(form)
      }
    }
  },
};
</script>
<style scoped lang="less">
.el-form--inline .el-form-item {
  margin-right: 83px;
}
.header-title {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 13px;
  margin-top: 38px;
  justify-content: space-between;
  .header-title-left {
    display: flex;
    align-items: center;
    gap: 13px;
    img {
      width: 12px;
      height: 19px;
    }
    div {
      flex-shrink: 0;
      font-weight: bold;
      font-size: 18px;
      color: #222222;
      line-height: 27px;
      font-family: "Source Han Sans CN Bold Bold";
      &:before {
        content: "*";
        color: #f56c6c;
        margin-right: 4px;
      }
    }
    span {
      flex-shrink: 0;
      font-weight: bold;
      font-size: 18px;
      color: #222222;
      line-height: 27px;
      font-family: "Source Han Sans CN Bold Bold";
    }
  }
  .header-title-left :first-child {
    margin-top: 0;
  }
}
.item-title {
  padding-left: 25px;
  span {
    flex-shrink: 0;
    font-weight: bold;
    font-size: 14px;
    color: #222222;
    line-height: 27px;
    font-family: "Source Han Sans CN Bold Bold";
    margin: 18px 0;
    &:before {
      content: "*";
      color: #f56c6c;
      margin-right: 4px;
    }
  }
}
.header-title:first-child {
  .header-title-left {
    margin-top: 0;
  }
}
.add-group {
  padding-left: 25px;
  margin-top: 14px;
  display: flex;
  align-items: center;
  margin-bottom: 19px;
  div {
    color: #f56c6c;
  }
  span {
    font-weight: 500;
    font-size: 14px;
    color: #222222;
    line-height: 21px;
    margin: 0 32px 0 8px;
  }
}
.groupTable {
  width: 65%;
  padding-left: 40px;
}
.rwuTable {
  width: 85%;
  padding-left: 40px;
}
.member-list {
  margin-top: 18px;
  display: flex;
  flex-wrap: wrap;
  gap: 28px;
  margin-left: 38px;
  .member-list-card {
    width: 340px;
    height: 400px;
    border-radius: 8px;
    border: 1px solid #dcdfe6;
    &:nth-child(1) {
      background: linear-gradient(
        to bottom,
        rgba(4, 156, 154, 0.2) 0%,
        rgba(5, 242, 194, 0) 70%
      );
    }
    &:nth-child(2) {
      background: linear-gradient(
        to bottom,
        rgba(5, 160, 193, 0.2) 0%,
        rgba(5, 242, 194, 0) 70%
      );
    }
    &:nth-child(3) {
      background: linear-gradient(
        to bottom,
        rgba(255, 77, 79, 0.2) 0%,
        rgba(255, 242, 194, 0) 70%
      );
    }
    &:nth-child(4) {
      background: linear-gradient(
        to bottom,
        rgba(250, 199, 20, 0.21) 0%,
        rgba(255, 242, 194, 0) 70%
      );
    }
    .member-item {
      height: 100%;
      display: flex;
      flex-direction: column;
      .member-title {
        margin-top: 20px;
        width: 100%;
        font-family: "Source Han Sans CN Bold Bold";
        font-weight: bold;
        font-size: 16px;
        color: rgba(0, 0, 0, 0.8);
        line-height: 16px;
        text-align: center;
      }
      .flex1 {
        flex: 1;
      }
      .member-name-box {
        flex: 1;
        display: flex;
        align-items: center;
        justify-content: center;
      }
      .member-name-box-2 {
        flex: 1;
        padding: 0 20px;
        padding-top: 40px;
        display: grid;
        grid-template-columns: repeat(4, 1fr);
        gap: 20px;
        justify-items: center;
        align-items: start;
      }
      .member-name {
        width: 60px;
        height: 60px;
        background: #7d8b79;
        border-radius: 50%;
        text-align: center;
        line-height: 60px;
        font-weight: 500;
        font-size: 16px;
        color: #ffffff;
        margin: 0;
      }
      .member-change {
        display: flex;
        justify-content: center;
        padding: 10px 0;
        margin-top: auto;
        cursor: pointer;
        .member-change-btn {
          background: #fff1f0;
          border-radius: 4px;
          border: 1px solid #ffccc7;
          padding: 1px 8px;
          font-weight: 400;
          font-size: 12px;
          color: #ff4d4f;
        }
      }
    }
  }
}
.add-project-footer {
  margin-top: 43px;
  button {
    width: 220px;
  }
  .save-btn {
    margin-right: 20px;
  }
}
</style>
src/views/dataManagement/dispatching/components/AddGroupDialog.vue
New file
@@ -0,0 +1,206 @@
<template>
  <el-dialog
    :title="title"
    :visible.sync="dialogVisible"
    width="70%"
    :before-close="handleClose"
    custom-class="add-group-dialog"
  >
    <el-form
      ref="form"
      :model="form"
      :rules="rules"
      label-width="80px"
      label-position="top"
    >
      <el-form-item label="组别名称" prop="groupName">
        <el-input
          v-model="form.groupName"
          placeholder="请输入"
          class="custom-input"
        ></el-input>
      </el-form-item>
      <el-form-item label="备注" prop="remark">
        <el-input
          type="textarea"
          v-model="form.remark"
          placeholder="请输入"
          :rows="4"
          class="custom-textarea"
        ></el-input>
      </el-form-item>
    </el-form>
    <div slot="footer" class="dialog-footer">
      <el-button @click="handleClose" class="cancel-btn">取消</el-button>
      <el-button type="primary" @click="handleSubmit" class="submit-btn"
        >保存</el-button
      >
    </div>
  </el-dialog>
</template>
<script>
export default {
  name: "AddGroupDialog",
  data() {
    return {
      dialogVisible: false,
      title: "添加组别",
      form: {
        groupName: "",
        remark: "",
        id: null
      },
      rules: {
        groupName: [
          { required: true, message: "请输入组别名称", trigger: "blur" },
        ],
      },
      isEdit: false,
    };
  },
  computed: {
    dialogWidth() {
      return window.innerWidth < 768 ? "90%" : "500px";
    },
    labelPosition() {
      return window.innerWidth < 768 ? "top" : "right";
    },
  },
  methods: {
    open(row) {
      this.dialogVisible = true;
      this.isEdit = !!row;
      if (row) {
        this.title = "编辑组别";
        this.form = JSON.parse(JSON.stringify({
          groupName: row.groupName || '',
          remark: row.remark || '',
          id: row.id
        }));
      } else {
        this.title = "添加组别";
        this.resetForm();
      }
    },
    handleClose() {
      this.dialogVisible = false;
      this.resetForm();
    },
    resetForm() {
      this.form = {
        groupName: "",
        remark: "",
        id: null
      };
      this.$nextTick(() => {
        this.$refs.form && this.$refs.form.resetFields();
      });
    },
    handleSubmit() {
      this.$refs.form.validate((valid) => {
        if (valid) {
          const eventName = this.isEdit ? "update" : "submit";
          this.$emit(eventName, {...this.form});
          this.handleClose();
        }
      });
    },
  },
};
</script>
<style lang="less" scoped>
.add-group-dialog {
  ::v-deep .el-dialog__header {
    padding: 20px;
    border-bottom: 1px solid #eee;
    .el-dialog__title {
      font-size: 16px;
      font-weight: 500;
      color: #333;
    }
    .el-dialog__headerbtn {
      top: 20px;
    }
  }
  .el-form {
    padding-left: 54px;
    padding-right: 54px;
    .el-form-item {
      margin-bottom: 20px;
      ::v-deep .el-form-item__label {
        font-size: 14px;
        color: #333;
      }
      .custom-input,
      .custom-textarea {
        ::v-deep .el-input__inner,
        ::v-deep .el-textarea__inner {
          border-radius: 4px;
          border-color: #dcdfe6;
          &:focus {
            border-color: #409eff;
          }
          &::placeholder {
            color: #999;
          }
        }
      }
    }
  }
  .dialog-footer {
    padding: 20px;
    border-top: 1px solid #eee;
    .cancel-btn {
      margin-right: 12px;
    }
    .submit-btn {
      min-width: 80px;
    }
  }
}
::v-deep .el-dialog__body {
  padding: 15px 24px 0px 14px !important;
}
::v-deep .el-dialog__footer {
  text-align: center !important;
  button {
    width: 150px;
  }
}
@media screen and (max-width: 768px) {
  .add-group-dialog {
    ::v-deep .el-dialog__body {
      padding: 20px 15px;
    }
    .el-form {
      .el-form-item {
        margin-bottom: 15px;
      }
    }
    .dialog-footer {
      padding: 15px;
      .el-button {
        width: 100%;
        margin: 5px 0;
      }
    }
  }
}
</style>
src/views/dataManagement/dispatching/components/AddTaskDialog.vue
New file
@@ -0,0 +1,236 @@
<template>
  <el-dialog :title="title" :visible.sync="dialogVisible" width="70%" :before-close="handleClose">
    <div class="task-form">
      <el-form ref="form" :model="form" :rules="rules" label-width="80px" label-position="top">
        <el-form-item label="任务名称" prop="taskName">
          <el-input v-model="form.taskName" placeholder="请输入任务名称" class="custom-input"></el-input>
        </el-form-item>
        <el-form-item label="负责人" prop="leader">
          <Table
            ref="table"
            :data="tableData"
            :total="0"
            class="rwuTable"
            @selection-change="handleSelectionChange">
            <el-table-column type="selection" width="55"></el-table-column>
            <el-table-column prop="role" label="角色" width="120">
              <template slot-scope="scope">
                <span>{{ scope.row.role || '实验师' }}</span>
              </template>
            </el-table-column>
            <el-table-column prop="name" label="姓名"></el-table-column>
            <el-table-column prop="avatar" label="头像" width="80">
              <template slot-scope="scope">
                <el-avatar :size="30" :src="scope.row.avatar">{{ scope.row.name.substr(0,1) }}</el-avatar>
              </template>
            </el-table-column>
            <el-table-column prop="createTime" label="创建时间"></el-table-column>
          </Table>
        </el-form-item>
        <el-form-item label="开始时间" prop="startTime">
          <el-date-picker
            v-model="form.startTime"
            type="datetime"
            placeholder="选择开始时间"
            value-format="yyyy-MM-dd HH:mm:ss"
            :picker-options="pickerOptions"
            :default-time="defaultTime">
          </el-date-picker>
        </el-form-item>
      </el-form>
    </div>
    <div slot="footer" class="dialog-footer">
      <el-button @click="handleClose">关闭</el-button>
      <el-button type="primary" @click="handleSubmit">保存</el-button>
    </div>
  </el-dialog>
</template>
<script>
export default {
  name: "AddTaskDialog",
  data() {
    return {
      dialogVisible: false,
      title: "新增任务",
      form: {
        taskName: "",
        startTime: "",
        selectedUsers: [], // 存储选中用户的id数组
        leader: "" // 存储选中用户的姓名字符串
      },
      rules: {
        taskName: [
          { required: true, message: "请输入任务名称", trigger: "blur" }
        ],
        startTime: [
          { required: true, message: "请选择开始时间", trigger: "change" }
        ]
      },
      tableData: [],
      pickerOptions: {
        shortcuts: [
          {
            text: '今天',
            onClick(picker) {
              picker.$emit('pick', new Date());
            }
          },
          {
            text: '明天',
            onClick(picker) {
              const date = new Date();
              date.setTime(date.getTime() + 3600 * 1000 * 24);
              picker.$emit('pick', date);
            }
          },
          {
            text: '一周后',
            onClick(picker) {
              const date = new Date();
              date.setTime(date.getTime() + 3600 * 1000 * 24 * 7);
              picker.$emit('pick', date);
            }
          }
        ],
        disabledDate(time) {
          return time.getTime() < Date.now() - 8.64e7;
        }
      },
      defaultTime: '09:00:00'
    };
  },
  methods: {
    open(row) {
      this.dialogVisible = true;
      this.getAvailableUsers();
      if (row) {
        this.title = "编辑任务";
        this.form = {
          taskName: row.taskName || '',
          startTime: row.startTime || '',
          selectedUsers: row.selectedUsers || [],
          leader: row.leader || ''
        };
        // 在表格数据加载完成后设置选中状态
        this.$nextTick(() => {
          if (this.$refs.table && this.form.selectedUsers.length) {
            this.tableData.forEach(row => {
              if (this.form.selectedUsers.includes(row.id)) {
                this.$refs.table.toggleRowSelection(row, true);
              }
            });
          }
        });
      } else {
        this.title = "新增任务";
        this.form = {
          taskName: "",
          startTime: "",
          selectedUsers: [],
          leader: ""
        };
      }
    },
    handleClose() {
      this.dialogVisible = false;
      this.$refs.form.resetFields();
      if (this.$refs.table) {
        this.$refs.table.clearSelection();
      }
      this.form = {
        taskName: "",
        startTime: "",
        selectedUsers: [],
        leader: ""
      };
    },
    handleSelectionChange(selection) {
      // 更新选中的用户数据
      this.form.selectedUsers = selection.map(item => item.id);
      this.form.leader = selection.map(item => item.name).join("、");
    },
    handleSubmit() {
      this.$refs.form.validate(valid => {
        if (valid) {
          if (this.form.selectedUsers.length === 0) {
            this.$message.error("请选择至少一个负责人");
            return;
          }
          const submitData = {
            taskName: this.form.taskName,
            startTime: this.form.startTime,
            selectedUsers: this.form.selectedUsers,
            leader: this.form.leader
          };
          this.$emit("submit", submitData);
          this.handleClose();
        }
      });
    },
    getAvailableUsers() {
      // 这里可以调用接口获取人员列表
      this.tableData = [
        {
          id: 1,
          role: "实验师",
          name: "曾奇胜",
          avatar: "",
          createTime: "2024-09-18 00:00:00"
        },
        {
          id: 2,
          role: "实验师",
          name: "李四",
          avatar: "",
          createTime: "2024-09-18 00:00:00"
        },
        {
          id: 3,
          role: "实验师",
          name: "王五",
          avatar: "",
          createTime: "2024-09-18 00:00:00"
        }
      ];
    }
  }
};
</script>
<style lang="less" scoped>
.task-form {
  padding: 0 20px;
  .custom-input {
    width: 100%;
  }
}
.rwuTable {
  margin: 10px 0;
  width: 100%;
}
::v-deep .el-dialog__body {
  padding: 15px 24px 0px 14px !important;
}
.dialog-footer {
  margin-top: 20px;
  text-align: center !important;
  button {
    width: 150px;
  }
}
::v-deep .el-date-editor {
  width: 100%;
}
</style>
src/views/dataManagement/dispatching/list.vue
@@ -1,17 +1,316 @@
<template>
    <div>这是列表</div>
  </template>
  <script>
  export default {
    name: 'dispatchList',
    data() {
      return {
  <div class="list">
    <TableCustom :queryForm="form" :tableData="tableData" :total="total">
      <template #search>
        <el-form :model="form" labelWidth="auto" inline>
          <el-form-item label="所属项目课题方案:">
            <el-input v-model="form.planName" placeholder="请输入"></el-input>
          </el-form-item>
          <el-form-item label="实验编号">
            <el-input
              v-model="form.experimentCode"
              placeholder="请输入"
            ></el-input>
          </el-form-item>
          <el-form-item label="通知时间">
            <el-date-picker
              v-model="form.createTime"
              type="daterange"
              range-separator="至"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              value-format="yyyy-MM-dd"
            ></el-date-picker>
          </el-form-item>
          <el-form-item label="状态">
            <el-select v-model="form.status" placeholder="请选择">
              <el-option label="全部" value=""></el-option>
              <el-option label="待确认" value="pending"></el-option>
              <el-option label="已确认" value="confirmed"></el-option>
              <el-option label="已取消" value="cancelled"></el-option>
            </el-select>
          </el-form-item>
          <el-form-item label="">
            <el-button type="default" @click="resetForm">重置</el-button>
            <el-button type="primary" @click="handleSearch">查询</el-button>
          </el-form-item>
        </el-form>
      </template>
      <template #setting>
        <div class="tableTitle">
          <div class="flex a-center">
            <div
              class="title"
              :class="{ active: currentType === 'list' }"
              @click="handleTypeChange('list')"
            >
              实验调度列表
            </div>
            <div
              class="drafts"
              :class="{ active: currentType === 'draft' }"
              @click="handleTypeChange('draft')"
            >
              草稿箱
            </div>
          </div>
          <el-button @click="handleAddPlan" class="el-icon-plus" type="primary">
            新增实验调度</el-button
          >
        </div>
      </template>
      <template #table>
        <el-table-column
          prop="experimentCode"
          label="所属项目课题方案"
        ></el-table-column>
        <el-table-column
          prop="experimentName"
          label="实验编号"
        ></el-table-column>
        <el-table-column prop="startTime" label="实验名称"></el-table-column>
        <el-table-column prop="endTime" label="通知时间"></el-table-column>
        <el-table-column
          prop="participants"
          label="实验开始时间"
        ></el-table-column>
        <el-table-column
          prop="createTime"
          label="实验结束时间"
        ></el-table-column>
        <el-table-column prop="people" label="参加人员"></el-table-column>
        <el-table-column prop="status" label="状态">
          <template slot-scope="scope">
            <el-tag :type="getStatusType(scope.row.status)">
              {{ getStatusText(scope.row.status) }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="200">
          <template slot-scope="scope">
            <el-button
              v-if="scope.row.status === 'pending'"
              type="text"
              @click="handleConfirm(scope.row)"
              >确认</el-button
            >
            <el-button type="text" @click="handleDelete(scope.row)"
              >删除</el-button
            >
            <el-button type="text" @click="handleDetail(scope.row)"
              >详情</el-button
            >
          </template>
        </el-table-column>
      </template>
    </TableCustom>
    <SignatureCanvas
      :visible="signatureDialogVisible"
      @confirm="handleSignatureConfirm"
    />
  </div>
</template>
<script>
import SignatureCanvas from "@/components/SignatureCanvas.vue";
export default {
  name: "dispatchingList",
  components: {
    SignatureCanvas,
  },
  data() {
    return {
      currentType: "list", // 当前显示类型:list-列表,draft-草稿箱
      form: {
        experimentName: "",
        experimentCode: "",
        createTime: [],
        status: "",
      },
      tableData: [],
      total: 0,
      // 模拟数据
      mockListData: [
        {
          experimentCode: "EXP-2024-001",
          experimentName: "材料力学性能测试实验",
          startTime: "2024-03-20 09:00",
          endTime: "2024-03-20 17:00",
          participants: "张三、李四、王五",
          createTime: "2024-03-15",
          status: "pending",
        },
        {
          experimentCode: "EXP-2024-002",
          experimentName: "化学合成实验",
          startTime: "2024-03-21 10:00",
          endTime: "2024-03-21 16:00",
          participants: "赵六、钱七、孙八",
          createTime: "2024-03-16",
          status: "confirmed",
        },
        {
          experimentCode: "EXP-2024-003",
          experimentName: "生物培养实验",
          startTime: "2024-03-22 08:00",
          endTime: "2024-03-22 18:00",
          participants: "周九、吴十、郑十一",
          createTime: "2024-03-17",
          status: "cancelled",
        },
      ],
      mockDraftData: [
        {
          experimentCode: "EXP-2024-004",
          experimentName: "物理光学实验(草稿)",
          startTime: "2024-03-23 09:00",
          endTime: "2024-03-23 17:00",
          participants: "王十二、李十三",
          createTime: "2024-03-18",
          status: "draft",
        },
      ],
      signatureDialogVisible: false,
      currentRow: null,
    };
  },
  created() {
    this.getTableData();
  },
  methods: {
    resetForm() {
      this.form = {
        experimentName: "",
        experimentCode: "",
        createTime: [],
        status: "",
      };
    },
    handleSearch() {
      // 实现查询逻辑
      console.log("查询条件:", this.form);
    },
    getStatusType(status) {
      const statusMap = {
        pending: "warning",
        confirmed: "success",
        cancelled: "danger",
        draft: "info",
      };
      return statusMap[status] || "info";
    },
    getStatusText(status) {
      const statusMap = {
        pending: "待确认",
        confirmed: "已确认",
        cancelled: "已取消",
        draft: "草稿",
      };
      return statusMap[status] || "未知";
    },
    handleAddPlan() {
      this.$router.push({
        path: "/dataManagement/addDispatch",
      });
    },
    handleConfirm(row) {
      this.currentRow = row;
      this.signatureDialogVisible = true;
    },
    handleSignatureConfirm(imageData) {
      console.log("imageData imageData", imageData);
      this.signatureDialogVisible = false;
      // 这里处理签名确认后的逻辑
      // this.$confirm('确认该实验调度吗?', '提示', {
      //   confirmButtonText: '确定',
      //   cancelButtonText: '取消',
      //   type: 'warning'
      // }).then(() => {
      //   // 这里可以将签名图片数据(imageData)连同其他数据一起提交到后端
      //   this.$message.success('确认成功');
      //   this.signatureDialogVisible = false;
      //   this.getTableData();
      // }).catch(() => {
      //   this.signatureDialogVisible = false;
      // });
    },
    handleDelete(row) {
      this.$confirm("确定要删除该实验调度吗?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          this.$message.success("删除成功");
          this.getTableData();
        })
        .catch(() => {});
    },
    handleDetail(row) {
      this.currentApprovalData = row;
      this.approvalDialogType = "view";
      this.approvalDialogVisible = true;
    },
    handleTypeChange(type) {
      this.currentType = type;
      this.getTableData();
    },
    getTableData() {
      // 根据currentType请求不同的数据
      if (this.currentType === "list") {
        this.tableData = this.mockListData;
        this.total = this.mockListData.length;
      } else {
        this.tableData = this.mockDraftData;
        this.total = this.mockDraftData.length;
      }
    },
    created() {
    }
  },
};
</script>
<style scoped lang="less">
.list {
  height: 100%;
}
.flex {
  display: flex;
  align-items: center;
}
.tableTitle {
  display: flex;
  padding-bottom: 20px;
  justify-content: space-between;
  align-items: center;
  .title {
    background: #fafafc;
    border-radius: 8px 8px 0px 0px;
    border: 1px solid #dcdfe6;
    padding: 16px 29px;
    font-weight: bold;
    font-size: 18px;
    color: #606266;
    width: unset;
    cursor: pointer;
  }
  </script>
  <style scoped></style>
  .drafts {
    padding: 16px 65px;
    background: #fafafc;
    border-radius: 8px 8px 0px 0px;
    border: 1px solid #dcdfe6;
    font-weight: 400;
    font-size: 18px;
    color: #606266;
    margin-left: 16px;
    cursor: pointer;
  }
  .active {
    color: #049c9a;
    background: #ffffff;
    border-radius: 8px 8px 0px 0px;
    border: 1px solid #049c9a;
  }
}
</style>
src/views/reportLibrary/feasibilityReport/components/approval/index.vue
New file
@@ -0,0 +1,393 @@
<template>
    <el-dialog :title="dialogTitle"  :visible.sync="visible" width="80%" po :close-on-click-modal="false"
        @close="handleClose">
        <div class="approval-dialog">
            <!-- 左侧审批内容 -->
            <div class="approval-content">
                <Card class="approval-content-card">
                    <template style="position: relative">
                        <div class="header-title" style="width: 100%;">
                            <div class="header-title-left">
                                <img src="@/assets/public/headercard.png" />
                                <div>所属项目组</div>
                            </div>
                        </div>
                        <Table :height="null" :queryForm="queryForm" :total="0" @currentChange="handleCurrentChange"
                            @sizeChange="handleSizeChange">
                            <template>
                                <el-table-column prop="name" label="项目组名称" />
                                <el-table-column prop="age" label="项目负责人" />
                                <el-table-column prop="age" label="项目组成员" />
                                <el-table-column prop="age" label="创建时间" />
                            </template>
                        </Table>
                        <el-form ref="form" :model="form" :rules="rules" inline label-position="top"
                            style="margin-top: 38px">
                            <div class="header-title" style="width: 100%;">
                                <div class="header-title-left">
                                    <img src="@/assets/public/headercard.png" />
                                    <div>报告编号</div>
                                </div>
                            </div>
                            <form-item prop="name" style="margin-top: 38px">
                                <el-input v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" />
                            </form-item>
                            <div class="header-title" style="width: 100%;">
                                <div class="header-title-left">
                                    <img src="@/assets/public/headercard.png" />
                                    <div>报告名称</div>
                                </div>
                            </div>
                            <form-item prop="name" style="margin-top: 38px">
                                <el-input v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" />
                            </form-item>
                            <div class="header-title" style="width: 100%;">
                                <div class="header-title-left">
                                    <img src="@/assets/public/headercard.png" />
                                    <div>报告正文</div>
                                </div>
                            </div>
                            <form-item prop="name" style="margin-top: 38px">
                                <ai-editor v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" />
                            </form-item>
                        </el-form>
                    </template>
                    <!-- <SelectMember ref="selectMember" /> -->
                </Card>
            </div>
            <!-- 右侧审批流程 -->
            <div class="approval-flow">
                <div class="flow-content">
                    <approval-process :status="form.status" :submit-time="form.createTime" :approver="form.approver"
                        :approve-time="form.approveTime" />
                </div>
            </div>
        </div>
        <div class="approval-dialog-approve">
            <el-row :span="24">
                <el-col :span="12">
                    <div class="status">
                        <div class="status-title">审批结果</div>
                        <div class="status-content">
                            <div class="resolve" :class="status == '1' && 'activeStatus'" @click.stop="status = 1">
                                通过
                            </div>
                            <div class="reject" :class="status == '2' && 'activeStatus'" @click.stop="status = 2">
                                驳回
                            </div>
                        </div>
                    </div>
                </el-col>
                <el-col :span="12">
                    <div class="remark">
                        <div class="remark-title">审批意见</div>
                        <el-input type="textarea" v-model="remark" placeholder="请输入审批意见" />
                    </div>
                </el-col>
            </el-row>
        </div>
        <div slot="footer" class="dialog-footer">
            <el-button @click="handleClose" >取 消</el-button>
            <el-button type="primary" @click="handleApprove" v-if="type === 'approve'">通过</el-button>
        </div>
    </el-dialog>
</template>
<script>
import ApprovalProcess from '@/components/approvalProcess'
import AiEditor from '@/components/AiEditor'
export default {
    name: "ApprovalDialog",
    components: {
        ApprovalProcess,
        AiEditor
    },
    props: {
        visible: {
            type: Boolean,
            default: false,
        },
        type: {
            type: String,
            default: "approve", // approve-审批,view-查看
        },
        data: {
            type: Object,
            default: () => ({}),
        },
    },
    data() {
        return {
            form: {
                planName: "",
                planCode: "",
                stage: "",
                creator: "",
                createTime: "",
                approvalComment: "",
                status: "pending",
                approver: "",
                approveTime: ""
            },
            radio1: 1,
            rules: {},
            status: "1",
            remark: "",
        };
    },
    computed: {
        dialogTitle() {
            return this.type === "approve" ? "审批" : "审批详情";
        },
    },
    watch: {
        data: {
            handler(val) {
                if (val) {
                    this.form = { ...val };
                }
            },
            immediate: true,
        },
    },
    methods: {
        handleClose() {
            this.$emit("close");
            this.form.approvalComment = "";
        },
        handleApprove() {
            if (!this.form.approvalComment) {
                this.$message.warning("请输入审批意见");
                return;
            }
            this.$emit("approve", {
                ...this.form,
                status: "approved",
            });
        },
        handleReject() {
            if (!this.form.approvalComment) {
                this.$message.warning("请输入审批意见");
                return;
            }
            this.$emit("reject", {
                ...this.form,
                status: "rejected",
            });
        },
    },
};
</script>
<style scoped lang="less">
::v-deep .el-dialog__header {
    border-bottom: 1px solid #e4e7ed;
}
.approval-dialog {
    display: flex;
    height: 40vh;
    .approval-content {
        flex: 3;
        margin-right: 20px;
        background: #ffffff;
        box-shadow: 0px 4px 12px 4px rgba(0, 0, 0, 0.08);
        border-radius: 10px;
    }
    .approval-flow {
        padding: 40px 20px;
        // width: 405px;
        flex: 2;
        background: #ffffff;
        box-shadow: 0px 4px 12px 4px rgba(0, 0, 0, 0.08);
        border-radius: 10px;
        .flow-title {
            font-size: 16px;
            font-weight: bold;
            margin-bottom: 20px;
            color: #303133;
        }
        .flow-content {
            height: calc(100% - 40px);
            overflow-y: auto;
            .el-form--inline .el-form-item {
                margin-right: 83px;
            }
        }
    }
}
.approval-content-card {
    height: calc(100% - 100px) !important;
    box-shadow: none !important;
}
.header-title {
    // display: flex;
    align-items: center;
    flex-wrap: wrap;
    margin-bottom: 20px;
    gap: 13px;
    .header-title-left {
        display: flex;
        align-items: center;
        gap: 13px;
        margin-top: 38px;
        img {
            width: 12px;
            height: 19px;
        }
        div {
            flex-shrink: 0;
            font-weight: bold;
            font-size: 18px;
            color: #222222;
            line-height: 27px;
            font-family: "Source Han Sans CN Bold Bold";
            &:before {
                content: "*";
                color: #f56c6c;
                margin-right: 4px;
            }
        }
        span {
            flex-shrink: 0;
            font-weight: bold;
            font-size: 18px;
            color: #222222;
            line-height: 27px;
            font-family: "Source Han Sans CN Bold Bold";
        }
    }
    .header-title-left :first-child {
        margin-top: 0;
    }
}
.header-title:first-child {
    .header-title-left {
        margin-top: 0;
    }
}
.item-title {
    padding-left: 25px;
    span {
        flex-shrink: 0;
        font-weight: bold;
        font-size: 14px;
        color: #222222;
        line-height: 27px;
        font-family: "Source Han Sans CN Bold Bold";
        margin: 18px 0;
        &:before {
            content: "*";
            color: #f56c6c;
            margin-right: 4px;
        }
    }
}
.approval-dialog-approve {
    padding: 38px 20px;
    // display: flex;
    align-content: center;
    .status {
        margin-right: 40px;
        max-width: 60%;
    }
    //   align-items: center;
    .status-title {
        color: #222222;
        font-family: "SourceHanSansCN-Medium";
        line-height: 14px;
        margin-bottom: 16px;
    }
    .status-content {
        display: flex;
        align-items: center;
        width: 100%;
        gap: 16px;
        background: #ffffff;
        border-radius: 10px;
        border: 1px solid rgba(4, 156, 154, 0.5);
        .resolve {
            border-radius: 10px;
            flex: 1;
            font-size: 16px;
            // padding: 5px 55px;
            font-weight: 400;
            color: #333333;
            cursor: pointer;
            line-height: 32px;
            display: flex;
            align-items: center;
            justify-content: center
        }
        .reject {
            flex: 1;
            border-radius: 10px;
            font-size: 16px;
            line-height: 32px;
            // padding: 5px 55px;
            font-weight: 400;
            color: #333333;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center
        }
        .activeStatus {
            background: #ebfefd;
            color: #049c9a;
            box-shadow: 0px 0px 6px 0px rgba(10, 109, 108, 0.25);
            border-radius: 10px;
        }
    }
    .remark-title {
        color: #222222;
        font-family: "SourceHanSansCN-Medium";
        line-height: 14px;
        margin-bottom: 16px;
    }
}
.dialog-footer {
    align-items: center;
    display: flex;
    justify-content: center;
    gap: 20px;
    button {
        width: 150px;
    }
}
</style>
src/views/reportLibrary/feasibilityReport/index.vue
@@ -53,20 +53,29 @@
                </el-table-column>
            </template>
        </TableCustom>
        <Approval :visible="showApproval" @close="showApproval = false" />
        <ShowDelConfirm :show="showDelConfirm" @close="showDelConfirm = false" @confirm="handleDelConfirm" />
        <ShowDelConfirm :title="changeStatusTitle" :tip="changeStatusTip" :show="changeStatus"
            @close="changeStatus = false" @confirm="handleChangeStatusConfirm" />
    </div>
</template>
<script>
import Approval from './components/approval'
export default {
    name: 'ProjectList',
    components: {
        Approval
    },
    data() {
        return {
            form: {
                name: ''
            },
            showApproval:false,
            showDelConfirm: false,
            rowId: '',
            changeStatus: false,
src/views/reportLibrary/feasibilityStudy/add.vue
New file
@@ -0,0 +1,173 @@
<template>
    <div>
        <Card>
            <div class="header-title" style="width: 100%;">
                <div class="header-title-left">
                    <img src="@/assets/public/headercard.png" />
                    <div>所属项目组</div>
                </div>
                <div class="header-title-right">
                    <el-button @click="showChoose = true" class="el-icon-circle-plus-outline" type="primary">
                        选择项目组</el-button>
                </div>
            </div>
            <Table :height="null" :queryForm="queryForm" :total="0">
                <template>
                    <el-table-column prop="name" label="项目组名称" />
                    <el-table-column prop="age" label="项目负责人" />
                    <el-table-column prop="age" label="项目组成员" />
                    <el-table-column prop="age" label="创建时间" />
                </template>
            </Table>
            <el-form ref="form" :model="form" :rules="rules" inline label-position="top" style="margin-top: 38px">
                <div class="header-title" style="width: 100%;">
                    <div class="header-title-left">
                        <img src="@/assets/public/headercard.png" />
                        <div>报告编号</div>
                    </div>
                </div>
                <form-item prop="name" style="margin-top: 38px">
                    <el-input v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" />
                </form-item>
                <div class="header-title" style="width: 100%;">
                    <div class="header-title-left">
                        <img src="@/assets/public/headercard.png" />
                        <div>报告名称</div>
                    </div>
                </div>
                <form-item prop="name" style="margin-top: 38px">
                    <el-input v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" />
                </form-item>
                <div class="header-title" style="width: 100%;">
                    <div class="header-title-left">
                        <img src="@/assets/public/headercard.png" />
                        <div>报告正文</div>
                    </div>
                </div>
                <form-item prop="name" style="margin-top: 38px">
                    <ai-editor v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" />
                </form-item>
                <div class="header-title" style="width: 100%;">
                    <div class="header-title-left">
                        <img src="@/assets/public/headercard.png" />
                        <div>附件</div>
                    </div>
                </div>
                <form-item prop="name" style="margin-top: 38px">
                    <el-upload action="https://jsonplaceholder.typicode.com/posts/" :file-list="fileList">
                        <el-button size="small" type="primary">点击上传</el-button>
                    </el-upload>
                </form-item>
                <div class="end-btn" style="margin-top: 38px">
                    <el-button type="primary">发送</el-button>
                    <el-button type="default">存草稿</el-button>
                </div>
            </el-form>
        </Card>
    </div>
</template>
<script>
import { Card } from 'element-ui';
import AiEditor from '@/components/AiEditor'
export default {
    components: { AiEditor },
    data() {
        return {
            form: {
                planName: "",
                planCode: "",
                stage: "",
                creator: "",
                createTime: "",
                approvalComment: "",
                status: "pending",
                approver: "",
                approveTime: ""
            },
            fileList: [], // 附件列表
            showChoose: false,
            radio1: 1,
            rules: {},
            status: "1",
            remark: "",
            queryForm: {
            }
        }
    }
}
</script>
<style lang="less" scoped>
.header-title {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    margin-bottom: 20px;
    gap: 13px;
    .header-title-left {
        display: flex;
        align-items: center;
        gap: 13px;
        margin-top: 38px;
        img {
            width: 12px;
            height: 19px;
        }
        div {
            flex-shrink: 0;
            font-weight: bold;
            font-size: 18px;
            color: #222222;
            line-height: 27px;
            font-family: "Source Han Sans CN Bold Bold";
            &:before {
                content: "*";
                color: #f56c6c;
                margin-right: 4px;
            }
        }
        span {
            flex-shrink: 0;
            font-weight: bold;
            font-size: 18px;
            color: #222222;
            line-height: 27px;
            font-family: "Source Han Sans CN Bold Bold";
        }
    }
    .header-title-left :first-child {
        margin-top: 0;
    }
}
.header-title:first-child {
    .header-title-left {
        margin-top: 0;
    }
}
.end-btn{
    display: flex;
    align-items: center;
    gap: 10px;
    button{
        width: 180px;
        height: 36px;
        // background: #409EFF;
    }
}
</style>
src/views/reportLibrary/feasibilityStudy/components/approval/index.vue
@@ -12,7 +12,7 @@
                                <div>所属项目组</div>
                            </div>
                        </div>
                        <Table :queryForm="queryForm" :total="0" @currentChange="handleCurrentChange"
                        <Table :height="null" :queryForm="queryForm" :total="0" @currentChange="handleCurrentChange"
                            @sizeChange="handleSizeChange">
                            <template>
                                <el-table-column prop="name" label="项目组名称" />
@@ -94,7 +94,7 @@
        </div>
        <div slot="footer" class="dialog-footer">
            <el-button @click="handleClose">取 消</el-button>
            <el-button @click="handleClose" >取 消</el-button>
            <el-button type="primary" @click="handleApprove" v-if="type === 'approve'">通过</el-button>
        </div>
    </el-dialog>
@@ -160,7 +160,7 @@
    },
    methods: {
        handleClose() {
            this.$emit("update:visible", false);
            this.$emit("close");
            this.form.approvalComment = "";
        },
        handleApprove() {
@@ -384,6 +384,7 @@
    align-items: center;
    display: flex;
    justify-content: center;
    gap: 20px;
    button {
        width: 150px;
src/views/reportLibrary/feasibilityStudy/index.vue
@@ -1,5 +1,15 @@
<template>
    <div class="list">
        <el-card class="header-box">
            <div class="box-title">
                <img src="@/assets/public/notice.png" class="header-icon"> <span>设立课题规则</span>
            </div>
            <div class="header-content">
                <p>1、根据可研报告、产品构思设计的工艺研究路线,一条工艺路线设立一个课题。如果一个课题中有多个化合物需要开发研究,则每个化合物作为一个分题;分题归集到该课题中,最终形成课题报告。不同课题报告中的分题不能重复使用。
                </p>
                <p>2、在可行研究阶段,工艺开发升级,重新规划工艺研究路线,则以新规划的工艺路线方案来设定课题。</p>
            </div>
        </el-card>
        <TableCustom :queryForm="queryForm" :total="total" @currentChange="handleCurrentChange"
            @sizeChange="handleSizeChange">
            <template #search>
@@ -8,6 +18,9 @@
                        <el-input v-model="form.name" placeholder="请输入"></el-input>
                    </el-form-item>
                    <el-form-item label="报告名称:">
                        <el-input v-model="form.name" placeholder="请输入"></el-input>
                    </el-form-item>
                    <el-form-item label="报告编号:">
                        <el-input v-model="form.name" placeholder="请输入"></el-input>
                    </el-form-item>
                    <el-form-item label="创建日期:">
@@ -22,15 +35,23 @@
                        </el-select>
                    </el-form-item>
                    <el-form-item label="" style="margin-left: 63px;">
                        <el-button type="default">重置</el-button>
                        <el-button type="default" style="margin-right: 10px;">重置</el-button>
                        <el-button type="primary">查询</el-button>
                    </el-form-item>
                </el-form>
            </template>
            <template #setting>
                <div class="table-title">
                    可研报告库
                <el-button @click="handleAddProject" class="el-icon-plus" type="primary">
                    新增可研报告</el-button>
                <div class="table-setting">
                    <div class="table-title">
                        可研报告库
                    </div>
                    <div class="table-tit">
                        草稿箱
                    </div>
                </div>
            </template>
            <template #table>
                <el-table-column prop="name" label="所属项目组" />
@@ -55,8 +76,6 @@
        </TableCustom>
        <Approval :visible="showApproval" @close="showApproval = false" />
        <ShowDelConfirm :show="showDelConfirm" @close="showDelConfirm = false" @confirm="handleDelConfirm" />
        <ShowDelConfirm :title="changeStatusTitle" :tip="changeStatusTip" :show="changeStatus"
            @close="changeStatus = false" @confirm="handleChangeStatusConfirm" />
@@ -69,7 +88,7 @@
export default {
    name: 'ProjectList',
    components: {
        Approval
        Approval
    },
    data() {
        return {
@@ -79,7 +98,7 @@
            showDelConfirm: false,
            rowId: '',
            changeStatus: false,
            showApproval: true,
            showApproval: false,
            changeStatusTitle: '',
            changeStatusTip: '',
            queryForm: {
@@ -91,9 +110,7 @@
    },
    methods: {
        handleAddProject() {
            this.$router.push({
                path: '/projectList/addProject'
            })
            this.$router.push('/reportLibrary/add')
        },
        handleDel(row) {
            this.rowId = row.id
@@ -135,6 +152,63 @@
</script>
<style scoped lang="less">
.el-icon-plus{
    margin-bottom: 20px;
}
.header-content {
    font-family: PingFangSC, PingFang SC;
    font-weight: 400;
    font-size: 14px;
    color: rgba(0, 0, 0, 0.88);
    margin-left: 30px;
}
.box-title {
    font-family: SourceHanSansCN, SourceHanSansCN;
    font-weight: bold;
    font-size: 18px;
    color: #222222;
    line-height: 27px;
    display: flex;
    align-items: center;
}
.header-icon {
    width: 20px;
    height: 20px;
    margin-right: 10px;
}
.header-box {
    border-radius: 16px;
    margin-bottom: 30px;
}
.table-setting {
    display: flex;
    gap: 14px;
}
.table-tit {
    background: #FAFAFC;
    border-radius: 8px 8px 0px 0px;
    border: 1px solid #DCDFE6;
    width: 166px;
    height: 50px;
    background: #FFFFFF;
    border-radius: 8px 8px 0px 0px;
    display: flex;
    align-items: center;
    justify-content: center;
    // margin-bottom: 21px;
    font-family: SourceHanSansCN, SourceHanSansCN;
    font-weight: bold;
    font-size: 18px;
    color: #049C9A;
    line-height: 27px;
}
.list {
    height: 100%;
}
@@ -148,7 +222,7 @@
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 21px;
    // margin-bottom: 21px;
    font-family: SourceHanSansCN, SourceHanSansCN;
    font-weight: bold;
    font-size: 18px;
src/views/reportLibrary/processDevelopment/components/approval/index.vue
New file
@@ -0,0 +1,393 @@
<template>
    <el-dialog :title="dialogTitle"  :visible.sync="visible" width="80%" po :close-on-click-modal="false"
        @close="handleClose">
        <div class="approval-dialog">
            <!-- 左侧审批内容 -->
            <div class="approval-content">
                <Card class="approval-content-card">
                    <template style="position: relative">
                        <div class="header-title" style="width: 100%;">
                            <div class="header-title-left">
                                <img src="@/assets/public/headercard.png" />
                                <div>所属项目组</div>
                            </div>
                        </div>
                        <Table :height="null" :queryForm="queryForm" :total="0" @currentChange="handleCurrentChange"
                            @sizeChange="handleSizeChange">
                            <template>
                                <el-table-column prop="name" label="项目组名称" />
                                <el-table-column prop="age" label="项目负责人" />
                                <el-table-column prop="age" label="项目组成员" />
                                <el-table-column prop="age" label="创建时间" />
                            </template>
                        </Table>
                        <el-form ref="form" :model="form" :rules="rules" inline label-position="top"
                            style="margin-top: 38px">
                            <div class="header-title" style="width: 100%;">
                                <div class="header-title-left">
                                    <img src="@/assets/public/headercard.png" />
                                    <div>报告编号</div>
                                </div>
                            </div>
                            <form-item prop="name" style="margin-top: 38px">
                                <el-input v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" />
                            </form-item>
                            <div class="header-title" style="width: 100%;">
                                <div class="header-title-left">
                                    <img src="@/assets/public/headercard.png" />
                                    <div>报告名称</div>
                                </div>
                            </div>
                            <form-item prop="name" style="margin-top: 38px">
                                <el-input v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" />
                            </form-item>
                            <div class="header-title" style="width: 100%;">
                                <div class="header-title-left">
                                    <img src="@/assets/public/headercard.png" />
                                    <div>报告正文</div>
                                </div>
                            </div>
                            <form-item prop="name" style="margin-top: 38px">
                                <ai-editor v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" />
                            </form-item>
                        </el-form>
                    </template>
                    <!-- <SelectMember ref="selectMember" /> -->
                </Card>
            </div>
            <!-- 右侧审批流程 -->
            <div class="approval-flow">
                <div class="flow-content">
                    <approval-process :status="form.status" :submit-time="form.createTime" :approver="form.approver"
                        :approve-time="form.approveTime" />
                </div>
            </div>
        </div>
        <div class="approval-dialog-approve">
            <el-row :span="24">
                <el-col :span="12">
                    <div class="status">
                        <div class="status-title">审批结果</div>
                        <div class="status-content">
                            <div class="resolve" :class="status == '1' && 'activeStatus'" @click.stop="status = 1">
                                通过
                            </div>
                            <div class="reject" :class="status == '2' && 'activeStatus'" @click.stop="status = 2">
                                驳回
                            </div>
                        </div>
                    </div>
                </el-col>
                <el-col :span="12">
                    <div class="remark">
                        <div class="remark-title">审批意见</div>
                        <el-input type="textarea" v-model="remark" placeholder="请输入审批意见" />
                    </div>
                </el-col>
            </el-row>
        </div>
        <div slot="footer" class="dialog-footer">
            <el-button @click="handleClose" >取 消</el-button>
            <el-button type="primary" @click="handleApprove" v-if="type === 'approve'">通过</el-button>
        </div>
    </el-dialog>
</template>
<script>
import ApprovalProcess from '@/components/approvalProcess'
import AiEditor from '@/components/AiEditor'
export default {
    name: "ApprovalDialog",
    components: {
        ApprovalProcess,
        AiEditor
    },
    props: {
        visible: {
            type: Boolean,
            default: false,
        },
        type: {
            type: String,
            default: "approve", // approve-审批,view-查看
        },
        data: {
            type: Object,
            default: () => ({}),
        },
    },
    data() {
        return {
            form: {
                planName: "",
                planCode: "",
                stage: "",
                creator: "",
                createTime: "",
                approvalComment: "",
                status: "pending",
                approver: "",
                approveTime: ""
            },
            radio1: 1,
            rules: {},
            status: "1",
            remark: "",
        };
    },
    computed: {
        dialogTitle() {
            return this.type === "approve" ? "审批" : "审批详情";
        },
    },
    watch: {
        data: {
            handler(val) {
                if (val) {
                    this.form = { ...val };
                }
            },
            immediate: true,
        },
    },
    methods: {
        handleClose() {
            this.$emit("close");
            this.form.approvalComment = "";
        },
        handleApprove() {
            if (!this.form.approvalComment) {
                this.$message.warning("请输入审批意见");
                return;
            }
            this.$emit("approve", {
                ...this.form,
                status: "approved",
            });
        },
        handleReject() {
            if (!this.form.approvalComment) {
                this.$message.warning("请输入审批意见");
                return;
            }
            this.$emit("reject", {
                ...this.form,
                status: "rejected",
            });
        },
    },
};
</script>
<style scoped lang="less">
::v-deep .el-dialog__header {
    border-bottom: 1px solid #e4e7ed;
}
.approval-dialog {
    display: flex;
    height: 40vh;
    .approval-content {
        flex: 3;
        margin-right: 20px;
        background: #ffffff;
        box-shadow: 0px 4px 12px 4px rgba(0, 0, 0, 0.08);
        border-radius: 10px;
    }
    .approval-flow {
        padding: 40px 20px;
        // width: 405px;
        flex: 2;
        background: #ffffff;
        box-shadow: 0px 4px 12px 4px rgba(0, 0, 0, 0.08);
        border-radius: 10px;
        .flow-title {
            font-size: 16px;
            font-weight: bold;
            margin-bottom: 20px;
            color: #303133;
        }
        .flow-content {
            height: calc(100% - 40px);
            overflow-y: auto;
            .el-form--inline .el-form-item {
                margin-right: 83px;
            }
        }
    }
}
.approval-content-card {
    height: calc(100% - 100px) !important;
    box-shadow: none !important;
}
.header-title {
    // display: flex;
    align-items: center;
    flex-wrap: wrap;
    margin-bottom: 20px;
    gap: 13px;
    .header-title-left {
        display: flex;
        align-items: center;
        gap: 13px;
        margin-top: 38px;
        img {
            width: 12px;
            height: 19px;
        }
        div {
            flex-shrink: 0;
            font-weight: bold;
            font-size: 18px;
            color: #222222;
            line-height: 27px;
            font-family: "Source Han Sans CN Bold Bold";
            &:before {
                content: "*";
                color: #f56c6c;
                margin-right: 4px;
            }
        }
        span {
            flex-shrink: 0;
            font-weight: bold;
            font-size: 18px;
            color: #222222;
            line-height: 27px;
            font-family: "Source Han Sans CN Bold Bold";
        }
    }
    .header-title-left :first-child {
        margin-top: 0;
    }
}
.header-title:first-child {
    .header-title-left {
        margin-top: 0;
    }
}
.item-title {
    padding-left: 25px;
    span {
        flex-shrink: 0;
        font-weight: bold;
        font-size: 14px;
        color: #222222;
        line-height: 27px;
        font-family: "Source Han Sans CN Bold Bold";
        margin: 18px 0;
        &:before {
            content: "*";
            color: #f56c6c;
            margin-right: 4px;
        }
    }
}
.approval-dialog-approve {
    padding: 38px 20px;
    // display: flex;
    align-content: center;
    .status {
        margin-right: 40px;
        max-width: 60%;
    }
    //   align-items: center;
    .status-title {
        color: #222222;
        font-family: "SourceHanSansCN-Medium";
        line-height: 14px;
        margin-bottom: 16px;
    }
    .status-content {
        display: flex;
        align-items: center;
        width: 100%;
        gap: 16px;
        background: #ffffff;
        border-radius: 10px;
        border: 1px solid rgba(4, 156, 154, 0.5);
        .resolve {
            border-radius: 10px;
            flex: 1;
            font-size: 16px;
            // padding: 5px 55px;
            font-weight: 400;
            color: #333333;
            cursor: pointer;
            line-height: 32px;
            display: flex;
            align-items: center;
            justify-content: center
        }
        .reject {
            flex: 1;
            border-radius: 10px;
            font-size: 16px;
            line-height: 32px;
            // padding: 5px 55px;
            font-weight: 400;
            color: #333333;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center
        }
        .activeStatus {
            background: #ebfefd;
            color: #049c9a;
            box-shadow: 0px 0px 6px 0px rgba(10, 109, 108, 0.25);
            border-radius: 10px;
        }
    }
    .remark-title {
        color: #222222;
        font-family: "SourceHanSansCN-Medium";
        line-height: 14px;
        margin-bottom: 16px;
    }
}
.dialog-footer {
    align-items: center;
    display: flex;
    justify-content: center;
    gap: 20px;
    button {
        width: 150px;
    }
}
</style>
src/views/reportLibrary/projectProposalLibrary/components/approval/index.vue
New file
@@ -0,0 +1,393 @@
<template>
    <el-dialog :title="dialogTitle"  :visible.sync="visible" width="80%" po :close-on-click-modal="false"
        @close="handleClose">
        <div class="approval-dialog">
            <!-- 左侧审批内容 -->
            <div class="approval-content">
                <Card class="approval-content-card">
                    <template style="position: relative">
                        <div class="header-title" style="width: 100%;">
                            <div class="header-title-left">
                                <img src="@/assets/public/headercard.png" />
                                <div>所属项目组</div>
                            </div>
                        </div>
                        <Table :height="null" :queryForm="queryForm" :total="0" @currentChange="handleCurrentChange"
                            @sizeChange="handleSizeChange">
                            <template>
                                <el-table-column prop="name" label="项目组名称" />
                                <el-table-column prop="age" label="项目负责人" />
                                <el-table-column prop="age" label="项目组成员" />
                                <el-table-column prop="age" label="创建时间" />
                            </template>
                        </Table>
                        <el-form ref="form" :model="form" :rules="rules" inline label-position="top"
                            style="margin-top: 38px">
                            <div class="header-title" style="width: 100%;">
                                <div class="header-title-left">
                                    <img src="@/assets/public/headercard.png" />
                                    <div>报告编号</div>
                                </div>
                            </div>
                            <form-item prop="name" style="margin-top: 38px">
                                <el-input v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" />
                            </form-item>
                            <div class="header-title" style="width: 100%;">
                                <div class="header-title-left">
                                    <img src="@/assets/public/headercard.png" />
                                    <div>报告名称</div>
                                </div>
                            </div>
                            <form-item prop="name" style="margin-top: 38px">
                                <el-input v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" />
                            </form-item>
                            <div class="header-title" style="width: 100%;">
                                <div class="header-title-left">
                                    <img src="@/assets/public/headercard.png" />
                                    <div>报告正文</div>
                                </div>
                            </div>
                            <form-item prop="name" style="margin-top: 38px">
                                <ai-editor v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" />
                            </form-item>
                        </el-form>
                    </template>
                    <!-- <SelectMember ref="selectMember" /> -->
                </Card>
            </div>
            <!-- 右侧审批流程 -->
            <div class="approval-flow">
                <div class="flow-content">
                    <approval-process :status="form.status" :submit-time="form.createTime" :approver="form.approver"
                        :approve-time="form.approveTime" />
                </div>
            </div>
        </div>
        <div class="approval-dialog-approve">
            <el-row :span="24">
                <el-col :span="12">
                    <div class="status">
                        <div class="status-title">审批结果</div>
                        <div class="status-content">
                            <div class="resolve" :class="status == '1' && 'activeStatus'" @click.stop="status = 1">
                                通过
                            </div>
                            <div class="reject" :class="status == '2' && 'activeStatus'" @click.stop="status = 2">
                                驳回
                            </div>
                        </div>
                    </div>
                </el-col>
                <el-col :span="12">
                    <div class="remark">
                        <div class="remark-title">审批意见</div>
                        <el-input type="textarea" v-model="remark" placeholder="请输入审批意见" />
                    </div>
                </el-col>
            </el-row>
        </div>
        <div slot="footer" class="dialog-footer">
            <el-button @click="handleClose" >取 消</el-button>
            <el-button type="primary" @click="handleApprove" v-if="type === 'approve'">通过</el-button>
        </div>
    </el-dialog>
</template>
<script>
import ApprovalProcess from '@/components/approvalProcess'
import AiEditor from '@/components/AiEditor'
export default {
    name: "ApprovalDialog",
    components: {
        ApprovalProcess,
        AiEditor
    },
    props: {
        visible: {
            type: Boolean,
            default: false,
        },
        type: {
            type: String,
            default: "approve", // approve-审批,view-查看
        },
        data: {
            type: Object,
            default: () => ({}),
        },
    },
    data() {
        return {
            form: {
                planName: "",
                planCode: "",
                stage: "",
                creator: "",
                createTime: "",
                approvalComment: "",
                status: "pending",
                approver: "",
                approveTime: ""
            },
            radio1: 1,
            rules: {},
            status: "1",
            remark: "",
        };
    },
    computed: {
        dialogTitle() {
            return this.type === "approve" ? "审批" : "审批详情";
        },
    },
    watch: {
        data: {
            handler(val) {
                if (val) {
                    this.form = { ...val };
                }
            },
            immediate: true,
        },
    },
    methods: {
        handleClose() {
            this.$emit("close");
            this.form.approvalComment = "";
        },
        handleApprove() {
            if (!this.form.approvalComment) {
                this.$message.warning("请输入审批意见");
                return;
            }
            this.$emit("approve", {
                ...this.form,
                status: "approved",
            });
        },
        handleReject() {
            if (!this.form.approvalComment) {
                this.$message.warning("请输入审批意见");
                return;
            }
            this.$emit("reject", {
                ...this.form,
                status: "rejected",
            });
        },
    },
};
</script>
<style scoped lang="less">
::v-deep .el-dialog__header {
    border-bottom: 1px solid #e4e7ed;
}
.approval-dialog {
    display: flex;
    height: 40vh;
    .approval-content {
        flex: 3;
        margin-right: 20px;
        background: #ffffff;
        box-shadow: 0px 4px 12px 4px rgba(0, 0, 0, 0.08);
        border-radius: 10px;
    }
    .approval-flow {
        padding: 40px 20px;
        // width: 405px;
        flex: 2;
        background: #ffffff;
        box-shadow: 0px 4px 12px 4px rgba(0, 0, 0, 0.08);
        border-radius: 10px;
        .flow-title {
            font-size: 16px;
            font-weight: bold;
            margin-bottom: 20px;
            color: #303133;
        }
        .flow-content {
            height: calc(100% - 40px);
            overflow-y: auto;
            .el-form--inline .el-form-item {
                margin-right: 83px;
            }
        }
    }
}
.approval-content-card {
    height: calc(100% - 100px) !important;
    box-shadow: none !important;
}
.header-title {
    // display: flex;
    align-items: center;
    flex-wrap: wrap;
    margin-bottom: 20px;
    gap: 13px;
    .header-title-left {
        display: flex;
        align-items: center;
        gap: 13px;
        margin-top: 38px;
        img {
            width: 12px;
            height: 19px;
        }
        div {
            flex-shrink: 0;
            font-weight: bold;
            font-size: 18px;
            color: #222222;
            line-height: 27px;
            font-family: "Source Han Sans CN Bold Bold";
            &:before {
                content: "*";
                color: #f56c6c;
                margin-right: 4px;
            }
        }
        span {
            flex-shrink: 0;
            font-weight: bold;
            font-size: 18px;
            color: #222222;
            line-height: 27px;
            font-family: "Source Han Sans CN Bold Bold";
        }
    }
    .header-title-left :first-child {
        margin-top: 0;
    }
}
.header-title:first-child {
    .header-title-left {
        margin-top: 0;
    }
}
.item-title {
    padding-left: 25px;
    span {
        flex-shrink: 0;
        font-weight: bold;
        font-size: 14px;
        color: #222222;
        line-height: 27px;
        font-family: "Source Han Sans CN Bold Bold";
        margin: 18px 0;
        &:before {
            content: "*";
            color: #f56c6c;
            margin-right: 4px;
        }
    }
}
.approval-dialog-approve {
    padding: 38px 20px;
    // display: flex;
    align-content: center;
    .status {
        margin-right: 40px;
        max-width: 60%;
    }
    //   align-items: center;
    .status-title {
        color: #222222;
        font-family: "SourceHanSansCN-Medium";
        line-height: 14px;
        margin-bottom: 16px;
    }
    .status-content {
        display: flex;
        align-items: center;
        width: 100%;
        gap: 16px;
        background: #ffffff;
        border-radius: 10px;
        border: 1px solid rgba(4, 156, 154, 0.5);
        .resolve {
            border-radius: 10px;
            flex: 1;
            font-size: 16px;
            // padding: 5px 55px;
            font-weight: 400;
            color: #333333;
            cursor: pointer;
            line-height: 32px;
            display: flex;
            align-items: center;
            justify-content: center
        }
        .reject {
            flex: 1;
            border-radius: 10px;
            font-size: 16px;
            line-height: 32px;
            // padding: 5px 55px;
            font-weight: 400;
            color: #333333;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center
        }
        .activeStatus {
            background: #ebfefd;
            color: #049c9a;
            box-shadow: 0px 0px 6px 0px rgba(10, 109, 108, 0.25);
            border-radius: 10px;
        }
    }
    .remark-title {
        color: #222222;
        font-family: "SourceHanSansCN-Medium";
        line-height: 14px;
        margin-bottom: 16px;
    }
}
.dialog-footer {
    align-items: center;
    display: flex;
    justify-content: center;
    gap: 20px;
    button {
        width: 150px;
    }
}
</style>
src/views/reportLibrary/verificationRelease/components/approval/index.vue
New file
@@ -0,0 +1,393 @@
<template>
    <el-dialog :title="dialogTitle"  :visible.sync="visible" width="80%" po :close-on-click-modal="false"
        @close="handleClose">
        <div class="approval-dialog">
            <!-- 左侧审批内容 -->
            <div class="approval-content">
                <Card class="approval-content-card">
                    <template style="position: relative">
                        <div class="header-title" style="width: 100%;">
                            <div class="header-title-left">
                                <img src="@/assets/public/headercard.png" />
                                <div>所属项目组</div>
                            </div>
                        </div>
                        <Table :height="null" :queryForm="queryForm" :total="0" @currentChange="handleCurrentChange"
                            @sizeChange="handleSizeChange">
                            <template>
                                <el-table-column prop="name" label="项目组名称" />
                                <el-table-column prop="age" label="项目负责人" />
                                <el-table-column prop="age" label="项目组成员" />
                                <el-table-column prop="age" label="创建时间" />
                            </template>
                        </Table>
                        <el-form ref="form" :model="form" :rules="rules" inline label-position="top"
                            style="margin-top: 38px">
                            <div class="header-title" style="width: 100%;">
                                <div class="header-title-left">
                                    <img src="@/assets/public/headercard.png" />
                                    <div>报告编号</div>
                                </div>
                            </div>
                            <form-item prop="name" style="margin-top: 38px">
                                <el-input v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" />
                            </form-item>
                            <div class="header-title" style="width: 100%;">
                                <div class="header-title-left">
                                    <img src="@/assets/public/headercard.png" />
                                    <div>报告名称</div>
                                </div>
                            </div>
                            <form-item prop="name" style="margin-top: 38px">
                                <el-input v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" />
                            </form-item>
                            <div class="header-title" style="width: 100%;">
                                <div class="header-title-left">
                                    <img src="@/assets/public/headercard.png" />
                                    <div>报告正文</div>
                                </div>
                            </div>
                            <form-item prop="name" style="margin-top: 38px">
                                <ai-editor v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" />
                            </form-item>
                        </el-form>
                    </template>
                    <!-- <SelectMember ref="selectMember" /> -->
                </Card>
            </div>
            <!-- 右侧审批流程 -->
            <div class="approval-flow">
                <div class="flow-content">
                    <approval-process :status="form.status" :submit-time="form.createTime" :approver="form.approver"
                        :approve-time="form.approveTime" />
                </div>
            </div>
        </div>
        <div class="approval-dialog-approve">
            <el-row :span="24">
                <el-col :span="12">
                    <div class="status">
                        <div class="status-title">审批结果</div>
                        <div class="status-content">
                            <div class="resolve" :class="status == '1' && 'activeStatus'" @click.stop="status = 1">
                                通过
                            </div>
                            <div class="reject" :class="status == '2' && 'activeStatus'" @click.stop="status = 2">
                                驳回
                            </div>
                        </div>
                    </div>
                </el-col>
                <el-col :span="12">
                    <div class="remark">
                        <div class="remark-title">审批意见</div>
                        <el-input type="textarea" v-model="remark" placeholder="请输入审批意见" />
                    </div>
                </el-col>
            </el-row>
        </div>
        <div slot="footer" class="dialog-footer">
            <el-button @click="handleClose" >取 消</el-button>
            <el-button type="primary" @click="handleApprove" v-if="type === 'approve'">通过</el-button>
        </div>
    </el-dialog>
</template>
<script>
import ApprovalProcess from '@/components/approvalProcess'
import AiEditor from '@/components/AiEditor'
export default {
    name: "ApprovalDialog",
    components: {
        ApprovalProcess,
        AiEditor
    },
    props: {
        visible: {
            type: Boolean,
            default: false,
        },
        type: {
            type: String,
            default: "approve", // approve-审批,view-查看
        },
        data: {
            type: Object,
            default: () => ({}),
        },
    },
    data() {
        return {
            form: {
                planName: "",
                planCode: "",
                stage: "",
                creator: "",
                createTime: "",
                approvalComment: "",
                status: "pending",
                approver: "",
                approveTime: ""
            },
            radio1: 1,
            rules: {},
            status: "1",
            remark: "",
        };
    },
    computed: {
        dialogTitle() {
            return this.type === "approve" ? "审批" : "审批详情";
        },
    },
    watch: {
        data: {
            handler(val) {
                if (val) {
                    this.form = { ...val };
                }
            },
            immediate: true,
        },
    },
    methods: {
        handleClose() {
            this.$emit("close");
            this.form.approvalComment = "";
        },
        handleApprove() {
            if (!this.form.approvalComment) {
                this.$message.warning("请输入审批意见");
                return;
            }
            this.$emit("approve", {
                ...this.form,
                status: "approved",
            });
        },
        handleReject() {
            if (!this.form.approvalComment) {
                this.$message.warning("请输入审批意见");
                return;
            }
            this.$emit("reject", {
                ...this.form,
                status: "rejected",
            });
        },
    },
};
</script>
<style scoped lang="less">
::v-deep .el-dialog__header {
    border-bottom: 1px solid #e4e7ed;
}
.approval-dialog {
    display: flex;
    height: 40vh;
    .approval-content {
        flex: 3;
        margin-right: 20px;
        background: #ffffff;
        box-shadow: 0px 4px 12px 4px rgba(0, 0, 0, 0.08);
        border-radius: 10px;
    }
    .approval-flow {
        padding: 40px 20px;
        // width: 405px;
        flex: 2;
        background: #ffffff;
        box-shadow: 0px 4px 12px 4px rgba(0, 0, 0, 0.08);
        border-radius: 10px;
        .flow-title {
            font-size: 16px;
            font-weight: bold;
            margin-bottom: 20px;
            color: #303133;
        }
        .flow-content {
            height: calc(100% - 40px);
            overflow-y: auto;
            .el-form--inline .el-form-item {
                margin-right: 83px;
            }
        }
    }
}
.approval-content-card {
    height: calc(100% - 100px) !important;
    box-shadow: none !important;
}
.header-title {
    // display: flex;
    align-items: center;
    flex-wrap: wrap;
    margin-bottom: 20px;
    gap: 13px;
    .header-title-left {
        display: flex;
        align-items: center;
        gap: 13px;
        margin-top: 38px;
        img {
            width: 12px;
            height: 19px;
        }
        div {
            flex-shrink: 0;
            font-weight: bold;
            font-size: 18px;
            color: #222222;
            line-height: 27px;
            font-family: "Source Han Sans CN Bold Bold";
            &:before {
                content: "*";
                color: #f56c6c;
                margin-right: 4px;
            }
        }
        span {
            flex-shrink: 0;
            font-weight: bold;
            font-size: 18px;
            color: #222222;
            line-height: 27px;
            font-family: "Source Han Sans CN Bold Bold";
        }
    }
    .header-title-left :first-child {
        margin-top: 0;
    }
}
.header-title:first-child {
    .header-title-left {
        margin-top: 0;
    }
}
.item-title {
    padding-left: 25px;
    span {
        flex-shrink: 0;
        font-weight: bold;
        font-size: 14px;
        color: #222222;
        line-height: 27px;
        font-family: "Source Han Sans CN Bold Bold";
        margin: 18px 0;
        &:before {
            content: "*";
            color: #f56c6c;
            margin-right: 4px;
        }
    }
}
.approval-dialog-approve {
    padding: 38px 20px;
    // display: flex;
    align-content: center;
    .status {
        margin-right: 40px;
        max-width: 60%;
    }
    //   align-items: center;
    .status-title {
        color: #222222;
        font-family: "SourceHanSansCN-Medium";
        line-height: 14px;
        margin-bottom: 16px;
    }
    .status-content {
        display: flex;
        align-items: center;
        width: 100%;
        gap: 16px;
        background: #ffffff;
        border-radius: 10px;
        border: 1px solid rgba(4, 156, 154, 0.5);
        .resolve {
            border-radius: 10px;
            flex: 1;
            font-size: 16px;
            // padding: 5px 55px;
            font-weight: 400;
            color: #333333;
            cursor: pointer;
            line-height: 32px;
            display: flex;
            align-items: center;
            justify-content: center
        }
        .reject {
            flex: 1;
            border-radius: 10px;
            font-size: 16px;
            line-height: 32px;
            // padding: 5px 55px;
            font-weight: 400;
            color: #333333;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center
        }
        .activeStatus {
            background: #ebfefd;
            color: #049c9a;
            box-shadow: 0px 0px 6px 0px rgba(10, 109, 108, 0.25);
            border-radius: 10px;
        }
    }
    .remark-title {
        color: #222222;
        font-family: "SourceHanSansCN-Medium";
        line-height: 14px;
        margin-bottom: 16px;
    }
}
.dialog-footer {
    align-items: center;
    display: flex;
    justify-content: center;
    gap: 20px;
    button {
        width: 150px;
    }
}
</style>