最新修改
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user