董国庆
昨天 fe6509e66e6852f6b5d740385bdae4fd0a11da77
laboratory/src/views/deliveryAssessment/testingAndEvaluation/components/approval/index.vue
@@ -1,499 +1,546 @@
<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" :total="0" :data="tableData">
                            <template>
                                <el-table-column prop="teamName" label="所属项目组" />
                                <el-table-column prop="itemName" label="检测项名称" />
                                <el-table-column prop="itemCode" label="检测项编号" />
                                <el-table-column prop="remark" label="备注" />
                                <el-table-column prop="createBy" label="创建人" />
                                <el-table-column prop="createTime" label="创建时间" />
                            </template>
                        </Table>
                        <el-form ref="form" :model="form" :rules="rules" inline label-position="top"
                            style="margin-top: 18px">
                            <el-form-item prop="name" label="报告内容">
                                <el-select v-model="form.reportContent" style="width: 100%;" disabled
                                    placeholder="请选择报告内容">
                                    <el-option label="国家标准" :value="1" />
                                    <el-option label="分析方法开发" :value="2" />
                                    <el-option label="方法验证报告" :value="3" />
                                    <el-option label="方法确认" :value="4" />
                                    <el-option label="操作规程" :value="5" />
                                    <el-option label="方法转移记录清单" :value="6" />
                                </el-select>
                            </el-form-item>
                            <div class="header-title" style="width: 100%;">
                                <div class="header-title-left">
                                    <img src="@/assets/public/headercard.png" />
                                    <div>报告正文</div>
                                </div>
                            </div>
                            <el-form-item prop="name" style="margin-top: 18px">
                                <ai-editor :value="form.reportText" :readOnly="true" style="width: 100%;"
                                    placeholder="请输入报告编号" />
                            </el-form-item>
                            <div class="header-title" style="width: 100%;">
                                <div class="header-title-left">
                                    <img src="@/assets/public/headercard.png" />
                                    <span>附件</span>
                                </div>
                            </div>
                            <el-form-item prop="name" style="margin-top: 18px">
                                <el-upload :on-preview="handlePreview"
                                    action="https://jsonplaceholder.typicode.com/posts/" :file-list="fileList">
                                    <!-- <el-button size="small" type="primary">点击上传</el-button> -->
                                </el-upload>
                            </el-form-item>
                        </el-form>
                    </template>
                    <!-- <SelectMember ref="selectMember" /> -->
                </Card>
  <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>
            <!-- 右侧审批流程 -->
            <div class="approval-flow">
                <div class="flow-content">
                    <approval-process :processData="form.processData" />
            <Table :height="null" :total="0" :data="tableData">
              <template>
                <el-table-column prop="teamName" label="所属项目组" />
                <el-table-column prop="itemName" label="检测项名称" />
                <el-table-column prop="itemCode" label="检测项编号" />
                <el-table-column prop="remark" label="备注" />
                <el-table-column prop="createBy" label="创建人" />
                <el-table-column prop="createTime" label="创建时间" />
              </template>
            </Table>
            <el-form
              ref="form"
              :model="form"
              :rules="rules"
              inline
              label-position="top"
              style="margin-top: 18px"
            >
              <el-form-item prop="name" label="报告内容">
                <el-select
                  v-model="form.reportContent"
                  style="width: 100%"
                  disabled
                  placeholder="请选择报告内容"
                >
                  <el-option label="国家标准" :value="1" />
                  <el-option label="分析方法开发" :value="2" />
                  <el-option label="方法验证报告" :value="3" />
                  <el-option label="方法确认" :value="4" />
                  <el-option label="操作规程" :value="5" />
                  <el-option label="方法转移记录清单" :value="6" />
                </el-select>
              </el-form-item>
              <div class="header-title" style="width: 100%">
                <div class="header-title-left">
                  <img src="@/assets/public/headercard.png" />
                  <div>报告正文</div>
                </div>
              </div>
              <el-form-item prop="name" style="margin-top: 18px">
                <ai-editor
                  :value="form.reportText"
                  :readOnly="true"
                  style="width: 100%"
                  placeholder="请输入报告编号"
                />
              </el-form-item>
              <div class="header-title" style="width: 100%">
                <div class="header-title-left">
                  <img src="@/assets/public/headercard.png" />
                  <span>附件</span>
                </div>
              </div>
              <el-form-item prop="name" style="margin-top: 18px">
                <el-upload
                  :on-preview="handlePreview"
                  action="https://jsonplaceholder.typicode.com/posts/"
                  :file-list="fileList"
                >
                  <!-- <el-button size="small" type="primary">点击上传</el-button> -->
                </el-upload>
              </el-form-item>
            </el-form>
          </template>
          <!-- <SelectMember ref="selectMember" /> -->
        </Card>
      </div>
      <!-- 右侧审批流程 -->
      <div class="approval-flow">
        <div class="flow-content">
          <approval-process :processData="form.processData" />
        </div>
      </div>
    </div>
    <div class="approval-dialog-approve" v-if="type === '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>
        <div class="approval-dialog-approve" v-if="type === '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>
          </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'
