feat: 接口联调

main
JINGYJ 2 weeks ago
parent 030a2efae2
commit 0188766a68

@ -16,6 +16,7 @@
"@types/three": "^0.175.0", "@types/three": "^0.175.0",
"axios": "^1.8.3", "axios": "^1.8.3",
"echarts": "^5.6.0", "echarts": "^5.6.0",
"exceljs": "^4.4.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"moment": "^2.30.1", "moment": "^2.30.1",
"postcss-scss": "^4.0.9", "postcss-scss": "^4.0.9",

File diff suppressed because it is too large Load Diff

@ -22,6 +22,11 @@ export const getAppearanceMonitorApi = (params: any) => {
return request.get(`/api/v1/record/record/`, params); return request.get(`/api/v1/record/record/`, params);
}; };
// 删除检测
export const deleteAppearanceMonitorApi = (data: any) => {
return request.delete(`/api/v1/record/record/${data.id}/`, data);
};
// 撑杆检测详情 // 撑杆检测详情
export const getAppearanceMonitorDetailApi = (params: any) => { export const getAppearanceMonitorDetailApi = (params: any) => {
return request.get(`/api/v1/record/record_detail_list/`, params); return request.get(`/api/v1/record/record_detail_list/`, params);

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

@ -95,6 +95,7 @@ onMounted(() => {
<template> <template>
<div class="flex justify-between h-full align-middle Navbar_wrap"> <div class="flex justify-between h-full align-middle Navbar_wrap">
<div class="flex items-center left"> <div class="flex items-center left">
<div class="bg_logo_left"></div>
</div> </div>
<div class="flex"> <div class="flex">
<!-- <div class="center_title" /> --> <!-- <div class="center_title" /> -->
@ -122,6 +123,15 @@ onMounted(() => {
.left { .left {
width: 30vw; width: 30vw;
.bg_logo_left {
margin-left: 22px;
width: 88px;
height: 40px;
background-image: url("@/assets/common/logo_left.png");
background-size: 100% 100%;
background-position: center;
background-repeat: no-repeat;
}
} }
.center_title { .center_title {

@ -107,6 +107,13 @@ class Request {
): Promise<T> { ): Promise<T> {
return this.request<T>({ ...config, method: "POST", url, data }); return this.request<T>({ ...config, method: "POST", url, data });
} }
delete<T = any>(
url: string,
data?: any,
config?: RequestConfig<T>
): Promise<T> {
return this.request<T>({ ...config, method: "DELETE", url, data });
}
// 其他方法类似... // 其他方法类似...
} }

@ -46,7 +46,7 @@
<div class="px-[16px]"> <div class="px-[16px]">
<div class="appearance-monitor-search-box"> <div class="appearance-monitor-search-box">
<el-select v-model="searchForm.fault_type" placeholder="站点" class="custom-select"> <el-select v-model="searchForm.station" placeholder="站点" class="custom-select">
<el-option label="小觉站" value="小觉站"></el-option> <el-option label="小觉站" value="小觉站"></el-option>
<el-option label="东西站" value="东西站"></el-option> <el-option label="东西站" value="东西站"></el-option>
<el-option label="立杆区" value="立杆区"></el-option> <el-option label="立杆区" value="立杆区"></el-option>
@ -86,8 +86,8 @@
</div> </div>
<PointModal v-model:value="isPointOpen" :info="currentRow" @close="isPointOpen = false" /> <PointModal v-model:value="isPointOpen" :info="currentRow" @close="isPointOpen = false" />
<AlarmModal v-model:value="isAlarmOpen" :info="currentRow" @close="isAlarmOpen = false" /> <AlarmModal v-model:value="isAlarmOpen" :info="currentRow" :image="currFileList" @close="isAlarmOpen = false" />
<DeleteModal v-model:value="isDeleteOpen" :info="currentRow" @close="isDeleteOpen = false" /> <DeleteModal v-model:value="isDeleteOpen" @delete-success="getList()" :info="currentRow" @close="isDeleteOpen = false" />
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -112,11 +112,11 @@ const activeIndex = ref(-1);
const swiperRef = ref(null); const swiperRef = ref(null);
const isPointOpen = ref<Boolean>(false); // const isPointOpen = ref<Boolean>(false); //
const isAlarmOpen = ref<Boolean>(false); // const isAlarmOpen = ref<Boolean>(false); //
const isDeleteOpen = ref<Boolean>(false); // const isDeleteOpen = ref<Boolean>(false); //
const columns = [ const columns = [
{ {
label: "站点", label: "站点",
property: "is_reviewed", property: "station",
width: 70, width: 70,
}, },
{ {
@ -256,6 +256,7 @@ const searchForm = reactive({
train_number: "", train_number: "",
train_carriage_number: "", train_carriage_number: "",
fault_type: "", fault_type: "",
station:"",
type: "appearance" type: "appearance"
}); });
const dataLoading = ref(true); const dataLoading = ref(true);
@ -288,7 +289,18 @@ const getFileList = async () => {
const res = await getAppearanceMonitorDetailApi({ id: currentRow.value?.id, current: 1, pageSize: 1000 }) const res = await getAppearanceMonitorDetailApi({ id: currentRow.value?.id, current: 1, pageSize: 1000 })
console.log(res.data, 'getDetailList_data') console.log(res.data, 'getDetailList_data')
if (isSuccessApi(res)) { if (isSuccessApi(res)) {
currFileList.value = res.data.data; // currFileList.value = res.data.data;
currFileList.value = [
{
image_url: 'https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg'
},{
image_url: 'https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg'
},{
image_url: 'https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg'
},{
image_url: 'https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg'
}
]
currFile.value = res.data.data[0]; currFile.value = res.data.data[0];
activeIndex.value = 0; activeIndex.value = 0;
} }

@ -14,6 +14,11 @@
<div class="pole-main-content px-[16px]"> <div class="pole-main-content px-[16px]">
<!-- 搜索区域 --> <!-- 搜索区域 -->
<div class="pole-monitor-search-box"> <div class="pole-monitor-search-box">
<el-select v-model="searchForm.station" placeholder="站点" class="custom-select">
<el-option label="小觉站" value="小觉站"></el-option>
<el-option label="东西站" value="东西站"></el-option>
<el-option label="立杆区" value="立杆区"></el-option>
</el-select>
<el-input v-model="searchForm.train_number" placeholder="请输入列车号" class="custom-input" clearable /> <el-input v-model="searchForm.train_number" placeholder="请输入列车号" class="custom-input" clearable />
<el-input v-model="searchForm.train_carriage_number" placeholder="请输入车厢号" class="custom-input" <el-input v-model="searchForm.train_carriage_number" placeholder="请输入车厢号" class="custom-input"
clearable /> clearable />
@ -83,6 +88,8 @@
</div> </div>
</div> </div>
</div> </div>
<AlarmModal v-model:value="isAlarmOpen" :info="currentRow" :image="currFileList" @close="isAlarmOpen = false" />
<DeleteModal v-model:value="isDeleteOpen" @delete-success="getList()" :info="currentRow" @close="isDeleteOpen = false" />
<!-- <div class="bg_footer_desp"> <!-- <div class="bg_footer_desp">
</div> --> </div> -->
</div> </div>
@ -96,6 +103,8 @@ import { Swiper, SwiperSlide } from "swiper/vue";
import { Navigation, Scrollbar } from "swiper/modules"; import { Navigation, Scrollbar } from "swiper/modules";
import { getAppearanceMonitorApi, getAppearanceMonitorDetailApi } from '@/api/dashboard'; import { getAppearanceMonitorApi, getAppearanceMonitorDetailApi } from '@/api/dashboard';
import { isSuccessApi } from "@/utils/forApi"; import { isSuccessApi } from "@/utils/forApi";
import AlarmModal from './components/AlarmModal.vue'
import DeleteModal from './components/DeleteModal.vue'
import "swiper/css"; import "swiper/css";
import 'swiper/scss'; import 'swiper/scss';
import 'swiper/scss/navigation'; import 'swiper/scss/navigation';
@ -107,49 +116,118 @@ const modules = [Navigation, Scrollbar];
const activeIndex = ref(-1); const activeIndex = ref(-1);
const swiperRef = ref(null); const swiperRef = ref(null);
const columns = [ const columns = [
{
label: "站点",
property: "station",
width: 70,
},
{ {
label: "车号", label: "车号",
property: "train_number", property: "train_number",
width: 130, width: 120,
}, },
{ {
label: "车型", label: "车型",
property: "train_model", property: "train_model",
width: 100, width: 70,
}, },
{ {
label: "车厢号", label: "车厢号",
property: "train_carriage_number", property: "train_carriage_number",
width: 100, width: 80,
}, },
{ {
label: "告警类型", label: "告警类型",
property: "alarm_type", property: "alarm_type",
width: 120, width: 100,
}, },
{ {
label: "故障类型", label: "故障类型",
property: "fault_type", property: "fault_type",
width: 120, width: 100,
}, },
{ {
label: "等级", label: "等级",
property: "level", property: "level",
width: 80, width: 60,
}, },
// {
// label: "",
// property: "is_reviewed",
// formatter: ({ is_reviewed }) => {
// return is_reviewed === true
// ? ""
// : "";
// },
// width: 80,
// },
{ {
label: "复核", label: "时间",
property: "is_reviewed", property: "created_at"
formatter: ({ is_reviewed }) => {
return is_reviewed === true
? "是"
: "否";
}, },
width: 80, {
slot: "operation",
label: "操作",
width: 120,
formatter: (row) => {
return h(
"div",
{
style: {
fontSize: "14px",
color:"#37EBFF"
}
}, },
[
// h("i", {
// class: `iconfont icon-zishebeizu pr-[8px]`
// }),
h(
"span",
{ {
label: "时间", fontSize: "14px",
property: "created_at" class: "pf-1",
},
[
h("i",
{
style: {
fontSize: "14px",
letterSpacing: "2px",
marginRight: "4px",
color:"#009DFF"
},
onClick: (row) => {
// console.log(row.id);
//
isAlarmOpen.value = true;
currentRow.value = row;
}
},
"详情"
),
h("i",
{
style: {
fontSize: "14px",
letterSpacing: "2px",
marginRight: "4px",
color:"#FF2727"
},
onClick: (row) => {
// console.log(row.id);
//
isDeleteOpen.value = true;
currentRow.value = row;
}
},
"删除"
),
]
)
]
);
}
} }
] ]
@ -163,9 +241,12 @@ const searchForm = reactive({
train_number: "", train_number: "",
train_carriage_number: "", train_carriage_number: "",
fault_type: "", fault_type: "",
station: "",
type: "pole" type: "pole"
}); });
const dataLoading = ref(true); const dataLoading = ref(true);
const isAlarmOpen = ref<Boolean>(false); //
const isDeleteOpen = ref<Boolean>(false); //
// const isCurrPlaying = computed(() => { // const isCurrPlaying = computed(() => {

@ -13,10 +13,9 @@
<!-- 图片区域 --> <!-- 图片区域 -->
<div class="alarm-content"> <div class="alarm-content">
<div class="alarm-content-top"> <div class="alarm-content-top">
<img src="https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg" alt=""></img> <template v-for="(item,index) in image" :key="index">
<img src="https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg" alt=""></img> <img :src="item.image_url" alt="" v-if="index < 4"></img>
<img src="https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg" alt=""></img> </template>
<img src="https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg" alt=""></img>
</div> </div>
<div class="alarm-content-bottom"> <div class="alarm-content-bottom">
<span class="alarm-content-bottom-title">列车信息:</span> <span class="alarm-content-bottom-title">列车信息:</span>
@ -29,6 +28,11 @@
<span class="mr-8">告警类型: <i>{{ info.alarm_type }}</i></span> <span class="mr-8">告警类型: <i>{{ info.alarm_type }}</i></span>
<span>故障类型: <i>{{ info.fault_type }}</i></span> <span>故障类型: <i>{{ info.fault_type }}</i></span>
</div> </div>
<div class="alarm-content-bottom-btn">
<el-button type="primary" @click="exportToExcel" class="alarm-btn">
<span class="icon"></span> 导出
</el-button>
</div>
</div> </div>
</div> </div>
</el-dialog> </el-dialog>
@ -36,18 +40,21 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { ref } from 'vue';
import ExcelJS from 'exceljs';
interface Props { interface Props {
/** 弹窗显隐 */ /** 弹窗显隐 */
value: boolean; value: boolean;
info: Record<string, any>; info: Record<string, any>;
image: any;
} }
interface Emits { interface Emits {
(e: "update:value", val: boolean): void; (e: "update:value", val: boolean): void;
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
value: false, value: false,
info: {} info: {},
image: []
}); });
const emit = defineEmits<Emits>(); const emit = defineEmits<Emits>();
@ -65,6 +72,62 @@ const show = computed({
emit("update:value", val); emit("update:value", val);
} }
}); });
// Excel
const exportToExcel = async () => {
const { info, image } = props;
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('Sheet1');
//
const data = [
['列车编号', '车型', '发生时间', '告警类型', '故障类型'],
[info.train_number, info.train_model, info.created_at, info.alarm_type, info.fault_type]
];
worksheet.addRows(data);
//
if (image.length > 0) {
for (let i = 0; i < Math.min(image.length, 4); i++) {
const imgUrl = image[i].image_url;
try {
console.log(`开始加载图片: ${imgUrl}`);
const response = await fetch(imgUrl);
if (!response.ok) {
console.error(`图片加载失败,状态码: ${response.status}URL: ${imgUrl}`);
continue;
}
const blob = await response.blob();
const arrayBuffer = await blob.arrayBuffer();
const imageId = workbook.addImage({
// 使 arrayBuffer
buffer: arrayBuffer,
extension: 'png',
});
worksheet.addImage(imageId, {
tl: { col: 0, row: i + 2 },
ext: { width: 200, height: 200 },
});
console.log(`图片 ${imgUrl} 已成功添加到 Excel`);
} catch (error) {
console.error(`图片处理过程中出错URL: ${imgUrl},错误信息:`, error);
}
}
}
try {
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'alarm_info.xlsx';
link.click();
URL.revokeObjectURL(url);
} catch (error) {
console.error('导出 Excel 文件时出错:', error);
}
};
</script> </script>
<style lang="scss"> <style lang="scss">
@ -74,13 +137,13 @@ const show = computed({
box-shadow: none; box-shadow: none;
background-color: transparent; background-color: transparent;
background-image: url("@/assets/common/bg_real_dialog.png"); background-image: url("@/assets/common/bg_real_dialog.png");
background-size: contain; background-size: 100% 100%;
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
width: 805px; width: 805px;
height: 612px; height: 712px;
padding: 0; padding: 0;
margin-top: calc(50vh - 316px); // margin-top: calc(50vh - 316px);
.el-dialog__header.show-close { .el-dialog__header.show-close {
padding: 0; padding: 0;
@ -99,7 +162,7 @@ const show = computed({
color: white; color: white;
padding: 0; padding: 0;
padding-top: 8px; padding-top: 8px;
margin-bottom: 10px;
.header-left { .header-left {
padding: 0 24px; padding: 0 24px;
font-weight: bold; font-weight: bold;
@ -161,6 +224,28 @@ const show = computed({
.alarm-content-bottom-info:nth-of-type(1) { .alarm-content-bottom-info:nth-of-type(1) {
margin: 4px 0; margin: 4px 0;
} }
.alarm-content-bottom-btn {
margin-top: 24px;
text-align: end;
.alarm-btn {
width: 96px;
height: 32px;
background: linear-gradient(180deg, #2589ff 0%, #46a9ed 100%);
border: 1px solid #42a5f5;
border-radius: 2px;
color: white;
margin-left: 0;
& .icon {
width: 14px;
height: 14px;
background-image: url("@/assets/common/export_icon.png");
background-size: contain;
background-position: center;
background-repeat: no-repeat;
margin-right: 5px;
}
}
}
} }
} }

@ -17,7 +17,7 @@
<template #footer> <template #footer>
<div class="delete-footer"> <div class="delete-footer">
<el-button class="delete-cancel" @click="handleClose"></el-button> <el-button class="delete-cancel" @click="handleClose"></el-button>
<el-button class="delete-confirm" @click="handleClose"> <el-button class="delete-confirm" @click="deleteData(info.id)">
确认 确认
</el-button> </el-button>
</div> </div>
@ -27,6 +27,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { ref } from 'vue';
import { deleteAppearanceMonitorApi } from '@/api/dashboard';
interface Props { interface Props {
/** 弹窗显隐 */ /** 弹窗显隐 */
@ -35,6 +36,7 @@ interface Props {
} }
interface Emits { interface Emits {
(e: "update:value", val: boolean): void; (e: "update:value", val: boolean): void;
(e: "delete-success"): void;
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
value: false, value: false,
@ -47,7 +49,20 @@ const emit = defineEmits<Emits>();
const handleClose = () => { const handleClose = () => {
emit("update:value", false); emit("update:value", false);
}; };
//
const deleteData = async (id:any) => {
console.log(emit('delete-success'));
try {
const res = await deleteAppearanceMonitorApi({id: id})
console.log(res, 'deleteData')
if(res.code === 200) {
handleClose()
emit('delete-success');
}
} catch (error) {
console.error('获取数据失败:', error)
}
};
const show = computed({ const show = computed({
get() { get() {
return props.value; return props.value;

Loading…
Cancel
Save