fix: 修改批量操作功能

This commit is contained in:
100011797 2023-03-21 18:09:35 +08:00
parent 0f796972f4
commit 219444d566
6 changed files with 626 additions and 168 deletions

View File

@ -0,0 +1,106 @@
<template>
<div>
<j-space v-if="_item.key && visible">
<PermissionButton
:type="'primary'"
:ghost="true"
:hasPermission="_item.permission ? _item.permission : true"
v-bind="{ ..._item, ..._item.selected }"
>
<template #icon><AIcon :type="_item.icon" /></template>
{{ _item.text }}
</PermissionButton>
<j-button type="link" @click="reload"
><AIcon type="RedoOutlined" />重选</j-button
>
</j-space>
<j-dropdown :overlayStyle="{ zIndex: 1000 }" v-else>
<j-button>批量操作 <AIcon type="DownOutlined" /></j-button>
<template #overlay>
<j-menu @click="handleMenuClick">
<j-menu-item v-for="item in actions" :key="item.key">
<PermissionButton
:hasPermission="
item.permission ? item.permission : true
"
v-bind="item"
:popConfirm="
item.popConfirm
? {
...item.popConfirm,
onCancel: onPopCancel,
onConfirm: (e) =>
onPopConfirm(
e,
item?.popConfirm?.onConfirm,
),
}
: undefined
"
>
<template #icon
><AIcon :type="item.icon"
/></template>
{{ item.text }}
</PermissionButton>
</j-menu-item>
</j-menu>
</template>
</j-dropdown>
</div>
</template>
<script lang="ts" setup>
import { PropType } from 'vue';
import { BatchActionsType } from './types';
const props = defineProps({
actions: {
type: Array as PropType<BatchActionsType[]>,
default: () => [],
},
isCheck: {
type: Boolean,
default: false,
},
});
const emits = defineEmits(['update:isCheck', 'change']);
const visible = ref<boolean>(false);
const _item = ref<Partial<BatchActionsType>>({});
const handleMenuClick = (e: any) => {
const val = props.actions.find((item) => item.key === e.key);
if(!(val?.popConfirm || val?.onClick)){
emits('update:isCheck', true);
emits('change', true);
}
if (val?.popConfirm) {
visible.value = false;
} else {
visible.value = true;
}
_item.value = (val || {}) as any;
};
const reload = () => {
_item.value = {};
emits('update:isCheck', false);
emits('change', false);
};
const onPopConfirm = (e: any, fun: any) => {
if (fun) {
fun(e);
onPopCancel();
}
};
const onPopCancel = () => {
visible.value = false;
};
</script>
<style lang="less" scoped>
</style>

16
src/components/BatchDropdown/types.d.ts vendored Normal file
View File

@ -0,0 +1,16 @@
import type { ButtonProps } from "ant-design-vue/es/button";
import type { PopconfirmProps } from "ant-design-vue/es/popconfirm";
export interface BatchActionsType extends ButtonProps {
key: string;
text?: string;
permission?: string;
onClick?: (data: any) => void;
style?: CSSProperties;
popConfirm?: PopconfirmProps;
icon?: string;
selected?: {// 需要选择表格数据,后触发的事件
popConfirm?: PopconfirmProps;
onClick?: (data: any) => void
}
}

View File

@ -55,6 +55,7 @@ import { CSSProperties, PropType } from 'vue'
import { TooltipProps, PopconfirmProps } from 'ant-design-vue/es' import { TooltipProps, PopconfirmProps } from 'ant-design-vue/es'
import { buttonProps } from 'ant-design-vue/es/button/button' import { buttonProps } from 'ant-design-vue/es/button/button'
import { usePermissionStore } from '@/store/permission'; import { usePermissionStore } from '@/store/permission';
import { omit } from 'lodash-es';
// interface PermissionButtonEmits { // interface PermissionButtonEmits {
// (e: 'click', data: MouseEvent): void; // (e: 'click', data: MouseEvent): void;
@ -88,7 +89,7 @@ const props = defineProps({
style: { style: {
type: Object as PropType<CSSProperties> type: Object as PropType<CSSProperties>
}, },
...buttonProps() ...omit(buttonProps(), 'icon')
}) })
// const { tooltip, popConfirm, hasPermission, noButton, ..._buttonProps } = props; // const { tooltip, popConfirm, hasPermission, noButton, ..._buttonProps } = props;

View File

