Commit 29e3131bbaf9b7db4057dddda911c1d00defc5c5

Authored by ww
1 parent c6c9460d

feat: implement package manage batch delete

@@ -45,7 +45,7 @@ export const getOtaPackagesList = (params: GetOtaPackagesParams) => { @@ -45,7 +45,7 @@ export const getOtaPackagesList = (params: GetOtaPackagesParams) => {
45 * @param params 45 * @param params
46 * @returns 46 * @returns
47 */ 47 */
48 -export const createOtaPackages = (params: CreateOtaPackageParams) => { 48 +export const createOtaPackage = (params: CreateOtaPackageParams) => {
49 return defHttp.post<OtaRecordDatum>( 49 return defHttp.post<OtaRecordDatum>(
50 { 50 {
51 url: Api.CREATE_OTA_PACKAGES, 51 url: Api.CREATE_OTA_PACKAGES,
@@ -76,7 +76,7 @@ export const uploadOtaPackages = (params: UploadOtaPackagesParams) => { @@ -76,7 +76,7 @@ export const uploadOtaPackages = (params: UploadOtaPackagesParams) => {
76 * @description 获取设备默认信息 76 * @description 获取设备默认信息
77 * @returns 77 * @returns
78 */ 78 */
79 -export const getDevicePRofileInfo = () => { 79 +export const getDefaultDeviceProfile = () => {
80 return defHttp.get<DefaultDeviceProfileInfo>( 80 return defHttp.get<DefaultDeviceProfileInfo>(
81 { 81 {
82 url: Api.GET_DEVICE_PROFILE_INFO_DEFAULT, 82 url: Api.GET_DEVICE_PROFILE_INFO_DEFAULT,
  1 +import { ModalOptionsEx, useMessage } from '../web/useMessage';
  2 +
  3 +export function useSyncConfirm() {
  4 + const { createConfirm } = useMessage();
  5 +
  6 + const createSyncConfirm = (options: ModalOptionsEx): Promise<boolean> => {
  7 + return new Promise((resolve, reject) => {
  8 + createConfirm({
  9 + ...options,
  10 + onOk: () => {
  11 + resolve(true);
  12 + },
  13 + onCancel: () => {
  14 + reject(false);
  15 + },
  16 + });
  17 + });
  18 + };
  19 +
  20 + return { createSyncConfirm };
  21 +}
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 import { BasicForm, useForm } from '/@/components/Form'; 3 import { BasicForm, useForm } from '/@/components/Form';
4 import { ALG, formSchema, PackageField } from '../config/packageDetail.config'; 4 import { ALG, formSchema, PackageField } from '../config/packageDetail.config';
5 import { ref } from 'vue'; 5 import { ref } from 'vue';
6 - import { createOtaPackages, uploadOtaPackages, deleteOtaPackage } from '/@/api/ota'; 6 + import { createOtaPackage, uploadOtaPackages, deleteOtaPackage } from '/@/api/ota';
7 import { CreateOtaPackageParams } from '/@/api/ota/model'; 7 import { CreateOtaPackageParams } from '/@/api/ota/model';
8 8
9 interface FieldsValue extends CreateOtaPackageParams { 9 interface FieldsValue extends CreateOtaPackageParams {
@@ -54,7 +54,7 @@ @@ -54,7 +54,7 @@
54 const handleCreatePackages = async (value: FieldsValue) => { 54 const handleCreatePackages = async (value: FieldsValue) => {
55 try { 55 try {
56 setLoading(true); 56 setLoading(true);
57 - const { id } = await createOtaPackages(value); 57 + const { id } = await createOtaPackage(value);
58 const { isURL } = value; 58 const { isURL } = value;
59 if (!isURL) { 59 if (!isURL) {
60 await handleUploadFile(value, id.id); 60 await handleUploadFile(value, id.id);
@@ -82,6 +82,14 @@ @@ -82,6 +82,14 @@
82 82
83 <template> 83 <template>
84 <BasicModal title="包管理" destroy-on-close @register="registerModal" @ok="handleSubmit"> 84 <BasicModal title="包管理" destroy-on-close @register="registerModal" @ok="handleSubmit">
85 - <BasicForm @register="registerForm" /> 85 + <BasicForm @register="registerForm" class="package-manage-form" />
86 </BasicModal> 86 </BasicModal>
87 </template> 87 </template>
  88 +
  89 +<style scoped lang="less">
  90 + .package-manage-form {
  91 + :deep(.ant-form-item-control-input-content > div > div) {
  92 + width: 100% !important;
  93 + }
  94 + }
  95 +</style>
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 - import { OtaRecordDatum } from '/@/api/ota/model'; 2 + import { DeviceProfileRecord, OtaRecordDatum } from '/@/api/ota/model';
3 import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; 3 import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
4 import { Tabs, Space, Button } from 'ant-design-vue'; 4 import { Tabs, Space, Button } from 'ant-design-vue';
5 import { useForm, BasicForm } from '/@/components/Form'; 5 import { useForm, BasicForm } from '/@/components/Form';
@@ -7,14 +7,23 @@ @@ -7,14 +7,23 @@
7 import { ref, unref } from 'vue'; 7 import { ref, unref } from 'vue';
8 import { PackageField } from '../config/packageDetail.config'; 8 import { PackageField } from '../config/packageDetail.config';
9 import { useMessage } from '/@/hooks/web/useMessage'; 9 import { useMessage } from '/@/hooks/web/useMessage';
10 - import { deleteOtaPackage, getDeviceProfileInfoById, getOtaPackageInfo } from '/@/api/ota'; 10 + import {
  11 + createOtaPackage,
  12 + deleteOtaPackage,
  13 + getDeviceProfileInfoById,
  14 + getOtaPackageInfo,
  15 + } from '/@/api/ota';
11 import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard'; 16 import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
12 import { useDownload } from '../hook/useDownload'; 17 import { useDownload } from '../hook/useDownload';
13 18
14 const emit = defineEmits(['register', 'update:list']); 19 const emit = defineEmits(['register', 'update:list']);
15 20
  21 + const loading = ref(false);
  22 +
16 const otaRecord = ref<OtaRecordDatum>({} as unknown as OtaRecordDatum); 23 const otaRecord = ref<OtaRecordDatum>({} as unknown as OtaRecordDatum);
17 24
  25 + const deviceProfileInfo = ref<DeviceProfileRecord>({} as unknown as DeviceProfileRecord);
  26 +
18 const { createConfirm, createMessage } = useMessage(); 27 const { createConfirm, createMessage } = useMessage();
19 28
20 const [registerForm, { setFieldsValue, getFieldsValue }] = useForm({ 29 const [registerForm, { setFieldsValue, getFieldsValue }] = useForm({
@@ -23,7 +32,7 @@ @@ -23,7 +32,7 @@
23 disabled: true, 32 disabled: true,
24 }); 33 });
25 34
26 - const [register, { closeDrawer }] = useDrawerInner(async (id: string) => { 35 + const [register, { closeDrawer, changeLoading }] = useDrawerInner(async (id: string) => {
27 try { 36 try {
28 const record = await getOtaPackageInfo(id); 37 const record = await getOtaPackageInfo(id);
29 const deviceInfo = await getDeviceProfileInfoById(record.deviceProfileId.id); 38 const deviceInfo = await getDeviceProfileInfoById(record.deviceProfileId.id);
@@ -32,11 +41,12 @@ @@ -32,11 +41,12 @@
32 [PackageField.DESCRIPTION]: record.additionalInfo.description, 41 [PackageField.DESCRIPTION]: record.additionalInfo.description,
33 [PackageField.DEVICE_PROFILE_INFO]: deviceInfo.name, 42 [PackageField.DEVICE_PROFILE_INFO]: deviceInfo.name,
34 }); 43 });
  44 + deviceProfileInfo.value = deviceInfo;
35 otaRecord.value = record; 45 otaRecord.value = record;
36 } catch (error) {} 46 } catch (error) {}
37 }); 47 });
38 48
39 - const openDetailPage = () => {}; 49 + // const openDetailPage = () => {};
40 50
41 const downloadPackage = async () => { 51 const downloadPackage = async () => {
42 await useDownload(unref(otaRecord)); 52 await useDownload(unref(otaRecord));
@@ -72,17 +82,40 @@ @@ -72,17 +82,40 @@
72 if (unref(isSuccessRef)) createMessage.success('复制成功'); 82 if (unref(isSuccessRef)) createMessage.success('复制成功');
73 }; 83 };
74 84
  85 + const setLoading = (status: boolean) => {
  86 + changeLoading(status);
  87 + loading.value = status;
  88 + };
  89 +
75 const handleSubmit = async () => { 90 const handleSubmit = async () => {
76 - getFieldsValue(); 91 + const value = getFieldsValue();
  92 + try {
  93 + setLoading(true);
  94 + await createOtaPackage({
  95 + ...unref(otaRecord),
  96 + additionalInfo: { description: value[PackageField.DESCRIPTION] },
  97 + } as any);
  98 + createMessage.success('修改成功');
  99 + } catch (error) {
  100 + } finally {
  101 + setLoading(false);
  102 + closeDrawer();
  103 + }
77 }; 104 };
78 </script> 105 </script>
79 106
80 <template> 107 <template>
81 - <BasicDrawer width="40%" class="relative" @register="register" @ok="handleSubmit"> 108 + <BasicDrawer
  109 + :title="otaRecord.title"
  110 + width="40%"
  111 + class="relative"
  112 + @register="register"
  113 + @ok="handleSubmit"
  114 + >
82 <Tabs> 115 <Tabs>
83 <Tabs.TabPane tab="详情" key="detail"> 116 <Tabs.TabPane tab="详情" key="detail">
84 <Space> 117 <Space>
85 - <Button type="primary" @click="openDetailPage">打开详情页</Button> 118 + <!-- <Button type="primary" @click="openDetailPage">打开详情页</Button> -->
86 <Button type="primary" @click="downloadPackage" :disabled="!!otaRecord.url"> 119 <Button type="primary" @click="downloadPackage" :disabled="!!otaRecord.url">
87 下载包 120 下载包
88 </Button> 121 </Button>
@@ -97,11 +130,13 @@ @@ -97,11 +130,13 @@
97 <BasicForm @register="registerForm" /> 130 <BasicForm @register="registerForm" />
98 </Tabs.TabPane> 131 </Tabs.TabPane>
99 </Tabs> 132 </Tabs>
100 - <div  
101 - class="absolute right-0 bottom-0 w-full border-t bg-light-50 border-t-gray-100 py-2 px-4 text-right"  
102 - >  
103 - <Button class="mr-2">取消</Button>  
104 - <Button type="primary">保存</Button>  
105 - </div> 133 + <template #footer>
  134 + <div
  135 + class="absolute right-0 bottom-0 w-full border-t bg-light-50 border-t-gray-100 py-2 px-4 text-right"
  136 + >
  137 + <Button class="mr-2" @click="closeDrawer">取消</Button>
  138 + <Button type="primary" :loading="loading" @click="handleSubmit">保存</Button>
  139 + </div>
  140 + </template>
106 </BasicDrawer> 141 </BasicDrawer>
107 </template> 142 </template>
1 -import { getDevicePRofileInfo, getDeviceProfileInfos } from '/@/api/ota'; 1 +import { getDefaultDeviceProfile, getDeviceProfileInfos } from '/@/api/ota';
2 import { Id } from '/@/api/ota/model'; 2 import { Id } from '/@/api/ota/model';
3 import { FormSchema } from '/@/components/Form'; 3 import { FormSchema } from '/@/components/Form';
4 import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue'; 4 import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue';
@@ -97,7 +97,7 @@ export const formSchema: FormSchema[] = [ @@ -97,7 +97,7 @@ export const formSchema: FormSchema[] = [
97 labelField: 'name', 97 labelField: 'name',
98 valueField: 'id', 98 valueField: 'id',
99 api: async () => { 99 api: async () => {
100 - const data = await getDevicePRofileInfo(); 100 + const data = await getDefaultDeviceProfile();
101 data.id = JSON.stringify(data.id) as unknown as Id; 101 data.id = JSON.stringify(data.id) as unknown as Id;
102 setFieldsValue({ [PackageField.DEVICE_PROFILE_INFO]: data.id }); 102 setFieldsValue({ [PackageField.DEVICE_PROFILE_INFO]: data.id });
103 return { data: [data] }; 103 return { data: [data] };
@@ -11,8 +11,10 @@ @@ -11,8 +11,10 @@
11 import { useDrawer } from '/@/components/Drawer'; 11 import { useDrawer } from '/@/components/Drawer';
12 import { useMessage } from '/@/hooks/web/useMessage'; 12 import { useMessage } from '/@/hooks/web/useMessage';
13 import { useDownload } from './hook/useDownload'; 13 import { useDownload } from './hook/useDownload';
  14 + import { computed } from 'vue';
  15 + import { useSyncConfirm } from '/@/hooks/component/useSyncConfirm';
14 16
15 - const [register, { reload }] = useTable({ 17 + const [register, { reload, getSelectRowKeys, getRowSelection, setSelectedRowKeys }] = useTable({
16 columns, 18 columns,
17 title: '包仓库', 19 title: '包仓库',
18 api: async (params: GetOtaPackagesParams) => { 20 api: async (params: GetOtaPackagesParams) => {
@@ -35,9 +37,13 @@ @@ -35,9 +37,13 @@
35 labelWidth: 120, 37 labelWidth: 120,
36 schemas: searchFormSchema, 38 schemas: searchFormSchema,
37 }, 39 },
  40 + rowKey: (record: OtaRecordDatum) => record.id.id,
38 showIndexColumn: false, 41 showIndexColumn: false,
39 useSearchForm: true, 42 useSearchForm: true,
40 showTableSetting: true, 43 showTableSetting: true,
  44 + rowSelection: {
  45 + type: 'checkbox',
  46 + },
41 }); 47 });
42 48
43 const { createConfirm, createMessage } = useMessage(); 49 const { createConfirm, createMessage } = useMessage();
@@ -71,6 +77,25 @@ @@ -71,6 +77,25 @@
71 }, 77 },
72 }); 78 });
73 }; 79 };
  80 +
  81 + const canDelete = computed(() => {
  82 + const rowSelection = getRowSelection();
  83 + return !rowSelection.selectedRowKeys?.length;
  84 + });
  85 +
  86 + const { createSyncConfirm } = useSyncConfirm();
  87 + const handleBatchDelete = async () => {
  88 + const rowKeys = getSelectRowKeys();
  89 + try {
  90 + await createSyncConfirm({ iconType: 'warning', content: '确认后所有选中的OTA升级将被删除' });
  91 + for (const key of rowKeys) {
  92 + await deleteOtaPackage(key);
  93 + }
  94 + createMessage.success('批量删除成功');
  95 + setSelectedRowKeys([]);
  96 + reload();
  97 + } catch (error) {}
  98 + };
74 </script> 99 </script>
75 100
76 <template> 101 <template>
@@ -78,6 +103,9 @@ @@ -78,6 +103,9 @@
78 <BasicTable @register="register" @row-click="handleOpenDetailDrawer" class="ota-list"> 103 <BasicTable @register="register" @row-click="handleOpenDetailDrawer" class="ota-list">
79 <template #toolbar> 104 <template #toolbar>
80 <Button @click="handleCreatePackage" type="primary">新增包</Button> 105 <Button @click="handleCreatePackage" type="primary">新增包</Button>
  106 + <Button @click="handleBatchDelete" :disabled="canDelete" type="primary" danger>
  107 + 批量删除
  108 + </Button>
81 </template> 109 </template>
82 <template #action="{ record }"> 110 <template #action="{ record }">
83 <TableAction 111 <TableAction