Commit bc1a6cea by liucan

feat:爬虫管理界面编辑弹窗添加文件导入编号功能

parent a2084a54
......@@ -16,6 +16,7 @@
"animate.css": "^4.1.1",
"axios": "^1.9.0",
"cron-parser": "^5.4.0",
"dayjs": "^1.11.19",
"echarts": "^5.6.0",
"element-plus": "^2.9.10",
"js-cookie": "^3.0.5",
......
......@@ -17,6 +17,7 @@
"animate.css": "^4.1.1",
"axios": "^1.9.0",
"cron-parser": "^5.4.0",
"dayjs": "^1.11.19",
"echarts": "^5.6.0",
"element-plus": "^2.9.10",
"js-cookie": "^3.0.5",
......
......@@ -2,88 +2,88 @@
<template>
<el-config-provider :locale="zhCn">
<el-pagination
v-show="total > 0"
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:background="true"
:page-sizes="[10]"
:pager-count="pagerCount"
:total="total"
class="mt-4"
layout="total,sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
jumper-text="跳转"
/>
v-show="total > 0"
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:background="true"
:page-sizes="[10]"
:pager-count="pagerCount"
:total="total"
class="mt-4"
layout="total,sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
jumper-text="跳转"
/>
</el-config-provider>
</template>
<script lang="ts" setup>
import { computed } from 'vue'
import { computed } from "vue";
// ElConfigProvider 组件
import { ElConfigProvider } from 'element-plus';
import { ElConfigProvider } from "element-plus";
// 引入中文包
import zhCn from 'element-plus/es/locale/lang/zh-cn';
defineOptions({ name: 'Pagination' })
import zhCn from "element-plus/es/locale/lang/zh-cn";
defineOptions({ name: "Pagination" });
// 更改分页文字
zhCn.el.pagination.total = '共 `{total} 条`';
zhCn.el.pagination.goto = '跳至';
zhCn.el.pagination.pagesize = '条/页';
zhCn.el.pagination.pageClassifier = '页';
zhCn.el.pagination.total = "共 {total} 条";
zhCn.el.pagination.goto = "跳至";
zhCn.el.pagination.pagesize = "条/页";
zhCn.el.pagination.pageClassifier = "页";
const props = defineProps({
// 总条目数
total: {
required: true,
type: Number
type: Number,
},
// 当前页数:pageNo
page: {
type: Number,
default: 1
default: 1,
},
// 每页显示条目个数:pageSize
limit: {
type: Number,
default: 20
default: 20,
},
// 设置最大页码按钮数。 页码按钮的数量,当总页数超过该值时会折叠
// 移动端页码按钮的数量端默认值 5
pagerCount: {
type: Number,
default: document.body.clientWidth < 992 ? 5 : 7
}
})
default: document.body.clientWidth < 992 ? 5 : 7,
},
});
const emit = defineEmits(['update:page', 'update:limit', 'pagination'])
const emit = defineEmits(["update:page", "update:limit", "pagination"]);
const currentPage = computed({
get() {
return props.page
return props.page;
},
set(val) {
// 触发 update:page 事件,更新 limit 属性,从而更新 pageNo
emit('update:page', val)
}
})
emit("update:page", val);
},
});
const pageSize = computed({
get() {
return props.limit
return props.limit;
},
set(val) {
// 触发 update:limit 事件,更新 limit 属性,从而更新 pageSize
emit('update:limit', val)
}
})
const handleSizeChange = (val:number) => {
emit("update:limit", val);
},
});
const handleSizeChange = (val: number) => {
// 如果修改后超过最大页面,强制跳转到第 1 页
if (currentPage.value * val > props.total) {
currentPage.value = 1
currentPage.value = 1;
}
// 触发 pagination 事件,重新加载列表
emit('pagination', { page: currentPage.value, limit: val })
}
const handleCurrentChange = (val:number) => {
emit("pagination", { page: currentPage.value, limit: val });
};
const handleCurrentChange = (val: number) => {
// 触发 pagination 事件,重新加载列表
emit('pagination', { page: val, limit: pageSize.value })
}
</script>
emit("pagination", { page: val, limit: pageSize.value });
};
</script>
\ No newline at end of file
......@@ -123,4 +123,17 @@
.el-popper__arrow::before{
background-color: #1D5484 !important;
}
//分页器总数据量文字颜色
.el-pagination__total{
color: white !important;
}
.el-select__placeholder,.el-pagination__goto,.el-pagination__classifier,.el-range-separator{
color: white !important;
}
.el-input__inner{
color: white;
}
\ No newline at end of file
......@@ -8,7 +8,7 @@
<el-input placeholder="请输入目标名称:" v-model="searchTargetName" style="width: 180px" />
</div>
<div>
<span style="color: white">时间范围</span>
<span style="color: white">采集时间</span>
<el-config-provider :locale="zhCn">
<el-date-picker
type="datetimerange"
......@@ -31,7 +31,7 @@
<div class="btns">
<el-button plain type="primary" @click="handleSearch">查询</el-button>
<el-button plain @click="resetForm">重置表格</el-button>
<el-button plain @click="resetForm">重置</el-button>
</div>
</div>
</table-search>
......
......@@ -8,7 +8,7 @@
<el-input placeholder="请输入目标名称" v-model="searchTargetName" style="width: 180px" />
</div>
<div>
<span style="color: white">时间范围</span>
<span style="color: white">采集时间</span>
<el-config-provider :locale="zhCn">
<el-date-picker
type="datetimerange"
......
......@@ -8,7 +8,7 @@
<el-input placeholder="请输入目标名称" style="width: 180px" v-model="searchTargetName" />
</div>
<div>
<span style="color: white">时间范围</span>
<span style="color: white">采集时间</span>
<el-config-provider :locale="zhCn">
<el-date-picker
v-model="timeValue"
......@@ -30,7 +30,7 @@
</div>
<div class="btns">
<el-button plain type="primary" @click="handleSearch">查询</el-button>
<el-button plain @click="resetForm">重置表格</el-button>
<el-button plain @click="resetForm">重置</el-button>
</div>
</div>
</table-search>
......
......@@ -15,12 +15,12 @@
<el-table-column property="number" label="序号" type="index" width="80" />
<el-table-column property="spider" label="爬虫代号" show-overflow-tooltip />
<el-table-column property="spider_name" label="爬虫名称" show-overflow-tooltip />
<el-table-column property="spider_info" label="任务描述" show-overflow-tooltip />
<el-table-column min-width="200" property="spider_info" label="任务描述" show-overflow-tooltip />
<el-table-column label="操作">
<template #default="scope">
<div class="btn-group">
<el-button type="primary" plain @click="handleDetails(scope.row)">查看任务</el-button>
<el-button type="primary" plain @click="handleEditSateId" v-if="scope.row.editable">编辑</el-button>
<el-button link type="primary" plain @click="handleDetails(scope.row)">查看任务</el-button>
<el-button link type="primary" plain @click="handleEditSateId" v-if="scope.row.editable">编辑</el-button>
</div>
</template>
</el-table-column>
......@@ -35,7 +35,7 @@
</div>
</div>
<el-dialog style="z-index: 999999" draggable v-model="editDialogVisible" title="指定下载以下卫星" width="400">
<el-dialog style="z-index: 999999" draggable v-model="editDialogVisible" title="指定下载以下卫星" width="550">
<div class="No-Content" ref="noContentRef">
<TransitionGroup
enter-active-class="animate__animated animate__slideInRight"
......@@ -65,7 +65,7 @@
style="width: 100px"
></el-input>
</div>
<div class="btn">
<div class="btns">
<el-button :disabled="curSateNo == ''" plain type="primary" @click="addNoToList">添加</el-button>
<el-popconfirm title="确定删除选中编号吗?" width="200" style="background-color: pink">
<template #reference>
......@@ -87,6 +87,16 @@
</el-button>
</template>
</el-popconfirm>
<el-upload
:on-change="handleFileChange"
accept=".txt"
action="#"
:auto-upload="false"
:show-file-list="false"
:before-upload="beforeUpload"
>
<el-button type="primary">导入编号文件</el-button>
</el-upload>
</div>
</div>
</el-dialog>
......@@ -94,13 +104,14 @@
</template>
<script setup lang="ts">
import { ref, onMounted, nextTick } from "vue";
import { ref, onMounted, nextTick, watch } from "vue";
import Pagination from "@/components/pagination/index.vue";
import { useRouter } from "vue-router";
import { getSpiderList, addSateNo, getSateIdList } from "@/api/system.ts";
import NoItem from "./components/NoItem.vue";
import { ElMessage } from "element-plus";
import { ElMessage, type UploadProps, type UploadRawFile } from "element-plus";
import MenuTitle from "@/components/MenuTitle.vue";
import { number } from "echarts";
const router = useRouter();
const tableData = ref([]);
......@@ -147,7 +158,7 @@ const handleSateDel = (no: string | number) => {
//添加编号到列表并整体发到后端
const addNoToList = async () => {
try {
if (sateNoList.value.includes(padZeroTo5Digits(curSateNo.value))) {
if (curSateNo.value && sateNoList.value.includes(padZeroTo5Digits(curSateNo.value))) {
ElMessage.error("当前编号已存在,请重新输入");
curSateNo.value = "";
return;
......@@ -167,6 +178,22 @@ const addNoToList = async () => {
}
};
//编号文件导入后发送到后端
const fileImptAddNoList = async () => {
try {
const res = await addSateNo({ id: sateNoList.value });
if (res.code === 0) {
ElMessage.success("编号导入成功");
} else {
sateNoList.value.pop();
ElMessage.error(res.message);
}
scrollToBottom();
} catch (error: any) {
ElMessage.error(error.message);
}
};
//删除选中编号
const delNoList = async () => {
try {
......@@ -221,12 +248,107 @@ const handleEditSateId = async () => {
}
};
//读取文本文件后存储读取的编号
const textFileNumbers = ref<number[]>([]);
//监听导入文件的数组变化
watch(textFileNumbers, (newVal) => {
if (newVal.length > 0) {
newVal.map((num) => {
if (!sateNoList.value.includes(padZeroTo5Digits(num))) {
sateNoList.value.push(padZeroTo5Digits(num));
}
});
fileImptAddNoList();
}
});
//判断上传文件类型
const beforeUpload: UploadProps["beforeUpload"] = (rawFile: UploadRawFile) => {
// 检查文件是否存在
if (!rawFile) {
ElMessage.error("请选择文件");
return Promise.reject();
}
// 检查文件类型
const isTxtType = rawFile.type === "text/plain";
// 检查文件后缀名
const fileName = rawFile.name;
const isTxtExt = fileName.lastIndexOf(".") > 0 && fileName.slice(fileName.lastIndexOf(".")).toLowerCase() === ".txt";
// 如果两种检查都不通过
if (!isTxtType && !isTxtExt) {
ElMessage.error("只能上传 .txt 格式的文件!");
//阻止上传
return Promise.reject();
}
// 校验通过
return true;
};
//处理文件上传
const handleFileChange: UploadProps["onChange"] = (uploadFile) => {
//清空之前的值
textFileNumbers.value = [];
//获取原生file对象
const file = uploadFile.raw;
if (!file || !(file instanceof File)) {
ElMessage.error("未获取到有效文件");
return;
}
//验证文件类型
if (file.type !== "text/plain" && !file.name.endsWith(".txt")) {
ElMessage.error("请上传.txt文件");
}
//使用FileReader读取文件内容
const reader = new FileReader();
//成功的回调
reader.onload = (event: ProgressEvent<FileReader>) => {
const textContent = event.target?.result as string;
if (!textContent) {
throw new Error("文件内容为空");
}
textFileNumbers.value = parseTextToNumbers(textContent);
};
//失败的回调
reader.onerror = () => {
ElMessage.error("文件导入失败,请检查文件是否损坏或重试");
};
//读取文件
reader.readAsText(file, "utf-8");
};
//解析文件内容
const parseTextToNumbers = (text: string): number[] => {
if (!text) return [];
//换行符分割
const lines = text.split(/\r?\n/);
//遍历处理
const numbers = lines
.map((line, index) => {
//去除首尾空格
const trimmedLine = line.trim();
if (trimmedLine === "") return null;
const number = Number(trimmedLine);
if (isNaN(number)) {
return null;
}
return number;
})
.filter((num): num is number => num !== null);
return numbers;
};
onMounted(() => {
getData();
});
</script>
<style scoped>
:deep(.el-input__inner) {
color: black;
}
/* 去除按钮边框 */
.el-button:focus {
outline: none;
......@@ -250,6 +372,11 @@ onMounted(() => {
color: white;
}
.btns {
display: flex;
gap: 10px;
}
.low-titme {
color: #ccc;
text-align: left;
......
......@@ -6,7 +6,7 @@
<el-button test-element="userSystem-AddUser" type="primary" plain @click="openAddUserDialog"
>创建用户</el-button
>
<el-button type="danger" plain @click="handleBatchDelete">批量删除</el-button>
<el-button type="danger" plain @click="handleBatchDelete" class="">批量删除</el-button>
</div>
</el-card>
<div class="table-content">
......@@ -37,8 +37,8 @@
<el-table-column property="create_time" label="创建时间" width="280" show-overflow-tooltip />
<el-table-column label="操作" width="220">
<template #default="scope">
<el-button type="primary" plain @click="handleEdit(scope.row)" id="editUser"> 编辑 </el-button>
<el-button type="danger" plain @click="handleDelete(scope.row)"> 删除 </el-button>
<el-button link type="primary" plain @click="handleEdit(scope.row)" id="editUser"> 编辑 </el-button>
<el-button link type="danger" plain @click="handleDelete(scope.row)"> 删除 </el-button>
</template>
</el-table-column>
</el-table>
......
......@@ -12,8 +12,8 @@
<el-form-item label="任务名称:" v-if="currentMode === AddMode.ADD_TASK" prop="taskName">
<el-input v-model="ruleForm.taskName" placeholder="请输入任务名称" style="width: 90%" />
</el-form-item>
<el-form-item label="所属爬虫:" v-if="currentMode === AddMode.ADD_TASK" prop="spiderTypeValue">
<el-select v-model="ruleForm.spiderTypeValue" placeholder="请选择所属爬虫" style="width: 90%">
<el-form-item label="选择爬虫:" v-if="currentMode === AddMode.ADD_TASK" prop="spiderTypeValue">
<el-select v-model="ruleForm.spiderTypeValue" placeholder="请选择爬虫" style="width: 90%">
<el-option
v-for="item in spiderTypeOptions"
:key="item.spider"
......
......@@ -4,7 +4,7 @@
<TableSearch>
<div class="form-content">
<div class="ipt">
<span style="color: white">所属爬虫:</span>
<span style="color: white">选择爬虫:</span>
<el-select
v-model="searchCondition.spiders"
placeholder="请选择"
......@@ -42,9 +42,11 @@
<el-button plain type="danger" @click="deleteTask(task)" class="deleteButton" :disabled="!task?.id"
>删除</el-button
>
</div>s
</div>
s
<div class="info">
<div class="item">s
<div class="item">
s
<span class="wordStyle">启用/停止: </span>
<el-switch
v-model="task.status"
......
......@@ -6,17 +6,17 @@
<table-search>
<div class="form-content">
<div class="timer">
<span style="color: white">时间</span>
<span style="color: white">采集日期</span>
<el-config-provider :locale="zhCn">
<el-date-picker
v-model="timeValue"
type="datetimerange"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
format="YYYY-MM-DD"
date-format="YYYY/MM/DD ddd"
time-format="A hh:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD"
/>
</el-config-provider>
</div>
......@@ -56,7 +56,7 @@
{{ scope.row.run_status === "unknown" ? "已结束" : scope.row.run_status }}
</template>
</el-table-column>
<el-table-column property="create_time" label="调度时间" width="200" show-overflow-tooltip />
<el-table-column property="create_time" label="采集时间" width="200" show-overflow-tooltip />
</el-table>
</div>
<div class="pagination w-full flex flex-row-reverse pr-4 m-t-4">
......@@ -81,6 +81,8 @@ import { getSpiderTaskRecord } from "@/api/spiderTask.ts";
import { ElMessage } from "element-plus";
import MenuTitle from "@/components/MenuTitle.vue";
import TableSearch from "@/components/TableSearch.vue";
//时间处理库
import dayjs from "dayjs";
// ElConfigProvider 组件
import { ElConfigProvider } from "element-plus";
// 引入中文包
......@@ -93,21 +95,8 @@ zhCn.el.pagination.pagesize = "条/页";
zhCn.el.pagination.pageClassifier = "页";
const route = useRoute();
const router = useRouter();
const timeValue = ref("");
const taskOptions = [
{
value: "task1",
label: "sk网",
},
{
value: "task2",
label: "nasa网",
},
{
value: "task3",
label: "网",
},
];
//初始数据为近七天
const timeValue = ref([dayjs().subtract(7, "day").format("YYYY-MM-DD"), dayjs().format("YYYY-MM-DD")]);
const tableData = ref([]);
const pageObj = ref({
total: 10,
......@@ -133,17 +122,18 @@ const tableLoading = ref(false);
//重置查询
const resetQuery = () => {
timeValue.value = "";
timeValue.value = [];
getData();
};
// 获取任务执行记录列表
const getData = async () => {
tableLoading.value = true;
const res = await getSpiderTaskRecord({ page: pageObj.value.pageNo, size: pageObj.value.pageSize, status: "total" });
pageObj.value.total = res.data.total;
tableData.value = res.data.list;
tableLoading.value = false;
// tableLoading.value = true;
// const res = await getSpiderTaskRecord({ page: pageObj.value.pageNo, size: pageObj.value.pageSize, status: "total" });
// pageObj.value.total = res.data.total;
// tableData.value = res.data.list;
// tableLoading.value = false;
searchData();
};
//查询数据的方法
......@@ -152,7 +142,7 @@ const searchData = async () => {
ElMessage.warning("请先选择时间段");
return;
}
let resTime = [];
let resTime: any[] = [];
const startTime = timeValue.value[0];
const endTime = timeValue.value[1];
resTime.push(startTime);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment