最新修改

This commit is contained in:
2026-05-26 14:08:13 +08:00
parent 93bd773c51
commit f54c58c366
18 changed files with 2180 additions and 1720 deletions

View File

@@ -20,9 +20,9 @@
<el-avatar :size="28">{{ staff.username.slice(0, 1) }}</el-avatar>
<span class="staff-name">{{ staff.username }}</span>
</div>
<el-tag type="success" effect="dark" round>
<span class="count-badge">
已锁定 {{ staff.lockedTickets.length }} 个站点
</el-tag>
</span>
</div>
</template>
<el-table :data="staff.lockedTickets" stripe border size="small" class="inner-table">
@@ -41,34 +41,112 @@
</el-table-column>
<el-table-column label="状态" width="100" align="center">
<template #default="{ row }">
<el-tag :type="Number(row.status) === 2 ? 'success' : 'info'" size="small">
<span class="status-badge" :class="'s' + Number(row.status)">
{{ statusLabel(row.status) }}
</el-tag>
</span>
</template>
</el-table-column>
</el-table>
</el-collapse-item>
</el-collapse>
</div>
<!-- 数据记录导出 -->
<div class="export-bar">
<span class="export-label">数据记录导出</span>
<div class="export-actions">
<el-radio-group v-model="exportRange" size="small">
<el-radio value="week">本周</el-radio>
<el-radio value="month">本月</el-radio>
</el-radio-group>
<el-button size="small" @click="handleExport">导出</el-button>
</div>
</div>
</el-card>
</div>
</template>
<script setup>
import { ref, onMounted, computed } from "vue";
import { ticketApi } from "@/api/ticket";
import { ticketApi, exportApi } from "@/api/ticket";
import { ElMessage } from "element-plus";
import { formatDate } from "@/utils/format";
import * as XLSX from "xlsx";
const loading = ref(true);
const staffUserList = ref([]);
const allTickets = ref([]);
const activeCollapse = ref("");
const showOnlyThisMonth = ref(false);
const exportRange = ref("week");
const statusMap = { 0: "未分配", 1: "进行中", 2: "已完成", 3: "已完结" };
const statusLabel = (status) => statusMap[Number(status)] || "未知";
const handleExport = () => {
// 使用接口获取需要导出的数据
exportApi.exportdata(exportRange.value).then((res) => {
if (res.code === 200) {
const data = res.data || [];
exportToExcel(data, exportRange.value === "week" ? "本周" : "本月", exportRange.value);
} else {
ElMessage.error("导出失败,请稍后再试");
}
}).catch(() => {
ElMessage.error("导出失败,请稍后再试");
});
};
const exportToExcel = (data, label,range) => {
data.sort((a, b) => {
const timeA = new Date(a.create_time).getTime();
const timeB = new Date(b.create_time).getTime();
if (timeA !== timeB) return timeA - timeB;
return a.username.localeCompare(b.username, "zh-CN");
});
const excelData = data.map((item) => ({
域名: item.website,
数据量: item.datanum || 0,
运营人员: item.operator_name,
采集人员: item.username,
备注: item.remark,
开始时间: item.create_time,
结束时间: item.lock_time,
}));
// 生成工作表
const worksheet = XLSX.utils.json_to_sheet(excelData);
// 自动调整列宽
const objectKeys = Object.keys(excelData[0] || {});
const max_widths = objectKeys.map((key) => {
let maxLen = key.replace(/[^\x00-\xff]/g, "00").length;
excelData.forEach((row) => {
const val = row[key] != null ? String(row[key]) : "";
const valLen = val.replace(/[^\x00-\xff]/g, "00").length;
if (valLen > maxLen) maxLen = valLen;
});
return { wch: maxLen + 3 };
});
worksheet["!cols"] = max_widths;
// 创建工作簿并导出
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "工单导出");
const now = new Date();
const month = now.getMonth() + 1;
const weekOfMonth = Math.ceil(now.getDate() / 7);
if (range === "week") {
XLSX.writeFile(workbook, `工单数据导出_${month}月第${weekOfMonth}周.xlsx`);
} else if (range === "month") {
XLSX.writeFile(workbook, `工单数据导出_${month}月.xlsx`);
}
ElMessage.success(`已导出${label}记录`);
}
onMounted(async () => {
loading.value = true;
try {
@@ -144,12 +222,21 @@ const staffWithLockedTickets = computed(() => {
<style scoped>
.stats-view {
padding: 20px;
padding: 0;
}
.box-card {
:deep(.el-card) {
background: #f5f6f8;
border: 1px solid rgba(0, 0, 0, 0.08);
border-radius: 12px;
border: 1px solid #e4e7ed;
box-shadow:
0 1px 3px rgba(0, 0, 0, 0.04),
0 4px 16px rgba(0, 0, 0, 0.035);
}
:deep(.el-card__header) {
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
padding: 18px 22px;
}
.card-header {
@@ -158,16 +245,17 @@ const staffWithLockedTickets = computed(() => {
align-items: center;
}
.card-header>span {
font-weight: 600;
font-size: 15px;
color: #1c1c28;
}
.header-actions {
display: flex;
align-items: center;
}
.card-header > span {
font-weight: bold;
font-size: 16px;
}
.collapse-title {
display: flex;
justify-content: space-between;
@@ -179,12 +267,27 @@ const staffWithLockedTickets = computed(() => {
.staff-info {
display: flex;
align-items: center;
gap: 12px;
gap: 10px;
}
.staff-name {
font-size: 15px;
font-weight: 500;
font-size: 14px;
font-weight: 600;
color: #1c1c28;
}
.count-badge {
display: inline-flex;
align-items: center;
padding: 1px 10px;
border-radius: 12px;
font-size: 11px;
font-weight: 600;
color: #15803d;
background: rgba(22, 163, 74, 0.1);
border: 1px solid rgba(22, 163, 74, 0.2);
white-space: nowrap;
line-height: 1.4;
}
.inner-table {
@@ -192,12 +295,104 @@ const staffWithLockedTickets = computed(() => {
margin: 0 16px 16px 16px;
}
:deep(.inner-table) {
border-radius: 8px;
overflow: hidden;
}
:deep(.el-collapse) {
border: none;
}
:deep(.el-collapse-item__header) {
padding: 0 16px;
height: 60px;
height: 52px;
background: transparent;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
color: #1c1c28;
font-weight: 500;
font-size: 14px;
}
:deep(.el-collapse-item__header:hover) {
background: rgba(0, 0, 0, 0.015);
}
:deep(.el-collapse-item__wrap) {
background: none;
border: none;
}
:deep(.el-collapse-item__content) {
padding-bottom: 0;
color: var(--text-primary);
}
:deep(.el-table) {
--el-table-bg-color: #fafbfc;
--el-table-header-bg-color: #f0f1f4;
--el-table-border-color: rgba(0, 0, 0, 0.04);
border-radius: 8px;
overflow: hidden;
}
:deep(.el-table th) {
font-size: 11px;
font-weight: 600;
color: #6b6d7a;
letter-spacing: 0.3px;
}
/* 状态徽章 */
.status-badge {
display: inline-block;
padding: 2px 10px;
border-radius: 10px;
font-size: 11px;
font-weight: 600;
}
.s0 {
color: #6b7280;
background: #f3f4f6;
}
.s1 {
color: #4f46e5;
background: #eef0ff;
}
.s2 {
color: #16a34a;
background: #ecfdf3;
}
.s3 {
color: #d97706;
background: #fffbeb;
}
/* 导出栏 */
.export-bar {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 20px;
padding: 14px 16px;
background: #fff;
border: 1px solid rgba(0, 0, 0, 0.06);
border-radius: 8px;
}
.export-label {
font-size: 13px;
font-weight: 600;
color: #1c1c28;
}
.export-actions {
display: flex;
align-items: center;
gap: 16px;
}
</style>