已添加1个文件
已修改6个文件
1406 ■■■■■ 文件已修改
src/api/collaborativeApproval/noticeManagement.js 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/collaborativeApproval/rulesRegulationsManagementFile.js 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Dialog/FileListDialog.vue 152 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/knowledgeBase/index.vue 181 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/noticeManagement/index.vue 629 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/rulesRegulationsManagement/index.vue 337 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/sealManagement/index.vue 53 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/collaborativeApproval/noticeManagement.js
@@ -50,3 +50,29 @@
        method: 'get',
    })
}
// æŸ¥è¯¢å…¬å‘Šç±»åž‹åˆ—表
export function listNoticeType() {
    return request({
        url: '/noticeType/list',
        method: 'get'
    })
}
// æ–°å¢žå…¬å‘Šç±»åž‹
export function addNoticeType(data) {
    return request({
        url: '/noticeType/add',
        method: 'post',
        data: data
    })
}
// åˆ é™¤å…¬å‘Šç±»åž‹
export function delNoticeType(id) {
    return request({
        url: '/noticeType/del',
        method: 'delete',
        data: { id }
    })
}
src/api/collaborativeApproval/rulesRegulationsManagementFile.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
import request from "@/utils/request";
// é™„件列表
export function listRuleFiles(query) {
  return request({
    url: "/rulesRegulationsManagementFile/listPage",
    method: "get",
    params: query,
  });
}
// æ–°å¢žé™„ä»¶
export function addRuleFile(data) {
  return request({
    url: "/rulesRegulationsManagementFile/add",
    method: "post",
    data,
  });
}
// åˆ é™¤é™„件(支持传递 id æ•°ç»„)
export function delRuleFile(ids) {
  return request({
    url: "/rulesRegulationsManagementFile/del",
    method: "delete",
    data: ids,
  });
}
src/components/Dialog/FileListDialog.vue
@@ -5,6 +5,37 @@
    :width="width" 
    :before-close="handleClose"
  >
    <div class="file-list-toolbar" v-if="showToolbar">
      <template v-if="useBuiltInUpload">
        <el-upload
          v-model:file-list="uploadFileList"
          class="upload-demo"
          :action="uploadAction"
          :headers="uploadHeaders"
          :show-file-list="false"
          :on-success="handleDefaultUploadSuccess"
          :on-error="handleDefaultUploadError"
        >
          <el-button
            v-if="showUploadButton"
            type="primary"
            size="small"
          >
            ä¸Šä¼ é™„ä»¶
          </el-button>
        </el-upload>
      </template>
      <template v-else>
        <el-button
          v-if="showUploadButton"
          type="primary"
          size="small"
          @click="handleUpload"
        >
          æ–°å¢žé™„ä»¶
        </el-button>
      </template>
    </div>
    <el-table :data="tableData" border :height="tableHeight">
      <el-table-column 
        :label="nameColumnLabel" 
@@ -38,6 +69,15 @@
          >
            é¢„览
          </el-button>
          <el-button
            v-if="showDeleteButton"
            link
            type="danger"
            size="small"
            @click="handleDelete(scope.row, scope.$index)"
          >
            åˆ é™¤
          </el-button>
          <slot name="actions" :row="scope.row"></slot>
        </template>
      </el-table-column>
