Commit 6369ad050c252143e9f6753ad1e40932685cb25c

Authored by xp.Huang
2 parents a186d845 1a6c4e73

Merge branch 'feat/add-rule-chain' into 'main_dev'

fix: 修改规则链相关的问题

See merge request yunteng/thingskit-front!850
... ... @@ -12,11 +12,11 @@ export const getDeviceProfile = (deviceType?: string) => {
12 12 };
13 13
14 14 // 获取历史数据
15   -export const getDeviceHistoryInfo = (params: Recordable) => {
  15 +export const getDeviceHistoryInfo = (params: Recordable, orderBy) => {
16 16 return defHttp.get<HistoryData>(
17 17 {
18 18 url: `/plugins/telemetry/DEVICE/${params.entityId}/values/timeseries`,
19   - params: { ...params, entityId: null, orderBy: 'ASC' },
  19 + params: { ...params, entityId: null, orderBy },
20 20 },
21 21 {
22 22 joinPrefix: false,
... ...
... ... @@ -161,15 +161,53 @@ export const createRuleChine = (params) => {
161 161 );
162 162 };
163 163
  164 +export const importRuleChine = (params) => {
  165 + return defHttp.post(
  166 + {
  167 + url: `${ScreenManagerApi.RULE_CHAIN}/metadata`,
  168 + params,
  169 + },
  170 + { joinPrefix: false }
  171 + );
  172 +};
  173 +
164 174 /**
165 175 * 删除规则链
166 176 */
167 177
168   -export const deleteRuleChine = (params) => {
  178 +export const deleteRuleChine = (id) => {
169 179 return defHttp.delete(
170 180 {
171 181 url: `${ScreenManagerApi.RULE_CHAIN}/`,
172   - params,
  182 + params: id,
  183 + },
  184 + { joinPrefix: false }
  185 + );
  186 +};
  187 +
  188 +/**
  189 + * 导出规则链
  190 + */
  191 +
  192 +export const exportRuleChine = (id) => {
  193 + return defHttp.get(
  194 + {
  195 + url: `${ScreenManagerApi.RULE_CHAIN}/`,
  196 + params: id + '/metadata',
  197 + },
  198 + { joinPrefix: false }
  199 + );
  200 +};
  201 +
  202 +/**
  203 + * 设置根规则链接
  204 + */
  205 +
  206 +export const settingRootChine = (id) => {
  207 + return defHttp.post(
  208 + {
  209 + url: `${ScreenManagerApi.RULE_CHAIN}/`,
  210 + params: id + '/root',
173 211 },
174 212 { joinPrefix: false }
175 213 );
... ...
... ... @@ -84,10 +84,22 @@
84 84 format: (val) => {
85 85 return formatToDateTime(val, 'YYYY-MM-DD HH:mm:ss');
86 86 },
  87 + sorter: 'descend',
87 88 },
88 89 ],
89 90 });
90 91
  92 + const handleTableChange = async (pag, filters, sorter: any) => {
  93 + console.log(pag, filters, sorter, 'pag, filters, sorter');
  94 + if (sorter.field == 'ts') {
  95 + if (sorter.order == 'descend') {
  96 + openHistoryPanel('ASC');
  97 + } else {
  98 + openHistoryPanel('DESC');
  99 + }
  100 + }
  101 + };
  102 +
91 103 const { setOptions, getInstance } = useECharts(chartRef as Ref<HTMLDivElement>);
92 104
93 105 const [register, method] = useTimePeriodForm({
... ... @@ -158,7 +170,7 @@
158 170 } catch (error) {}
159 171 };
160 172
161   - const openHistoryPanel = async () => {
  173 + const openHistoryPanel = async (orderBy?: string) => {
162 174 await nextTick();
163 175 method.updateSchema({
164 176 field: 'keys',
... ... @@ -177,14 +189,17 @@
177 189
178 190 const keys = props.attr ? props.attr : unref(getDeviceKeys).join();
179 191
180   - const res = await getDeviceHistoryInfo({
181   - entityId: props.deviceDetail.tbDeviceId,
182   - keys,
183   - startTs: Date.now() - 1 * 24 * 60 * 60 * 1000,
184   - endTs: Date.now(),
185   - agg: AggregateDataEnum.NONE,
186   - limit: 7,
187   - });
  192 + const res = await getDeviceHistoryInfo(
  193 + {
  194 + entityId: props.deviceDetail.tbDeviceId,
  195 + keys,
  196 + startTs: Date.now() - 1 * 24 * 60 * 60 * 1000,
  197 + endTs: Date.now(),
  198 + agg: AggregateDataEnum.NONE,
  199 + limit: 7,
  200 + },
  201 + orderBy
  202 + );
188 203 historyData.value = getTableHistoryData(res);
189 204
190 205 // 判断对象是否为空
... ... @@ -238,7 +253,11 @@
238 253 </div>
239 254 <Empty v-show="!isNull && mode === EnumTableChartMode.CHART" />
240 255
241   - <BasicTable v-show="mode === EnumTableChartMode.TABLE" @register="registerTable">
  256 + <BasicTable
  257 + @change="handleTableChange"
  258 + v-show="mode === EnumTableChartMode.TABLE"
  259 + @register="registerTable"
  260 + >
242 261 <template #toolbar>
243 262 <div class="flex h-70px items-center justify-end p-2">
244 263 <ModeSwitchButton
... ...
... ... @@ -136,6 +136,7 @@ export const useGenDynamicForm = () => {
136 136 fieldTypeMap.clear();
137 137 const formSchema = schemas.map((item) => {
138 138 const { functionName, identifier, dataType } = item;
  139 + console.log(item, 'item');
139 140 const { type } = dataType || {};
140 141
141 142 fieldTypeMap.set(identifier!, dataType!.type);
... ...
... ... @@ -72,7 +72,11 @@
72 72 <script lang="ts" setup>
73 73 import { ref, unref, reactive, nextTick } from 'vue';
74 74 import { BasicModal, useModalInner } from '/@/components/Modal';
75   - import { deviceConfigAddOrEdit, deviceConfigGetDetail } from '/@/api/device/deviceConfigApi';
  75 + import {
  76 + deviceConfigAddOrEdit,
  77 + deviceConfigGetDetail,
  78 + deviceConfigGetRuleChain,
  79 + } from '/@/api/device/deviceConfigApi';
76 80 import { useMessage } from '/@/hooks/web/useMessage';
77 81 import { steps } from './device.profile.data';
78 82 import { isEmpty } from '/@/utils/is';
... ... @@ -119,6 +123,12 @@
119 123 unref(DevConStRef)?.editOrAddDeviceTypeStatus(true);
120 124 } else {
121 125 unref(DevConStRef)?.editOrAddDeviceTypeStatus(false);
  126 + const values = ref([]) as any;
  127 + if (!values.value.length) {
  128 + values.value = await deviceConfigGetRuleChain();
  129 + }
  130 + const defaultRuleChainId = unref(values).filter((item) => item.root)[0].id.id;
  131 + await unref(DevConStRef)?.setFieldsdefaultRuleChainId(defaultRuleChainId);
122 132 }
123 133 });
124 134 const handleChange = (e) => {
... ...
... ... @@ -196,7 +196,6 @@ export const step1Schemas: FormSchema[] = [
196 196 label: '规则链',
197 197 component: 'ApiSelect',
198 198 colProps: { span: 14 },
199   -
200 199 componentProps: {
201 200 api: async () => {
202 201 const data = await deviceConfigGetRuleChain();
... ...
... ... @@ -28,7 +28,7 @@
28 28 </div>
29 29 </template>
30 30 <script lang="ts" setup>
31   - import { ref } from 'vue';
  31 + import { ref, nextTick } from 'vue';
32 32 import { BasicForm, useForm } from '/@/components/Form';
33 33 import { step1Schemas } from '../device.profile.data';
34 34 import { uploadApi } from '/@/api/personal/index';
... ... @@ -90,6 +90,12 @@
90 90 }
91 91 return isJpgOrPng && isLt2M;
92 92 };
  93 +
  94 + const setFieldsdefaultRuleChainId = async (id) => {
  95 + await nextTick();
  96 + setFieldsValue({ defaultRuleChainId: id });
  97 + };
  98 +
93 99 async function customSubmitFunc() {
94 100 const values = await validate();
95 101 if (!values) return;
... ... @@ -129,6 +135,7 @@
129 135 resetFormData,
130 136 getFormData,
131 137 editOrAddDeviceTypeStatus,
  138 + setFieldsdefaultRuleChainId,
132 139 });
133 140 </script>
134 141 <style lang="less" scoped>
... ...
  1 +<template>
  2 + <div>属性</div>
  3 +</template>
  4 +
  5 +<script setup lang="ts"></script>
  6 +
  7 +<style lang="less" scoped></style>
... ...
  1 +<template>
  2 + <div>警告</div>
  3 +</template>
  4 +
  5 +<script setup lang="ts"></script>
  6 +
  7 +<style lang="less" scoped></style>
... ...
  1 +import ChainDetailDrawer from './index.vue';
  2 +export { ChainDetailDrawer };
... ...
  1 +<template>
  2 + <BasicDrawer
  3 + v-bind="$attrs"
  4 + isDetail
  5 + @register="register"
  6 + destroyOnClose
  7 + @close="closeDrawer"
  8 + :title="deviceDetail.alias || deviceDetail.name"
  9 + width="80%"
  10 + >
  11 + <Tabs v-model:activeKey="activeKey" :size="size">
  12 + <TabPane key="1" tab="详情">
  13 + <div>详情</div>
  14 + </TabPane>
  15 + <TabPane key="2" tab="属性">
  16 + <Attribute />
  17 + </TabPane>
  18 + <TabPane key="3" tab="最新遥测数据"><div>最新遥测数据</div></TabPane>
  19 + <TabPane key="4" tab="警告">
  20 + <div>警告</div>
  21 + </TabPane>
  22 + <TabPane key="5" tab="事件">
  23 + <div>事件</div>
  24 + </TabPane>
  25 + <!-- 网关设备并且场家是TBox -->
  26 + <TabPane key="6" tab="关联">
  27 + <div>关联</div>
  28 + </TabPane>
  29 + <!-- 网关设备并且是TBox -->
  30 +
  31 + <TabPane key="7" tab="审计日志">
  32 + <div>审计日志</div>
  33 + </TabPane>
  34 + </Tabs>
  35 + </BasicDrawer>
  36 +</template>
  37 +<script lang="ts" setup>
  38 + import { ref } from 'vue';
  39 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  40 +
  41 + import { Tabs, TabPane } from 'ant-design-vue';
  42 + import { DeviceRecord } from '/@/api/device/model/deviceModel';
  43 +
  44 + import Attribute from './component/Attribute.vue';
  45 +
  46 + // defineProps({});
  47 +
  48 + // defineEmits([]);
  49 +
  50 + const activeKey = ref('1');
  51 + const size = ref('small');
  52 + const deviceDetail = ref<DeviceRecord>({} as unknown as DeviceRecord);
  53 + // 详情回显
  54 + const [register] = useDrawerInner(async (data) => {
  55 + console.log(data, 'data');
  56 + });
  57 + const closeDrawer = () => {
  58 + activeKey.value = '1';
  59 + };
  60 +</script>
... ...
... ... @@ -5,7 +5,7 @@
5 5 v-bind="$attrs"
6 6 width="30rem"
7 7 @register="register"
8   - title="添加规则链"
  8 + :title="ruleTile"
9 9 @ok="handleSuccess"
10 10 @close="handleClose"
11 11 >
... ... @@ -17,49 +17,73 @@
17 17 </template>
18 18 <script setup lang="ts">
19 19 import { BasicModal, useModalInner } from '/@/components/Modal';
20   - import { ExecuteReportRecord } from '/@/api/export/model/exportModel';
21 20 import { useForm, BasicForm } from '/@/components/Form';
22 21 import { formSchema } from './config';
23 22 import { createRuleChine } from '/@/api/ruleengine/ruleengineApi';
24 23 import { useMessage } from '/@/hooks/web/useMessage';
  24 + import { ref, unref } from 'vue';
25 25
26 26 const emit = defineEmits(['register', 'success']);
27 27
28 28 const { createMessage } = useMessage();
29 29
30   - const [registerForm, { getFieldsValue, validate }] = useForm({
31   - labelWidth: 120,
  30 + const ruleTile = ref();
  31 +
  32 + const [registerForm, { getFieldsValue, validate, setFieldsValue }] = useForm({
  33 + labelWidth: 70,
32 34 schemas: formSchema,
33 35 showActionButtonGroup: false,
34 36 });
35 37
36   - const [register, { setModalProps, closeModal }] = useModalInner(
37   - async (data: { record: ExecuteReportRecord }) => {
38   - setModalProps({ loading: true });
39   - console.log(data, 'record');
40   - }
41   - );
  38 + const updateValue = ref({});
  39 + const isUpdate = ref<boolean>(true);
  40 +
  41 + const [register, { setModalProps, closeModal }] = useModalInner(async (data) => {
  42 + setModalProps({ loading: true });
  43 + const { text, record } = data || {};
  44 + console.log(data, 'data');
  45 + isUpdate.value = record ? true : false;
  46 + ruleTile.value = text;
  47 + const { name, additionalInfo, debugMode } = record || {};
  48 + const { description } = additionalInfo || {};
  49 + updateValue.value = record;
  50 + unref(isUpdate) && setFieldsValue({ name, debugMode, description });
  51 + setModalProps({ loading: false });
  52 + });
42 53
43 54 const handleClose = () => {
44 55 closeModal();
45 56 };
46 57
47 58 const handleSuccess = async () => {
48   - console.log(1, '1', getFieldsValue());
49 59 await validate();
50 60 const record = getFieldsValue();
51 61 const { description, debugMode, name } = record;
52   - const form = {
53   - additionalInfo: {
54   - description,
55   - },
56   - debugMode,
57   - name,
58   - type: 'CORE',
59   - };
  62 + if (!isUpdate.value) {
  63 + const form = {
  64 + additionalInfo: {
  65 + description,
  66 + },
  67 + debugMode,
  68 + name,
  69 + type: 'CORE',
  70 + };
  71 + await createRuleChine(form);
  72 + createMessage.success('添加成功');
  73 + } else {
  74 + const value = {
  75 + ...updateValue.value,
  76 + additionalInfo: {
  77 + description,
  78 + },
  79 + debugMode,
  80 + name,
  81 + };
  82 + console.log(value, 'value');
  83 + await createRuleChine(value);
  84 + createMessage.success('编辑成功');
  85 + }
60 86
61   - await createRuleChine(form);
62   - createMessage.success('添加成功');
63 87 handleClose();
64 88 emit('success');
65 89 };
... ...
... ... @@ -9,6 +9,7 @@ export const formSchema: FormSchema[] = [
9 9 required: true,
10 10 componentProps: {
11 11 placeholder: '请输入名称',
  12 + max: 120,
12 13 },
13 14 },
14 15 {
... ...
... ... @@ -16,7 +16,7 @@ export const columns: BasicColumn[] = [
16 16 width: 200,
17 17 },
18 18 {
19   - title: '是否链',
  19 + title: '是否链',
20 20 dataIndex: 'root',
21 21 slots: {
22 22 customRender: 'root',
... ... @@ -41,3 +41,20 @@ export const searchFormSchema: FormSchema[] = [
41 41 export const encode = (string: string) => {
42 42 return encodeURIComponent(string);
43 43 };
  44 +
  45 +export const exportJSONFile = (value: Recordable, name: string) => {
  46 + const blob = new Blob([JSON.stringify(value, null, 2)], { type: 'text/json' });
  47 + const objectURL = URL.createObjectURL(blob);
  48 + const element = document.createElement('a');
  49 + element.href = objectURL;
  50 + element.download = `${name}.json`;
  51 + element.style.display = 'none';
  52 + document.body.appendChild(element);
  53 + element.click();
  54 + element.remove();
  55 + URL.revokeObjectURL(objectURL);
  56 +};
  57 +
  58 +export enum RuleChainPermisssion {
  59 + DETAIL = 'rule:chain:detail',
  60 +}
... ...
... ... @@ -5,6 +5,9 @@
5 5 <Authority>
6 6 <a-button type="primary" @click="handleAdd"> 新增规则链 </a-button>
7 7 </Authority>
  8 + <Upload :show-upload-list="false" :customRequest="handleImport">
  9 + <Button type="primary" :loading="importLoading"> 导入规则链 </Button>
  10 + </Upload>
8 11 <!-- <Authority>
9 12 <Popconfirm
10 13 title="您确定要批量删除数据"
... ... @@ -23,10 +26,37 @@
23 26 <TableAction
24 27 :actions="[
25 28 {
26   - label: '查看',
  29 + label: '打开规则链',
27 30 icon: 'ant-design:eye-outlined',
28 31 onClick: handleView.bind(null, record),
29 32 },
  33 + // {
  34 + // label: '详情',
  35 + // icon: 'ant-design:field-time-outlined',
  36 + // onClick: handleDetail.bind(null, record),
  37 + // },
  38 + {
  39 + label: '编辑',
  40 + icon: 'clarity:note-edit-line',
  41 + onClick: handleBussinessModal.bind(null, record),
  42 + },
  43 + ]"
  44 + :dropDownActions="[
  45 + {
  46 + label: '设置为根规则链',
  47 + icon: 'ant-design:gateway-outlined',
  48 + color: 'error',
  49 + ifShow: !record.root,
  50 + popConfirm: {
  51 + title: '是否确认设置成根规则链',
  52 + confirm: handleSettingRoot.bind(null, record),
  53 + },
  54 + },
  55 + {
  56 + label: '导出规则链',
  57 + icon: 'ant-design:vertical-align-bottom-outlined',
  58 + onClick: handleExport.bind(null, record),
  59 + },
30 60 {
31 61 label: '删除',
32 62 icon: 'ant-design:delete-outlined',
... ... @@ -42,24 +72,49 @@
42 72 </template>
43 73 </BasicTable>
44 74 <RuleChainModal @register="registerModal" @success="handleSuccess" />
  75 +
  76 + <!-- <ChainDetailDrawer @register="registerDrawer" /> -->
45 77 </div>
46 78 </template>
47 79 <script lang="ts" setup>
48 80 import { BasicTable, useTable, TableAction } from '/@/components/Table';
49   - import { columns, encode, searchFormSchema } from './config/config.data';
50   - import { deleteRuleChine, getRuleChinsList } from '/@/api/ruleengine/ruleengineApi';
  81 + import {
  82 + RuleChainPermisssion,
  83 + columns,
  84 + encode,
  85 + exportJSONFile,
  86 + searchFormSchema,
  87 + } from './config/config.data';
  88 + import {
  89 + deleteRuleChine,
  90 + getRuleChinsList,
  91 + exportRuleChine,
  92 + settingRootChine,
  93 + importRuleChine,
  94 + createRuleChine,
  95 + } from '/@/api/ruleengine/ruleengineApi';
51 96 import { useModal } from '/@/components/Modal';
52 97 import { Authority } from '/@/components/Authority';
53   - import { Tag } from 'ant-design-vue';
  98 + import { Tag, Button, Upload } from 'ant-design-vue';
54 99 import { RuleChainModal } from './component/index';
55 100 import { useMessage } from '/@/hooks/web/useMessage';
56 101 import { usePermission } from '/@/hooks/web/usePermission';
57 102 import { useRouter } from 'vue-router';
  103 + import { ref } from 'vue';
  104 + import { isObject, isString } from '/@/utils/is';
  105 + // import { ChainDetailDrawer } from './chainDetail/index';
  106 + // import { useDrawer } from '/@/components/Drawer';
58 107
59 108 const [registerTable, { reload, setProps }] = useTable({
60 109 title: '规则链库',
61 110 api: getRuleChinsList,
  111 + rowKey: (record) => record.id.id,
62 112 columns,
  113 + pagination: true,
  114 + useSearchForm: true,
  115 + showTableSetting: true,
  116 + bordered: true,
  117 + showIndexColumn: false,
63 118 formConfig: {
64 119 labelWidth: 120,
65 120 schemas: searchFormSchema,
... ... @@ -68,19 +123,21 @@
68 123 pageField: 'page',
69 124 listField: 'data',
70 125 },
71   - pagination: true,
72   - useSearchForm: true,
73   - showTableSetting: true,
74   - bordered: true,
75   - showIndexColumn: false,
76 126 beforeFetch(params) {
77 127 Reflect.set(params, 'page', params.page - 1);
78 128 Reflect.set(params, 'sortProperty', 'createdTime');
79 129 Reflect.set(params, 'sortOrder', 'DESC');
80 130 return params;
81 131 },
  132 + rowSelection: {
  133 + type: 'checkbox',
  134 + getCheckboxProps: (record: Recordable) => {
  135 + console.log(record, 'record');
  136 + return { disabled: record.root };
  137 + },
  138 + },
82 139 actionColumn: {
83   - width: 200,
  140 + width: 220,
84 141 title: '操作',
85 142 dataIndex: 'action',
86 143 slots: { customRender: 'action' },
... ... @@ -90,12 +147,23 @@
90 147
91 148 const [registerModal, { openModal }] = useModal();
92 149
  150 + // const [registerDrawer, { openDrawer }] = useDrawer();
  151 +
93 152 const handleSuccess = () => {
94 153 reload();
95 154 };
96 155
97 156 const handleAdd = () => {
98   - openModal(true);
  157 + openModal(true, {
  158 + text: '创建规则链',
  159 + });
  160 + };
  161 +
  162 + const handleBussinessModal = (record) => {
  163 + openModal(true, {
  164 + text: '编辑规则链',
  165 + record,
  166 + });
99 167 };
100 168
101 169 const { createMessage } = useMessage();
... ... @@ -103,13 +171,110 @@
103 171 const router = useRouter();
104 172
105 173 const handleView = (record: Recordable) => {
106   - const hasDetailPermission = hasPermission('rule:chain:detail');
  174 + const hasDetailPermission = hasPermission(RuleChainPermisssion.DETAIL);
107 175 if (hasDetailPermission) {
108 176 const boardId = encode(record.id.id);
109 177 router.push(`/rule/chain/${boardId}`);
110 178 } else createMessage.warning('没有权限');
111 179 };
112 180
  181 + // const handleRowClick = (record) => {
  182 + // openDrawer(true, { record });
  183 + // console.log('点击行', record);
  184 + // };
  185 +
  186 + // const handleDetail = (record) => {
  187 + // console.log(record, '详情');
  188 + // };
  189 +
  190 + const paseJSON = (string: string) => {
  191 + let data = null;
  192 + let flag = false;
  193 + try {
  194 + if (!isString(string)) return { flag: false, data };
  195 + data = JSON.parse(string);
  196 + flag = true;
  197 + if (!isObject(data)) flag = false;
  198 + } catch (error) {}
  199 + return { flag, data };
  200 + };
  201 +
  202 + const isEmptyObject = (value: any) => isObject(value) && !Object.keys(value).length;
  203 +
  204 + const importLoading = ref<boolean>(false);
  205 + const handleImport = (data: { file: File }) => {
  206 + const fileReader = new FileReader();
  207 +
  208 + fileReader.onload = async () => {
  209 + const { flag, data } = paseJSON(fileReader.result as string);
  210 + if (!flag) {
  211 + createMessage.warning('JSON解析失败,请导入正确的JSON~');
  212 + return;
  213 + }
  214 + try {
  215 + importLoading.value = true;
  216 +
  217 + Object.keys(data || {}).forEach((key) => {
  218 + const value = (data || {})[key];
  219 + if (value && isEmptyObject(value)) {
  220 + (data || {})[key] = [];
  221 + }
  222 + });
  223 + const { ruleChain, metadata } = data as any;
  224 +
  225 + const value = await createRuleChine(ruleChain);
  226 + const { id } = value;
  227 +
  228 + const values = {
  229 + ruleChainId: id,
  230 + ...metadata,
  231 + };
  232 + const rules = await importRuleChine(values);
  233 +
  234 + rules
  235 + ? createMessage.success('导入成功~')
  236 + : createMessage.error('JSON解析失败,请导入正确的JSON~');
  237 +
  238 + rules && reload();
  239 + } catch (error) {
  240 + throw error;
  241 + } finally {
  242 + importLoading.value = false;
  243 + }
  244 + };
  245 +
  246 + fileReader.readAsText(data.file, 'utf-8');
  247 + };
  248 +
  249 + const handleExport = async (record: Recordable) => {
  250 + if (!record) return;
  251 + const { additionalInfo, name, type, firstRuleNodeId, root, debugMode, configuration } =
  252 + record || {};
  253 + const { firstNodeIndex, nodes, connections, ruleChainConnections } = await exportRuleChine(
  254 + record.id.id
  255 + );
  256 + const value = {
  257 + ruleChain: { additionalInfo, name, type, firstRuleNodeId, root, debugMode, configuration },
  258 + metadata: { firstNodeIndex, nodes, connections, ruleChainConnections },
  259 + };
  260 + exportJSONFile(value, name);
  261 + };
  262 +
  263 + const handleSettingRoot = async (record) => {
  264 + setProps({
  265 + loading: true,
  266 + });
  267 + try {
  268 + await settingRootChine(record.id.id);
  269 + createMessage.success('设置成功');
  270 + } finally {
  271 + setProps({
  272 + loading: false,
  273 + });
  274 + }
  275 + reload();
  276 + };
  277 +
113 278 const handleDeleteOrBatchDelete = async (record: Recordable) => {
114 279 setProps({
115 280 loading: true,
... ...