@ -10,10 +10,14 @@
:columns="columns" :columns="columns"
:request="query" :request="query"
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }" :defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }"
:rowSelection="{ :rowSelection="
selectedRowKeys: _selectedRowKeys, isCheck
onChange: onSelectChange, ? {
}" selectedRowKeys: _selectedRowKeys,
onChange: onSelectChange,
}
: false
"
:params="params" :params="params"
> >
<template #headerTitle> <template #headerTitle>
@ -26,7 +30,12 @@
<template #icon><AIcon type="PlusOutlined" /></template> <template #icon><AIcon type="PlusOutlined" /></template>
新增 新增
</PermissionButton> </PermissionButton>
<j-dropdown> <BatchDropdown
v-model:isCheck="isCheck"
:actions="batchActions"
@change="onCheckChange"
/>
<!-- <j-dropdown>
<j-button <j-button
>批量操作 <AIcon type="DownOutlined" >批量操作 <AIcon type="DownOutlined"
/></j-button> /></j-button>
@ -131,7 +140,7 @@
</j-menu-item> </j-menu-item>
</j-menu> </j-menu>
</template> </template>
</j-dropdown> </j-dropdown> -->
</j-space> </j-space>
</template> </template>
<template #card="slotProps"> <template #card="slotProps">
@ -155,10 +164,7 @@
</template> </template>
<template #content> <template #content>
<Ellipsis style="width: calc(100% - 100px)"> <Ellipsis style="width: calc(100% - 100px)">
<span <span style="font-size: 16px; font-weight: 600">
style="font-size: 16px; font-weight: 600"
@click.stop="handleView(slotProps.id)"
>
{{ slotProps.name }} {{ slotProps.name }}
</span> </span>
</Ellipsis> </Ellipsis>
@ -233,7 +239,11 @@
type="link" type="link"
style="padding: 0 5px" style="padding: 0 5px"
:danger="i.key === 'delete'" :danger="i.key === 'delete'"
:hasPermission="i.key === 'view' ? true : 'device/Instance:' + i.key" :hasPermission="
i.key === 'view'
? true
: 'device/Instance:' + i.key
"
> >
<template #icon><AIcon :type="i.icon" /></template> <template #icon><AIcon :type="i.icon" /></template>
</PermissionButton> </PermissionButton>
@ -296,6 +306,8 @@ import { useMenuStore } from '@/store/menu';
import type { ActionsType } from './typings'; import type { ActionsType } from './typings';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import BadgeStatus from '@/components/BadgeStatus/index.vue'; import BadgeStatus from '@/components/BadgeStatus/index.vue';
import BatchDropdown from '@/components/BatchDropdown/index.vue';
import { BatchActionsType } from '@/components/BatchDropdown/types';
const instanceRef = ref<Record<string, any>>({}); const instanceRef = ref<Record<string, any>>({});
const params = ref<Record<string, any>>({}); const params = ref<Record<string, any>>({});
@ -307,6 +319,7 @@ const current = ref<Record<string, any>>({});
const operationVisible = ref<boolean>(false); const operationVisible = ref<boolean>(false);
const api = ref<string>(''); const api = ref<string>('');
const type = ref<string>(''); const type = ref<string>('');
const isCheck = ref<boolean>(false);
const menuStory = useMenuStore(); const menuStory = useMenuStore();
@ -657,14 +670,22 @@ const onSelectChange = (keys: string[]) => {
}; };
const handleClick = (dt: any) => { const handleClick = (dt: any) => {
if (_selectedRowKeys.value.includes(dt.id)) { if (isCheck.value) {
const _index = _selectedRowKeys.value.findIndex((i) => i === dt.id); if (_selectedRowKeys.value.includes(dt.id)) {
_selectedRowKeys.value.splice(_index, 1); const _index = _selectedRowKeys.value.findIndex((i) => i === dt.id);
_selectedRowKeys.value.splice(_index, 1);
} else {
_selectedRowKeys.value = [..._selectedRowKeys.value, dt.id];
}
} else { } else {
_selectedRowKeys.value = [..._selectedRowKeys.value, dt.id]; handleView(dt.id);
} }
}; };
const onCheckChange = () => {
_selectedRowKeys.value = [];
};
const activeAllDevice = () => { const activeAllDevice = () => {
type.value = 'active'; type.value = 'active';
const activeAPI = `${BASE_API_PATH}/device-instance/deploy?:X_Access_Token=${LocalStore.get( const activeAPI = `${BASE_API_PATH}/device-instance/deploy?:X_Access_Token=${LocalStore.get(
@ -684,6 +705,10 @@ const syncDeviceStatus = () => {
}; };
const delSelectedDevice = async () => { const delSelectedDevice = async () => {
if(!_selectedRowKeys.value.length){
message.error('请选择设备')
return
}
const resp = await batchDeleteDevice(_selectedRowKeys.value); const resp = await batchDeleteDevice(_selectedRowKeys.value);
if (resp.status === 200) { if (resp.status === 200) {
message.success('操作成功!'); message.success('操作成功!');
@ -692,16 +717,24 @@ const delSelectedDevice = async () => {
} }
}; };
const activeSelectedDevice = async () => { // const activeSelectedDevice = async () => {
const resp = await batchDeployDevice(_selectedRowKeys.value); // if(!_selectedRowKeys.value.length){
if (resp.status === 200) { // message.error('')
message.success('操作成功!'); // return
_selectedRowKeys.value = []; // }
instanceRef.value?.reload(); // const resp = await batchDeployDevice(_selectedRowKeys.value);
} // if (resp.status === 200) {
}; // message.success('');
// _selectedRowKeys.value = [];
// instanceRef.value?.reload();
// }
// };
const disabledSelectedDevice = async () => { const disabledSelectedDevice = async () => {
if(!_selectedRowKeys.value.length){
message.error('请选择设备')
return
}
const resp = await batchUndeployDevice(_selectedRowKeys.value); const resp = await batchUndeployDevice(_selectedRowKeys.value);
if (resp.status === 200) { if (resp.status === 200) {
message.success('操作成功!'); message.success('操作成功!');
@ -710,6 +743,87 @@ const disabledSelectedDevice = async () => {
} }
}; };
const batchActions: BatchActionsType[] = [
{
key: 'export',
text: '批量导出设备',
permission: 'device/Instance:export',
icon: 'ExportOutlined',
onClick: () => {
exportVisible.value = true;
},
},
{
key: 'import',
text: '批量导入设备',
permission: 'device/Instance:import',
icon: 'ImportOutlined',
onClick: () => {
importVisible.value = true;
},
},
{
key: 'activeAll',
text: '启用全部设备',
ghost: true,
type: 'primary',
permission: 'device/Instance:action',
icon: 'CheckCircleOutlined',
popConfirm: {
title: '确认启用全部设备?',
onConfirm: activeAllDevice,
},
},
{
key: 'sync',
text: '同步设备状态',
type: 'primary',
ghost: true,
icon: 'SyncOutlined',
onClick: syncDeviceStatus,
},
{
key: 'delete',
text: '批量删除设备',
danger: true,
permission: 'device/Instance:delete',
icon: 'DeleteOutlined',
selected: {
popConfirm: {
title: '已启用的设备无法删除,确认删除选中的禁用状态设备?',
onConfirm: delSelectedDevice,
},
},
},
// {
// key: 'active',
// text: '',
// ghost: true,
// type: 'primary',
// icon: 'CheckOutlined',
// permission: 'device/Instance:action',
// selected: {
// popConfirm: {
// title: '',
// onConfirm: activeSelectedDevice,
// },
// },
// },
{
key: 'disable',
text: '批量禁用设备',
danger: true,
icon: 'StopOutlined',
permission: 'device/Instance:action',
selected: {
popConfirm: {
title: '确认禁用选中设备?',
onConfirm: disabledSelectedDevice,
}
},
},
];
const saveBtn = () => { const saveBtn = () => {
visible.value = false; visible.value = false;
instanceRef.value?.reload(); instanceRef.value?.reload();

View File

@ -42,12 +42,12 @@ const props = defineProps({
const type = ref<string>('xlsx'); const type = ref<string>('xlsx');
const handleOk = () => { const handleOk = () => {
console.log(props.data);
_export(type.value, props.data).then((res: any) => { _export(type.value, props.data).then((res: any) => {
console.log(res)
if (res) { if (res) {
const blob = new Blob([res], { type: type.value }); const blob = new Blob([res], { type: type.value });
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
console.log(url); console.log(url, 123);
downloadFileByUrl( downloadFileByUrl(
url, url,
`物联卡管理-${moment(new Date()).format( `物联卡管理-${moment(new Date()).format(

View File

@ -1,21 +1,44 @@
<!-- 物联卡管理 --> <!-- 物联卡管理 -->
<template> <template>
<page-container> <page-container>
<pro-search :columns="columns" target="iot-card-management-search" @search="handleSearch" /> <pro-search
<j-pro-table :scroll="{x: 1366}" ref="cardManageRef" :columns="columns" :request="query" :columns="columns"
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }" :rowSelection="{ target="iot-card-management-search"
selectedRowKeys: _selectedRowKeys, @search="handleSearch"
onChange: onSelectChange, />
}" @cancelSelect="cancelSelect" :params="params" :gridColumn="3"> <j-pro-table
:scroll="{ x: 1366 }"
ref="cardManageRef"
:columns="columns"
:request="query"
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }"
:rowSelection="
isCheck
? {
selectedRowKeys: _selectedRowKeys,
onChange: onSelectChange,
}
: false
"
@cancelSelect="cancelSelect"
:params="params"
:gridColumn="3"
>
<template #headerTitle> <template #headerTitle>
<j-space> <j-space>
<!-- <a-button type="primary" @click="handleAdd"> <PermissionButton
<AIcon type="PlusOutlined" />新增 @click="handleAdd"
</a-button> --> :hasPermission="'iot-card/CardManagement:add'"
<PermissionButton @click="handleAdd" :hasPermission="'iot-card/CardManagement:add'" type="primary"> type="primary"
>
<AIcon type="PlusOutlined" />新增 <AIcon type="PlusOutlined" />新增
</PermissionButton> </PermissionButton>
<j-dropdown> <BatchDropdown
v-model:isCheck="isCheck"
:actions="batchActions"
@change="onCheckChange"
/>
<!-- <j-dropdown>
<j-button> <j-button>
批量操作 批量操作
<AIcon type="DownOutlined" /> <AIcon type="DownOutlined" />
@ -23,86 +46,122 @@
<template #overlay> <template #overlay>
<j-menu> <j-menu>
<j-menu-item> <j-menu-item>
<PermissionButton @click="exportVisible = true" <PermissionButton
:hasPermission="'iot-card/CardManagement:export'"> @click="exportVisible = true"
:hasPermission="'iot-card/CardManagement:export'"
>
<AIcon type="ExportOutlined" /> <AIcon type="ExportOutlined" />
批量导出 批量导出
</PermissionButton> </PermissionButton>
</j-menu-item> </j-menu-item>
<j-menu-item> <j-menu-item>
<PermissionButton @click="importVisible = true" <PermissionButton
:hasPermission="'iot-card/CardManagement:import'"> @click="importVisible = true"
:hasPermission="'iot-card/CardManagement:import'"
>
<AIcon type="ImportOutlined" />批量导入 <AIcon type="ImportOutlined" />批量导入
</PermissionButton> </PermissionButton>
</j-menu-item> </j-menu-item>
<j-menu-item> <j-menu-item>
<PermissionButton :popConfirm="{ <PermissionButton
title: '确认激活吗?', :popConfirm="{
onConfirm: handleActive, title: '确认激活吗?',
}" :hasPermission="'iot-card/CardManagement:active'"> onConfirm: handleActive,
}"
:hasPermission="'iot-card/CardManagement:active'"
>
<AIcon type="CheckCircleOutlined" /> <AIcon type="CheckCircleOutlined" />
批量激活 批量激活
</PermissionButton> </PermissionButton>
</j-menu-item> </j-menu-item>
<j-menu-item> <j-menu-item>
<PermissionButton :popConfirm="{ <PermissionButton
title: '确认停用吗?', :popConfirm="{
onConfirm: handleStop, title: '确认停用吗?',
}" ghost type="primary" :hasPermission="'iot-card/CardManagement:action'"> onConfirm: handleStop,
}"
ghost
type="primary"
:hasPermission="'iot-card/CardManagement:action'"
>
<AIcon type="StopOutlined" /> <AIcon type="StopOutlined" />
批量停用 批量停用
</PermissionButton> </PermissionButton>
</j-menu-item> </j-menu-item>
<j-menu-item> <j-menu-item>
<PermissionButton :popConfirm="{ <PermissionButton
title: '确认复机吗?', :popConfirm="{
onConfirm: handleResumption, title: '确认复机吗?',
}" ghost type="primary" :hasPermission="'iot-card/CardManagement:action'"> onConfirm: handleResumption,
}"
ghost
type="primary"
:hasPermission="'iot-card/CardManagement:action'"
>
<AIcon type="PoweroffOutlined" /> <AIcon type="PoweroffOutlined" />
批量复机 批量复机
</PermissionButton> </PermissionButton>
</j-menu-item> </j-menu-item>
<j-menu-item> <j-menu-item>
<PermissionButton :popConfirm="{ <PermissionButton
title: '确认同步状态吗?', :popConfirm="{
onConfirm: handleSync, title: '确认同步状态吗?',
}" ghost type="primary" :hasPermission="'iot-card/CardManagement:sync'"> onConfirm: handleSync,
}"
ghost
type="primary"
:hasPermission="'iot-card/CardManagement:sync'"
>
<AIcon type="SwapOutlined" /> <AIcon type="SwapOutlined" />
同步状态 同步状态
</PermissionButton> </PermissionButton>
</j-menu-item> </j-menu-item>
<j-menu-item v-if="_selectedRowKeys.length > 0"> <j-menu-item v-if="_selectedRowKeys.length > 0">
<PermissionButton :popConfirm="{ <PermissionButton
title: '确认删除吗?', :popConfirm="{
onConfirm: handelRemove, title: '确认删除吗?',
}" ghost type="primary" :hasPermission="'iot-card/CardManagement:delete'"> onConfirm: handelRemove,
}"
ghost
type="primary"
:hasPermission="'iot-card/CardManagement:delete'"
>
<AIcon type="SwapOutlined" /> <AIcon type="SwapOutlined" />
批量删除 批量删除
</PermissionButton> </PermissionButton>
</j-menu-item> </j-menu-item>
</j-menu> </j-menu>
</template> </template>
</j-dropdown> </j-dropdown> -->
</j-space> </j-space>
</template> </template>
<template #card="slotProps"> <template #card="slotProps">
<CardBox :value="slotProps" @click="handleClick" :actions="getActions(slotProps, 'card')" v-bind="slotProps" <CardBox
:active="_selectedRowKeys.includes(slotProps.id)" :status="slotProps.cardStateType.value" :value="slotProps"
:statusText="slotProps.cardStateType.text" :statusNames="{ @click="handleClick"
:actions="getActions(slotProps, 'card')"
v-bind="slotProps"
:active="_selectedRowKeys.includes(slotProps.id)"
:status="slotProps.cardStateType.value"
:statusText="slotProps.cardStateType.text"
:statusNames="{
using: 'processing', using: 'processing',
toBeActivated: 'default', toBeActivated: 'default',
deactivate: 'error', deactivate: 'error',
}"> }"
>
<template #img> <template #img>
<slot name="img"> <slot name="img">
<img :src="getImage('/iot-card/iot-card-bg.png')" /> <img :src="getImage('/iot-card/iot-card-bg.png')" />
</slot> </slot>
</template> </template>
<template #content> <template #content>
<h3 class="card-item-content-title"> <Ellipsis style="width: calc(100% - 100px)">
{{ slotProps.id }} <span style="font-size: 16px; font-weight: 600">
</h3> {{ slotProps.id }}
<j-row> </span>
</Ellipsis>
<j-row style="margin-top: 20px">
<j-col :span="8"> <j-col :span="8">
<div class="card-item-content-text"> <div class="card-item-content-text">
平台对接 平台对接
@ -114,46 +173,72 @@
<div>{{ slotProps.cardType.text }}</div> <div>{{ slotProps.cardType.text }}</div>
</j-col> </j-col>
<j-col :span="6"> <j-col :span="6">
<div class="card-item-content-text">绑定设备</div> <div class="card-item-content-text">
绑定设备
</div>
<div>{{ slotProps.deviceName }}</div> <div>{{ slotProps.deviceName }}</div>
</j-col> </j-col>
</j-row> </j-row>
<j-divider style="margin: 12px 0" /> <j-divider style="margin: 12px 0" />
<div class="content-bottom"> <div class="content-bottom">
<div v-if="slotProps.usedFlow === 0"> <div v-if="slotProps.usedFlow === 0">
<span class="flow-text"> <span class="flow-text">
{{ slotProps.totalFlow }} {{ slotProps.totalFlow }}
</span> </span>
<span class="card-item-content-text"> <span class="card-item-content-text">
M 使用流量</span> M 使用流量</span
</div> >
<div v-else> </div>
<div class="progress-text"> <div v-else>
<div> <div class="progress-text">
{{ <div>
(slotProps.usedFlow / slotProps.totalFlow * 100).toFixed(2) {{
}} (
% (slotProps.usedFlow /
</div> slotProps.totalFlow) *
<div class="card-item-content-text"> 100
总共 {{ slotProps.totalFlow }} M ).toFixed(2)
</div> }}
%
</div>
<div class="card-item-content-text">
总共 {{ slotProps.totalFlow }} M
</div>
</div>
<j-progress
:strokeColor="'#ADC6FF'"
:showInfo="false"
:percent="
(slotProps.usedFlow /
slotProps.totalFlow) *
100
"
/>
</div> </div>
<j-progress :strokeColor="'#ADC6FF'" :showInfo="false" :percent="slotProps.usedFlow / slotProps.totalFlow * 100" />
</div>
</div> </div>
</template> </template>
<template #actions="item"> <template #actions="item">
<PermissionButton :disabled="item.disabled" :popConfirm="item.popConfirm" :tooltip="{ <PermissionButton
...item.tooltip, :disabled="item.disabled"
}" @click="item.onClick" :hasPermission="'iot-card/CardManagement:' + item.key"> :popConfirm="item.popConfirm"
<AIcon type="DeleteOutlined" v-if="item.key === 'delete'" /> :tooltip="{
...item.tooltip,
}"
@click="item.onClick"
:hasPermission="
'iot-card/CardManagement:' + item.key
"
>
<AIcon
type="DeleteOutlined"
v-if="item.key === 'delete'"
/>
<template v-else> <template v-else>
<AIcon :type="item.icon" /> <AIcon :type="item.icon" />
<span>{{ item?.text }}</span> <span>{{ item?.text }}</span>
</template> </template>
</PermissionButton> </PermissionButton>
<!-- <a-tooltip <!-- <a-tooltip
v-bind="item.tooltip" v-bind="item.tooltip"
:title="item.disabled && item.tooltip.title" :title="item.disabled && item.tooltip.title"
> >
@ -199,8 +284,8 @@
<div> <div>
{{ {{
slotProps.totalFlow slotProps.totalFlow
? slotProps.totalFlow.toFixed(2) + ' M' ? slotProps.totalFlow.toFixed(2) + ' M'
: '' : ''
}} }}
</div> </div>
</template> </template>
@ -208,8 +293,8 @@
<div> <div>
{{ {{
slotProps.usedFlow slotProps.usedFlow
? slotProps.usedFlow.toFixed(2) + ' M' ? slotProps.usedFlow.toFixed(2) + ' M'
: '' : ''
}} }}
</div> </div>
</template> </template>
@ -217,8 +302,8 @@
<div> <div>
{{ {{
slotProps.residualFlow slotProps.residualFlow
? slotProps.residualFlow.toFixed(2) + ' M' ? slotProps.residualFlow.toFixed(2) + ' M'
: '' : ''
}} }}
</div> </div>
</template> </template>
@ -239,28 +324,43 @@
<template #activationDate="slotProps"> <template #activationDate="slotProps">
{{ {{
slotProps.activationDate slotProps.activationDate
? dayjs(slotProps.activationDate).format( ? dayjs(slotProps.activationDate).format(
'YYYY-MM-DD HH:mm:ss', 'YYYY-MM-DD HH:mm:ss',
) )
: '' : ''
}} }}
</template> </template>
<template #updateTime="slotProps"> <template #updateTime="slotProps">
{{ {{
slotProps.updateTime slotProps.updateTime
? dayjs(slotProps.updateTime).format( ? dayjs(slotProps.updateTime).format(
'YYYY-MM-DD HH:mm:ss', 'YYYY-MM-DD HH:mm:ss',
) )
: '' : ''
}} }}
</template> </template>
<template #action="slotProps"> <template #action="slotProps">
<j-space :size="16"> <j-space :size="16">
<template v-for="i in getActions(slotProps, 'table')" :key="i.key"> <template
<PermissionButton :disabled="i.disabled" :popConfirm="i.popConfirm" :tooltip="{ v-for="i in getActions(slotProps, 'table')"
...i.tooltip, :key="i.key"
}" @click="i.onClick" type="link" style="padding: 0px" >
:hasPermission="'iot-card/CardManagement:' + i.key"> <PermissionButton
:disabled="i.disabled"
:popConfirm="i.popConfirm"
:tooltip="{
...i.tooltip,
}"
@click="i.onClick"
type="link"
style="padding: 0px"
:hasPermission="
i.key === 'view'
? true
: 'iot-card/CardManagement:' + i.key
"
:danger="i.key === 'delete'"
>
<template #icon> <template #icon>
<AIcon :type="i.icon" /> <AIcon :type="i.icon" />
</template> </template>
@ -272,11 +372,24 @@
<!-- 批量导入 --> <!-- 批量导入 -->
<Import v-if="importVisible" @close="importVisible = false" /> <Import v-if="importVisible" @close="importVisible = false" />
<!-- 批量导出 --> <!-- 批量导出 -->
<Export v-if="exportVisible" @close="exportVisible = false" :data="_selectedRowKeys" /> <Export
v-if="exportVisible"
@close="exportVisible = false"
:data="_selectedRowKeys"
/>
<!-- 绑定设备 --> <!-- 绑定设备 -->
<BindDevice v-if="bindDeviceVisible" :cardId="cardId" @change="bindDevice" /> <BindDevice
v-if="bindDeviceVisible"
:cardId="cardId"
@change="bindDevice"
/>
<!-- 新增编辑 --> <!-- 新增编辑 -->
<Save v-if="visible" :type="saveType" :data="current" @change="saveChange" /> <Save
v-if="visible"
:type="saveType"
:data="current"
@change="saveChange"
/>
</page-container> </page-container>
</template> </template>
@ -304,11 +417,13 @@ import BindDevice from './BindDevice.vue';
import Import from './Import.vue'; import Import from './Import.vue';
import Export from './Export.vue'; import Export from './Export.vue';
import Save from './Save.vue'; import Save from './Save.vue';
import { useMenuStore } from 'store/menu' import { useMenuStore } from 'store/menu';
import BadgeStatus from '@/components/BadgeStatus/index.vue'; import BadgeStatus from '@/components/BadgeStatus/index.vue';
import BatchDropdown from '@/components/BatchDropdown/index.vue';
import { BatchActionsType } from '@/components/BatchDropdown/types';
const router = useRouter(); const router = useRouter();
const menuStory = useMenuStore() const menuStory = useMenuStore();
const cardManageRef = ref<Record<string, any>>({}); const cardManageRef = ref<Record<string, any>>({});
const params = ref<Record<string, any>>({}); const params = ref<Record<string, any>>({});
const _selectedRowKeys = ref<string[]>([]); const _selectedRowKeys = ref<string[]>([]);
@ -320,6 +435,7 @@ const importVisible = ref<boolean>(false);
const cardId = ref<any>(); 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 columns = [ const columns = [
{ {
@ -472,21 +588,7 @@ const getActions = (
type: 'card' | 'table', type: 'card' | 'table',
): ActionsType[] => { ): ActionsType[] => {
if (!data) return []; if (!data) return [];
return [ const arr = [
{
key: 'view',
text: '查看',
tooltip: {
title: '查看',
},
icon: 'EyeOutlined',
onClick: () => {
// router.push({
// path: `/iot-card/CardManagement/detail/${data.id}`,
// });
menuStory.jumpPage('iot-card/CardManagement/Detail', { id: data.id })
},
},
{ {
key: 'update', key: 'update',
text: '编辑', text: '编辑',
@ -509,18 +611,18 @@ const getActions = (
icon: data.deviceId ? 'DisconnectOutlined' : 'LinkOutlined', icon: data.deviceId ? 'DisconnectOutlined' : 'LinkOutlined',
popConfirm: data.deviceId popConfirm: data.deviceId
? { ? {
title: '确认解绑设备?', title: '确认解绑设备?',
okText: '确定', okText: '确定',
cancelText: '取消', cancelText: '取消',
onConfirm: async () => { onConfirm: async () => {
unbind(data.id).then((resp: any) => { unbind(data.id).then((resp: any) => {
if (resp.status === 200) { if (resp.status === 200) {
message.success('操作成功') message.success('操作成功');
cardManageRef.value?.reload(); cardManageRef.value?.reload();
} }
}); });
}, },
} }
: undefined, : undefined,
onClick: () => { onClick: () => {
if (!data.deviceId) { if (!data.deviceId) {
@ -530,55 +632,58 @@ const getActions = (
}, },
}, },
{ {
key: data.cardStateType?.value === 'toBeActivated' ? 'active' : 'action', key:
data.cardStateType?.value === 'toBeActivated'
? 'active'
: 'action',
text: text:
data.cardStateType?.value === 'toBeActivated' data.cardStateType?.value === 'toBeActivated'
? '激活' ? '激活'
: data.cardStateType?.value === 'deactivate' : data.cardStateType?.value === 'deactivate'
? '复机' ? '复机'
: '停用', : '停用',
tooltip: { tooltip: {
title: title:
data.cardStateType?.value === 'toBeActivated' data.cardStateType?.value === 'toBeActivated'
? '激活' ? '激活'
: data.cardStateType?.value === 'deactivate' : data.cardStateType?.value === 'deactivate'
? '复机' ? '复机'
: '停用', : '停用',
}, },
icon: icon:
data.cardStateType?.value === 'toBeActivated' data.cardStateType?.value === 'toBeActivated'
? 'CheckCircleOutlined' ? 'CheckCircleOutlined'
: data.cardStateType?.value === 'deactivate' : data.cardStateType?.value === 'deactivate'
? 'PoweroffOutlined' ? 'PoweroffOutlined'
: 'StopOutlined', : 'StopOutlined',
popConfirm: { popConfirm: {
title: title:
data.cardStateType?.value === 'toBeActivated' data.cardStateType?.value === 'toBeActivated'
? '确认激活?' ? '确认激活?'
: data.cardStateType?.value === 'deactivate' : data.cardStateType?.value === 'deactivate'
? '确认复机?' ? '确认复机?'
: '确认停用?', : '确认停用?',
okText: '确定', okText: '确定',
cancelText: '取消', cancelText: '取消',
onConfirm: async () => { onConfirm: async () => {
if (data.cardStateType?.value === 'toBeActivated') { if (data.cardStateType?.value === 'toBeActivated') {
changeDeploy(data.id).then((resp) => { changeDeploy(data.id).then((resp) => {
if (resp.status === 200) { if (resp.status === 200) {
message.success('操作成功') message.success('操作成功');
cardManageRef.value?.reload(); cardManageRef.value?.reload();
} }
}); });
} else if (data.cardStateType?.value === 'deactivate') { } else if (data.cardStateType?.value === 'deactivate') {
resumption(data.id).then((resp) => { resumption(data.id).then((resp) => {
if (resp.status === 200) { if (resp.status === 200) {
message.success('操作成功') message.success('操作成功');
cardManageRef.value?.reload(); cardManageRef.value?.reload();
} }
}); });
} else { } else {
unDeploy(data.id).then((resp) => { unDeploy(data.id).then((resp) => {
if (resp.status === 200) { if (resp.status === 200) {
message.success('操作成功') message.success('操作成功');
cardManageRef.value?.reload(); cardManageRef.value?.reload();
} }
}); });
@ -599,7 +704,7 @@ const getActions = (
onConfirm: async () => { onConfirm: async () => {
const resp: any = await del(data.id); const resp: any = await del(data.id);
if (resp.status === 200) { if (resp.status === 200) {
message.success('操作成功') message.success('操作成功');
cardManageRef.value?.reload(); cardManageRef.value?.reload();
} else { } else {
message.error('操作失败!'); message.error('操作失败!');
@ -609,6 +714,26 @@ const getActions = (
icon: 'DeleteOutlined', icon: 'DeleteOutlined',
}, },
]; ];
if (type === 'card') {
return arr;
} else {
return [
{
key: 'view',
text: '查看',
tooltip: {
title: '查看',
},
icon: 'EyeOutlined',
onClick: () => {
menuStory.jumpPage('iot-card/CardManagement/Detail', {
id: data.id,
});
},
},
...arr,
];
}
}; };
const handleSearch = (e: any) => { const handleSearch = (e: any) => {
@ -625,14 +750,24 @@ const cancelSelect = () => {
}; };
const handleClick = (dt: any) => { const handleClick = (dt: any) => {
if (_selectedRowKeys.value.includes(dt.id)) { if (isCheck.value) {
const _index = _selectedRowKeys.value.findIndex((i) => i === dt.id); if (_selectedRowKeys.value.includes(dt.id)) {
_selectedRowKeys.value.splice(_index, 1); const _index = _selectedRowKeys.value.findIndex((i) => i === dt.id);
_selectedRowKeys.value.splice(_index, 1);
} else {
_selectedRowKeys.value = [..._selectedRowKeys.value, dt.id];
}
} else { } else {
_selectedRowKeys.value = [..._selectedRowKeys.value, dt.id]; menuStory.jumpPage('iot-card/CardManagement/Detail', {
id: dt.id,
});
} }
}; };
const onCheckChange = () => {
_selectedRowKeys.value = [];
};
/** /**
* 新增 * 新增
*/ */
@ -694,7 +829,7 @@ const handleStop = () => {
) { ) {
unDeployBatch(_selectedRowKeys.value).then((res: any) => { unDeployBatch(_selectedRowKeys.value).then((res: any) => {
if (res.status === 200) { if (res.status === 200) {
message.success('操作成功') message.success('操作成功');
} }
}); });
} else { } else {
@ -712,7 +847,7 @@ const handleResumption = () => {
) { ) {
resumptionBatch(_selectedRowKeys.value).then((res: any) => { resumptionBatch(_selectedRowKeys.value).then((res: any) => {
if (res.status === 200) { if (res.status === 200) {
message.success('操作成功') message.success('操作成功');
} }
}); });
} else { } else {
@ -736,20 +871,106 @@ const handleSync = () => {
* 批量删除 * 批量删除
*/ */
const handelRemove = async () => { const handelRemove = async () => {
if (!_selectedRow.value.length) {
message.error('请选择数据');
return;
}
const resp = await removeCards(_selectedRow.value); const resp = await removeCards(_selectedRow.value);
if (resp.status === 200) { if (resp.status === 200) {
message.success('操作成功') message.success('操作成功');
_selectedRowKeys.value = []; _selectedRowKeys.value = [];
_selectedRow.value = []; _selectedRow.value = [];
cardManageRef.value?.reload(); cardManageRef.value?.reload();
} }
}; };
const batchActions: BatchActionsType[] = [
{
key: 'export',
text: '批量导出',
permission: 'iot-card/CardManagement:export',
icon: 'ExportOutlined',
onClick: () => {
exportVisible.value = true;
},
},
{
key: 'import',
text: '批量导入',
permission: 'iot-card/CardManagement:import',
icon: 'ImportOutlined',
onClick: () => {
importVisible.value = true;
},
},
// {
// key: 'active',
// text: '',
// permission: 'iot-card/CardManagement:active',
// icon: 'CheckCircleOutlined',
// selected: {
// popConfirm: {
// title: '',
// onConfirm: handleActive,
// },
// },
// },
{
key: 'stop',
text: '批量停用',
permission: 'iot-card/CardManagement:action',
icon: 'StopOutlined',
selected: {
popConfirm: {
title: '确认停用吗?',
onConfirm: handleStop,
},
},
},
{
key: 'resumption',
text: '批量复机',
ghost: true,
type: 'primary',
permission: 'iot-card/CardManagement:action',
icon: 'PoweroffOutlined',
selected: {
popConfirm: {
title: '确认复机吗?',
onConfirm: handleResumption,
},
},
},
{
key: 'sync',
text: '同步状态',
ghost: true,
type: 'primary',
permission: 'iot-card/CardManagement:sync',
icon: 'SwapOutlined',
popConfirm: {
title: '确认同步状态吗?',
onConfirm: handleSync,
},
},
{
key: 'delete',
text: '批量删除',
danger: true,
permission: 'iot-card/CardManagement:delete',
icon: 'StopOutlined',
selected: {
popConfirm: {
title: '确认删除吗?',
onConfirm: handelRemove,
},
},
},
];
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
.content-bottom { .content-bottom {
height: 45px; height: 38px;
} }
.flow-text { .flow-text {
font-size: 20px; font-size: 20px;