fix: 优化批量同步操作方式;物联卡详情中新增停机状态信息
* fix: 优化批量同步操作方式;物联卡详情中新增停机状态信息 * fix: 优化docker
This commit is contained in:
parent
5c793611da
commit
2437dbb126
|
@ -26,13 +26,13 @@ export const unDeploy = (cardId: string) => server.get(`/network/card/${cardId}/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 复机已停机物联卡
|
* 复机已停机物联卡
|
||||||
* @param cardId
|
* @param cardId
|
||||||
*/
|
*/
|
||||||
export const resumption = (cardId: string) => server.get(`/network/card/${cardId}/_resumption`);
|
export const resumption = (cardId: string) => server.get(`/network/card/${cardId}/_resumption`);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除物联卡
|
* 删除物联卡
|
||||||
* @param id
|
* @param id
|
||||||
*/
|
*/
|
||||||
export const del = (id: string) => server.remove(`/network/card/${id}`);
|
export const del = (id: string) => server.remove(`/network/card/${id}`);
|
||||||
|
|
||||||
|
@ -139,4 +139,7 @@ export const queryRechargeList = (data: any) => server.post(`/network/card/recha
|
||||||
* 充值
|
* 充值
|
||||||
* @param data
|
* @param data
|
||||||
*/
|
*/
|
||||||
export const recharge = (data: any) => server.post(`/network/card/_recharge`, data)
|
export const recharge = (data: any) => server.post(`/network/card/_recharge`, data)
|
||||||
|
export const queryCount = (data: any) => server.post(`/network/card/_count`,data)
|
||||||
|
|
||||||
|
export const queryDeactivate = (id: string) => server.get(`/network/card/${id}/stop/reason`)
|
||||||
|
|
|
@ -25,8 +25,8 @@
|
||||||
</j-tag>
|
</j-tag>
|
||||||
</template>
|
</template>
|
||||||
<template #username="slotProps">
|
<template #username="slotProps">
|
||||||
|
|
||||||
<!-- <j-tag color="geekblue"> -->
|
<!-- <j-tag color="geekblue"> -->
|
||||||
<div class="userName">
|
<div class="userName">
|
||||||
<Ellipsis style="max-width: 100px;">
|
<Ellipsis style="max-width: 100px;">
|
||||||
{{ slotProps.context.userName }}
|
{{ slotProps.context.userName }}
|
||||||
|
@ -34,9 +34,9 @@
|
||||||
<!-- </j-tag> -->
|
<!-- </j-tag> -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<template #action="slotProps">
|
<template #action="slotProps">
|
||||||
<j-space :size="16">
|
<j-space :size="16">
|
||||||
<j-tooltip
|
<j-tooltip
|
||||||
|
@ -111,12 +111,7 @@
|
||||||
{{ descriptionsData?.parameters }}
|
{{ descriptionsData?.parameters }}
|
||||||
</j-descriptions-item>
|
</j-descriptions-item>
|
||||||
<j-descriptions-item label="异常信息" :span="2">
|
<j-descriptions-item label="异常信息" :span="2">
|
||||||
<j-textarea
|
{{ descriptionsData.exception }}
|
||||||
v-model:value="descriptionsData.exception"
|
|
||||||
placeholder="暂无数据"
|
|
||||||
:auto-size="{ minRows: 3, maxRows: 20 }"
|
|
||||||
readonly
|
|
||||||
/>
|
|
||||||
</j-descriptions-item>
|
</j-descriptions-item>
|
||||||
</j-descriptions>
|
</j-descriptions>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
|
|
|
@ -92,11 +92,14 @@
|
||||||
</j-tag>
|
</j-tag>
|
||||||
<span>{{ descriptionsData?.message }}</span>
|
<span>{{ descriptionsData?.message }}</span>
|
||||||
</div>
|
</div>
|
||||||
<j-textarea
|
<div class="warn-content">
|
||||||
v-model:value="descriptionsData.exceptionStack"
|
{{ descriptionsData.exceptionStack }}
|
||||||
placeholder="暂无数据"
|
</div>
|
||||||
:auto-size="{ minRows: 24, maxRows: 28 }"
|
<!-- <j-textarea-->
|
||||||
/>
|
<!-- v-model:value=""-->
|
||||||
|
<!-- placeholder="暂无数据"-->
|
||||||
|
<!-- :auto-size="{ minRows: 24, maxRows: 28 }"-->
|
||||||
|
<!-- />-->
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<j-button type="primary" @click="handleOk">关闭</j-button>
|
<j-button type="primary" @click="handleOk">关闭</j-button>
|
||||||
</template>
|
</template>
|
||||||
|
@ -254,4 +257,9 @@ const handleSearch = (e: any) => {
|
||||||
.mb-10 {
|
.mb-10 {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
.warn-content {
|
||||||
|
border: 1px solid #d9d9d9;
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -20,8 +20,11 @@ const useMetadata = (type: 'device' | 'product', key?: MetadataType, ): {
|
||||||
const { current: productCurrent } = storeToRefs(productStore)
|
const { current: productCurrent } = storeToRefs(productStore)
|
||||||
|
|
||||||
const handleMetadata = (_metadataStr: string) => {
|
const handleMetadata = (_metadataStr: string) => {
|
||||||
|
|
||||||
|
if(!_metadataStr) return
|
||||||
|
|
||||||
const fileTypeReg = new RegExp('"fileType":',"g")
|
const fileTypeReg = new RegExp('"fileType":',"g")
|
||||||
const _dealMetadata = _metadataStr.replaceAll(fileTypeReg,'"bodyType":')
|
const _dealMetadata = _metadataStr.replace(fileTypeReg,'"bodyType":')
|
||||||
const _metadata = JSON.parse(_dealMetadata || '{}')
|
const _metadata = JSON.parse(_dealMetadata || '{}')
|
||||||
const newMetadata = (key ? _metadata?.[key] || [] : []) as any[]
|
const newMetadata = (key ? _metadata?.[key] || [] : []) as any[]
|
||||||
|
|
||||||
|
@ -89,4 +92,4 @@ const useMetadata = (type: 'device' | 'product', key?: MetadataType, ): {
|
||||||
productNoEdit
|
productNoEdit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export default useMetadata
|
export default useMetadata
|
||||||
|
|
|
@ -83,9 +83,18 @@
|
||||||
? detail.residualFlow.toFixed(2) + ' M'
|
? detail.residualFlow.toFixed(2) + ' M'
|
||||||
: ''
|
: ''
|
||||||
}}</j-descriptions-item>
|
}}</j-descriptions-item>
|
||||||
<j-descriptions-item label="状态">{{
|
<j-descriptions-item label="状态">
|
||||||
|
{{
|
||||||
detail?.cardState?.text
|
detail?.cardState?.text
|
||||||
}}</j-descriptions-item>
|
}}
|
||||||
|
<span v-if="deactivateData.show" style="padding-left: 8px;">
|
||||||
|
<a-tooltip
|
||||||
|
:title="deactivateData.tip"
|
||||||
|
>
|
||||||
|
<AIcon type="ExclamationCircleOutlined" style="color: var(--ant-error-color);"/>
|
||||||
|
</a-tooltip>
|
||||||
|
</span>
|
||||||
|
</j-descriptions-item>
|
||||||
<j-descriptions-item label="说明">{{
|
<j-descriptions-item label="说明">{{
|
||||||
detail?.describe
|
detail?.describe
|
||||||
}}</j-descriptions-item>
|
}}</j-descriptions-item>
|
||||||
|
@ -178,10 +187,10 @@
|
||||||
</page-container>
|
</page-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts" name="CardDetail">
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import type { CardManagement } from '../typing';
|
import type { CardManagement } from '../typing';
|
||||||
import { queryDetail } from '@/api/iot-card/cardManagement';
|
import {queryDeactivate, queryDetail} from '@/api/iot-card/cardManagement';
|
||||||
import Save from '../Save.vue';
|
import Save from '../Save.vue';
|
||||||
import Guide from '@/views/iot-card/components/Guide.vue';
|
import Guide from '@/views/iot-card/components/Guide.vue';
|
||||||
import LineChart from '@/views/iot-card/components/LineChart.vue';
|
import LineChart from '@/views/iot-card/components/LineChart.vue';
|
||||||
|
@ -203,6 +212,11 @@ const dayOptions = ref<any[]>([]);
|
||||||
const monthOptions = ref<any[]>([]);
|
const monthOptions = ref<any[]>([]);
|
||||||
const yearOptions = ref<any[]>([]);
|
const yearOptions = ref<any[]>([]);
|
||||||
|
|
||||||
|
const deactivateData = reactive({
|
||||||
|
show: false,
|
||||||
|
tip: ''
|
||||||
|
})
|
||||||
|
|
||||||
const quickBtnList = [
|
const quickBtnList = [
|
||||||
{ label: '昨日', value: 'yesterday' },
|
{ label: '昨日', value: 'yesterday' },
|
||||||
{ label: '近一周', value: 'week' },
|
{ label: '近一周', value: 'week' },
|
||||||
|
@ -212,8 +226,18 @@ const quickBtnList = [
|
||||||
|
|
||||||
const getDetail = () => {
|
const getDetail = () => {
|
||||||
queryDetail(route.params.id).then((resp: any) => {
|
queryDetail(route.params.id).then((resp: any) => {
|
||||||
if (resp.status === 200) {
|
if (resp.success) {
|
||||||
detail.value = resp.result;
|
detail.value = resp.result;
|
||||||
|
|
||||||
|
if (resp.result.cardStateType?.value === 'deactivate') {
|
||||||
|
deactivateData.show = true
|
||||||
|
// 获取停机原因
|
||||||
|
queryDeactivate(route.params.id as string).then((deacResp: any) => {
|
||||||
|
if (deacResp.success && deacResp.result?.message) {
|
||||||
|
deactivateData.tip = deacResp.result.message.toString()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
<template>
|
||||||
|
<j-modal
|
||||||
|
visible
|
||||||
|
width="800px"
|
||||||
|
:maskClosable="false"
|
||||||
|
title="同步"
|
||||||
|
:closable="false"
|
||||||
|
>
|
||||||
|
<div style="margin: 10px 0px 20px 0px; padding-right: 10px;">
|
||||||
|
<div v-if="flag">
|
||||||
|
<div>正在同步物联卡状态</div>
|
||||||
|
<j-progress :percent="_percent" />
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<p>同步成功:{{ syncData.count }}条</p>
|
||||||
|
<p>同步失败:{{ syncData.error }}条</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<a-button v-if="!flag" type="primary" @click="handleCancel">完成</a-button>
|
||||||
|
</template>
|
||||||
|
</j-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup name="SyncModal">
|
||||||
|
import {BASE_API_PATH} from "@/utils/variable";
|
||||||
|
import {paramsEncodeQuery} from "@/utils/encodeQuery";
|
||||||
|
import {getToken} from "@/utils/comm";
|
||||||
|
import { EventSourcePolyfill } from 'event-source-polyfill';
|
||||||
|
import {queryCount} from "@/api/iot-card/cardManagement";
|
||||||
|
|
||||||
|
const emit = defineEmits(['close']);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
params: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const flag = ref(true)
|
||||||
|
const syncData = reactive({
|
||||||
|
count: 0,
|
||||||
|
total: 0,
|
||||||
|
error: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
const _percent = computed(() => {
|
||||||
|
return syncData.total ? ((syncData.error + syncData.count) / syncData.total * 100).toFixed(2) : 0
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
|
|
||||||
|
const getData = () => {
|
||||||
|
const _params = paramsEncodeQuery(props.params)
|
||||||
|
const urlParams = new URLSearchParams()
|
||||||
|
|
||||||
|
Object.keys(_params).forEach(key => {
|
||||||
|
if (_params[key]) {
|
||||||
|
urlParams.append(key, _params[key])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const api = `${BASE_API_PATH}/network/card/state/_sync?:X_Access_Token=${getToken()}&${urlParams}`
|
||||||
|
const esp = new EventSourcePolyfill(api)
|
||||||
|
|
||||||
|
esp.onmessage = (e) => {
|
||||||
|
syncData.count += Number(e.data)
|
||||||
|
if (syncData.count >= syncData.total) {
|
||||||
|
esp.close()
|
||||||
|
flag.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
esp.onerror = (e) => {
|
||||||
|
esp.close()
|
||||||
|
flag.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const getTotal = () => {
|
||||||
|
queryCount(props.params).then(res => {
|
||||||
|
if (res.success) {
|
||||||
|
syncData.total = res.result
|
||||||
|
getData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getTotal()
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -370,6 +370,12 @@
|
||||||
:data="current"
|
:data="current"
|
||||||
@change="saveChange"
|
@change="saveChange"
|
||||||
/>
|
/>
|
||||||
|
<!-- 批量同步 -->
|
||||||
|
<SyncModal
|
||||||
|
v-if="syncVisible"
|
||||||
|
:params="params"
|
||||||
|
@close="syncClose"
|
||||||
|
/>
|
||||||
</page-container>
|
</page-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -403,6 +409,7 @@ import { BatchActionsType } from '@/components/BatchDropdown/types';
|
||||||
import { usePermissionStore } from 'store/permission';
|
import { usePermissionStore } from 'store/permission';
|
||||||
import { useRouterParams } from '@/utils/hooks/useParams';
|
import { useRouterParams } from '@/utils/hooks/useParams';
|
||||||
import { OperatorMap } from '@/views/iot-card/data';
|
import { OperatorMap } from '@/views/iot-card/data';
|
||||||
|
import SyncModal from './Sync.vue'
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const menuStory = useMenuStore();
|
const menuStory = useMenuStore();
|
||||||
|
@ -418,6 +425,7 @@ const cardId = ref<any>();
|
||||||
const current = ref<Partial<CardManagement>>({});
|
const current = ref<Partial<CardManagement>>({});
|
||||||
const saveType = ref<string>('');
|
const saveType = ref<string>('');
|
||||||
const isCheck = ref<boolean>(false);
|
const isCheck = ref<boolean>(false);
|
||||||
|
const syncVisible = ref(false)
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
|
@ -901,19 +909,28 @@ const handleResumption = () => {
|
||||||
* 同步状态
|
* 同步状态
|
||||||
*/
|
*/
|
||||||
const handleSync = async() => {
|
const handleSync = async() => {
|
||||||
if (!_selectedRowKeys.value.length) {
|
syncVisible.value = true
|
||||||
onlyMessage('请选择数据', 'error');
|
// if (!_selectedRowKeys.value.length) {
|
||||||
return;
|
// onlyMessage('请选择数据', 'error');
|
||||||
}
|
// return;
|
||||||
const resp = await sync(
|
// }
|
||||||
_selectedRowKeys.value.map((v) => ({ id: v })),
|
|
||||||
);
|
// const api = `${BASE_API_PATH}/network/card/state/_sync`
|
||||||
|
// const _source = new EventSourcePolyfill(api)
|
||||||
if (resp.status === 200) {
|
//
|
||||||
_selectedRowKeys.value = [];
|
// _source.onmessage = (e: any) => {
|
||||||
cardManageRef.value?.reload();
|
// console.log(e)
|
||||||
onlyMessage('同步状态成功');
|
// }
|
||||||
}
|
//
|
||||||
|
// const resp = await sync(
|
||||||
|
// _selectedRowKeys.value.map((v) => ({ id: v })),
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// if (resp.status === 200) {
|
||||||
|
// _selectedRowKeys.value = [];
|
||||||
|
// cardManageRef.value?.reload();
|
||||||
|
// onlyMessage('同步状态成功');
|
||||||
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -998,12 +1015,7 @@ const batchActions: BatchActionsType[] = [
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
permission: 'iot-card/CardManagement:sync',
|
permission: 'iot-card/CardManagement:sync',
|
||||||
icon: 'SwapOutlined',
|
icon: 'SwapOutlined',
|
||||||
selected:{
|
onClick: handleSync
|
||||||
popConfirm: {
|
|
||||||
title: '确认同步状态吗?',
|
|
||||||
onConfirm: handleSync,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'delete',
|
key: 'delete',
|
||||||
|
@ -1020,6 +1032,11 @@ const batchActions: BatchActionsType[] = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const syncClose = () => {
|
||||||
|
syncVisible.value = false
|
||||||
|
cardManageRef.value?.reload();
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (routerParams.params.value.type === 'add' && paltformPermission) {
|
if (routerParams.params.value.type === 'add' && paltformPermission) {
|
||||||
handleAdd();
|
handleAdd();
|
||||||
|
|
|
@ -185,7 +185,7 @@ const detail = async (id: string) => {
|
||||||
cert: result.configs?.cert ? result.configs?.cert : result.configs?.trust
|
cert: result.configs?.cert ? result.configs?.cert : result.configs?.trust
|
||||||
},
|
},
|
||||||
mode: result.mode.value,
|
mode: result.mode.value,
|
||||||
authenticationMethod: result.authenticationMethod.value,
|
authenticationMethod: result.authenticationMethod?.value,
|
||||||
type,
|
type,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,9 +96,14 @@ const init = new Array(50).fill(0).map((_, index) => {
|
||||||
|
|
||||||
const dataSource = ref<Item[]>(init);
|
const dataSource = ref<Item[]>(init);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
const handleSearch = async (id: string, arr: Item[]) => {
|
const handleSearch = async (id: string, arr: Item[]) => {
|
||||||
const resp = await channelApi.opFunction(id, 'QueryPreset');
|
const params: Record<string, string> = {}
|
||||||
|
if (route.query.type === 'gb28181-2016') {
|
||||||
|
params.channel = props.data.channelId
|
||||||
|
}
|
||||||
|
const resp = await channelApi.opFunction(id, 'QueryPreset', params);
|
||||||
if (resp.status === 200) {
|
if (resp.status === 200) {
|
||||||
dataSource.value = unionBy([ ...arr, ...init], 'id').map((item) => {
|
dataSource.value = unionBy([ ...arr, ...init], 'id').map((item) => {
|
||||||
const _item = (resp.result?.[0] || []).find(
|
const _item = (resp.result?.[0] || []).find(
|
||||||
|
@ -204,4 +209,4 @@ watch(
|
||||||
immediate: true,
|
immediate: true,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -96,11 +96,12 @@ export default defineConfig(({ mode}) => {
|
||||||
// target: 'http://192.168.32.244:8881',
|
// target: 'http://192.168.32.244:8881',
|
||||||
// target: 'http://192.168.32.163:8844', //张本地
|
// target: 'http://192.168.32.163:8844', //张本地
|
||||||
// target: 'http://120.77.179.54:8844', // 120测试
|
// target: 'http://120.77.179.54:8844', // 120测试
|
||||||
target: 'http://192.168.33.46:8844', // 本地开发环境
|
target: 'http://192.168.32.66:8800', // 本地开发环境
|
||||||
// target: 'http://192.168.32.167:8844', // 本地开发环境1
|
// target: 'http://192.168.32.167:8844', // 本地开发环境1
|
||||||
// target: 'http://192.168.33.1:8848', // 社区版开发环境
|
// target: 'http://192.168.33.1:8848', // 社区版开发环境
|
||||||
// target: 'http://192.168.32.207:8844', // 刘本地
|
// target: 'http://192.168.32.207:8844', // 刘本地
|
||||||
// target: 'http://192.168.32.187:8844', // 谭本地
|
// target: 'http://192.168.32.187:8844', // 谭本地
|
||||||
|
// target: 'http://192.168.33.66:8844', // 苟本地
|
||||||
ws: 'ws://192.168.33.46:8844',
|
ws: 'ws://192.168.33.46:8844',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (path) => path.replace(/^\/api/, '')
|
rewrite: (path) => path.replace(/^\/api/, '')
|
||||||
|
|
Loading…
Reference in New Issue