fix: 刷新表格
This commit is contained in:
parent
9e3857302b
commit
eb7eaef064
|
@ -19,6 +19,7 @@
|
|||
"ant-design-vue": "^3.2.15",
|
||||
"axios": "^1.2.1",
|
||||
"echarts": "^5.4.1",
|
||||
"event-source-polyfill": "^1.0.31",
|
||||
"jetlinks-store": "^0.0.3",
|
||||
"js-cookie": "^3.0.1",
|
||||
"less": "^4.1.3",
|
||||
|
|
|
@ -51,4 +51,25 @@ export const _deploy = (id: string) => server.post(`/device-instance/${id}/deplo
|
|||
* @param data
|
||||
* @returns
|
||||
*/
|
||||
export const _undeploy = (id: string) => server.post(`/device-instance/${id}/undeploy`)
|
||||
export const _undeploy = (id: string) => server.post(`/device-instance/${id}/undeploy`)
|
||||
|
||||
/**
|
||||
* 批量激活设备
|
||||
* @param data 设备id数组
|
||||
* @returns
|
||||
*/
|
||||
export const batchDeployDevice = (data: string[]) => server.put(`/device-instance/batch/_deploy`, data)
|
||||
|
||||
/**
|
||||
* 批量注销设备
|
||||
* @param data 设备id数组
|
||||
* @returns
|
||||
*/
|
||||
export const batchUndeployDevice = (data: string[]) => server.put(`/device-instance/batch/_unDeploy`, data)
|
||||
|
||||
/**
|
||||
* 批量删除
|
||||
* @param data 设备id数组
|
||||
* @returns
|
||||
*/
|
||||
export const batchDeleteDevice = (data: string[]) => server.put(`/device-instance/batch/_delete`, data)
|
||||
|
|
|
@ -21,7 +21,11 @@ const iconKeys = [
|
|||
'StopOutlined',
|
||||
'CheckOutlined',
|
||||
'CloseOutlined',
|
||||
'DownOutlined'
|
||||
'DownOutlined',
|
||||
'ImportOutlined',
|
||||
'ExportOutlined',
|
||||
'SyncOutlined',
|
||||
'ExclamationCircleOutlined'
|
||||
]
|
||||
|
||||
const Icon = (props: {type: string}) => {
|
||||
|
|
|
@ -204,9 +204,13 @@ const JTable = defineComponent<JTableProps>({
|
|||
loading.value = false
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
handleSearch(props.params)
|
||||
})
|
||||
watch(
|
||||
() => props.params,
|
||||
(newValue) => {
|
||||
handleSearch(newValue)
|
||||
},
|
||||
{deep: true, immediate: true}
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
window.onresize = () => {
|
||||
|
@ -266,7 +270,7 @@ const JTable = defineComponent<JTableProps>({
|
|||
onClose={() => {
|
||||
emit('cancelSelect')
|
||||
}}
|
||||
closeText={<a>取消选择</a>}
|
||||
closeText={<a-button type="link">取消选择</a-button>}
|
||||
/>
|
||||
</div> : null
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
export default function encodeQuery(params: any) {
|
||||
if (!params) return {};
|
||||
const queryParam = {
|
||||
// pageIndex: 0,
|
||||
current: params.current,
|
||||
};
|
||||
const { terms, sorts } = params;
|
||||
Object.keys(params).forEach((key: string) => {
|
||||
if (key === 'terms') {
|
||||
let index = 0;
|
||||
if (!terms) return;
|
||||
Object.keys(terms).forEach((k: string) => {
|
||||
if (
|
||||
!(
|
||||
terms[k] === '' ||
|
||||
terms[k] === undefined ||
|
||||
terms[k].length === 0 ||
|
||||
terms[k] === {} ||
|
||||
terms[k] === null
|
||||
)
|
||||
) {
|
||||
if (k.indexOf('$LIKE') > -1 && terms[k].toString().indexOf('%') === -1) {
|
||||
terms[k] = `%${terms[k]}%`;
|
||||
}
|
||||
if (k.indexOf('$IN') > -1) {
|
||||
terms[k] = terms[k].toString();
|
||||
} else if (k.indexOf('$START') > -1) {
|
||||
terms[k] = `%${terms[k]}`;
|
||||
} else if (k.indexOf('$END') > -1) {
|
||||
terms[k] = `${terms[k]}%`;
|
||||
}
|
||||
if (k.indexOf('@') > -1) {
|
||||
const temp = k.split('@');
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
queryParam[`terms[${index}].column`] = temp[0];
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
queryParam[`terms[${index}].type`] = temp[1];
|
||||
} else {
|
||||
queryParam[`terms[${index}].column`] = k;
|
||||
}
|
||||
queryParam[`terms[${index}].value`] = terms[k];
|
||||
index += 1;
|
||||
}
|
||||
});
|
||||
} else if (key === 'sorts') {
|
||||
// 当前Ant Design排序只支持单字段排序
|
||||
if (!sorts) return;
|
||||
Object.keys(sorts).forEach((s, index) => {
|
||||
queryParam[`sorts[${index}].name`] = s;
|
||||
queryParam[`sorts[${index}].order`] = sorts[s].replace('end', '');
|
||||
});
|
||||
// if (Object.keys(sorts).length > 0) {
|
||||
// queryParam[`sorts[0].name`] = sorts.field;
|
||||
// queryParam[`sorts[0].order`] = (sorts.order || '').replace('end', '');
|
||||
// }
|
||||
} else {
|
||||
queryParam[key] = params[key];
|
||||
}
|
||||
});
|
||||
|
||||
// queryParam.pageIndex = current - 1;
|
||||
|
||||
return queryParam;
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
import moment from "moment";
|
||||
import { LocalStore } from "./comm";
|
||||
import { TOKEN_KEY } from "./variable";
|
||||
|
||||
/**
|
||||
* 把数据下载成JSON
|
||||
* @param record
|
||||
|
@ -18,4 +22,34 @@ export const downloadObject = (record: Record<string, any>, fileName: string, fo
|
|||
ghostLink.click();
|
||||
//移除
|
||||
document.body.removeChild(ghostLink);
|
||||
};
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
* @param url 下载链接
|
||||
* @param params 参数
|
||||
*/
|
||||
export const downloadFile = (url: string, params?: Record<string, any>) => {
|
||||
const formElement = document.createElement('form');
|
||||
formElement.style.display = 'display:none;';
|
||||
formElement.method = 'GET';
|
||||
formElement.action = url;
|
||||
// 添加参数
|
||||
if (params) {
|
||||
Object.keys(params).forEach((key: string) => {
|
||||
const inputElement = document.createElement('input');
|
||||
inputElement.type = 'hidden';
|
||||
inputElement.name = key;
|
||||
inputElement.value = params[key];
|
||||
formElement.appendChild(inputElement);
|
||||
});
|
||||
}
|
||||
const inputElement = document.createElement('input');
|
||||
inputElement.type = 'hidden';
|
||||
inputElement.name = ':X_Access_Token';
|
||||
inputElement.value = LocalStore.get(TOKEN_KEY);
|
||||
formElement.appendChild(inputElement);
|
||||
document.body.appendChild(formElement);
|
||||
formElement.submit();
|
||||
document.body.removeChild(formElement);
|
||||
};
|
|
@ -0,0 +1,75 @@
|
|||
<template>
|
||||
<a-modal :maskClosable="false" width="800px" :visible="true" title="导出" @ok="handleOk" @cancel="handleCancel">
|
||||
<div style="background-color: rgb(236, 237, 238)">
|
||||
<p style="padding: 10px">
|
||||
<AIcon type="ExclamationCircleOutlined" />
|
||||
选择单个产品时可导出其下属设备的详细数据,不选择产品时导出所有设备的基础数据。
|
||||
</p>
|
||||
</div>
|
||||
<div style="margin-top: 20px">
|
||||
<a-form :layout="'vertical'">
|
||||
<a-form-item label="产品">
|
||||
<a-select showSearch v-model:value="modelRef.product" placeholder="请选择产品">
|
||||
<a-select-option :value="item.id" v-for="item in productList" :key="item.id" :title="item.name"></a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="文件格式">
|
||||
<a-radio-group button-style="solid" v-model:value="modelRef.fileType" placeholder="请选择文件格式">
|
||||
<a-radio-button value="xlsx">xlsx</a-radio-button>
|
||||
<a-radio-button value="csv">csv</a-radio-button>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { queryNoPagingPost } from '@/api/device/product'
|
||||
import { downloadFile } from '@/utils/utils'
|
||||
import encodeQuery from '@/utils/encodeQuery'
|
||||
import { BASE_API_PATH } from '@/utils/variable'
|
||||
|
||||
const emit = defineEmits(['close'])
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: undefined
|
||||
}
|
||||
})
|
||||
const modelRef = reactive({
|
||||
product: undefined,
|
||||
fileType: 'xlsx'
|
||||
});
|
||||
|
||||
const productList = ref<Record<string, any>[]>([])
|
||||
|
||||
watch(
|
||||
() => props.data,
|
||||
() => {
|
||||
queryNoPagingPost({paging: false}).then(resp => {
|
||||
if(resp.status === 200){
|
||||
productList.value = resp.result as Record<string, any>[]
|
||||
}
|
||||
})
|
||||
},
|
||||
{immediate: true, deep: true}
|
||||
)
|
||||
|
||||
const handleOk = () => {
|
||||
const params = encodeQuery(props.data);
|
||||
if(modelRef.product){
|
||||
downloadFile(
|
||||
`${BASE_API_PATH}/device/instance/${modelRef.product}/export.${modelRef.fileType}`,
|
||||
params
|
||||
);
|
||||
} else {
|
||||
downloadFile(`${BASE_API_PATH}/device/instance/export.${modelRef.fileType}`, params);
|
||||
}
|
||||
emit('close')
|
||||
}
|
||||
|
||||
const handleCancel = () => {
|
||||
emit('close')
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,14 @@
|
|||
<template>
|
||||
<a-modal :maskClosable="false" width="800px" :visible="true" title="导入" @ok="handleOk" @cancel="handleCancel">
|
||||
123
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const handleOk = () => {
|
||||
|
||||
}
|
||||
const handleCancel = () => {
|
||||
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,51 @@
|
|||
<template>
|
||||
<a-modal :maskClosable="false" width="800px" :visible="true" title="当前进度" @ok="handleOk" @cancel="handleCancel">
|
||||
<div>
|
||||
<a-badge v-if="flag" status="processing" text="进行中" />
|
||||
<a-badge v-else status="success" text="已完成" />
|
||||
</div>
|
||||
<p>总数量:{{count}}</p>
|
||||
<a></a>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { downloadFile } from '@/utils/utils'
|
||||
|
||||
const emit = defineEmits(['close'])
|
||||
const props = defineProps({
|
||||
api: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
const eventSource = ref<Record<string, any>>({})
|
||||
const count = ref<number>(0)
|
||||
const flag = ref<boolean>(false)
|
||||
const errMessage = ref<string>('')
|
||||
const isSource = ref<boolean>(false)
|
||||
const id = ref<string>('')
|
||||
|
||||
const handleOk = () => {
|
||||
emit('close')
|
||||
}
|
||||
|
||||
const handleCancel = () => {
|
||||
emit('close')
|
||||
}
|
||||
|
||||
const getData = () => {
|
||||
|
||||
}
|
||||
|
||||
watch(() => props.api,
|
||||
() => {
|
||||
getData()
|
||||
},
|
||||
{deep: true, immediate: true}
|
||||
)
|
||||
</script>
|
|
@ -1,5 +1,16 @@
|
|||
<template>
|
||||
<JTable ref="instanceRef" :columns="columns" :request="query" :defaultParams="{sorts: [{name: 'createTime', order: 'desc'}]}" :params="{pageIndex: 0, pageSize: 12}">
|
||||
<JTable
|
||||
ref="instanceRef"
|
||||
:columns="columns"
|
||||
:request="query"
|
||||
:defaultParams="{sorts: [{name: 'createTime', order: 'desc'}]}"
|
||||
:rowSelection="{
|
||||
selectedRowKeys: _selectedRowKeys,
|
||||
onChange: onSelectChange
|
||||
}"
|
||||
@cancelSelect="cancelSelect"
|
||||
:params="params"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<a-space>
|
||||
<a-button type="primary" @click="handleAdd">新增</a-button>
|
||||
|
@ -8,13 +19,33 @@
|
|||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item>
|
||||
<a href="javascript:;">1st menu item</a>
|
||||
<a-button @click="exportVisible = true"><AIcon type="ExportOutlined" />批量导出设备</a-button>
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<a href="javascript:;">2nd menu item</a>
|
||||
<a-button @click="importVisible = true"><AIcon type="ImportOutlined" />批量导入设备</a-button>
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<a href="javascript:;">3rd menu item</a>
|
||||
<a-popconfirm @confirm="activeAllDevice" title="确认激活全部设备?">
|
||||
<a-button type="primary" ghost><AIcon type="CheckCircleOutlined" />激活全部设备</a-button>
|
||||
</a-popconfirm>
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<a-button @click="syncDeviceStatus" type="primary"><AIcon type="SyncOutlined" />同步设备状态</a-button>
|
||||
</a-menu-item>
|
||||
<a-menu-item v-if="_selectedRowKeys.length">
|
||||
<a-popconfirm @confirm="delSelectedDevice" title="已启用的设备无法删除,确认删除选中的禁用状态设备?">
|
||||
<a-button type="primary" danger><AIcon type="DeleteOutlined" />删除选中设备</a-button>
|
||||
</a-popconfirm>
|
||||
</a-menu-item>
|
||||
<a-menu-item v-if="_selectedRowKeys.length" title="确认激活选中设备?">
|
||||
<a-popconfirm @confirm="activeSelectedDevice" >
|
||||
<a-button type="primary"><AIcon type="CheckOutlined" />激活选中设备</a-button>
|
||||
</a-popconfirm>
|
||||
</a-menu-item>
|
||||
<a-menu-item v-if="_selectedRowKeys.length">
|
||||
<a-popconfirm @confirm="disabledSelectedDevice" title="确认禁用选中设备?">
|
||||
<a-button type="primary" danger><AIcon type="StopOutlined" />禁用选中设备</a-button>
|
||||
</a-popconfirm>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
|
@ -24,9 +55,10 @@
|
|||
<template #card="slotProps">
|
||||
<CardBox
|
||||
:value="slotProps"
|
||||
@click="handleView"
|
||||
@click="handleClick"
|
||||
:actions="getActions(slotProps, 'card')"
|
||||
v-bind="slotProps"
|
||||
:active="_selectedRowKeys.includes(slotProps.id)"
|
||||
:status="slotProps.state.value"
|
||||
:statusText="slotProps.state.text"
|
||||
:statusNames="{
|
||||
|
@ -41,7 +73,7 @@
|
|||
</slot>
|
||||
</template>
|
||||
<template #content>
|
||||
<h3>{{ slotProps.name }}</h3>
|
||||
<h3 @click="handleView(slotProps.id)">{{ slotProps.name }}</h3>
|
||||
<a-row>
|
||||
<a-col :span="12">
|
||||
<div class="card-item-content-text">设备类型</div>
|
||||
|
@ -116,15 +148,30 @@
|
|||
</a-space>
|
||||
</template>
|
||||
</JTable>
|
||||
<Import v-if="importVisible" @close="importVisible = false" />
|
||||
<Export v-if="exportVisible" @close="exportVisible = false" :data="params" />
|
||||
<Process v-if="operationVisible" @close="operationVisible = false" :api="api" :type="type" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { query, _delete, _deploy, _undeploy } from '@/api/device/instance'
|
||||
import { query, _delete, _deploy, _undeploy, batchUndeployDevice, batchDeployDevice, batchDeleteDevice } from '@/api/device/instance'
|
||||
import type { ActionsType } from '@/components/Table/index.vue'
|
||||
import { getImage } from '@/utils/comm';
|
||||
import { getImage, LocalStore } from '@/utils/comm';
|
||||
import { message } from "ant-design-vue";
|
||||
import Import from './Import/index.vue'
|
||||
import Export from './Export/index.vue'
|
||||
import Process from './Process/index.vue'
|
||||
import { BASE_API_PATH, TOKEN_KEY } from '@/utils/variable';
|
||||
|
||||
const instanceRef = ref<Record<string, any>>({});
|
||||
const params = ref<Record<string, any>>({pageIndex: 0, pageSize: 12})
|
||||
const _selectedRowKeys = ref<string[]>([])
|
||||
const importVisible = ref<boolean>(false)
|
||||
const exportVisible = ref<boolean>(false)
|
||||
const current = ref<Record<string, any>>({})
|
||||
const operationVisible = ref<boolean>(false)
|
||||
const api = ref<string>('')
|
||||
const type = ref<string>('')
|
||||
|
||||
const statusMap = new Map();
|
||||
statusMap.set('online', 'processing');
|
||||
|
@ -173,12 +220,45 @@ const columns = [
|
|||
}
|
||||
]
|
||||
|
||||
const paramsFormat = (config: any, _terms: any, name?: string) => {
|
||||
if (config?.terms && Array.isArray(config.terms) && config?.terms.length > 0) {
|
||||
(config?.terms || []).map((item: any, index: number) => {
|
||||
if (item?.type) {
|
||||
_terms[`${name ? `${name}.` : ''}terms[${index}].type`] = item.type;
|
||||
}
|
||||
paramsFormat(item, _terms, `${name ? `${name}.` : ''}terms[${index}]`);
|
||||
});
|
||||
} else if (!config?.terms && Object.keys(config).length > 0) {
|
||||
Object.keys(config).forEach((key) => {
|
||||
if (config[key]) {
|
||||
_terms[`${name ? `${name}.` : ''}${key}`] = config[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const handleParams = (config: any) => {
|
||||
const _terms: any = {};
|
||||
paramsFormat(config, _terms);
|
||||
const url = new URLSearchParams();
|
||||
Object.keys(_terms).forEach((key) => {
|
||||
url.append(key, _terms[key]);
|
||||
});
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
const handleAdd = () => {
|
||||
message.warn('123')
|
||||
message.warn('新增')
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看
|
||||
*/
|
||||
const handleView = (dt: any) => {
|
||||
|
||||
// message.warn('查看')
|
||||
}
|
||||
|
||||
const getActions = (data: Partial<Record<string, any>>, type: 'card' | 'table'): ActionsType[] => {
|
||||
|
@ -257,4 +337,61 @@ const getActions = (data: Partial<Record<string, any>>, type: 'card' | 'table'):
|
|||
return actions
|
||||
}
|
||||
|
||||
const onSelectChange = (keys: string[]) => {
|
||||
_selectedRowKeys.value = [...keys]
|
||||
}
|
||||
|
||||
const cancelSelect = () => {
|
||||
_selectedRowKeys.value = []
|
||||
}
|
||||
|
||||
const handleClick = (dt: any) => {
|
||||
if(_selectedRowKeys.value.includes(dt.id)) {
|
||||
const _index = _selectedRowKeys.value.findIndex(i => i === dt.id)
|
||||
_selectedRowKeys.value.splice(_index, 1)
|
||||
} else {
|
||||
_selectedRowKeys.value = [..._selectedRowKeys.value, dt.id]
|
||||
}
|
||||
}
|
||||
|
||||
const activeAllDevice = () => {
|
||||
type.value = 'active'
|
||||
const activeAPI = `/${BASE_API_PATH}/device-instance/deploy?:X_Access_Token=${LocalStore.get(TOKEN_KEY)}&${handleParams(params)}`;
|
||||
api.value = activeAPI
|
||||
operationVisible.value = true
|
||||
}
|
||||
|
||||
const syncDeviceStatus = () => {
|
||||
type.value = 'sync'
|
||||
const syncAPI = `/${BASE_API_PATH}/device-instance/state/_sync?:X_Access_Token=${LocalStore.get(TOKEN_KEY)}&${handleParams(params)}`;
|
||||
api.value = syncAPI
|
||||
operationVisible.value = true
|
||||
}
|
||||
|
||||
const delSelectedDevice = async () => {
|
||||
const resp = await batchDeleteDevice(_selectedRowKeys.value)
|
||||
if(resp.status === 200){
|
||||
message.success('操作成功!')
|
||||
_selectedRowKeys.value = []
|
||||
instanceRef.value?.reload()
|
||||
}
|
||||
}
|
||||
|
||||
const activeSelectedDevice = async () => {
|
||||
const resp = await batchDeployDevice(_selectedRowKeys.value)
|
||||
if(resp.status === 200){
|
||||
message.success('操作成功!')
|
||||
_selectedRowKeys.value = []
|
||||
instanceRef.value?.reload()
|
||||
}
|
||||
}
|
||||
|
||||
const disabledSelectedDevice = async () => {
|
||||
const resp = await batchUndeployDevice(_selectedRowKeys.value)
|
||||
if(resp.status === 200){
|
||||
message.success('操作成功!')
|
||||
_selectedRowKeys.value = []
|
||||
instanceRef.value?.reload()
|
||||
}
|
||||
}
|
||||
</script>
|
Loading…
Reference in New Issue