huminmin
2026-06-01 a563ea879ef5fb6897e76d2df661e465dce2ab9b
src/views/collaborativeApproval/rulesRegulationsManagement/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,629 @@
<template>
  <div class="app-container">
    <!-- è§„章制度管理-->
    <el-card class="box-card">
      <template #header>
        <div class="card-header">
          <span>规章制度发布</span>
        </div>
      </template>
      <div class="tab-content">
        <el-row :gutter="20"
                class="mb-20">
          <span class="ml-10">制度标题:</span>
          <el-col :span="6">
            <el-input v-model="regulationSearchForm.title"
                      placeholder="请输入制度标题"
                      clearable />
          </el-col>
          <span class="search_title">制度分类:</span>
          <el-col :span="4">
            <el-select v-model="regulationSearchForm.category"
                       placeholder="制度分类"
                       clearable>
              <el-option label="人事制度"
                         value="hr" />
              <el-option label="财务制度"
                         value="finance" />
              <el-option label="安全制度"
                         value="safety" />
              <el-option label="技术制度"
                         value="tech" />
            </el-select>
          </el-col>
          <el-col :span="8">
            <el-button type="primary"
                       @click="searchRegulations">搜索</el-button>
            <el-button @click="resetRegulationSearch">重置</el-button>
            <el-button @click="handleExport">导出</el-button>
            <el-button type="success"
                       @click="handleAdd">
              å‘布制度
            </el-button>
          </el-col>
        </el-row>
        <PIMTable
          rowKey="id"
          :column="regulationTableColumn"
          :tableData="regulations"
          :tableLoading="tableLoading"
          :page="page"
          :isShowPagination="true"
          @pagination="paginationChange"
        />
      </div>
    </el-card>
    <!-- ç”¨å°ç”³è¯·å¯¹è¯æ¡†ï¼ˆå·²ç§»é™¤ï¼‰ -->
    <!-- è§„章制度发布对话框 -->
    <el-dialog v-model="showRegulationDialog"
               :title="operationType === 'add' ? '发布制度' : '编辑制度'"
               width="800px">
      <el-form :model="regulationForm"
               :rules="regulationRules"
               ref="regulationFormRef"
               label-width="100px">
        <el-form-item label="制度编号"
                      prop="regulationNum">
          <el-input v-model="regulationForm.regulationNum"
                    placeholder="请输入制度编号" />
        </el-form-item>
        <el-form-item label="制度标题"
                      prop="title">
          <el-input v-model="regulationForm.title"
                    placeholder="请输入制度标题" />
        </el-form-item>
        <el-form-item label="制度分类"
                      prop="category">
          <el-select v-model="regulationForm.category"
                     placeholder="请选择制度分类"
                     style="width: 100%">
            <el-option label="人事制度"
                       value="hr" />
            <el-option label="财务制度"
                       value="finance" />
            <el-option label="安全制度"
                       value="safety" />
            <el-option label="技术制度"
                       value="tech" />
          </el-select>
        </el-form-item>
        <el-form-item label="制度内容"
                      prop="content">
          <el-input v-model="regulationForm.content"
                    type="textarea"
                    :rows="10"
                    placeholder="请输入制度详细内容" />
        </el-form-item>
        <el-form-item label="制度版本"
                      prop="version">
          <el-input v-model="regulationForm.version"
                    placeholder="请输入制度版本" />
        </el-form-item>
        <el-form-item label="生效时间"
                      prop="effectiveTime">
          <el-date-picker v-model="regulationForm.effectiveTime"
                          type="datetime"
                          format="YYYY-MM-DD HH:mm:ss"
                          value-format="YYYY-MM-DD HH:mm:ss"
                          placeholder="选择生效时间"
                          style="width: 100%" />
        </el-form-item>
        <el-form-item label="适用范围"
                      prop="scope">
          <el-checkbox-group v-model="regulationForm.scope">
            <el-checkbox label="all">全体员工</el-checkbox>
            <el-checkbox label="manager">管理层</el-checkbox>
            <el-checkbox label="hr">人事部门</el-checkbox>
            <el-checkbox label="finance">财务部门</el-checkbox>
            <el-checkbox label="tech">技术部门</el-checkbox>
          </el-checkbox-group>
        </el-form-item>
        <el-form-item label="是否需要确认"
                      prop="requireConfirm">
          <el-switch v-model="regulationForm.requireConfirm" />
          <span class="ml-10">开启后员工需要阅读确认</span>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button type="primary" @click="submitRegulation">发布制度</el-button>
          <el-button @click="showRegulationDialog = false">取消</el-button>
        </span>
      </template>
    </el-dialog>
    <!-- ç”¨å°è¯¦æƒ…对话框(已移除) -->
    <!-- è§„章制度详情对话框 -->
    <el-dialog v-model="showRegulationDetailDialog"
               title="规章制度详情"
               width="800px">
      <div v-if="currentRegulationDetail">
        <el-descriptions :column="2"
                         border>
          <el-descriptions-item label="制度编号">{{ currentRegulationDetail.id }}</el-descriptions-item>
          <el-descriptions-item label="制度标题">{{ currentRegulationDetail.title }}</el-descriptions-item>
          <el-descriptions-item label="分类">{{ getCategoryText(currentRegulationDetail.category) }}</el-descriptions-item>
          <el-descriptions-item label="版本">{{ currentRegulationDetail.version }}</el-descriptions-item>
          <el-descriptions-item label="发布人">{{ currentRegulationDetail.createUserName }}</el-descriptions-item>
          <el-descriptions-item label="发布时间">{{ currentRegulationDetail.createTime }}</el-descriptions-item>
        </el-descriptions>
        <div class="mt-20">
          <h4>制度内容</h4>
          <div class="regulation-content">{{ currentRegulationDetail.content }}</div>
        </div>
        <!-- å¦‚æžœtableData>0 æ˜¾ç¤º -->
        <div style="margin: 10px 0;"
             v-if="tableData && tableData.length > 0">
          <el-button type="success"
                     @click="resetForm(currentRegulationDetail)">确认查看</el-button>
        </div>
      </div>
    </el-dialog>
    <!-- ç‰ˆæœ¬åŽ†å²å¯¹è¯æ¡† -->
    <el-dialog v-model="showVersionHistoryDialog"
               title="版本历史"
               width="800px">
      <el-table :data="versionHistory"
                style="width: 100%;margin-bottom: 10px">
        <el-table-column prop="version"
                         label="版本号"
                         width="100" />
        <el-table-column prop="updateTime"
                         label="更新时间"
                         width="180" />
        <el-table-column prop="createUserName"
                         label="更新人"
                         width="120" />
        <el-table-column prop="changeLog"
                         label="变更说明">
          <template #default="scope">
            <el-tag :type="scope.row.status === 'active' ? 'success' : 'info'">
              {{ scope.row.status === 'active' ? '生效中' : '已废止' }}
            </el-tag>
          </template>
        </el-table-column>
      </el-table>
    </el-dialog>
    <!-- é˜…读状态对话框 -->
    <el-dialog v-model="showReadStatusDialog"
               title="阅读状态"
               width="800px">
      <el-table :data="readStatusList"
                style="width: 100%;margin-bottom: 10px">
        <el-table-column prop="employee"
                         label="员工姓名"
                         width="120" />
        <el-table-column prop="department"
                         label="所属部门"
                         width="150" />
        <el-table-column prop="createTime"
                         label="阅读时间"
                         width="180" />
        <el-table-column prop="confirmTime"
                         label="确认时间"
                         width="180" />
        <el-table-column prop="status"
                         label="状态"
                         width="100">
          <template #default="scope">
            <el-tag :type="scope.row.status === 'confirmed' ? 'success' : 'warning'">
              {{ scope.row.status === 'confirmed' ? '已确认' : '未确认' }}
            </el-tag>
          </template>
        </el-table-column>
      </el-table>
    </el-dialog>
    <FileList v-if="fileDialogVisible"  v-model:visible="fileDialogVisible" record-type="rules_regulations_management" :record-id="recordId"  />
  </div>
