fix: 优化批量同步操作方式;物联卡详情中新增停机状态信息

* fix: 优化批量同步操作方式;物联卡详情中新增停机状态信息

* fix: 优化docker
This commit is contained in:
XieYongHong 2024-04-29 19:33:42 +08:00 committed by GitHub
parent 5c793611da
commit 2437dbb126
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 204 additions and 49 deletions

View File

@ -140,3 +140,6 @@ 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`)

View File

@ -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>

View File

@ -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>

View File

@ -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[]

View File

@ -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()
}
})
}
} }
}); });
}; };

View File

@ -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>

View File

@ -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 })),
);
if (resp.status === 200) { // const api = `${BASE_API_PATH}/network/card/state/_sync`
_selectedRowKeys.value = []; // const _source = new EventSourcePolyfill(api)
cardManageRef.value?.reload(); //
onlyMessage('同步状态成功'); // _source.onmessage = (e: any) => {
} // console.log(e)
// }
//
// 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();

View File

@ -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,
}; };
} }

View File

@ -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(

View File

@ -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/, '')