import { getDetailInfo, getDetail, detailAuditReport } from '../../service'
import apiConfig from '@/utils/baseurl';
import { getAllocateIp } from '@/utils/utils'
import ApprovalProcess from "@/components/approvalProcess";
import AiEditor from "@/components/AiEditor";
import { getDetailInfo, getDetail, detailAuditReport } from "../../service";
import apiConfig from "@/utils/baseurl";
import { getAllocateIp, downloadFileByUrl, isImageFile } from "@/utils/utils";
export default {
    name: "ApprovalDialog",
    components: {
        ApprovalProcess,
        AiEditor
  name: "ApprovalDialog",
  components: {
    ApprovalProcess,
    AiEditor,
  },
  props: {
    visible: {
      type: Boolean,
      default: false,
    },
    props: {
        visible: {
            type: Boolean,
            default: false,
        },
        type: {
            type: String,
            default: "approve", // approve-审批,view-查看
        },
        data: {
            type: Object,
            default: () => ({}),
        },
        id: {
            type: String,
            default: "",
        },
    type: {
      type: String,
      default: "approve", // approve-审批,view-查看
    },
    data() {
        return {
            form: {
                reportText: "",
                reportContent: "",
                qaReportFiles: [],
                processData: [],
            },
            tableData: [],
            fileList: [],
            radio1: 1,
            rules: {},
            status: "1",
            remark: "",
        };
    data: {
      type: Object,
      default: () => ({}),
    },
    computed: {
        dialogTitle() {
            return this.type === "approve" ? "方法验证报告审批" : "方法验证报告详情";
        },
    id: {
      type: String,
      default: "",
    },
    watch: {
        visible: {
            handler(val) {
                if (val && this.data.id) {
                    this.getDetailInfo()
                }
                if (val && this.data.itemId) {
                    this.getDetail()
                }
            },
            immediate: true,
        },
  },
  data() {
    return {
      form: {
        reportText: "",
        reportContent: "",
        qaReportFiles: [],
        processData: [],
      },
      tableData: [],
      fileList: [],
      radio1: 1,
      rules: {},
      status: "1",
      remark: "",
    };
  },
  computed: {
    dialogTitle() {
      return this.type === "approve" ? "方法验证报告审批" : "方法验证报告详情";
    },
    methods: {
        handlePreview(file) {
            console.log('url', file)
            if (file && file.url) {
                if (file.url && file.url.startsWith(getAllocateIp())) {
                    window.open(file.url, '_blank');
                } else {
                    let newUrl = getAllocateIp() + file.url;
                    window.open(newUrl, '_blank');
                }
            }
        },
        getDetailInfo() {
            getDetailInfo({ id: this.data.id }).then(res => {
                if (res) {
                    this.form = { ...res, reportContent: Number(res.reportContent), processData: [] }
                    if (res.qaReportFileList && res.qaReportFileList.length > 0) {
                        this.fileList = res.qaReportFileList.map(file => ({
                            name: file.fileName,
                            url: getFullUrl(file.fileUrl),
                            uid: file.id
                        }))
                        this.form.qaReportFileList = res.fileList
                    } else {
                        this.fileList = []
                        this.form.qaReportFileList = []
                    }
                    // 组装流程数据
                    let processData = [];
                    // 提交节点
                    processData.push({
                        type: "primary",
                        mode: "list",
                        fields: [
                            { label: "提交人:", value: res.updateBy || "" },
                            { label: "提交时间:", value: res.createTime || "" },
                        ],
                    });
                    if (res.status == 2 || res.status == 3) {
                        processData.push({
                            type:
                                res.status === 2
                                    ? "primary"
                                    : res.status === 3
                                        ? "danger"
                                        : "warning",
                            mode: "list",
                            fields: [
                                {
                                    label: "审核结果:",
                                    value:
                                        res.status === 2
                                            ? "通过"
                                            : res.status === 3
                                                ? "驳回"
                                                : "待审批",
                                },
                                { label: "审批意见:", value: res.auditRemark || "" },
                                { label: "审核人:", value: res.auditPersonName || "" },
                                { label: "审核时间:", value: res.auditTime || "" },
                            ],
                        });
                    } else {
                        processData.push({
                            type: "warning",
                            mode: "list",
                            fields: [
                                { label: "等待审核" },
                            ],
                        });
                    }
                    // 如有卡片模式,按前述结构 push
  },
  watch: {
    visible: {
      handler(val) {
        if (val && this.data.id) {
          this.getDetailInfo();
        }
        if (val && this.data.itemId) {
          this.getDetail();
        }
      },
      immediate: true,
    },
  },
  methods: {
    handlePreview(file) {
      if (file && file.url) {
        // 判断是否为图片文件
        const isImage = isImageFile(file.url);
                    this.$nextTick(() => {
                        this.form.processData = processData;
                    })
                }
            })
        },
        getDetail() {
            getDetail(this.data.itemId).then(res => {
                if (res) {
                    this.tableData = [{ ...res, teamName: res.projectTeamVO.teamName }]
                }
            })
        },
        handleClose() {
        if (isImage) {
          // 图片文件:使用 window.open 预览
          if (file.url && file.url.startsWith(getAllocateIp())) {
            console.log("图片链接", file.url);
            window.open(file.url, "_blank");
          } else {
            let newUrl = getAllocateIp() + file.url;
            console.log("图片链接", newUrl);
            window.open(newUrl, "_blank");
          }
        } else {
          // 非图片文件:使用下载方式
          downloadFileByUrl(file.url, file.name);
        }
      }
    },
    getDetailInfo() {
      getDetailInfo({ id: this.data.id }).then((res) => {
        if (res) {
          this.form = {
            ...res,
            reportContent: Number(res.reportContent),
            processData: [],
          };
          if (res.qaReportFileList && res.qaReportFileList.length > 0) {
            this.fileList = res.qaReportFileList.map((file) => ({
              name: file.fileName,
              url: getFullUrl(file.fileUrl),
              uid: file.id,
            }));
            this.form.qaReportFileList = res.fileList;
          } else {
            this.fileList = [];
            this.form.qaReportFileList = [];
          }
          // 组装流程数据
          let processData = [];
          // 提交节点
          processData.push({
            type: "primary",
            mode: "list",
            fields: [
              { label: "提交人:", value: res.updateBy || "" },
              { label: "提交时间:", value: res.createTime || "" },
            ],
          });
          if (res.status == 2 || res.status == 3) {
            processData.push({
              type:
                res.status === 2
                  ? "primary"
                  : res.status === 3
                  ? "danger"
                  : "warning",
              mode: "list",
              fields: [
                {
                  label: "审核结果:",
                  value:
                    res.status === 2
                      ? "通过"
                      : res.status === 3
                      ? "驳回"
                      : "待审批",
                },
                { label: "审批意见:", value: res.auditRemark || "" },
                { label: "审核人:", value: res.auditPersonName || "" },
                { label: "审核时间:", value: res.auditTime || "" },
              ],
            });
          } else {
            processData.push({
              type: "warning",
              mode: "list",
              fields: [{ label: "等待审核" }],
            });
          }
          // 如有卡片模式,按前述结构 push
          this.$nextTick(() => {
            this.form.processData = processData;
          });
        }
      });
    },
    getDetail() {
      getDetail(this.data.itemId).then((res) => {
        if (res) {
          this.tableData = [{ ...res, teamName: res.projectTeamVO.teamName }];
        }
      });
    },
    handleClose() {
      this.$emit("close");
      this.form.approvalComment = "";
    },
    handleApprove() {
      if (!this.remark) {
        this.$message.warning("请输入审批意见");
        return;
      }
      const params = {
        id: this.data.id,
        auditRemark: this.remark,
        auditStatus: this.status === "1" ? 2 : 3,
      };
      detailAuditReport(params)
        .then((res) => {
          if (res) {
            this.$message.success("审核成功");
            this.$emit("close");
            this.form.approvalComment = "";
        },
        handleApprove() {
            if (!this.remark) {
                this.$message.warning("请输入审批意见");
                return;
            }
            const params = {
                id: this.data.id,
                auditRemark: this.remark,
                auditStatus: this.status === '1' ? 2 : 3
            };
            detailAuditReport(params).then(res => {
                if (res) {
                    this.$message.success('审核成功');
                    this.$emit("close");
                }
            }).catch(err => {
                this.$message.error(err.message || '审核失败');
            });
        },
        handleReject() {
            if (!this.form.approvalComment) {
                this.$message.warning("请输入审批意见");
                return;
            }
            this.$emit("reject", {
                ...this.form,
                status: "rejected",
            });
        },
          }
        })
        .catch((err) => {
          this.$message.error(err.message || "审核失败");
        });
    },
    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;
  border-bottom: 1px solid #e4e7ed;
}
.approval-dialog {
    display: flex;
    height: 40vh;
  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-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;
    }
    .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-content {
      height: calc(100% - 40px);
      overflow-y: auto;
        .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;
            }
        }
      .el-form--inline .el-form-item {
        margin-right: 83px;
      }
    }
  }
}
.approval-content-card {
    height: calc(100% - 100px) !important;
    box-shadow: none !important;
  height: calc(100% - 100px) !important;
  box-shadow: none !important;
}
.header-title {
    // display: flex;
  // display: flex;
  align-items: center;
  flex-wrap: wrap;
  margin-bottom: 20px;
  gap: 13px;
  .header-title-left {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    margin-bottom: 20px;
    gap: 13px;
    margin-top: 18px;
    .header-title-left {
        display: flex;
        align-items: center;
        gap: 13px;
        margin-top: 18px;
        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";
        }
    img {
      width: 12px;
      height: 19px;
    }
    .header-title-left :first-child {
        margin-top: 0;
    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;
    }
  .header-title-left {
    margin-top: 0;
  }
}
.item-title {
    padding-left: 25px;
  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;
  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;
        }
    &:before {
      content: "*";
      color: #f56c6c;
      margin-right: 4px;
    }
  }
}
.approval-dialog-approve {
    padding: 18px 20px;
    // display: flex;
    align-content: center;
  padding: 18px 20px;
  // display: flex;
  align-content: center;
    .status {
        margin-right: 40px;
        max-width: 60%;
  .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;
    }
    //   align-items: center;
    .status-title {
        color: #222222;
        font-family: "SourceHanSansCN-Medium";
        line-height: 14px;
        margin-bottom: 16px;
    .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;
    }
    .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;
        }
    .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;
    }
  .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;
  align-items: center;
  display: flex;
  justify-content: center;
  gap: 20px;
    button {
        width: 150px;
    }
  button {
    width: 150px;
  }
}
</style>