@@ -49,7 +89,9 @@
<script setup>
import { ref, computed, getCurrentInstance } from 'vue'
import { ElMessage } from 'element-plus'
import filePreview from '@/components/filePreview/index.vue'
import { getToken } from '@/utils/auth'
const props = defineProps({
  modelValue: {
@@ -82,7 +124,7 @@
  },
  actionColumnWidth: {
    type: [String, Number],
    default: 100
    default: 160
  },
  showActions: {
    type: Boolean,
@@ -96,6 +138,14 @@
    type: Boolean,
    default: true
  },
  showUploadButton: {
    type: Boolean,
    default: false
  },
  showDeleteButton: {
    type: Boolean,
    default: false
  },
  urlField: {
    type: String,
    default: 'url'
@@ -107,13 +157,30 @@
  previewMethod: {
    type: Function,
    default: null
  },
  uploadMethod: {
    type: Function,
    default: null
  },
  deleteMethod: {
    type: Function,
    default: null
  },
  rulesRegulationsManagementId: {
    type: [String, Number],
    default: ''
  },
  uploadUrl: {
    type: String,
    default: `${import.meta.env.VITE_APP_BASE_API}/file/upload`
  }
})
const emit = defineEmits(['update:modelValue', 'close', 'download', 'preview'])
const emit = defineEmits(['update:modelValue', 'close', 'download', 'preview', 'upload', 'delete'])
const { proxy } = getCurrentInstance()
const filePreviewRef = ref(null)
const uploadFileList = ref([])
const dialogVisible = computed({
  get: () => props.modelValue,
@@ -121,6 +188,12 @@
})
const tableData = ref([])
const showToolbar = computed(() => props.showUploadButton)
const useBuiltInUpload = computed(() => !props.uploadMethod)
const uploadAction = computed(() => props.uploadUrl)
const uploadHeaders = computed(() => ({
  Authorization: `Bearer ${getToken()}`
}))
const handleClose = () => {
  emit('close')
@@ -154,11 +227,84 @@
  tableData.value = list || []
}
const handleUpload = async () => {
  if (props.uploadMethod) {
    const newItem = await props.uploadMethod()
    if (newItem) {
      addAttachment(newItem)
    }
  }
  emit('upload')
}
const handleDelete = async (row, index) => {
  if (props.deleteMethod) {
    const result = await props.deleteMethod(row, index)
    if (result === false) {
      return
    }
    // å¦‚果提供了 deleteMethod,由父组件负责刷新列表,不在这里删除
  } else {
    // å¦‚果没有提供 deleteMethod,才在组件内部删除
    removeAttachment(index)
  }
  emit('delete', row)
}
const addAttachment = (item) => {
  tableData.value = [...tableData.value, item]
}
const handleDefaultUploadSuccess = async (res, file) => {
  if (res?.code !== 200) {
    ElMessage.error(res?.msg || '文件上传失败')
    return
  }
  if (!props.rulesRegulationsManagementId) {
    ElMessage.error('缺少规章制度ID,无法保存附件')
    return
  }
  const fileName = res?.data?.originalName || file?.name
  const fileUrl = res?.data?.tempPath || res?.data?.url
  const payload = {
    fileName,
    fileUrl,
    rulesRegulationsManagementId: props.rulesRegulationsManagementId,
    raw: res?.data || {}
  }
  emit('upload', payload)
}
const handleDefaultUploadError = () => {
  ElMessage.error('文件上传失败')
}
const removeAttachment = (index) => {
  if (index > -1 && index < tableData.value.length) {
    const newList = [...tableData.value]
    newList.splice(index, 1)
    tableData.value = newList
  }
}
const setList = (list) => {
  tableData.value = list || []
}
defineExpose({
  open
  open,
  addAttachment,
  removeAttachment,
  setList,
  handleUpload,
  handleDelete
})
</script>
<style scoped>
.file-list-toolbar {
  margin-bottom: 8px;
  text-align: right;
}
</style>
src/views/collaborativeApproval/knowledgeBase/index.vue
@@ -13,11 +13,12 @@
        />
        <span class="search_title ml10">知识类型:</span>
        <el-select v-model="searchForm.type" clearable @change="handleQuery" style="width: 240px">
          <el-option label="合同特批" :value="'contract'" />
          <el-option label="审批案例" :value="'approval'" />
          <el-option label="解决方案" :value="'solution'" />
          <el-option label="经验总结" :value="'experience'" />
          <el-option label="操作指南" :value="'guide'" />
          <el-option
              v-for="item in knowledgeTypeOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
          />
        </el-select>
        <el-button type="primary" @click="handleQuery" style="margin-left: 10px">
          æœç´¢
@@ -61,11 +62,12 @@
          <el-col :span="12">
            <el-form-item label="知识类型" prop="type">
              <el-select v-model="form.type" placeholder="请选择知识类型" style="width: 100%">
                <el-option label="合同特批" value="contract" />
                <el-option label="审批案例" value="approval" />
                <el-option label="解决方案" value="solution" />
                <el-option label="经验总结" value="experience" />
                <el-option label="操作指南" value="guide" />
                <el-option
                    v-for="item in knowledgeTypeOptions"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value"
                />
              </el-select>
            </el-form-item>
          </el-col>
@@ -231,7 +233,7 @@
<script setup>
import { Search } from "@element-plus/icons-vue";
import { onMounted, ref, reactive, toRefs, getCurrentInstance } from "vue";
import { onMounted, ref, reactive, toRefs, getCurrentInstance, computed } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import PIMTable from "@/components/PIMTable/PIMTable.vue";
import { listKnowledgeBase, delKnowledgeBase,addKnowledgeBase,updateKnowledgeBase } from "@/api/collaborativeApproval/knowledgeBase.js";
@@ -313,24 +315,10 @@
    prop: "type",
    dataType: "tag",
    formatData: (params) => {
      const typeMap = {
        contract: "合同特批",
        approval: "审批案例",
        solution: "解决方案",
        experience: "经验总结",
        guide: "操作指南"
      };
      return typeMap[params] || params;
      return getKnowledgeTypeLabel(params);
    },
    formatType: (params) => {
      const typeMap = {
        contract: "success",
        approval: "warning",
        solution: "primary",
        experience: "info",
        guide: "danger"
      };
      return typeMap[params] || "info";
      return getKnowledgeTypeTagType(params);
    }
  },
  {
@@ -401,111 +389,6 @@
  }
]);
// æ¨¡æ‹Ÿæ•°æ®
// let mockData = [
//   {
//     id: "1",
//     title: "特殊合同审批流程优化方案",
//     type: "contract",
//     scenario: "大额合同快速审批",
//     efficiency: "high",
//     problem: "大额合同审批流程复杂,审批时间长,影响业务进展",
//     solution: "建立绿色通道,对符合条件的合同采用简化审批流程,由部门负责人直接审批,平均审批时间从3天缩短至1天",
//     keyPoints: "绿色通道条件,简化流程,审批权限,时间控制",
//     creator: "张经理",
//     usageCount: 15,
//     createTime: "2024-01-15 10:30:00"
//   },
//   {
//     id: "2",
//     title: "跨部门协作审批经验总结",
//     type: "experience",
//     scenario: "多部门协作项目",
//     efficiency: "medium",
//     problem: "跨部门项目审批时,各部门意见不统一,审批进度缓慢",
//     solution: "建立项目协调机制,指定项目负责人,定期召开协调会议,统一各方意见后再进行审批",
//     keyPoints: "项目协调,定期会议,统一意见,负责人制度",
//     creator: "李主管",
//     usageCount: 8,
//     createTime: "2024-01-14 15:20:00"
//   },
//   {
//     id: "3",
//     title: "紧急采购审批操作指南",
//     type: "guide",
//     scenario: "紧急采购需求",
//     efficiency: "high",
//     problem: "紧急采购时审批流程复杂,无法满足紧急需求",
//     solution: "制定紧急采购审批标准,明确紧急程度分级,不同级别采用不同审批流程,确保紧急需求得到及时处理",
//     keyPoints: "紧急分级,标准制定,流程简化,及时处理",
//     creator: "王专员",
//     usageCount: 12,
//     createTime: "2024-01-13 09:15:00"
//   }
// ];
// çŸ¥è¯†æ ‡é¢˜æ¨¡æ¿
const titleTemplates = [
  "{type}审批流程优化方案",
  "{scenario}处理经验总结",
  "{type}特殊情况处理指南",
  "{scenario}快速审批方案",
  "{type}标准化操作流程",
  "{scenario}问题解决方案",
  "{type}最佳实践总结",
  "{scenario}效率提升方案"
];
// çŸ¥è¯†ç±»åž‹é…ç½®
const knowledgeTypes = [
  { type: "contract", label: "合同特批", efficiency: "high" },
  { type: "approval", label: "审批案例", efficiency: "medium" },
  { type: "solution", label: "解决方案", efficiency: "high" },
  { type: "experience", label: "经验总结", efficiency: "medium" },
  { type: "guide", label: "操作指南", efficiency: "low" }
];
// åœºæ™¯åˆ—表
const scenarios = ["大额合同审批", "跨部门协作", "紧急采购", "特殊申请", "流程优化", "问题处理", "标准化建设", "效率提升"];
// è‡ªåŠ¨ç”Ÿæˆæ–°æ•°æ®
const generateNewData = () => {
  const newId = (mockData.length + 1).toString();
  const now = new Date();
  const randomType = knowledgeTypes[Math.floor(Math.random() * knowledgeTypes.length)];
  const randomScenario = scenarios[Math.floor(Math.random() * scenarios.length)];
  // ç”Ÿæˆéšæœºæ ‡é¢˜
  let title = titleTemplates[Math.floor(Math.random() * titleTemplates.length)];
  title = title
    .replace('{type}', randomType.label)
    .replace('{scenario}', randomScenario);
  const newKnowledge = {
    id: newId,
    title: title,
    type: randomType.type,
    scenario: randomScenario,
    efficiency: randomType.efficiency,
    problem: `在${randomScenario}过程中遇到的问题描述...`,
    solution: `针对${randomScenario}的解决方案和操作步骤...`,
    keyPoints: "关键要点1,关键要点2,关键要点3,关键要点4",
    creator: ["张经理", "李主管", "王专员", "刘总监"][Math.floor(Math.random() * 4)],
    usageCount: Math.floor(Math.random() * 20) + 1,
    createTime: now.toLocaleString()
  };
  // æ·»åŠ åˆ°æ•°æ®å¼€å¤´
  mockData.unshift(newKnowledge);
  // ä¿æŒæ•°æ®é‡åœ¨åˆç†èŒƒå›´å†…(最多保留30条)
  if (mockData.length > 30) {
    mockData = mockData.slice(0, 30);
  }
  console.log(`[${new Date().toLocaleString()}] è‡ªåŠ¨ç”Ÿæˆæ–°çŸ¥è¯†: ${title}`);
};
// ç”Ÿå‘½å‘¨æœŸ
onMounted(() => {
  getList();
@@ -515,7 +398,6 @@
// å¼€å§‹è‡ªåŠ¨åˆ·æ–°
const startAutoRefresh = () => {
  setInterval(() => {
    generateNewData();
    getList();
  }, 600000); // 10分钟刷新一次 (10 * 60 * 1000 = 600000ms)
};
@@ -605,14 +487,7 @@
// èŽ·å–ç±»åž‹æ ‡ç­¾æ–‡æœ¬
const getTypeLabel = (type) => {
  const typeMap = {
    contract: "合同特批",
    approval: "审批案例",
    solution: "解决方案",
    experience: "经验总结",
    guide: "操作指南"
  };
  return typeMap[type] || type;
  return getKnowledgeTypeLabel(type);
};
// èŽ·å–æ•ˆçŽ‡æ ‡ç­¾ç±»åž‹
@@ -675,18 +550,6 @@
  });
};
// æ”¶è—çŸ¥è¯†
const markAsFavorite = () => {
  // å¢žåŠ ä½¿ç”¨æ¬¡æ•°
  const index = mockData.findIndex(item => item.id === currentKnowledge.value.id);
  if (index !== -1) {
    mockData[index].usageCount += 1;
    currentKnowledge.value.usageCount += 1;
  }
  ElMessage.success("已收藏,使用次数+1");
};
// æäº¤çŸ¥è¯†è¡¨å•
const submitForm = async () => {
  try {
@@ -745,6 +608,18 @@
// å¯¼å‡º
const { proxy } = getCurrentInstance()
const { knowledge_type } = proxy.useDict("knowledge_type")
// å­—典工具
const knowledgeTypeOptions = computed(() => knowledge_type?.value || [])
const getKnowledgeTypeLabel = (val) => {
  const item = knowledgeTypeOptions.value.find(i => String(i.value) === String(val))
  return item ? item.label : val
}
const getKnowledgeTypeTagType = (val) => {
  const item = knowledgeTypeOptions.value.find(i => String(i.value) === String(val))
  return item?.elTagType || "info"
}
const handleExport = () => {
  proxy.download('/knowledgeBase/export', { ...searchForm.value }, '知识库.xlsx')
}
src/views/collaborativeApproval/noticeManagement/index.vue
@@ -4,136 +4,89 @@
    <div class="search_form">
      <div>
        <el-button type="primary" @click="openForm('add')">新增公告</el-button>
        <el-button type="danger" plain @click="handleDelete" :disabled="!selectedIds.length">删除</el-button>
        <el-button type="info" @click="openNoticeTypeDialog">公告类型配置</el-button>
      </div>
    </div>
    <!-- é€šçŸ¥å…¬å‘Šæ¿ -->
    <div class="notice-board">
      <!-- æ”¾å‡é€šçŸ¥åŒºåŸŸ -->
      <div class="notice-section" v-if="holidayNoticeCount > 0">
        <div class="section-header">
          <h3>📅 æ”¾å‡é€šçŸ¥</h3>
          <span class="section-count">{{ holidayNoticeCount }}条</span>
        </div>
        <div class="notice-cards">
          <div
              v-for="notice in holidayNotices"
              :key="notice.id"
              class="notice-card holiday-card"
              :class="{ 'urgent': notice.priority === '3' }"
          >
            <div class="card-header">
              <div class="card-title">
                <el-icon class="holiday-icon">
                  <Calendar/>
                </el-icon>
                {{ notice.title }}
              </div>
              <div class="card-actions">
                <el-button link type="primary" @click="handleEdit(notice)" :disabled="isNoticeExpired(notice)">编辑</el-button>
                <el-button link type="danger" @click="handleDelete(notice.id)">删除</el-button>
      <el-tabs v-model="activeNoticeTypeTab" @tab-change="handleNoticeTypeTabChange">
        <el-tab-pane
            v-for="noticeType in noticeTypeList"
            :key="noticeType.id"
            :label="noticeType.noticeType"
            :name="String(noticeType.id)"
        >
          <template #label>
            <span>{{ noticeType.noticeType }}
              <span class="tab-count" v-if="getNoticeCountByType(noticeType.id) > 0">
                ({{ getNoticeCountByType(noticeType.id) }})
              </span>
            </span>
          </template>
          <div class="notice-section">
            <div class="notice-cards">
              <div
                  v-for="notice in getNoticesByType(noticeType.id)"
                  :key="notice.id"
                  class="notice-card"
                  :class="{ 'urgent': notice.priority === '3' }"
              >
                <div class="card-header">
                  <div class="card-title">
                    <el-icon class="notice-icon">
                      <Calendar/>
                    </el-icon>
                    {{ notice.title }}
                  </div>
                  <div class="card-actions">
                    <el-button link type="primary" @click="handleEdit(notice)" :disabled="isNoticeExpired(notice)" v-if="notice.status !== 1">编辑</el-button>
                    <el-button link type="success" @click="handlePublish(notice)" v-if="notice.status === 0">发布</el-button>
                    <el-button link type="danger" @click="handleDelete(notice.id)" v-if="notice.status !== 1">删除</el-button>
                  </div>
                </div>
                <div class="card-content">
                  <p>{{ notice.content }}</p>
                </div>
                <div class="card-footer">
                  <div class="card-meta">
                    <span class="priority" :class="'priority-' + notice.priority">
                      {{ getPriorityText(notice.priority) }}
                    </span>
                    <span class="status" :class="'status-' + getNoticeStatus(notice)">
                      {{ getStatusText(getNoticeStatus(notice)) }}
                    </span>
                  </div>
                  <div class="card-info">
                    <span class="creator">{{ notice.createUserName }}</span>
                    <span class="expiration" v-if="notice.expirationDate">截止日期:{{ notice.expirationDate }}</span>
                  </div>
                </div>
                <div class="card-remark" v-if="notice.remark">
                  <el-icon>
                    <InfoFilled/>
                  </el-icon>
                  <span>{{ notice.remark }}</span>
                </div>
              </div>
            </div>
            <div class="card-content">
              <p>{{ notice.content }}</p>
            </div>
            <div class="card-footer">
              <div class="card-meta">
                <span class="priority" :class="'priority-' + notice.priority">
                  {{ getPriorityText(notice.priority) }}
                </span>
                <span class="status" :class="'status-' + getNoticeStatus(notice)">
                  {{ getStatusText(getNoticeStatus(notice)) }}
                </span>
              </div>
              <div class="card-info">
                <span class="creator">{{ notice.createUserName }}</span>
              <span class="expiration" v-if="notice.expirationDate">截止日期:{{ notice.expirationDate }}</span>
              </div>
            </div>
            <div class="card-remark" v-if="notice.remark">
              <el-icon>
                <InfoFilled/>
              </el-icon>
              <span>{{ notice.remark }}</span>
            <pagination
                v-if="getNoticePageByType(noticeType.id).total > 0"
                :total="getNoticePageByType(noticeType.id).total"
                :page="getNoticePageByType(noticeType.id).current"
                :limit="getNoticePageByType(noticeType.id).size"
                @pagination="(val) => handleNoticeCurrentChange(noticeType.id, val)"
            />
            <!-- ç©ºçŠ¶æ€ -->
            <div class="empty-state" v-if="getNoticesByType(noticeType.id).length === 0">
              <el-empty description="暂无通知公告"/>
            </div>
          </div>
        </div>
      </div>
      <pagination
          v-if="holidayNoticePage.total > 0"
          :total="holidayNoticePage.total"
          :page="holidayNoticePage.current"
          :limit="holidayNoticePage.size"
          @pagination="handleHolidayNoticeCurrentChange"
      />
      <!-- è®¾å¤‡ç»´ä¿®é€šçŸ¥åŒºåŸŸ -->
      <div class="notice-section" v-if="maintenanceNoticeCount > 0">
        <div class="section-header">
          <h3>🔧 è®¾å¤‡ç»´ä¿®é€šçŸ¥</h3>
          <span class="section-count">{{ maintenanceNoticeCount }}条</span>
        </div>
        <div class="notice-cards">
          <div
              v-for="notice in maintenanceNotices"
              :key="notice.id"
              class="notice-card maintenance-card"
              :class="{ 'urgent': notice.priority === '3' }"
          >
            <div class="card-header">
              <div class="card-title">
                <el-icon class="maintenance-icon">
                  <Tools/>
                </el-icon>
                {{ notice.title }}
              </div>
              <div class="card-actions">
                <el-button link type="primary" @click="handleEdit(notice)" :disabled="isNoticeExpired(notice)">编辑</el-button>
                <el-button link type="danger" @click="handleDelete(notice.id)">删除</el-button>
              </div>
            </div>
            <div class="card-content">
              <p>{{ notice.content }}</p>
            </div>
            <div class="card-footer">
              <div class="card-meta">
                <span class="priority" :class="'priority-' + notice.priority">
                  {{ getPriorityText(notice.priority) }}
                </span>
                <span class="status" :class="'status-' + getNoticeStatus(notice)">
                  {{ getStatusText(getNoticeStatus(notice)) }}
                </span>
              </div>
              <div class="card-info">
                <span class="creator">{{ notice.createUserName }}</span>
              <span class="expiration" v-if="notice.expirationDate">截止日期:{{ notice.expirationDate }}</span>
              </div>
            </div>
            <div class="card-remark" v-if="notice.remark">
              <el-icon>
                <InfoFilled/>
              </el-icon>
              <span>{{ notice.remark }}</span>
            </div>
          </div>
        </div>
      </div>
      <pagination
          v-if="maintenanceNoticePage.total > 0"
          :total="maintenanceNoticePage.total"
          :page="maintenanceNoticePage.current"
          :limit="maintenanceNoticePage.size"
          @pagination="handleMaintenanceNoticeCurrentChange"
      />
      <!-- ç©ºçŠ¶æ€ -->
      <div class="empty-state" v-if="holidayNotices.length === 0 && maintenanceNotices.length === 0">
        <el-empty description="暂无通知公告"/>
      </div>
        </el-tab-pane>
      </el-tabs>
    </div>
    <!-- æ–°å¢ž/编辑对话框 -->
@@ -154,8 +107,12 @@
          <el-col :span="12">
            <el-form-item label="公告类型" prop="type">
              <el-select v-model="form.type" placeholder="请选择公告类型" style="width: 100%">
                <el-option label="放假通知" :value="1"/>
                <el-option label="设备维修通知" :value="2"/>
                <el-option
                    v-for="item in noticeTypeList"
                    :key="item.id"
                    :label="item.noticeType"
                    :value="item.id"
                />
              </el-select>
            </el-form-item>
          </el-col>
@@ -223,24 +180,96 @@
        </div>
      </template>
    </el-dialog>
    <!-- å…¬å‘Šç±»åž‹é…ç½®å¼¹æ¡† -->
    <el-dialog
        v-model="noticeTypeDialogVisible"
        title="公告类型配置"
        width="800px"
        @close="handleNoticeTypeDialogClose"
    >
      <div class="notice-type-container">
        <div class="notice-type-header">
          <el-button type="primary" @click="handleAddNoticeType">新增类型</el-button>
        </div>
        <el-table :data="noticeTypeList" border style="width: 100%">
          <el-table-column prop="id" label="ID" width="80" align="center"/>
          <el-table-column prop="noticeType" label="公告类型" align="center">
            <template #default="scope">
              <el-input
                  v-if="scope.row.editing"
                  v-model="scope.row.noticeType"
                  placeholder="请输入公告类型"
              />
              <span v-else>{{ scope.row.noticeType }}</span>
            </template>
          </el-table-column>
          <el-table-column label="操作" width="200" align="center">
            <template #default="scope">
              <el-button
                  v-if="scope.row.editing"
                  link
                  type="primary"
                  size="small"
                  @click="handleSaveNoticeType(scope.row)"
              >
                ä¿å­˜
              </el-button>
              <el-button
                  v-if="scope.row.editing"
                  link
                  type="info"
                  size="small"
                  @click="handleCancelEdit(scope.row)"
              >
                å–消
              </el-button>
              <el-button
                  v-if="!scope.row.editing"
                  link
                  type="primary"
                  size="small"
                  @click="handleEditNoticeType(scope.row)"
              >
                ç¼–辑
              </el-button>
              <el-button
                  v-if="!scope.row.editing"
                  link
                  type="danger"
                  size="small"
                  @click="handleDeleteNoticeType(scope.row)"
              >
                åˆ é™¤
              </el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>
    </el-dialog>
  </div>
</template>
<script setup>
import {Search, Calendar, Tools, InfoFilled} from "@element-plus/icons-vue";
import {Calendar, InfoFilled} from "@element-plus/icons-vue";
import {onMounted, ref, reactive, toRefs, computed} from "vue";
import {ElMessage, ElMessageBox} from "element-plus";
import {useRoute} from "vue-router";
import useUserStore from "@/store/modules/user";
import {
  addNotice,
  delNotice,
  getCount,
  listNotice,
  updateNotice
  updateNotice,
  listNoticeType,
  addNoticeType,
  delNoticeType
} from "../../../api/collaborativeApproval/noticeManagement.js";
import pagination from "../../../components/PIMTable/Pagination.vue";
const userStore = useUserStore();
const route = useRoute();
// å“åº”式数据
const data = reactive({
@@ -280,8 +309,16 @@
// é¡µé¢çŠ¶æ€
const dialogVisible = ref(false);
const dialogTitle = ref("");
const selectedIds = ref([]);
const formRef = ref();
// å…¬å‘Šç±»åž‹é…ç½®ç›¸å…³
const noticeTypeDialogVisible = ref(false);
const noticeTypeList = ref([]);
const activeNoticeTypeTab = ref('');
// é€šçŸ¥æ•°æ® - ä½¿ç”¨ Map å­˜å‚¨ï¼Œkey ä¸ºç±»åž‹ id
const noticesMap = ref({});
const noticePagesMap = ref({});
// è®¡ç®—属性
@@ -398,6 +435,28 @@
  });
};
const handlePublish = (notice) => {
  ElMessageBox.confirm(
      "确认发布这条公告吗?",
      "提示",
      {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "info"
      }
  ).then(() => {
    updateNotice({
      ...notice,
      status: 1
    }).then(res => {
      if (res.code === 200) {
        ElMessage.success("发布成功");
        resetTable()
      }
    })
  });
};
const submitForm = () => {
  formRef.value.validate((valid) => {
    if (valid) {
@@ -419,78 +478,257 @@
  });
};
const holidayNoticeCount = ref()
const maintenanceNoticeCount = ref()
const fetchCount = () => {
  getCount().then(res => {
    holidayNoticeCount.value = res.data.filter(item => {
      return item.type === 1
    })[0].count;
    maintenanceNoticeCount.value = res.data.filter(item => {
      return item.type === 2
    })[0].count;
  });
}
// åˆå§‹åŒ–某个类型的分页数据
const initNoticePage = (typeId) => {
  if (!noticePagesMap.value[typeId]) {
    noticePagesMap.value[typeId] = {
      total: 0,
      current: 1,
      size: 10
    };
  }
  if (!noticesMap.value[typeId]) {
    noticesMap.value[typeId] = [];
  }
};
const holidayNotices = ref([])
const maintenanceNotices = ref([])
const holidayNoticePage = ref({
  total: 0,
  current: 1,
  size: 9
})
// èŽ·å–æŸä¸ªç±»åž‹çš„é€šçŸ¥åˆ—è¡¨
const getNoticesByType = (typeId) => {
  return noticesMap.value[typeId] || [];
};
const maintenanceNoticePage = ref({
  total: 0,
  current: 1,
  size: 9
})
// èŽ·å–æŸä¸ªç±»åž‹çš„åˆ†é¡µæ•°æ®
const getNoticePageByType = (typeId) => {
  return noticePagesMap.value[typeId] || { total: 0, current: 1, size: 10 };
};
const fetchHolidayNotices = () => {
  listNotice({...holidayNoticePage.value, type: 1}).then(res => {
    holidayNotices.value = res.data.records
    holidayNoticePage.value.total = res.data.total
// èŽ·å–æŸä¸ªç±»åž‹çš„æ•°é‡
const getNoticeCountByType = (typeId) => {
  return getNoticePageByType(typeId).total || 0;
};
// èŽ·å–æŸä¸ªç±»åž‹çš„é€šçŸ¥æ•°æ®
const fetchNoticesByType = (typeId) => {
  initNoticePage(typeId);
  const pageData = noticePagesMap.value[typeId];
  listNotice({...pageData, type: typeId}).then(res => {
    if (res.code === 200) {
      noticesMap.value[typeId] = res.data.records || [];
      noticePagesMap.value[typeId].total = res.data.total || 0;
    }
  });
};
const fetchMaintenanceNotices = () => {
  listNotice({...holidayNoticePage.value, type: 2}).then(res => {
    maintenanceNotices.value = res.data.records
    maintenanceNoticePage.value.total = res.data.total
  });
// å¤„理分页变化
const handleNoticeCurrentChange = (typeId, val) => {
  initNoticePage(typeId);
  noticePagesMap.value[typeId].size = val.limit;
  noticePagesMap.value[typeId].current = val.page;
  fetchNoticesByType(typeId);
};
const handleHolidayNoticeCurrentChange = (val) => {
  holidayNoticePage.value.size = val.limit
  holidayNoticePage.value.current = val.page
  fetchHolidayNotices()
};
const handleMaintenanceNoticeCurrentChange = (val) => {
  maintenanceNoticePage.value.size = val.limit
  maintenanceNoticePage.value.current = val.page
  fetchMaintenanceNotices()
// å¤„理 tab åˆ‡æ¢
const handleNoticeTypeTabChange = (tabName) => {
  activeNoticeTypeTab.value = tabName;
  const typeId = Number(tabName);
  fetchNoticesByType(typeId);
};
const resetTable = () => {
  holidayNoticePage.value.current = 1
  holidayNoticePage.value.size = 9
  maintenanceNoticePage.value.current = 1
  maintenanceNoticePage.value.size = 9
  fetchHolidayNotices()
  fetchMaintenanceNotices()
  fetchCount()
  // é‡ç½®æ‰€æœ‰ç±»åž‹çš„分页并重新获取数据
  noticeTypeList.value.forEach(type => {
    initNoticePage(type.id);
    noticePagesMap.value[type.id].current = 1;
    noticePagesMap.value[type.id].size = 10;
    fetchNoticesByType(type.id);
  });
};
const resetForm = () => {
  formRef.value?.resetFields();
};
// å…¬å‘Šç±»åž‹é…ç½®ç›¸å…³æ–¹æ³•
const openNoticeTypeDialog = () => {
  noticeTypeDialogVisible.value = true;
  fetchNoticeTypeList();
};
const fetchNoticeTypeList = () => {
  return listNoticeType().then(res => {
    if (res.code === 200) {
      noticeTypeList.value = res.data.map(item => ({
        ...item,
        editing: false
      }));
      // æ£€æŸ¥è·¯ç”±å‚数中的 type
      const routeType = route.query.type;
      let targetTypeId = null;
      if (routeType) {
        // å¦‚果路由参数中有 type,查找对应的类型
        const typeId = Number(routeType);
        const foundType = noticeTypeList.value.find(item => item.id === typeId);
        if (foundType) {
          targetTypeId = typeId;
        }
      }
      // å¦‚果有类型数据
      if (noticeTypeList.value.length > 0) {
        // å¦‚果路由参数指定了类型且存在,使用路由参数的类型
        // å¦åˆ™å¦‚果没有选中 tab,默认选中第一个
        if (targetTypeId !== null) {
          activeNoticeTypeTab.value = String(targetTypeId);
          fetchNoticesByType(targetTypeId);
        } else if (!activeNoticeTypeTab.value) {
          activeNoticeTypeTab.value = String(noticeTypeList.value[0].id);
          fetchNoticesByType(noticeTypeList.value[0].id);
        }
      }
    }
  });
};
const handleAddNoticeType = () => {
  const newItem = {
    id: undefined,
    noticeType: '',
    editing: true
  };
  noticeTypeList.value.push(newItem);
};
const handleEditNoticeType = (row) => {
  // ä¿å­˜åŽŸå§‹å€¼
  row.originalNoticeType = row.noticeType;
  row.editing = true;
};
const handleSaveNoticeType = (row) => {
  if (!row.noticeType || row.noticeType.trim() === '') {
    ElMessage.warning('公告类型不能为空');
    return;
  }
  const data = {
    noticeType: row.noticeType.trim()
  };
  if (row.id) {
    // ç¼–辑模式 - å…ˆåˆ é™¤å†æ·»åŠ ï¼ˆå› ä¸ºåªæœ‰ add å’Œ del æŽ¥å£ï¼‰
    delNoticeType(row.id).then(res => {
      if (res.code === 200) {
        addNoticeType(data).then(addRes => {
          if (addRes.code === 200) {
            ElMessage.success('编辑成功');
            row.editing = false;
            delete row.originalNoticeType;
            fetchNoticeTypeList().then(() => {
              // å¦‚果当前选中的类型被编辑,需要重新获取数据
              if (activeNoticeTypeTab.value === String(row.id)) {
                fetchNoticesByType(addRes.data?.id || row.id);
              }
            });
          }
        });
      }
    });
  } else {
    // æ–°å¢žæ¨¡å¼
    addNoticeType(data).then(res => {
      if (res.code === 200) {
        ElMessage.success('新增成功');
        row.editing = false;
        fetchNoticeTypeList();
      }
    });
  }
};
const handleDeleteNoticeType = (row) => {
  // å¦‚果没有id,说明是新增但未保存的行,直接从前端删除
  if (!row.id) {
    const index = noticeTypeList.value.indexOf(row);
    if (index > -1) {
      noticeTypeList.value.splice(index, 1);
    }
    return;
  }
  // å¦‚果有id,调用后端接口删除
  ElMessageBox.confirm(
      "确认删除这个公告类型吗?",
      "提示",
      {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      }
  ).then(() => {
    delNoticeType(row.id).then(res => {
      if (res.code === 200) {
        ElMessage.success("删除成功");
        // å¦‚果删除的是当前选中的类型,切换到第一个类型
        if (activeNoticeTypeTab.value === String(row.id)) {
          fetchNoticeTypeList().then(() => {
            if (noticeTypeList.value.length > 0) {
              activeNoticeTypeTab.value = String(noticeTypeList.value[0].id);
              fetchNoticesByType(noticeTypeList.value[0].id);
            } else {
              activeNoticeTypeTab.value = '';
            }
          });
        } else {
          fetchNoticeTypeList();
        }
      }
    });
  });
};
const handleCancelEdit = (row) => {
  if (!row.id) {
    // å¦‚果是新增但未保存的行,移除它
    const index = noticeTypeList.value.indexOf(row);
    if (index > -1) {
      noticeTypeList.value.splice(index, 1);
    }
  } else {
    // å¦‚果是编辑中的行,取消编辑状态并恢复原值
    row.editing = false;
    if (row.originalNoticeType !== undefined) {
      row.noticeType = row.originalNoticeType;
      delete row.originalNoticeType;
    }
  }
};
const handleNoticeTypeDialogClose = () => {
  // å…³é—­å¼¹æ¡†æ—¶ï¼Œå–消所有编辑状态
  noticeTypeList.value.forEach(item => {
    if (item.editing && !item.id) {
      // å¦‚果是新增但未保存的行,移除它
      const index = noticeTypeList.value.indexOf(item);
      if (index > -1) {
        noticeTypeList.value.splice(index, 1);
      }
    } else if (item.editing) {
      // å¦‚果是编辑中的行,取消编辑状态并恢复原值
      item.editing = false;
      if (item.originalNoticeType !== undefined) {
        item.noticeType = item.originalNoticeType;
        delete item.originalNoticeType;
      }
    }
  });
};
// ç”Ÿå‘½å‘¨æœŸ
onMounted(() => {
  fetchCount()
  fetchHolidayNotices()
  fetchMaintenanceNotices()
  // å…ˆèŽ·å–å…¬å‘Šç±»åž‹åˆ—è¡¨ï¼Œç„¶åŽæ ¹æ®ç±»åž‹èŽ·å–é€šçŸ¥æ•°æ®
  fetchNoticeTypeList();
});
</script>
@@ -569,12 +807,16 @@
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
}
.holiday-card {
  border-left-color: #67c23a;
.notice-icon {
  color: #409eff;
  margin-right: 8px;
  font-size: 18px;
}
.maintenance-card {
  border-left-color: #e6a23c;
.tab-count {
  color: #909399;
  font-size: 12px;
  margin-left: 4px;
}
.urgent {
@@ -598,17 +840,6 @@
  flex: 1;
}
.holiday-icon {
  color: #67c23a;
  margin-right: 8px;
  font-size: 18px;
}
.maintenance-icon {
  color: #e6a23c;
  margin-right: 8px;
  font-size: 18px;
}
.card-actions {
  display: flex;
@@ -713,6 +944,16 @@
  text-align: right;
}
.notice-type-container {
  padding: 10px 0;
}
.notice-type-header {
  margin-bottom: 15px;
  display: flex;
  justify-content: flex-end;
}
/* å“åº”式设计 */
@media (max-width: 768px) {
  .notice-cards {
src/views/collaborativeApproval/rulesRegulationsManagement/index.vue
@@ -52,54 +52,21 @@
                  </template>
                </el-table-column>
                <el-table-column prop="readCount" label="已读人数" width="100" />
                <el-table-column label="操作" width="250" fixed="right">
                <el-table-column label="操作" width="320" fixed="right">
                  <template #default="scope">
                    <el-button link @click="viewRegulation(scope.row)">查看</el-button>
                    <el-button link type="primary" @click="handleEdit(scope.row)">编辑</el-button>
                    <el-button link type="danger" @click="repealEdit(scope.row)">废弃</el-button>
                    <el-button link type="success" @click="viewVersionHistory(scope.row)">版本历史</el-button>
                    <el-button link type="warning" @click="viewReadStatus(scope.row)">阅读状态</el-button>
                    <el-button link type="primary" @click="openFileDialog(scope.row)">附件</el-button>
                  </template>
                </el-table-column>
              </el-table>
            </div>
          </el-card>
    <!-- ç”¨å°ç”³è¯·å¯¹è¯æ¡† -->
    <!-- <el-dialog v-model="showSealApplyDialog" title="申请用印" width="600px">
      <el-form :model="sealForm" :rules="sealRules" ref="sealFormRef" label-width="100px">
        <el-form-item label="申请编号" prop="applicationNum">
          <el-input v-model="sealForm.applicationNum" placeholder="请输入申请编号" />
        </el-form-item>
        <el-form-item label="申请标题" prop="title">
          <el-input v-model="sealForm.title" placeholder="请输入申请标题" />
        </el-form-item>
        <el-form-item label="用印类型" prop="sealType">
          <el-select v-model="sealForm.sealType" placeholder="请选择用印类型" style="width: 100%">
            <el-option label="公章" value="official" />
            <el-option label="合同专用章" value="contract" />
            <el-option label="财务专用章" value="finance" />
            <el-option label="法人章" value="legal" />
          </el-select>
        </el-form-item>
        <el-form-item label="申请原因" prop="reason">
          <el-input v-model="sealForm.reason" type="textarea" :rows="4" placeholder="请详细说明用印原因" />
        </el-form-item>
        <el-form-item label="紧急程度" prop="urgency">
          <el-radio-group v-model="sealForm.urgency">
            <el-radio label="normal">普通</el-radio>
            <el-radio label="urgent">紧急</el-radio>
            <el-radio label="very-urgent">特急</el-radio>
          </el-radio-group>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="showSealApplyDialog = false">取消</el-button>
          <el-button type="primary" @click="submitSealApplication">提交申请</el-button>
        </span>
      </template>
    </el-dialog> -->
    <!-- ç”¨å°ç”³è¯·å¯¹è¯æ¡†ï¼ˆå·²ç§»é™¤ï¼‰ -->
    <!-- è§„章制度发布对话框 -->
    <el-dialog v-model="showRegulationDialog" :title="operationType === 'add' ? '发布制度' : '编辑制度'" width="800px">
@@ -150,25 +117,7 @@
      </template>
    </el-dialog>
    <!-- ç”¨å°è¯¦æƒ…对话框 -->
    <!-- <el-dialog v-model="showSealDetailDialog" title="用印申请详情" width="700px">
      <div v-if="currentSealDetail" class="mb10">
        <el-descriptions :column="2" border>
          <el-descriptions-item label="申请编号">{{ currentSealDetail.id }}</el-descriptions-item>
          <el-descriptions-item label="申请标题">{{ currentSealDetail.title }}</el-descriptions-item>
          <el-descriptions-item label="申请人">{{ currentSealDetail.createUserName }}</el-descriptions-item>
          <el-descriptions-item label="所属部门">{{ currentSealDetail.department }}</el-descriptions-item>
          <el-descriptions-item label="用印类型">{{ getSealTypeText(currentSealDetail.sealType) }}</el-descriptions-item>
          <el-descriptions-item label="申请时间">{{ currentSealDetail.createTime }}</el-descriptions-item>
          <el-descriptions-item label="状态">
            <el-tag :type="getStatusType(currentSealDetail.status)">
              {{ getStatusText(currentSealDetail.status) }}
            </el-tag>
          </el-descriptions-item>
          <el-descriptions-item label="申请原因" :span="2">{{ currentSealDetail.reason }}</el-descriptions-item>
        </el-descriptions>
      </div>
    </el-dialog> -->
    <!-- ç”¨å°è¯¦æƒ…对话框(已移除) -->
    <!-- è§„章制度详情对话框 -->
    <el-dialog v-model="showRegulationDetailDialog" title="规章制度详情" width="800px">
@@ -224,54 +173,42 @@
        </el-table-column>
      </el-table>
    </el-dialog>
    <FileListDialog
      ref="fileListDialogRef"
      v-model="fileDialogVisible"
      :show-upload-button="true"
      :show-delete-button="true"
      :delete-method="handleAttachmentDelete"
      :rules-regulations-management-id="currentFileRuleId"
      :name-column-label="'附件名称'"
      @upload="handleAttachmentUpload"
    />
  </div>
</template>
<script setup>
import { ref, reactive, onMounted, getCurrentInstance } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import { listSealApplication, addSealApplication, updateSealApplication,listRuleManagement,addRuleManagement,updateRuleManagement,delRuleManagement,getReadingStatusByRuleId,getReadingStatusList,addReadingStatus,updateReadingStatus  } from '@/api/collaborativeApproval/sealManagement.js'
import { el } from 'element-plus/es/locales.mjs'
import { getUserProfile } from '@/api/system/user.js'
import {staffJoinDel, staffJoinListPage} from "@/api/personnelManagement/onboarding.js";
import useUserStore from '@/store/modules/user'
import { userLoginFacotryList } from "@/api/system/user.js"
import { listRuleManagement,addRuleManagement,updateRuleManagement,delRuleManagement,getReadingStatusByRuleId,addReadingStatus,updateReadingStatus  } from '@/api/collaborativeApproval/sealManagement.js'
import FileListDialog from '@/components/Dialog/FileListDialog.vue'
import { listRuleFiles, delRuleFile, addRuleFile } from '@/api/collaborativeApproval/rulesRegulationsManagementFile.js'
// å“åº”式数据
const currentUser = ref(null)
const activeTab = ref('seal')
const operationType = ref('add')
const tableData = ref([])
// ç”¨å°ç”³è¯·ç›¸å…³
const userStore = useUserStore()
const showSealApplyDialog = ref(false)
const tableLoading = ref(false)
const showSealDetailDialog = ref(false)
const currentSealDetail = ref(null)
const sealFormRef = ref()
const sealForm = reactive({
  applicationNum: '',
  title: '',
  sealType: '',
  reason: '',
  urgency: 'normal',
  status: 'pending'
})
const sealRules = {
  applicationNum: [{ required: true, message: '请输入申请编号', trigger: 'blur' }],
  title: [{ required: true, message: '请输入申请标题', trigger: 'blur' }],
  sealType: [{ required: true, message: '请选择用印类型', trigger: 'change' }],
  reason: [{ required: true, message: '请输入申请原因', trigger: 'blur' }]
}
const sealSearchForm = reactive({
  title: '',
  status: ''
})
// åˆ†é¡µå‚æ•°
const page = reactive({
  current: 1,
  size: 10,
  total: 0
})
// é™„件弹窗
const fileDialogVisible = ref(false)
const fileListDialogRef = ref(null)
const currentFileRuleId = ref(null)
const filePage = reactive({
  current: 1,
  size: 10,
  total: 0
@@ -320,9 +257,6 @@
  category: ''
})
// å‡æ•°æ®
const sealApplications = ref([])
const regulations = ref([])
const versionHistory = ref([])
@@ -332,34 +266,6 @@
  // { 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 getStatusType = (status) => {
  const statusMap = {
    pending: 'warning',
    approved: 'success',
    rejected: 'danger'
  }
  return statusMap[status] || 'info'
}
// åˆ¶åº¦çŠ¶æ€
const getStatusText = (status) => {
  const statusMap = {
    pending: '待审批',
    approved: '已通过',
    rejected: '已拒绝'
  }
  return statusMap[status] || '未知'
}
// ç”¨å°ç±»åž‹
const getSealTypeText = (sealType) => {
  const sealTypeMap = {
    official: '公章',
    contract: '合同专用章',
    finance: '财务专用章',
    tegal: '技术专用章'
  }
  return sealTypeMap[sealType] || '未知'
}
// åˆ¶åº¦åˆ†ç±»
const getCategoryText = (category) => {
  const categoryMap = {
@@ -369,19 +275,6 @@
    tech: '技术制度'
  }
  return categoryMap[category] || '未知'
}
// æœç´¢å°ç« ç”³è¯·
const searchSealApplications = () => {
  page.current=1
  getSealApplicationList()
  // ElMessage.success('搜索完成')
}
// é‡ç½®å°ç« ç”³è¯·æœç´¢
const resetSealSearch = () => {
  sealSearchForm.title = ''
  sealSearchForm.status = ''
  searchSealApplications()
}
// æœç´¢åˆ¶åº¦
const searchRegulations = () => {
@@ -393,32 +286,6 @@
  regulationSearchForm.title = ''
  regulationSearchForm.category = ''
  searchRegulations()
}
// æäº¤ç”¨å°ç”³è¯·
const submitSealApplication = async () => {
  try {
    await sealFormRef.value.validate()
    addSealApplication(sealForm).then(res => {
      if(res.code == 200){
        ElMessage.success('申请提交成功')
        showSealApplyDialog.value = false
        getSealApplicationList()
        Object.assign(sealForm, {
        applicationNum: '',
        title: '',
        sealType: '',
        reason: '',
        urgency: 'normal',
        status: 'pending'
      })
      }
    }).catch(err => {
      ElMessage.error(err.msg)
    })
  } catch (error) {
    ElMessage.error('请完善申请信息')
  }
}
// æ–°å¢ž
const handleAdd = () => {
@@ -501,72 +368,6 @@
}
// æŸ¥çœ‹ç”¨å°ç”³è¯·è¯¦æƒ…
const viewSealDetail = (row) => {
  currentSealDetail.value = row
  showSealDetailDialog.value = true
}
// å®¡æ‰¹ç”¨å°ç”³è¯·
const approveSeal = (row) => {
  console.log(row)
  ElMessageBox.confirm('确认通过该用印申请?', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
    row.status = 'approved'
    updateSealApplication(row).then(res => {
      if(res.code == 200){
        ElMessage.success('审批通过')
      }
    })
  })
}
// æ‹’绝用印申请
const rejectSeal = (row) => {
  ElMessageBox.prompt('请输入拒绝原因', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    inputPattern: /\S+/,
    inputErrorMessage: '拒绝原因不能为空'
  }).then(({ value }) => {
    row.status = 'rejected'
    updateSealApplication(row).then(res => {
      if(res.code == 200){
        ElMessage.success('审批拒绝')
      }
    })
    ElMessage.success('已拒绝申请')
  })
}
// èŽ·å–åœ¨èŒå‘˜å·¥åˆ—è¡¨
const getList = () => {
  tableLoading.value = true;
      //获取当前登录用户信息
  getUserProfile().then(res => {
    if(res.code == 200){
      console.log(res.data.userName)
      currentUser.value = res.data.userName
    }
  })
  staffJoinListPage({staffState: 1}).then(res => {
    tableLoading.value = false;
    // tableData.value = res.data.records
    // //筛选出和currentUser同名的人员
    tableData.value = res.data.records.filter(item => item.staffName === currentUser.value)
    console.log("tableData",tableData.value)
    page.total = res.data.total;
    if(tableData.value.length == 0){
    ElMessage.error('当前用户未加入任何部门')
    }
  }).catch(err => {
    tableLoading.value = false;
  })
};
// æŸ¥çœ‹åˆ¶åº¦ç‰ˆæœ¬åŽ†å²
const viewVersionHistory = (row) => {
  showVersionHistoryDialog.value = true
@@ -582,7 +383,6 @@
}
// æŸ¥çœ‹åˆ¶åº¦è¯¦æƒ…
const viewRegulation = (row) => {
  getList()
  currentRegulationDetail.value = row
  showRegulationDetailDialog.value = true
  getReadingStatusByRuleId(row.id).then(res => {
@@ -659,32 +459,64 @@
  proxy.download('/rulesRegulationsManagement/export', { ...regulationSearchForm }, '规章制度.xlsx')
}
// èŽ·å–å°ç« ç”³è¯·åˆ—è¡¨æ•°æ®
const getSealApplicationList = async () => {
  tableLoading.value = true
  listSealApplication(page,sealSearchForm)
  .then(res => {
    //获取当前登录的部门信息
// èŽ·å–å½“å‰ç™»å½•çš„éƒ¨é—¨ä¿¡æ¯å¹¶è¿‡æ»¤æ•°æ®
    const currentFactoryName = userStore.currentFactoryName
    if (currentFactoryName) {
      // æ ¹æ®currentFactoryName过滤出department相同的数据
      sealApplications.value = res.data.records.filter(item => item.department === currentFactoryName)
      // æ›´æ–°è¿‡æ»¤åŽçš„æ€»æ•°
      page.value.total = sealApplications.value.length
    } else {
      // å¦‚果没有currentFactoryName,则显示所有数据
      sealApplications.value = res.data.records
      page.value.total = res.data.total
    }
    // sealApplications.value = res.data.records
    // page.value.total = res.data.total;
    tableLoading.value = false;
  }).catch(err => {
    tableLoading.value = false;
  })
// é™„件:查询
const fetchRuleFiles = async (rulesRegulationsManagementId) => {
  const params = {
    current: filePage.current,
    size: filePage.size,
    rulesRegulationsManagementId
  }
  const res = await listRuleFiles(params)
  const records = res?.data?.records || []
  filePage.total = res?.data?.total || records.length
  const mapped = records.map(item => ({
    id: item.id,
    name: item.fileName || item.name,
    url: item.fileUrl || item.url,
    raw: item
  }))
  fileListDialogRef.value?.setList(mapped)
}
// æ‰“开附件弹窗
const openFileDialog = async (row) => {
  currentFileRuleId.value = row.id
  fileDialogVisible.value = true
  await fetchRuleFiles(row.id)
}
// åˆ·æ–°é™„件列表
const refreshFileList = async () => {
  if (!currentFileRuleId.value) return
  await fetchRuleFiles(currentFileRuleId.value)
}
// ä¸Šä¼ é™„件(由子组件触发)
const handleAttachmentUpload = async (filePayload) => {
  if (!currentFileRuleId.value) return
  const payload = {
    name: filePayload?.fileName || filePayload?.name,
    url: filePayload?.fileUrl || filePayload?.url,
    rulesRegulationsManagementId: currentFileRuleId.value
  }
  await addRuleFile(payload)
  ElMessage.success('文件上传成功')
  await refreshFileList()
}
// åˆ é™¤é™„ä»¶
const handleAttachmentDelete = async (row) => {
  if (!row?.id) return false
  try {
    await ElMessageBox.confirm('确认删除该附件?', '提示', { type: 'warning' })
  } catch {
    return false
  }
  await delRuleFile([row.id])
  ElMessage.success('删除成功')
  await refreshFileList()
}
// èŽ·å–è§„ç« åˆ¶åº¦åˆ—è¡¨æ•°æ®
const getRegulationList = async () => {
  tableLoading.value = true
@@ -704,7 +536,6 @@
onMounted(() => {
  // åˆå§‹åŒ–
  getSealApplicationList()
  getRegulationList()
})
</script>
src/views/collaborativeApproval/sealManagement/index.vue
@@ -12,11 +12,15 @@
        <div class="tab-content">
            <el-row :gutter="20" class="mb-20 ">
              <span class="ml-10">用印标题:</span>
              <el-col :span="6">
              <el-col :span="4">
                <el-input v-model="sealSearchForm.title" placeholder="请输入申请标题" clearable />
              </el-col>
              <span class="ml-10">用印编号:</span>
              <el-col :span="4">
                <el-input v-model="sealSearchForm.applicationNum" placeholder="请输入用印编号" clearable />
              </el-col>
              <span class="search_title">审批状态:</span>
              <el-col :span="6">
              <el-col :span="4">
                <el-select v-model="sealSearchForm.status" placeholder="审批状态" clearable>
                  <el-option label="待审批" value="pending" />
                  <el-option label="已通过" value="approved" />
@@ -96,6 +100,16 @@
        </el-form-item>
        <el-form-item label="申请原因" prop="reason">
          <el-input v-model="sealForm.reason" type="textarea" :rows="4" placeholder="请详细说明用印原因" />
        </el-form-item>
        <el-form-item label="审批人" prop="approveUserId">
          <el-select v-model="sealForm.approveUserId" placeholder="请选择审批人" style="width: 100%" filterable>
            <el-option
                v-for="user in userList"
                :key="user.userId"
                :label="user.nickName"
                :value="user.userId"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="紧急程度" prop="urgency">
          <el-radio-group v-model="sealForm.urgency">
@@ -240,12 +254,13 @@
</template>
<script setup>
import { ref, reactive, onMounted, getCurrentInstance } from 'vue'
import { ref, reactive, onMounted, getCurrentInstance, watch } from 'vue'
import { useRoute } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import { listSealApplication, addSealApplication, updateSealApplication,listRuleManagement,addRuleManagement,updateRuleManagement,delRuleManagement,getReadingStatusByRuleId,getReadingStatusList,addReadingStatus,updateReadingStatus  } from '@/api/collaborativeApproval/sealManagement.js'
import { el } from 'element-plus/es/locales.mjs'
import { getUserProfile } from '@/api/system/user.js'
import { getUserProfile, userListNoPageByTenantId } from '@/api/system/user.js'
import {staffJoinDel, staffJoinListPage} from "@/api/personnelManagement/onboarding.js";
import useUserStore from '@/store/modules/user'
import { userLoginFacotryList } from "@/api/system/user.js"
@@ -257,16 +272,19 @@
const tableData = ref([])
// ç”¨å°ç”³è¯·ç›¸å…³
const userStore = useUserStore()
const route = useRoute()
const showSealApplyDialog = ref(false)
const tableLoading = ref(false)
const showSealDetailDialog = ref(false)
const currentSealDetail = ref(null)
const sealFormRef = ref()
const userList = ref([])
const sealForm = reactive({
  applicationNum: '',
  title: '',
  sealType: '',
  reason: '',
  approveUserId: '',
  urgency: 'normal',
  status: 'pending'
})
@@ -275,12 +293,14 @@
  applicationNum: [{ required: true, message: '请输入申请编号', trigger: 'blur' }],
  title: [{ required: true, message: '请输入申请标题', trigger: 'blur' }],
  sealType: [{ required: true, message: '请选择用印类型', trigger: 'change' }],
  reason: [{ required: true, message: '请输入申请原因', trigger: 'blur' }]
  reason: [{ required: true, message: '请输入申请原因', trigger: 'blur' }],
  approveUserId: [{ required: true, message: '请选择审批人', trigger: 'change' }]
}
const sealSearchForm = reactive({
  title: '',
  status: ''
  status: '',
  applicationNum: ''
})
// åˆ†é¡µå‚æ•°
const page = reactive({
@@ -393,6 +413,7 @@
const resetSealSearch = () => {
  sealSearchForm.title = ''
  sealSearchForm.status = ''
  sealSearchForm.applicationNum = ''
  searchSealApplications()
}
// æœç´¢åˆ¶åº¦
@@ -420,6 +441,7 @@
        title: '',
        sealType: '',
        reason: '',
        approveUserId: '',
        urgency: 'normal',
        status: 'pending'
      })
@@ -713,9 +735,24 @@
  })
}
// ç›‘听对话框打开,获取用户列表
watch(showSealApplyDialog, (newVal) => {
  if (newVal) {
    userListNoPageByTenantId().then((res) => {
      userList.value = res.data;
    });
  }
});
onMounted(() => {
  // åˆå§‹åŒ–
  getSealApplicationList()
  // è·¯ç”±æºå¸¦ applicationNum æ—¶ï¼Œé¢„填并查询
  if (route.query.applicationNum) {
    sealSearchForm.applicationNum = String(route.query.applicationNum)
    page.current = 1
    getSealApplicationList()
  } else {
    getSealApplicationList()
  }
  getRegulationList()
})
</script>