前言
泛微E9版本的后台对于流程使用分析功能上还是比较欠缺的,公司使用OA系统的时间也比较久了,有很多没有必要的流程还存在在系统重,如果单条筛选工作量巨大,之前就发现DS对泛微数据库的结构记录的比较准确,索性就让DS帮我完成这一工作,再进阶成网页形式展现出来,也方便日后再做流程统计的时候查看。
效果图
最终版SQL代码
WITH CurrentFlows AS (
SELECT
wb.id,
wb.workflowname,
wb.activeVersionID,
wb.isvalid, -- 添加 isvalid 字段
wb.workflowtype, -- 添加 workflowtype 字段
MAX(wf.createdate) AS last_created
FROM workflow_base wb
JOIN workflow_requestbase wf ON wb.id = wf.workflowid
WHERE wb.id = wb.activeVersionID OR wb.activeVersionID IS NULL
GROUP BY wb.id, wb.workflowname, wb.activeVersionID, wb.isvalid, wb.workflowtype
),
TotalCounts AS (
SELECT
wb.workflowname,
COUNT(*) AS total_submissions,
SUM(CASE WHEN wf.createdate >= '2025-01-01' AND wf.createdate < '2026-01-01'
THEN 1 ELSE 0 END) AS submissions_2025
FROM workflow_base wb
JOIN workflow_requestbase wf ON wb.id = wf.workflowid
GROUP BY wb.workflowname
)
SELECT
cf.id AS 流程类型ID,
cf.workflowname AS 流程类型名称,
cf.activeVersionID AS 活动版本ID,
-- 映射 isvalid 字段
CASE cf.isvalid
WHEN 0 THEN '无效'
WHEN 1 THEN '有效'
WHEN 2 THEN '测试'
ELSE '未知状态'
END AS 流程状态,
-- 获取 workflowtype 的中文名称
wt.typename AS 路径类型,
tc.total_submissions AS 历史总提交次数,
tc.submissions_2025 AS [2025年提交次数],
cf.last_created AS 最后创建时间
FROM CurrentFlows cf
JOIN TotalCounts tc ON cf.workflowname = tc.workflowname
-- 关联 workflow_type 表获取路径类型中文名
LEFT JOIN workflow_type wt ON cf.workflowtype = wt.id
ORDER BY cf.last_created DESC;
最终版PHP代码
<?php
// 数据库配置信息
$serverName = "数据IP,1433"; // 服务器地址(IP:端口)
$databaseName = "数据表名"; // 数据库名称
$username = "数据库用户名"; // 登录用户名
$password = "数据库密码"; // 登录密码
// 连接选项
$connectionOptions = [
"Database" => $databaseName, // 目标数据库
"Uid" => $username, // 用户名
"PWD" => $password, // 密码
"CharacterSet" => "UTF-8" // 字符集
];
// 尝试连接数据库
$conn = sqlsrv_connect($serverName, $connectionOptions);
// 检查连接是否成功
if ($conn === false) {
die("<div class='container mt-5'><h3>❌ 数据库连接失败!</h3><pre>" . print_r(sqlsrv_errors(SQLSRV_ERR_ALL), true) . "</pre></div>");
}
// 定义用户提供的 SQL 查询
$query = "
WITH CurrentFlows AS (
SELECT
wb.id,
wb.workflowname,
wb.activeVersionID,
wb.isvalid,
wb.workflowtype,
MAX(wf.createdate) AS last_created
FROM workflow_base wb
JOIN workflow_requestbase wf ON wb.id = wf.workflowid
WHERE wb.id = wb.activeVersionID OR wb.activeVersionID IS NULL
GROUP BY wb.id, wb.workflowname, wb.activeVersionID, wb.isvalid, wb.workflowtype
),
TotalCounts AS (
SELECT
wb.workflowname,
COUNT(*) AS total_submissions,
SUM(CASE WHEN wf.createdate >= '2025-01-01' AND wf.createdate < '2026-01-01'
THEN 1 ELSE 0 END) AS submissions_2025
FROM workflow_base wb
JOIN workflow_requestbase wf ON wb.id = wf.workflowid
GROUP BY wb.workflowname
)
SELECT
cf.id AS 流程类型ID,
cf.workflowname AS 流程类型名称,
cf.activeVersionID AS 活动版本ID,
CASE cf.isvalid
WHEN 0 THEN '无效'
WHEN 1 THEN '有效'
WHEN 2 THEN '测试'
ELSE '未知状态'
END AS 流程状态,
wt.typename AS 路径类型,
tc.total_submissions AS 历史总提交次数,
tc.submissions_2025 AS [2025年提交次数],
cf.last_created AS 最后创建时间
FROM CurrentFlows cf
JOIN TotalCounts tc ON cf.workflowname = tc.workflowname
LEFT JOIN workflow_type wt ON cf.workflowtype = wt.id
ORDER BY wt.typename ASC;
";
// 执行查询
$result = sqlsrv_query($conn, $query);
// 检查查询是否成功
if ($result === false) {
die("<div class='container mt-5'><h3>❌ 查询执行失败!</h3><pre>" . print_r(sqlsrv_errors(SQLSRV_ERR_ALL), true) . "</pre></div>");
}
// 获取结果集并统计行数
$rows = [];
$rowCount = 0;
while ($row = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) {
$rows[] = $row;
$rowCount++;
}
// 释放资源并关闭连接
sqlsrv_free_stmt($result);
sqlsrv_close($conn);
// 处理路径类型字符串的函数
function cleanPathType($pathType) {
// 如果包含特殊格式,提取中文名称
if (preg_match('/~`~`\d+\s+([\x{4e00}-\x{9fa5}]+)/u', $pathType, $matches)) {
return $matches[1]; // 返回匹配到的中文部分
}
// 如果包含"系统默认工作流"的变体,统一替换
if (strpos($pathType, '系统默认工作流') !== false ||
strpos($pathType, 'System default workflow') !== false ||
strpos($pathType, '系統默認工作流') !== false) {
return '系统默认工作流';
}
return $pathType;
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>流程数据查询结果 - 增强版</title>
<!-- 使用 BootCDN 的 Bootstrap 5.3.0 -->
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
<!-- 引入 Bootstrap Icons -->
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/bootstrap-icons/1.13.1/font/bootstrap-icons.css">
<style>
body {
background: linear-gradient(135deg, #f5f7fa 0%, #e4edf5 100%);
padding: 20px;
font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
}
.header-container {
background: linear-gradient(to right, #4e73df, #224abe);
color: white;
padding: 25px 30px;
border-radius: 10px;
margin-bottom: 30px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}
.table-container {
background-color: white;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 5px 25px rgba(0, 0, 0, 0.08);
margin-bottom: 30px;
overflow-x: auto;
}
.table {
min-width: 1200px;
margin-bottom: 0;
}
.table thead th {
background-color: #4e73df;
color: white;
font-weight: 600;
vertical-align: middle;
white-space: nowrap;
cursor: pointer;
position: relative;
padding-right: 30px;
}
.table th, .table td {
padding: 14px 16px;
vertical-align: middle;
}
.sort-indicator {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
opacity: 0.6;
}
.sort-active .sort-indicator {
opacity: 1;
}
/* 指定居中显示的列 */
.text-center {
text-align: center !important;
}
.table-striped tbody tr:nth-of-type(odd) {
background-color: rgba(78, 115, 223, 0.05);
}
.table-hover tbody tr:hover {
background-color: rgba(78, 115, 223, 0.1);
transition: background-color 0.3s;
}
.status-badge {
display: inline-block;
padding: 4px 10px;
border-radius: 15px;
font-size: 13px;
font-weight: 500;
}
.valid {
background-color: #d1e7dd;
color: #0f5132;
}
.invalid {
background-color: #f8d7da;
color: #842029;
}
.testing {
background-color: #fff3cd;
color: #664d03;
}
.summary-card {
background: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
}
.footer {
text-align: center;
color: #6c757d;
font-size: 14px;
margin-top: 30px;
padding: 15px;
}
.highlight {
font-weight: 600;
color: #4e73df;
}
.scroll-hint {
position: fixed;
bottom: 20px;
right: 20px;
background: rgba(78, 115, 223, 0.9);
color: white;
padding: 8px 15px;
border-radius: 20px;
font-size: 14px;
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.2);
display: none;
}
/* 序号列样式 */
.serial-column {
width: 60px;
min-width: 60px;
background-color: rgba(78, 115, 223, 0.1);
text-align: center;
font-weight: 600;
}
@media (max-width: 768px) {
.header-container {
padding: 15px;
}
h1 {
font-size: 1.5rem;
}
}
/* 筛选面板样式 */
.filter-panel {
background-color: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
margin-bottom: 25px;
transition: all 0.3s ease;
}
.filter-header {
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
padding: 5px 0 15px;
border-bottom: 1px solid #eaeaea;
margin-bottom: 15px;
}
.filter-header h3 {
margin: 0;
font-size: 1.25rem;
font-weight: 600;
color: #4e73df;
}
.filter-header i {
transition: transform 0.3s ease;
}
.filter-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 15px;
}
.filter-group {
margin-bottom: 10px;
}
.filter-group label {
display: block;
margin-bottom: 5px;
font-weight: 500;
color: #495057;
font-size: 0.9rem;
}
.filter-control {
width: 100%;
padding: 8px 12px;
border: 1px solid #ced4da;
border-radius: 5px;
font-size: 0.9rem;
transition: border-color 0.15s ease-in-out;
}
.filter-control:focus {
border-color: #4e73df;
outline: 0;
box-shadow: 0 0 0 0.2rem rgba(78, 115, 223, 0.25);
}
.filter-actions {
display: flex;
justify-content: flex-end;
gap: 10px;
margin-top: 10px;
padding-top: 15px;
border-top: 1px solid #eaeaea;
}
/* 高亮匹配项 */
.highlight {
background-color: #fff3cd;
font-weight: 600;
}
/* 响应式调整 */
@media (max-width: 768px) {
.filter-grid {
grid-template-columns: 1fr;
}
.filter-actions {
flex-direction: column;
}
.filter-actions .btn {
width: 100%;
margin-bottom: 5px;
}
}
</style>
</head>
<body>
<div class="container-fluid">
<!-- 标题区域 -->
<div class="header-container">
<div class="row align-items-center">
<div class="col-md-8">
<h1 class="mb-0"><i class="bi bi-diagram-3 me-2"></i>流程数据统计结果</h1>
</div>
<div class="col-md-4 text-md-end">
<div class="text-white-50">最后更新时间: <?= date('Y-m-d H:i:s') ?></div>
</div>
</div>
</div>
<!-- 筛选面板 -->
<div class="filter-panel">
<div class="filter-header" id="filterHeader">
<h3><i class="bi bi-funnel me-2"></i>数据筛选面板</h3>
<i class="bi bi-chevron-down" id="filterToggle"></i>
</div>
<div id="filterBody">
<div class="filter-grid">
<div class="filter-group">
<label for="filterName">流程名称</label>
<input type="text" id="filterName" class="filter-control" placeholder="输入流程名称...">
</div>
<div class="filter-group">
<label for="filterStatus">流程状态</label>
<select id="filterStatus" class="filter-control">
<option value="">所有状态</option>
<option value="有效">有效</option>
<option value="无效">无效</option>
<option value="测试">测试</option>
</select>
</div>
<div class="filter-group">
<label for="filterPath">路径类型</label>
<input type="text" id="filterPath" class="filter-control" placeholder="输入路径类型...">
</div>
<div class="filter-group">
<label for="filterMinTotal">最小总提交数</label>
<input type="number" id="filterMinTotal" class="filter-control" placeholder="最小值">
</div>
<div class="filter-group">
<label for="filterMin2025">最小2025年提交数</label>
<input type="number" id="filterMin2025" class="filter-control" placeholder="最小值">
</div>
</div>
<div class="filter-actions">
<button id="resetFilters" class="btn btn-outline-secondary">
<i class="bi bi-x-circle me-1"></i> 重置筛选
</button>
<button id="applyFilters" class="btn btn-primary">
<i class="bi bi-filter me-1"></i> 应用筛选
</button>
</div>
</div>
</div>
<!-- 数据统计卡片 -->
<div class="row mb-4">
<div class="col-md-4 mb-3">
<div class="summary-card h-100">
<div class="d-flex align-items-center">
<div class="bg-primary p-3 rounded-circle me-3">
<i class="fas fa-list-alt text-white fs-4"></i>
</div>
<div>
<div class="text-muted small">流程总数</div>
<div class="fs-3 fw-bold"><?= $rowCount ?></div>
</div>
</div>
</div>
</div>
<div class="col-md-4 mb-3">
<div class="summary-card h-100">
<div class="d-flex align-items-center">
<div class="bg-success p-3 rounded-circle me-3">
<i class="fas fa-check-circle text-white fs-4"></i>
</div>
<div>
<div class="text-muted small">有效流程</div>
<div class="fs-3 fw-bold">
<?= count(array_filter($rows, function($row) {
return $row['流程状态'] === '有效';
})) ?>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-4 mb-3">
<div class="summary-card h-100">
<div class="d-flex align-items-center">
<div class="bg-info p-3 rounded-circle me-3">
<i class="fas fa-calendar-alt text-white fs-4"></i>
</div>
<div>
<div class="text-muted small">2025年提交总数</div>
<div class="fs-3 fw-bold">
<?= array_sum(array_column($rows, '2025年提交次数')) ?>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 表格区域(带滚动条) -->
<div class="table-container">
<table class="table table-striped table-hover" id="dataTable">
<thead>
<tr>
<th class="text-center serial-column">序号</th>
<th class="sortable" data-column="流程类型ID">
流程类型ID
<span class="sort-indicator"><i class="bi bi-arrow-down-up"></i></span>
</th>
<th class="sortable" data-column="流程类型名称">
流程类型名称
<span class="sort-indicator"><i class="bi bi-arrow-down-up"></i></span>
</th>
<th class="sortable" data-column="活动版本ID">
活动版本ID
<span class="sort-indicator"><i class="bi bi-arrow-down-up"></i></span>
</th>
<th class="sortable" data-column="流程状态">
流程状态
<span class="sort-indicator"><i class="bi bi-arrow-down-up"></i></span>
</th>
<th class="sortable" data-column="路径类型">
路径类型
<span class="sort-indicator"><i class="bi bi-arrow-down-up"></i></span>
</th>
<th class="sortable" data-column="历史总提交次数">
历史总提交次数
<span class="sort-indicator"><i class="bi bi-arrow-down-up"></i></span>
</th>
<th class="sortable" data-column="2025年提交次数">
2025年提交次数
<span class="sort-indicator"><i class="bi bi-arrow-down-up"></i></span>
</th>
<th class="sortable" data-column="最后创建时间">
最后创建时间
<span class="sort-indicator"><i class="bi bi-arrow-down-up"></i></span>
</th>
</tr>
</thead>
<tbody>
<?php if ($rowCount > 0): ?>
<?php $counter = 1; ?>
<?php foreach ($rows as $row): ?>
<tr>
<td class="serial-column text-center"><?= $counter++ ?></td>
<td class="text-center"><?= htmlspecialchars($row['流程类型ID'] ?? '') ?></td>
<td class="name-cell">
<?php
// 处理路径类型字符串
$pathType = $row['流程类型名称'] ?? '';
$cleanedPathType = cleanPathType($pathType);
?>
<?= htmlspecialchars($cleanedPathType) ?>
</td>
<td class="text-center"><?= htmlspecialchars($row['活动版本ID'] ?? '') ?></td>
<td class="text-center status-cell">
<span class="status-badge <?=
($row['流程状态'] === '有效') ? 'valid' :
(($row['流程状态'] === '无效') ? 'invalid' :
(($row['流程状态'] === '测试') ? 'testing' : ''))
?>">
<?= htmlspecialchars($row['流程状态'] ?? '') ?>
</span>
</td>
<td class="path-cell">
<?php
// 处理路径类型字符串
$pathType = $row['路径类型'] ?? '';
$cleanedPathType = cleanPathType($pathType);
?>
<?= htmlspecialchars($cleanedPathType) ?>
</td>
<td class="text-center total-submissions"><?= number_format($row['历史总提交次数'] ?? 0) ?></td>
<td class="text-center submissions-2025"><?= number_format($row['2025年提交次数'] ?? 0) ?></td>
<td class="text-center"><?= htmlspecialchars($row['最后创建时间'] ?? '') ?></td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr>
<td colspan="9" class="text-center py-5">
<div class="text-muted">
<i class="bi bi-inbox me-2"></i> 未查询到符合条件的记录
</div>
</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
<!-- 底部统计信息 -->
<div class="d-flex justify-content-between align-items-center">
<div class="text-muted">
显示 <span class="fw-bold" id="visibleCount"><?= $rowCount ?></span> 条记录中的
<span class="fw-bold" id="filteredCount"><?= $rowCount ?></span> 条
</div>
<div>
<button class="btn btn-outline-primary btn-sm me-2">
<i class="bi bi-download me-1"></i> 导出数据
</button>
<button class="btn btn-primary btn-sm" id="refreshData">
<i class="bi bi-arrow-repeat me-1"></i> 刷新数据
</button>
</div>
</div>
<!-- 页脚 -->
<div class="footer">
<div class="text-muted">
<i class="bi bi-database me-1"></i> 数据源: ecology 数据库 |
<i class="bi bi-server me-1"></i> 服务器: 192.168.5.29
</div>
</div>
<!-- 滚动提示(小屏幕显示) -->
<div class="scroll-hint">
<i class="bi bi-arrows-expand me-2"></i> 左右滑动查看完整表格
</div>
</div>
<!-- 引入 Bootstrap JS -->
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
<script>
// 显示滚动提示(在小屏幕上)
if (window.innerWidth < 992) {
document.querySelector('.scroll-hint').style.display = 'block';
// 3秒后自动隐藏提示
setTimeout(() => {
document.querySelector('.scroll-hint').style.opacity = '0';
setTimeout(() => {
document.querySelector('.scroll-hint').style.display = 'none';
}, 500);
}, 3000);
}
// 排序状态管理
let currentSort = {
column: null,
direction: 'asc' // 'asc' 或 'desc'
};
// 筛选功能实现
document.addEventListener('DOMContentLoaded', function() {
const filterHeader = document.getElementById('filterHeader');
const filterBody = document.getElementById('filterBody');
const filterToggle = document.getElementById('filterToggle');
const applyFilters = document.getElementById('applyFilters');
const resetFilters = document.getElementById('resetFilters');
const refreshData = document.getElementById('refreshData');
// 筛选面板折叠/展开功能
filterHeader.addEventListener('click', function() {
if (filterBody.style.display === 'none') {
filterBody.style.display = 'block';
filterToggle.classList.remove('bi-chevron-down');
filterToggle.classList.add('bi-chevron-up');
} else {
filterBody.style.display = 'none';
filterToggle.classList.remove('bi-chevron-up');
filterToggle.classList.add('bi-chevron-down');
}
});
// 应用筛选功能
applyFilters.addEventListener('click', function() {
applyFilterLogic();
});
// 重置筛选功能
resetFilters.addEventListener('click', function() {
document.getElementById('filterName').value = '';
document.getElementById('filterStatus').value = '';
document.getElementById('filterPath').value = '';
document.getElementById('filterMinTotal').value = '';
document.getElementById('filterMin2025').value = '';
applyFilterLogic();
});
// 刷新数据
refreshData.addEventListener('click', function() {
location.reload();
});
// 筛选逻辑
function applyFilterLogic() {
const filterName = document.getElementById('filterName').value.toLowerCase();
const filterStatus = document.getElementById('filterStatus').value;
const filterPath = document.getElementById('filterPath').value.toLowerCase();
const filterMinTotal = parseInt(document.getElementById('filterMinTotal').value) || 0;
const filterMin2025 = parseInt(document.getElementById('filterMin2025').value) || 0;
const rows = document.querySelectorAll('#dataTable tbody tr');
let visibleCount = 0;
rows.forEach(row => {
if (row.cells.length < 9) return;
const nameCell = row.querySelector('.name-cell');
const statusCell = row.querySelector('.status-cell');
const pathCell = row.querySelector('.path-cell');
const totalSubmissions = parseInt(row.querySelector('.total-submissions').textContent.replace(/,/g, ''));
const submissions2025 = parseInt(row.querySelector('.submissions-2025').textContent.replace(/,/g, ''));
// 移除之前的高亮效果
nameCell.innerHTML = nameCell.innerHTML.replace(/<span class="highlight">|<\/span>/g, '');
pathCell.innerHTML = pathCell.innerHTML.replace(/<span class="highlight">|<\/span>/g, '');
// 检查筛选条件
const nameMatch = nameCell.textContent.toLowerCase().includes(filterName);
const statusMatch = filterStatus === '' || statusCell.textContent.includes(filterStatus);
const pathMatch = pathCell.textContent.toLowerCase().includes(filterPath);
const totalMatch = totalSubmissions >= filterMinTotal;
const yearMatch = submissions2025 >= filterMin2025;
if (nameMatch && statusMatch && pathMatch && totalMatch && yearMatch) {
row.style.display = '';
visibleCount++;
// 高亮匹配文本
if (filterName) {
const regex = new RegExp(filterName, 'gi');
nameCell.innerHTML = nameCell.textContent.replace(regex,
match => `<span class="highlight">${match}</span>`);
}
if (filterPath) {
const regex = new RegExp(filterPath, 'gi');
pathCell.innerHTML = pathCell.textContent.replace(regex,
match => `<span class="highlight">${match}</span>`);
}
} else {
row.style.display = 'none';
}
});
// 更新计数
document.getElementById('filteredCount').textContent = visibleCount;
// 如果没有匹配项
if (visibleCount === 0) {
document.querySelector('#dataTable tbody').innerHTML = `
<tr>
<td colspan="9" class="text-center py-5">
<div class="text-muted">
<i class="bi bi-search me-2"></i> 没有找到匹配的记录
</div>
</td>
</tr>
`;
}
}
// 为筛选输入框添加回车键支持
const filterInputs = document.querySelectorAll('.filter-control');
filterInputs.forEach(input => {
input.addEventListener('keyup', function(event) {
if (event.key === 'Enter') {
applyFilterLogic();
}
});
});
// 表格排序功能
const sortableHeaders = document.querySelectorAll('th.sortable');
sortableHeaders.forEach(header => {
header.addEventListener('click', function() {
const column = this.getAttribute('data-column');
let direction = 'asc';
// 如果点击的是当前已排序的列,则切换排序方向
if (currentSort.column === column) {
direction = currentSort.direction === 'asc' ? 'desc' : 'asc';
} else {
// 重置所有排序指示器
sortableHeaders.forEach(h => {
h.classList.remove('sort-active');
const indicator = h.querySelector('.sort-indicator');
indicator.innerHTML = '<i class="bi bi-arrow-down-up"></i>';
});
}
// 更新当前排序状态
currentSort.column = column;
currentSort.direction = direction;
// 更新UI
this.classList.add('sort-active');
const indicator = this.querySelector('.sort-indicator');
indicator.innerHTML = direction === 'asc'
? '<i class="bi bi-arrow-up"></i>'
: '<i class="bi bi-arrow-down"></i>';
// 执行排序
sortTable(column, direction);
});
});
// 表格排序函数
function sortTable(column, direction) {
const table = document.getElementById('dataTable');
const tbody = table.querySelector('tbody');
const rows = Array.from(tbody.querySelectorAll('tr:not([style*="display: none"])'));
// 如果没有行,则返回
if (rows.length === 0) return;
// 获取列索引
let columnIndex;
const headers = table.querySelectorAll('thead th');
headers.forEach((header, index) => {
if (header.getAttribute('data-column') === column) {
columnIndex = index;
}
});
// 排序行
rows.sort((a, b) => {
const aValue = a.cells[columnIndex].textContent.trim();
const bValue = b.cells[columnIndex].textContent.trim();
// 尝试转换为数字
const aNum = parseFloat(aValue.replace(/,/g, ''));
const bNum = parseFloat(bValue.replace(/,/g, ''));
// 尝试转换为日期
const aDate = new Date(aValue);
const bDate = new Date(bValue);
let comparison = 0;
// 数值比较
if (!isNaN(aNum) && !isNaN(bNum)) {
comparison = aNum - bNum;
}
// 日期比较
else if (aDate instanceof Date && !isNaN(aDate) && bDate instanceof Date && !isNaN(bDate)) {
comparison = aDate - bDate;
}
// 状态比较(特殊处理)
else if (column === '流程状态') {
const statusOrder = { '有效': 1, '测试': 2, '无效': 3 };
const aStatus = statusOrder[aValue] || 4;
const bStatus = statusOrder[bValue] || 4;
comparison = aStatus - bStatus;
}
// 文本比较
else {
comparison = aValue.localeCompare(bValue);
}
return direction === 'asc' ? comparison : -comparison;
});
// 重新添加行到tbody
rows.forEach(row => tbody.appendChild(row));
}
});
</script>
</body>
</html>