Commit 49fb79a6 by 陈岩

feat: 新增精准客流修复

1 parent 2ccbd4b6
<template> <template>
<a-form :model="queryForm" layout="inline" :label-col="{ style: { width: '100px' } }"> <a-tabs v-model:activeKey="activeKey">
<a-form-item label="集团:" style="padding: 5px 0"> <a-tab-pane key="CustomerFlow" tab="客流数据修补">
<a-select v-model:value="queryForm.account_id" <CustomerFlow />
style="width: 280px" </a-tab-pane>
mode="multiple" <a-tab-pane key="AccurateCustomerFlow" tab="精准客流修补">
:maxTagCount="1" <AccurateCustomerFlow />
@change="onAccountChange" </a-tab-pane>
:options="accountList" </a-tabs>
optionFilterProp="label"
show-search
>
</a-select>
</a-form-item>
<a-form-item label="广场:" style="padding: 5px 0">
<a-select v-model:value="queryForm.plaza_id"
style="width: 280px"
mode="multiple"
:maxTagCount="1"
@change="onPlazaChange"
:options="plazaList"
optionFilterProp="label"
show-search
>
</a-select>
</a-form-item>
<a-form-item label="监控点名称:" style="padding: 5px 0">
<a-select v-model:value="queryForm.gate_id"
style="width: 280px"
mode="multiple"
:maxTagCount="1"
@change="onGateChange"
:options="gateList"
optionFilterProp="label"
show-search
>
<template #dropdownRender="{ menuNode: menu }">
<v-nodes :vnodes="menu"/>
<a-divider style="margin: 4px 0"/>
<div
@mousedown="e => e.preventDefault()"
>
<a-button @click="selectAll('监控点名称')" type="link">全选</a-button>
<a-button @click="clearAll('监控点名称')" type="link">清空</a-button>
</div>
</template>
</a-select>
</a-form-item>
<a-form-item label="设备通道号:" style="padding: 5px 0">
<a-select v-model:value="queryForm.channel_id"
style="width: 280px"
mode="multiple"
:maxTagCount="1"
:options="channelList"
optionFilterProp="label"
show-search
>
<template #dropdownRender="{ menuNode: menu }">
<v-nodes :vnodes="menu"/>
<a-divider style="margin: 4px 0"/>
<div
@mousedown="e => e.preventDefault()"
>
<a-button @click="selectAll('设备通道号')" type="link">全选</a-button>
<a-button @click="clearAll('设备通道号')" type="link">清空</a-button>
</div>
</template>
</a-select>
</a-form-item>
<a-form-item label="修补日期:" style="padding: 5px 0">
<a-date-picker v-model:value="queryForm.repairDate" style="width: 280px"/>
</a-form-item>
<a-form-item label="参考日期:" style="padding: 5px 0">
<a-date-picker v-model:value="queryForm.referenceDate" style="width: 280px"/>
</a-form-item>
<a-form-item label="开始时间:" style="padding: 5px 0">
<a-time-picker v-model:value="queryForm.startTime" style="width: 280px"/>
</a-form-item>
<a-form-item label="结束时间:" style="padding: 5px 0">
<a-time-picker v-model:value="queryForm.endTime" style="width: 280px"/>
</a-form-item>
<a-form-item label="数据波动比例:" style="padding: 5px 0">
<a-input v-model:value="queryForm.minFactor" style="width: 129px"/>
<a-input v-model:value="queryForm.maxFactor" style="width: 129px"/>
</a-form-item>
<a-form-item style="padding: 5px 0">
<a-button type="primary" @click="preview" :loading="isLoading">预览</a-button>
</a-form-item>
<a-form-item style="padding: 5px 0">
<a-button type="primary" @click="repair" :loading="isLoading">修补</a-button>
</a-form-item>
</a-form>
<div style="display:flex; justify-content: flex-end;padding: 3px">
<a-button @click="suspendRepair" type="primary">暂停修复</a-button>
</div>
<a-table :dataSource="dataList" v-loading="isLoading" :columns="columns" :pagination="false">
<template #status="{ text }">
<span :class="getClass(text)">{{ text }}</span>
</template>
<template #operation="{ record }">
<div>
<a-button @click="deleteRecord(record)" type="primary" danger>删除任务</a-button>
</div>
</template>
</a-table>
</template> </template>
<script setup>
import { ref } from "vue";
import AccurateCustomerFlow from "./components/AccurateCustomerFlow.vue";
import CustomerFlow from "./components/CustomerFlow.vue";
<script> const activeKey = ref("AccurateCustomerFlow");
import {reactive, ref, toRaw} from 'vue'
import moment from 'moment'
import snapshotRecordApi from '@/views/SnapshotCluster/SnapshotRecord/SnapshotRecordApi'
import {isArray} from '@/PublicUtil/Judgment'
import {filterEmptyValueInObject, formatDate, formatTime} from '@/PublicUtil/PublicUtil'
import dataRepairApi from '@/views/DataRepair/DataRepairApi'
import {PlusOutlined} from '@ant-design/icons-vue'
const columns = [
{
title: '监控点名称',
dataIndex: 'gatename',
align: 'center',
},
{
title: '设备号',
dataIndex: 'deviceSerialnum',
align: 'center',
},
{
title: '通道号',
dataIndex: 'channelSerialnum',
align: 'center',
},
{
title: '参考范围数据条数',
dataIndex: 'sourceCount',
align: 'center',
},
{
title: '修复范围数据条数',
dataIndex: 'targetCount',
align: 'center',
},
{
title: '参考范围客流量',
dataIndex: 'sourceInnum',
align: 'center',
},
{
title: '修复范围客流量',
dataIndex: 'targetInnum',
align: 'center',
},
{
title: '状态',
dataIndex: 'status',
align: 'center',
slots: {
customRender: 'status',
},
},
{
title: '操作',
dataIndex: 'operation',
align: 'center',
slots: {
customRender: 'operation',
},
},
]
export default {
components: {
PlusOutlined,
VNodes: (_, {attrs}) => {
return attrs.vnodes
},
},
setup() {
// scalar
const isLoading = ref(false)
const isSuspended = ref(false)
// sequence
const resultList = ref([])
const accountList = ref([])
const plazaList = ref([])
const zoneList = ref([])
const gateList = ref([])
const channelList = ref([])
const dataList = ref([])
const queryForm = reactive(
{
account_id: [],
plaza_id: [],
gate_id: [],
channel_id: [],
repairDate: moment(moment().format('YYYY-MM-DD'), 'YYYY-MM-DD'),
referenceDate: moment(moment().format('YYYY-MM-DD'), 'YYYY-MM-DD'),
startTime: moment('00:00:00', 'HH:mm:ss'),
endTime: moment('23:59:59', 'HH:mm:ss'),
minFactor: 0.85,
maxFactor: 1.2,
}
)
const onAccountChange = function() {
getPlazaList()
queryForm.gate_id = []
gateList.value = []
queryForm.channel_id = []
channelList.value = []
}
const onPlazaChange = function() {
getGateList()
queryForm.channel_id = []
channelList.value = []
}
const onGateChange = function() {
getChannelList()
}
const getPlazaList = function() {
queryForm.plaza_id = []
plazaList.value = []
snapshotRecordApi.getPlazaList(
{
account_id: queryForm.account_id.toString()
}
).then(
(r) => {
if (isArray(r))
{
for (const item of r)
{
plazaList.value.push(
{
value: item.id,
label: item.name,
}
)
}
}
}
)
}
const getAccountList = function() {
queryForm.account_id = []
accountList.value = []
snapshotRecordApi.getAccountList().then(
(r) => {
if (isArray(r))
{
for (const item of r)
{
accountList.value.push(
{
value: item.id,
label: item.name,
}
)
}
}
}
)
}
const getGateList = async function() {
queryForm.gate_id = []
gateList.value = []
let tempList = []
for (const account of queryForm.account_id)
{
for (const plaza of queryForm.plaza_id)
{
const r = await dataRepairApi.getGateList(
{
accountIds: account,
mallIds: plaza,
}
)
if (isArray(r))
{
for (const item of r)
{
tempList.push(
{
value: item.id,
label: item.name,
}
)
}
}
}
}
gateList.value = [...new Set(tempList)]
}
const getChannelList = async function() {
queryForm.channel_id = []
channelList.value = []
let tempList = []
for (const gate of queryForm.gate_id)
{
const r = await dataRepairApi.getChannelList(
{
gateId: gate,
}
)
if (isArray(r))
{
for (const item of r)
{
tempList.push(
{
value: item,
label: item,
}
)
}
}
}
channelList.value = tempList
}
const floatToPercent = function(floatNum) {
if (!floatNum)
{
return 0
}
let formatNum = Math.floor(floatNum * 100)
return formatNum >= 100 ? 100 : formatNum
}
const preview = async function() {
isLoading.value = true
isSuspended.value = false
dataList.value = []
const rawData = toRaw(queryForm)
for (const channelId of rawData.channel_id)
{
if (isSuspended.value === true)
{
isLoading.value = false
return
}
const data = filterEmptyValueInObject(
{
channelSerialnum: channelId,
maxFactor: rawData.maxFactor,
minFactor: rawData.minFactor,
targetStartDate: formatDate(rawData.repairDate) + ' ' + formatTime(rawData.startTime),
targetEndDate: formatDate(rawData.repairDate) + ' ' + formatTime(rawData.endTime),
sourceStartDate: formatDate(rawData.referenceDate) + ' ' + formatTime(rawData.startTime),
sourceEndDate: formatDate(rawData.referenceDate) + ' ' + formatTime(rawData.endTime),
}
)
const r = await dataRepairApi.preview(data)
r.data.status = '未执行'
dataList.value.push(r.data)
}
isLoading.value = false
isSuspended.value = false
}
const repair = async function() {
isLoading.value = true
isSuspended.value = false
dataList.value = []
const rawData = toRaw(queryForm)
for (const channelId of rawData.channel_id)
{
if (isSuspended.value === true)
{
isLoading.value = false
return
}
const data = filterEmptyValueInObject(
{
channelSerialnum: channelId,
maxFactor: rawData.maxFactor,
minFactor: rawData.minFactor,
targetStartDate: formatDate(rawData.repairDate) + ' ' + formatTime(rawData.startTime),
targetEndDate: formatDate(rawData.repairDate) + ' ' + formatTime(rawData.endTime),
sourceStartDate: formatDate(rawData.referenceDate) + ' ' + formatTime(rawData.startTime),
sourceEndDate: formatDate(rawData.referenceDate) + ' ' + formatTime(rawData.endTime),
}
)
const r = await dataRepairApi.repair(data)
if (r.msg_code === 200)
{
r.data.status = '已修复'
}
else
{
r.data.status = '未执行'
}
dataList.value.push(r.data)
}
isLoading.value = false
isSuspended.value = false
}
const getClass = function(text) {
switch (text)
{
case '已修复':
{
return 'success'
}
case '未执行':
{
return 'failed'
}
default:
{
break
}
}
}
const deleteRecord = function({channelSerialnum}) {
if (channelSerialnum === undefined)
{
return
}
dataList.value = dataList.value.filter(
item => item.channelSerialnum !== channelSerialnum
)
queryForm.channel_id = queryForm.channel_id.filter(
item => item !== channelSerialnum
)
}
const suspendRepair = function() {
if (isLoading.value === true)
{
isSuspended.value = true
}
}
const selectAll = function(text) {
switch (text)
{
case '监控点名称':
{
queryForm.gate_id = []
for (const item of gateList.value)
{
queryForm.gate_id.push(item.value)
}
onGateChange()
break
}
case '设备通道号':
{
queryForm.channel_id = []
for (const item of channelList.value)
{
queryForm.channel_id.push(item.value)
}
break
}
default:
{
break
}
}
}
const clearAll = function(text) {
switch (text)
{
case '监控点名称':
{
queryForm.gate_id = []
onGateChange()
break
}
case '设备通道号':
{
queryForm.channel_id = []
break
}
default:
{
break
}
}
}
const __main = function() {
getAccountList()
}
__main()
return {
// scalar
isLoading,
// sequence
accountList,
plazaList,
zoneList,
gateList,
channelList,
resultList,
dataList,
queryForm,
columns,
// function
onAccountChange,
onPlazaChange,
onGateChange,
preview,
repair,
getClass,
deleteRecord,
suspendRepair,
selectAll,
clearAll,
}
}
}
</script> </script>
<style lang="less" scoped>
@import "./DataRepair.less";
</style>
...@@ -41,6 +41,17 @@ class DataRepairApi { ...@@ -41,6 +41,17 @@ class DataRepairApi {
} }
) )
} }
// 精准客流修复
accurateRepairApi(data){
return axiosInstance.request(
{
method: 'POST',
url: `/simulation/reid`,
data
}
)
}
} }
const dataRepairApi = new DataRepairApi() const dataRepairApi = new DataRepairApi()
......
<template>
<a-form
:model="queryForm"
layout="inline"
:label-col="{ style: { width: '100px' } }"
>
<a-form-item label="集团:" style="padding: 5px 0">
<a-select
v-model:value="queryForm.account_id"
style="width: 280px"
@change="onAccountChange"
:options="accountList"
optionFilterProp="label"
show-search
placeholder="请选择集团"
>
</a-select>
</a-form-item>
<a-form-item label="广场:" style="padding: 5px 0">
<a-select
v-model:value="queryForm.mallId"
style="width: 280px"
:maxTagCount="1"
@change="onPlazaChange"
:options="plazaList"
optionFilterProp="label"
show-search
placeholder="请选择广场"
>
</a-select>
</a-form-item>
<a-form-item label="监控点名称:" style="padding: 5px 0">
<a-select
v-model:value="queryForm.gate_id"
style="width: 280px"
mode="multiple"
:maxTagCount="1"
@change="onGateChange"
:options="gateList"
optionFilterProp="label"
show-search
placeholder="请选择监控点名称"
>
<template #dropdownRender="{ menuNode: menu }">
<v-nodes :vnodes="menu" />
<a-divider style="margin: 4px 0" />
<div @mousedown="(e) => e.preventDefault()">
<a-button @click="selectAll('监控点名称')" type="link"
>全选</a-button
>
<a-button @click="clearAll('监控点名称')" type="link"
>清空</a-button
>
</div>
</template>
</a-select>
</a-form-item>
<a-form-item label="修补日期:" style="padding: 5px 0">
<a-date-picker
v-model:value="queryForm.targetDate"
valueFormat="YYYY-MM-DD"
style="width: 280px"
:allowClear="false"
/>
</a-form-item>
<a-form-item label="参考日期:" style="padding: 5px 0">
<a-date-picker
v-model:value="queryForm.sourceDate"
valueFormat="YYYY-MM-DD"
style="width: 280px"
:allowClear="false"
/>
</a-form-item>
<a-form-item label="开始时间:" style="padding: 5px 0">
<a-time-picker
v-model:value="queryForm.startTime"
:allowClear="false"
valueFormat="HH:mm:ss"
style="width: 280px"
/>
</a-form-item>
<a-form-item label="结束时间:" style="padding: 5px 0">
<a-time-picker
v-model:value="queryForm.endTime"
:allowClear="false"
valueFormat="HH:mm:ss"
style="width: 280px"
/>
</a-form-item>
<a-form-item label="数据变化百分比:" style="padding: 5px 0">
<div style="display: flex; align-items: center">
<a-slider
v-model:value="queryForm.threshold"
:min="-60"
:max="60"
style="width: 180px"
/>
<div style="width: 60px; text-align: center">
{{ queryForm.threshold }}%
</div>
</div>
<!-- <a-input v-model:value="queryForm.threshold" style="width: 129px" /> -->
</a-form-item>
<a-form-item style="padding: 5px 0">
<a-button type="primary" @click="repair" :loading="isLoading"
>修补</a-button
>
</a-form-item>
</a-form>
<!--
<div style="display: flex; justify-content: flex-end; padding: 3px">
<a-button @click="suspendRepair" type="primary">暂停修复</a-button>
</div> -->
<!-- <a-table
:dataSource="dataList"
v-loading="isLoading"
:columns="columns"
:pagination="false"
>
<template #status="{ text }">
<span :class="getClass(text)">{{ text }}</span>
</template>
<template #operation="{ record }">
<div>
<a-button @click="deleteRecord(record)" type="primary" danger
>删除任务</a-button
>
</div>
</template>
</a-table> -->
</template>
<script>
import { reactive, ref, toRaw } from "vue";
import moment from "moment";
import snapshotRecordApi from "@/views/SnapshotCluster/SnapshotRecord/SnapshotRecordApi";
import { isArray } from "@/PublicUtil/Judgment";
import {
filterEmptyValueInObject,
formatDate,
formatTime,
} from "@/PublicUtil/PublicUtil";
import dataRepairApi from "@/views/DataRepair/DataRepairApi";
import { message } from "ant-design-vue";
const columns = [
{
title: "监控点名称",
dataIndex: "gatename",
align: "center",
},
{
title: "设备号",
dataIndex: "deviceSerialnum",
align: "center",
},
{
title: "通道号",
dataIndex: "channelSerialnum",
align: "center",
},
{
title: "参考范围数据条数",
dataIndex: "sourceCount",
align: "center",
},
{
title: "修复范围数据条数",
dataIndex: "targetCount",
align: "center",
},
{
title: "参考范围客流量",
dataIndex: "sourceInnum",
align: "center",
},
{
title: "修复范围客流量",
dataIndex: "targetInnum",
align: "center",
},
{
title: "状态",
dataIndex: "status",
align: "center",
slots: {
customRender: "status",
},
},
{
title: "操作",
dataIndex: "operation",
align: "center",
slots: {
customRender: "operation",
},
},
];
export default {
components: {
VNodes: (_, { attrs }) => {
return attrs.vnodes;
},
},
setup() {
// scalar
const isLoading = ref(false);
const isSuspended = ref(false);
// sequence
const resultList = ref([]);
const accountList = ref([]);
const plazaList = ref([]);
const zoneList = ref([]);
const gateList = ref([]);
const channelList = ref([]);
const dataList = ref([]);
const queryForm = reactive({
account_id: null,
mallId: null,
gate_id: [],
targetDate: moment(Date.now()).format("YYYY-MM-DD"),
sourceDate: moment(Date.now()).format("YYYY-MM-DD"),
startTime: "00:00:00",
endTime: "23:59:59",
threshold: 0,
});
const onAccountChange = function () {
getPlazaList();
queryForm.gate_id = [];
gateList.value = [];
queryForm.channel_id = [];
channelList.value = [];
};
const onPlazaChange = function () {
getGateList();
queryForm.channel_id = [];
channelList.value = [];
};
const onGateChange = function () {
getChannelList();
};
const getPlazaList = function () {
queryForm.mallId = null;
plazaList.value = [];
snapshotRecordApi
.getPlazaList({
account_id: queryForm.account_id.toString(),
})
.then((r) => {
if (isArray(r)) {
for (const item of r) {
plazaList.value.push({
value: item.id,
label: item.name,
});
}
}
});
};
// 获取集团列表
const getAccountList = function () {
accountList.value = [];
snapshotRecordApi.getAccountList().then((r) => {
if (isArray(r)) {
for (const item of r) {
accountList.value.push({
value: item.id,
label: item.name,
});
}
}
});
};
const getGateList = async function () {
try {
queryForm.gate_id = [];
gateList.value = [];
const r = await dataRepairApi.getGateList({
accountIds: queryForm.account_id,
mallIds: queryForm.mallId,
});
if (isArray(r)) {
gateList.value = r.map((item) => {
return {
value: item.id,
label: item.name,
};
});
}
} catch (error) {
console.log(error);
}
};
const getChannelList = async function () {
queryForm.channel_id = [];
channelList.value = [];
let tempList = [];
for (const gate of queryForm.gate_id) {
const r = await dataRepairApi.getChannelList({
gateId: gate,
});
if (isArray(r)) {
for (const item of r) {
tempList.push({
value: item,
label: item,
});
}
}
}
channelList.value = tempList;
};
const preview = async function () {
isLoading.value = true;
isSuspended.value = false;
dataList.value = [];
const rawData = toRaw(queryForm);
for (const channelId of rawData.channel_id) {
if (isSuspended.value === true) {
isLoading.value = false;
return;
}
const data = filterEmptyValueInObject({
channelSerialnum: channelId,
maxFactor: rawData.maxFactor,
minFactor: rawData.minFactor,
targetStartDate:
formatDate(rawData.repairDate) +
" " +
formatTime(rawData.startTime),
targetEndDate:
formatDate(rawData.repairDate) + " " + formatTime(rawData.endTime),
sourceStartDate:
formatDate(rawData.referenceDate) +
" " +
formatTime(rawData.startTime),
sourceEndDate:
formatDate(rawData.referenceDate) +
" " +
formatTime(rawData.endTime),
});
const r = await dataRepairApi.preview(data);
r.data.status = "未执行";
dataList.value.push(r.data);
}
isLoading.value = false;
isSuspended.value = false;
};
const repair = async function () {
try {
if (!queryForm.account_id) {
return message.error("必须选择一个集团");
}
if (!queryForm.mallId) {
return message.error("必须选择一个广场");
}
if (!queryForm.gate_id || queryForm.gate_id.length === 0) {
return message.error("必须选择一个监控点");
}
isLoading.value = true;
isSuspended.value = false;
dataList.value = [];
const rawData = toRaw(queryForm);
const params = {
...rawData,
gateIds: rawData.gate_id?.join(","),
};
delete params.account_id;
delete params.gate_id;
delete params.channel_id;
const { code, msg } = await dataRepairApi.accurateRepairApi(params);
const type = code === 200 ? "success" : "error";
// 提示信息
message[type](msg);
// dataList.value.push(r.data);
} catch (error) {
console.log(error);
}
// for (const channelId of rawData.channel_id) {
// if (isSuspended.value === true) {
// isLoading.value = false;
// return;
// }
// const data = filterEmptyValueInObject({
// channelSerialnum: channelId,
// maxFactor: rawData.maxFactor,
// minFactor: rawData.minFactor,
// targetStartDate:
// formatDate(rawData.repairDate) +
// " " +
// formatTime(rawData.startTime),
// targetEndDate:
// formatDate(rawData.repairDate) + " " + formatTime(rawData.endTime),
// sourceStartDate:
// formatDate(rawData.referenceDate) +
// " " +
// formatTime(rawData.startTime),
// sourceEndDate:
// formatDate(rawData.referenceDate) +
// " " +
// formatTime(rawData.endTime),
// });
// const r = await dataRepairApi.repair(data);
// if (r.msg_code === 200) {
// r.data.status = "已修复";
// } else {
// r.data.status = "未执行";
// }
// }
isLoading.value = false;
isSuspended.value = false;
};
const getClass = function (text) {
switch (text) {
case "已修复": {
return "success";
}
case "未执行": {
return "failed";
}
default: {
break;
}
}
};
const deleteRecord = function ({ channelSerialnum }) {
if (channelSerialnum === undefined) {
return;
}
dataList.value = dataList.value.filter(
(item) => item.channelSerialnum !== channelSerialnum
);
queryForm.channel_id = queryForm.channel_id.filter(
(item) => item !== channelSerialnum
);
};
const suspendRepair = function () {
if (isLoading.value === true) {
isSuspended.value = true;
}
};
const selectAll = function (text) {
switch (text) {
case "监控点名称": {
queryForm.gate_id = [];
for (const item of gateList.value) {
queryForm.gate_id.push(item.value);
}
onGateChange();
break;
}
case "设备通道号": {
queryForm.channel_id = [];
for (const item of channelList.value) {
queryForm.channel_id.push(item.value);
}
break;
}
default: {
break;
}
}
};
const clearAll = function (text) {
switch (text) {
case "监控点名称": {
queryForm.gate_id = [];
onGateChange();
break;
}
case "设备通道号": {
queryForm.channel_id = [];
break;
}
default: {
break;
}
}
};
const __main = function () {
getAccountList();
};
__main();
return {
// scalar
isLoading,
// sequence
accountList,
plazaList,
zoneList,
gateList,
channelList,
resultList,
dataList,
queryForm,
columns,
// function
onAccountChange,
onPlazaChange,
onGateChange,
preview,
repair,
getClass,
deleteRecord,
suspendRepair,
selectAll,
clearAll,
};
},
};
</script>
<style lang="less" scoped>
@import "../DataRepair.less";
</style>
<template>
<a-form
:model="queryForm"
layout="inline"
:label-col="{ style: { width: '100px' } }"
>
<a-form-item label="集团:" style="padding: 5px 0">
<a-select
v-model:value="queryForm.account_id"
style="width: 280px"
mode="multiple"
:maxTagCount="1"
@change="onAccountChange"
:options="accountList"
optionFilterProp="label"
show-search
>
</a-select>
</a-form-item>
<a-form-item label="广场:" style="padding: 5px 0">
<a-select
v-model:value="queryForm.plaza_id"
style="width: 280px"
mode="multiple"
:maxTagCount="1"
@change="onPlazaChange"
:options="plazaList"
optionFilterProp="label"
show-search
>
</a-select>
</a-form-item>
<a-form-item label="监控点名称:" style="padding: 5px 0">
<a-select
v-model:value="queryForm.gate_id"
style="width: 280px"
mode="multiple"
:maxTagCount="1"
@change="onGateChange"
:options="gateList"
optionFilterProp="label"
show-search
>
<template #dropdownRender="{ menuNode: menu }">
<v-nodes :vnodes="menu" />
<a-divider style="margin: 4px 0" />
<div @mousedown="(e) => e.preventDefault()">
<a-button @click="selectAll('监控点名称')" type="link"
>全选</a-button
>
<a-button @click="clearAll('监控点名称')" type="link"
>清空</a-button
>
</div>
</template>
</a-select>
</a-form-item>
<a-form-item label="设备通道号:" style="padding: 5px 0">
<a-select
v-model:value="queryForm.channel_id"
style="width: 280px"
mode="multiple"
:maxTagCount="1"
:options="channelList"
optionFilterProp="label"
show-search
>
<template #dropdownRender="{ menuNode: menu }">
<v-nodes :vnodes="menu" />
<a-divider style="margin: 4px 0" />
<div @mousedown="(e) => e.preventDefault()">
<a-button @click="selectAll('设备通道号')" type="link"
>全选</a-button
>
<a-button @click="clearAll('设备通道号')" type="link"
>清空</a-button
>
</div>
</template>
</a-select>
</a-form-item>
<a-form-item label="修补日期:" style="padding: 5px 0">
<a-date-picker
v-model:value="queryForm.repairDate"
style="width: 280px"
/>
</a-form-item>
<a-form-item label="参考日期:" style="padding: 5px 0">
<a-date-picker
v-model:value="queryForm.referenceDate"
style="width: 280px"
/>
</a-form-item>
<a-form-item label="开始时间:" style="padding: 5px 0">
<a-time-picker v-model:value="queryForm.startTime" style="width: 280px" />
</a-form-item>
<a-form-item label="结束时间:" style="padding: 5px 0">
<a-time-picker v-model:value="queryForm.endTime" style="width: 280px" />
</a-form-item>
<a-form-item label="数据波动比例:" style="padding: 5px 0">
<a-input v-model:value="queryForm.minFactor" style="width: 129px" />
<a-input v-model:value="queryForm.maxFactor" style="width: 129px" />
</a-form-item>
<a-form-item style="padding: 5px 0">
<a-button type="primary" @click="preview" :loading="isLoading"
>预览</a-button
>
</a-form-item>
<a-form-item style="padding: 5px 0">
<a-button type="primary" @click="repair" :loading="isLoading"
>修补</a-button
>
</a-form-item>
</a-form>
<div style="display: flex; justify-content: flex-end; padding: 3px">
<a-button @click="suspendRepair" type="primary">暂停修复</a-button>
</div>
<a-table
:dataSource="dataList"
v-loading="isLoading"
:columns="columns"
:pagination="false"
>
<template #status="{ text }">
<span :class="getClass(text)">{{ text }}</span>
</template>
<template #operation="{ record }">
<div>
<a-button @click="deleteRecord(record)" type="primary" danger
>删除任务</a-button
>
</div>
</template>
</a-table>
</template>
<script>
import { reactive, ref, toRaw } from "vue";
import moment from "moment";
import snapshotRecordApi from "@/views/SnapshotCluster/SnapshotRecord/SnapshotRecordApi";
import { isArray } from "@/PublicUtil/Judgment";
import {
filterEmptyValueInObject,
formatDate,
formatTime,
} from "@/PublicUtil/PublicUtil";
import dataRepairApi from "@/views/DataRepair/DataRepairApi";
import { PlusOutlined } from "@ant-design/icons-vue";
const columns = [
{
title: "监控点名称",
dataIndex: "gatename",
align: "center",
},
{
title: "设备号",
dataIndex: "deviceSerialnum",
align: "center",
},
{
title: "通道号",
dataIndex: "channelSerialnum",
align: "center",
},
{
title: "参考范围数据条数",
dataIndex: "sourceCount",
align: "center",
},
{
title: "修复范围数据条数",
dataIndex: "targetCount",
align: "center",
},
{
title: "参考范围客流量",
dataIndex: "sourceInnum",
align: "center",
},
{
title: "修复范围客流量",
dataIndex: "targetInnum",
align: "center",
},
{
title: "状态",
dataIndex: "status",
align: "center",
slots: {
customRender: "status",
},
},
{
title: "操作",
dataIndex: "operation",
align: "center",
slots: {
customRender: "operation",
},
},
];
export default {
components: {
PlusOutlined,
VNodes: (_, { attrs }) => {
return attrs.vnodes;
},
},
setup() {
// scalar
const isLoading = ref(false);
const isSuspended = ref(false);
// sequence
const resultList = ref([]);
const accountList = ref([]);
const plazaList = ref([]);
const zoneList = ref([]);
const gateList = ref([]);
const channelList = ref([]);
const dataList = ref([]);
const queryForm = reactive({
account_id: [],
plaza_id: [],
gate_id: [],
channel_id: [],
repairDate: moment(moment().format("YYYY-MM-DD"), "YYYY-MM-DD"),
referenceDate: moment(moment().format("YYYY-MM-DD"), "YYYY-MM-DD"),
startTime: moment("00:00:00", "HH:mm:ss"),
endTime: moment("23:59:59", "HH:mm:ss"),
minFactor: 0.85,
maxFactor: 1.2,
});
const onAccountChange = function () {
getPlazaList();
queryForm.gate_id = [];
gateList.value = [];
queryForm.channel_id = [];
channelList.value = [];
};
const onPlazaChange = function () {
getGateList();
queryForm.channel_id = [];
channelList.value = [];
};
const onGateChange = function () {
getChannelList();
};
const getPlazaList = function () {
queryForm.plaza_id = [];
plazaList.value = [];
snapshotRecordApi
.getPlazaList({
account_id: queryForm.account_id.toString(),
})
.then((r) => {
if (isArray(r)) {
for (const item of r) {
plazaList.value.push({
value: item.id,
label: item.name,
});
}
}
});
};
const getAccountList = function () {
queryForm.account_id = [];
accountList.value = [];
snapshotRecordApi.getAccountList().then((r) => {
if (isArray(r)) {
for (const item of r) {
accountList.value.push({
value: item.id,
label: item.name,
});
}
}
});
};
const getGateList = async function () {
queryForm.gate_id = [];
gateList.value = [];
let tempList = [];
for (const account of queryForm.account_id) {
for (const plaza of queryForm.plaza_id) {
const r = await dataRepairApi.getGateList({
accountIds: account,
mallIds: plaza,
});
if (isArray(r)) {
for (const item of r) {
tempList.push({
value: item.id,
label: item.name,
});
}
}
}
}
gateList.value = [...new Set(tempList)];
};
const getChannelList = async function () {
queryForm.channel_id = [];
channelList.value = [];
let tempList = [];
for (const gate of queryForm.gate_id) {
const r = await dataRepairApi.getChannelList({
gateId: gate,
});
if (isArray(r)) {
for (const item of r) {
tempList.push({
value: item,
label: item,
});
}
}
}
channelList.value = tempList;
};
const floatToPercent = function (floatNum) {
if (!floatNum) {
return 0;
}
let formatNum = Math.floor(floatNum * 100);
return formatNum >= 100 ? 100 : formatNum;
};
const preview = async function () {
isLoading.value = true;
isSuspended.value = false;
dataList.value = [];
const rawData = toRaw(queryForm);
for (const channelId of rawData.channel_id) {
if (isSuspended.value === true) {
isLoading.value = false;
return;
}
const data = filterEmptyValueInObject({
channelSerialnum: channelId,
maxFactor: rawData.maxFactor,
minFactor: rawData.minFactor,
targetStartDate:
formatDate(rawData.repairDate) +
" " +
formatTime(rawData.startTime),
targetEndDate:
formatDate(rawData.repairDate) + " " + formatTime(rawData.endTime),
sourceStartDate:
formatDate(rawData.referenceDate) +
" " +
formatTime(rawData.startTime),
sourceEndDate:
formatDate(rawData.referenceDate) +
" " +
formatTime(rawData.endTime),
});
const r = await dataRepairApi.preview(data);
r.data.status = "未执行";
dataList.value.push(r.data);
}
isLoading.value = false;
isSuspended.value = false;
};
const repair = async function () {
isLoading.value = true;
isSuspended.value = false;
dataList.value = [];
const rawData = toRaw(queryForm);
for (const channelId of rawData.channel_id) {
if (isSuspended.value === true) {
isLoading.value = false;
return;
}
const data = filterEmptyValueInObject({
channelSerialnum: channelId,
maxFactor: rawData.maxFactor,
minFactor: rawData.minFactor,
targetStartDate:
formatDate(rawData.repairDate) +
" " +
formatTime(rawData.startTime),
targetEndDate:
formatDate(rawData.repairDate) + " " + formatTime(rawData.endTime),
sourceStartDate:
formatDate(rawData.referenceDate) +
" " +
formatTime(rawData.startTime),
sourceEndDate:
formatDate(rawData.referenceDate) +
" " +
formatTime(rawData.endTime),
});
const r = await dataRepairApi.repair(data);
if (r.msg_code === 200) {
r.data.status = "已修复";
} else {
r.data.status = "未执行";
}
dataList.value.push(r.data);
}
isLoading.value = false;
isSuspended.value = false;
};
const getClass = function (text) {
switch (text) {
case "已修复": {
return "success";
}
case "未执行": {
return "failed";
}
default: {
break;
}
}
};
const deleteRecord = function ({ channelSerialnum }) {
if (channelSerialnum === undefined) {
return;
}
dataList.value = dataList.value.filter(
(item) => item.channelSerialnum !== channelSerialnum
);
queryForm.channel_id = queryForm.channel_id.filter(
(item) => item !== channelSerialnum
);
};
const suspendRepair = function () {
if (isLoading.value === true) {
isSuspended.value = true;
}
};
const selectAll = function (text) {
switch (text) {
case "监控点名称": {
queryForm.gate_id = [];
for (const item of gateList.value) {
queryForm.gate_id.push(item.value);
}
onGateChange();
break;
}
case "设备通道号": {
queryForm.channel_id = [];
for (const item of channelList.value) {
queryForm.channel_id.push(item.value);
}
break;
}
default: {
break;
}
}
};
const clearAll = function (text) {
switch (text) {
case "监控点名称": {
queryForm.gate_id = [];
onGateChange();
break;
}
case "设备通道号": {
queryForm.channel_id = [];
break;
}
default: {
break;
}
}
};
const __main = function () {
getAccountList();
};
__main();
return {
// scalar
isLoading,
// sequence
accountList,
plazaList,
zoneList,
gateList,
channelList,
resultList,
dataList,
queryForm,
columns,
// function
onAccountChange,
onPlazaChange,
onGateChange,
preview,
repair,
getClass,
deleteRecord,
suspendRepair,
selectAll,
clearAll,
};
},
};
</script>
<style lang="less" scoped>
@import "../DataRepair.less";
</style>
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!