</template>
<script setup>
  import { ref, reactive, onMounted, getCurrentInstance } from "vue";
  import { ElMessage, ElMessageBox } from "element-plus";
  import {
    listRuleManagement,
    addRuleManagement,
    updateRuleManagement,
    delRuleManagement,
    getReadingStatusByRuleId,
    addReadingStatus,
    updateReadingStatus,
  } from "@/api/collaborativeApproval/sealManagement.js";
  const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
  import {
    listRuleFiles,
    delRuleFile,
    addRuleFile,
  } from "@/api/collaborativeApproval/rulesRegulationsManagementFile.js";
  import PIMTable from "@/components/PIMTable/PIMTable.vue";
  // å“åº”式数据
  const operationType = ref("add");
  const tableData = ref([]);
  const tableLoading = ref(false);
  // åˆ†é¡µå‚æ•°
  const page = reactive({
    current: 1,
    size: 10,
    total: 0,
  });
  // é™„件弹窗
  const currentFileRuleId = ref(null);
  // è§„章制度相关
  const showRegulationDialog = ref(false);
  const showRegulationDetailDialog = ref(false);
  const showVersionHistoryDialog = ref(false);
  const showReadStatusDialog = ref(false);
  const currentRegulationDetail = ref(null);
  const regulationFormRef = ref();
  const regulationForm = reactive({
    id: "",
    regulationNum: "",
    title: "",
    category: "",
    content: "",
    version: "",
    status: "active",
    readCount: 0,
    effectiveTime: "",
    scope: [],
    requireConfirm: false,
  });
  const readStatus = ref({
    id: "",
    ruleId: "",
    employee: "",
    department: "",
    createTime: "",
    confirmTime: "",
    status: "unconfirmed",
  });
  const regulationRules = {
    title: [{ required: true, message: "请输入制度标题", trigger: "blur" }],
    category: [{ required: true, message: "请选择制度分类", trigger: "change" }],
    content: [{ required: true, message: "请输入制度内容", trigger: "blur" }],
    effectiveTime: [
      { required: true, message: "请选择生效时间", trigger: "change" },
    ],
    scope: [{ required: true, message: "请选择适用范围", trigger: "change" }],
  };
  const regulationSearchForm = reactive({
    title: "",
    category: "",
  });
  const regulations = ref([]);
  // è¡¨æ ¼åˆ—配置
  const regulationTableColumn = ref([
    { label: "制度编号", prop: "regulationNum"},
    { label: "制度标题", prop: "title" },
    {
      label: "分类",
      prop: "category",
      dataType: "tag",
      formatData: (v) => getCategoryText(v),
      formatType: () => "info",
    },
    { label: "版本", prop: "version", width: 120 },
    { label: "发布人", prop: "createUserName", width: 120 },
    { label: "发布时间", prop: "createTime", width: 180 },
    {
      label: "状态",
      prop: "status",
      width: 100,
      dataType: "tag",
      formatData: (v) => (v === "active" ? "生效中" : "已废止"),
      formatType: (v) => (v === "active" ? "success" : "info"),
    },
    { label: "已读人数", prop: "readCount", width: 100 },
    {
      dataType: "action",
      label: "操作",
      width: 320,
      fixed: "right",
      align: "center",
      operation: [
        { name: "编辑", clickFun: (row) => handleEdit(row) },
        { name: "废弃", clickFun: (row) => repealEdit(row) },
        { name: "版本历史", clickFun: (row) => viewVersionHistory(row) },
        { name: "详情", clickFun: (row) => viewRegulation(row) },
        { name: "附件", clickFun: (row) => openFileDialog(row) },
      ],
    },
  ]);
  const versionHistory = ref([]);
  const readStatusList = ref([]);
  // { employee: '陈志强', department: '销售部', readTime: '2025-01-11 10:30:00', confirmTime: '2025-01-11 10:35:00', status: 'confirmed' },
  // { employee: '刘雅婷', department: '技术部', readTime: '2025-01-11 14:20:00', confirmTime: '', status: 'unconfirmed' },
  // { employee: '王建国', department: '财务部', readTime: '2025-01-12 09:15:00', confirmTime: '2025-01-12 09:20:00', status: 'confirmed' }
  // åˆ¶åº¦åˆ†ç±»
  const getCategoryText = category => {
    const categoryMap = {
      hr: "人事制度",
      finance: "财务制度",
      safety: "安全制度",
      tech: "技术制度",
    };
    return categoryMap[category] || "未知";
  };
  // æœç´¢åˆ¶åº¦
  const searchRegulations = () => {
    page.current = 1;
    getRegulationList();
  };
  // é‡ç½®åˆ¶åº¦æœç´¢
  const resetRegulationSearch = () => {
    regulationSearchForm.title = "";
    regulationSearchForm.category = "";
    searchRegulations();
  };
  // æ–°å¢ž
  const handleAdd = () => {
    operationType.value = "add";
    resetRegulationForm();
    showRegulationDialog.value = true;
  };
  // ç¼–辑
  const handleEdit = row => {
    operationType.value = "edit";
    Object.assign(regulationForm, row);
    showRegulationDialog.value = true;
  };
  // åºŸå¼ƒ
  const repealEdit = row => {
    operationType.value = "edit";
    Object.assign(regulationForm, row);
    regulationForm.status = "repealed";
    ElMessageBox.confirm("确认废弃该制度?", "提示", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning",
    })
      .then(() => {
        updateRuleManagement(regulationForm).then(res => {
          if (res.code == 200) {
            ElMessage.success("制度废弃成功");
            // showRegulationDialog.value = false
            getRegulationList();
            resetRegulationForm();
          }
        });
      })
      .catch(() => {
        ElMessage({
          type: "info",
          message: "已取消废弃",
        });
      });
  };
  // å‘布制度
  const submitRegulation = async () => {
    try {
      await regulationFormRef.value.validate();
      if (operationType.value == "add") {
        addRuleManagement(regulationForm).then(res => {
          if (res.code == 200) {
            ElMessage.success("制度发布成功");
            showRegulationDialog.value = false;
            getRegulationList();
            resetRegulationForm();
          }
        });
      } else {
        updateRuleManagement(regulationForm).then(res => {
          if (res.code == 200) {
            ElMessage.success("制度编辑成功");
            showRegulationDialog.value = false;
            resetRegulationForm();
            getRegulationList();
          }
        });
      }
    } catch (err) {
      ElMessage.error(err.msg);
    }
  };
  //重置制度表单
  const resetRegulationForm = () => {
    Object.assign(regulationForm, {
      id: "",
      regulationNum: "",
      title: "",
      category: "",
      content: "",
      version: "",
      status: "active",
      readCount: 0,
      effectiveTime: "",
      scope: [],
      requireConfirm: false,
    });
  };
  // æŸ¥çœ‹åˆ¶åº¦ç‰ˆæœ¬åŽ†å²
  const viewVersionHistory = row => {
    showVersionHistoryDialog.value = true;
    const params = {
      category: row.category,
    };
    listRuleManagement(page, params).then(res => {
      if (res.code == 200) {
        versionHistory.value = res.data.records;
      }
    });
  };
  // æŸ¥çœ‹åˆ¶åº¦è¯¦æƒ…
  const viewRegulation = row => {
    currentRegulationDetail.value = row;
    showRegulationDetailDialog.value = true;
    getReadingStatusByRuleId(row.id).then(res => {
      if (res.code == 200) {
        readStatusList.value = res.data;
        if (readStatusList.value.length == 0 && tableData.value.length > 0) {
          const params = {
            ruleId: row.id,
            employee: tableData.value[0].staffName,
            department: tableData.value[0].postJob,
            status: "unconfirmed",
          };
          addReadingStatus(params).then(res => {
            if (res.code == 200) {
              ElMessage.success("制度阅读成功");
            }
          });
        }
      }
    });
  };
  // æŸ¥çœ‹åˆ¶åº¦é˜…读状态
  const viewReadStatus = row => {
    showReadStatusDialog.value = true;
    //查看阅读状态列表
    getReadingStatusByRuleId(row.id).then(res => {
      if (res.code == 200) {
        readStatusList.value = res.data;
      }
    });
  };
  //确认查看
  const resetForm = row => {
    console.log("row", row);
    row.readCount = row.readCount + 1;
    updateRuleManagement(row).then(res => {
      if (res.code == 200) {
        ElMessage.success("查看数量修改成功");
        //修改阅读状态
        //根据制度id和当前登录的员工得到阅读状态
        // let item = readStatusList.value.filter(item => item.employee == tableData.value[0].staffName )
        // if(item.length>0){
        //   item[0].status = 'confirmed',
        //   item[0].confirmTime = new Date().toISOString().replace('T', ' ').split('.')[0];
        // }
        // ç­›é€‰å½“前员工对应该制度的阅读状态记录
        let statusItem = readStatusList.value.find(
          item =>
            item.employee === tableData.value[0].staffName &&
            item.ruleId === row.id
        );
        if (statusItem) {
          // å¦‚果找到记录,更新状态和确认时间
          statusItem.status = "confirmed";
          // æ ¼å¼åŒ–时间为"YYYY-MM-DD HH:mm:ss"格式
          const now = new Date();
          statusItem.confirmTime = `${now.getFullYear()}-${String(
            now.getMonth() + 1
          ).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")} ${String(
            now.getHours()
          ).padStart(2, "0")}:${String(now.getMinutes()).padStart(
            2,
            "0"
          )}:${String(now.getSeconds()).padStart(2, "0")}`;
          // statusItem.confirmTime = new Date().toISOString().replace('T', ' ').split('.')[0];
          updateReadingStatus(statusItem).then(res => {
            if (res.code == 200) {
              ElMessage.success("制度阅读状态修改成功");
            }
          });
        }
      }
    });
  };
  // å¯¼å‡ºè§„章制度
  const { proxy } = getCurrentInstance();
  const handleExport = () => {
    proxy.download(
      "/rulesRegulationsManagement/export",
      { ...regulationSearchForm },
      "规章制度.xlsx"
    );
  };
  // æ‰“开附件弹窗
  const recordId =ref(0)
  const fileDialogVisible = ref(false)
  // æ‰“开附件弹框
  const openFileDialog = async (row) => {
    recordId.value = row.id
    fileDialogVisible.value = true
  }
  // èŽ·å–è§„ç« åˆ¶åº¦åˆ—è¡¨æ•°æ®
  const getRegulationList = async () => {
    tableLoading.value = true;
    listRuleManagement(page, regulationSearchForm)
      .then(res => {
        regulations.value = res.data.records;
        // è¿‡æ»¤æŽ‰å·²åºŸå¼ƒçš„制度
        // regulations.value = res.data.records.filter(item => item.status !== 'repealed')
        page.total = res.data.total;
        tableLoading.value = false;
      })
      .catch(err => {
        tableLoading.value = false;
      });
  };
  // åˆ†é¡µå˜åŒ–处理
  const paginationChange = (obj) => {
    page.current = obj.page;
    page.size = obj.limit;
    getRegulationList();
  };
  onMounted(() => {
    // åˆå§‹åŒ–
    getRegulationList();
  });
</script>
<style scoped>
  .app-container {
    padding: 20px;
  }
  .card-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
  .tab-content {
    padding: 20px 0;
  }
  .mb-20 {
    margin-bottom: 20px;
  }
  .mt-20 {
    margin-top: 20px;
  }
  .ml-10 {
    margin-left: 10px;
  }
  .regulation-content {
    background-color: #f5f5f5;
    padding: 15px;
    border-radius: 4px;
    line-height: 1.6;
    white-space: pre-wrap;
    height: 200px;
  }
  .dialog-footer {
    text-align: center;
  }
</style>