Browse Source

Merge pull request #823 from colinin/fix-lost-changes

fix: restore lost changes
pull/830/head
yx lin 3 years ago
committed by GitHub
parent
commit
af44c36a25
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 73
      apps/vue/src/components/Excel/src/Export2Excel.ts
  2. 14
      apps/vue/src/components/Excel/src/typing.ts
  3. 4
      apps/vue/src/components/Form/src/components/ApiSelect.vue
  4. 3
      apps/vue/src/components/Form/src/components/ApiTransfer.vue
  5. 88
      apps/vue/src/components/Form/src/hooks/useFormEvents.ts
  6. 2
      apps/vue/src/components/Form/src/types/form.ts
  7. 63
      apps/vue/src/components/FormDesign/src/components/VFormDesign/modules/CollapseItem.vue
  8. 1
      apps/vue/src/components/Modal/src/BasicModal.vue
  9. 8
      apps/vue/src/components/Table/src/BasicTable.vue
  10. 41
      apps/vue/src/components/Table/src/components/AdvancedSearch.vue
  11. 4
      apps/vue/src/components/Table/src/components/settings/ColumnSetting.vue
  12. 2
      apps/vue/src/components/Table/src/hooks/useTableForm.ts
  13. 8
      apps/vue/src/components/Tree/src/hooks/useTree.ts
  14. 2
      apps/vue/src/components/Upload/src/helper.ts
  15. 33
      apps/vue/src/hooks/web/useECharts.ts
  16. 6
      apps/vue/src/hooks/web/useWatermark.ts
  17. 2
      apps/vue/src/layouts/default/setting/components/SettingFooter.vue
  18. 16
      apps/vue/src/store/modules/app.ts
  19. 8
      apps/vue/src/store/modules/errorLog.ts
  20. 8
      apps/vue/src/store/modules/locale.ts
  21. 4
      apps/vue/src/store/modules/lock.ts
  22. 12
      apps/vue/src/store/modules/multipleTab.ts
  23. 20
      apps/vue/src/store/modules/permission.ts
  24. 24
      apps/vue/src/store/modules/user.ts
  25. 68
      apps/vue/src/views/webhooks/send-attempts/components/SendAttemptModal.vue
  26. 14
      apps/vue/src/views/webhooks/send-attempts/components/SendAttemptTable.vue
  27. 19
      apps/vue/src/views/webhooks/subscriptions/components/SubscriptionModal.vue
  28. 17
      apps/vue/src/views/webhooks/subscriptions/components/SubscriptionTable.vue

73
apps/vue/src/components/Excel/src/Export2Excel.ts

@ -1,17 +1,19 @@
import * as xlsx from 'xlsx'; import * as xlsx from 'xlsx';
import type { WorkBook } from 'xlsx'; import type { WorkBook } from 'xlsx';
import type { JsonToSheet, AoAToSheet } from './typing'; import type { JsonToSheet, AoAToSheet } from './typing';
import { AoaToMultipleSheet, JsonToMultipleSheet } from './typing';
const { utils, writeFile } = xlsx; const { utils, writeFile } = xlsx;
const DEF_FILE_NAME = 'excel-list.xlsx'; const DEF_FILE_NAME = 'excel-list.xlsx';
const DEF_SHEET_NAME = 'sheet';
/** /**
* @param data source data * @param data source data
* @param worksheet worksheet object * @param worksheet worksheet object
* @param min min width * @param min min width
*/ */
function setColumnWidth(data, worksheet, min = 3) { function setColumnWidth(data, worksheet, min = 3) {
const obj = {}; const obj = {};
worksheet['!cols'] = []; worksheet['!cols'] = [];
data.forEach((item) => { data.forEach((item) => {
@ -32,6 +34,7 @@ export function jsonToSheetXlsx<T = any>({
data, data,
header, header,
filename = DEF_FILE_NAME, filename = DEF_FILE_NAME,
sheetName = DEF_SHEET_NAME,
json2sheetOpts = {}, json2sheetOpts = {},
write2excelOpts = { bookType: 'xlsx' }, write2excelOpts = { bookType: 'xlsx' },
}: JsonToSheet<T>) { }: JsonToSheet<T>) {
@ -45,9 +48,9 @@ export function jsonToSheetXlsx<T = any>({
setColumnWidth(arrData, worksheet); setColumnWidth(arrData, worksheet);
/* add worksheet to workbook */ /* add worksheet to workbook */
const workbook: WorkBook = { const workbook: WorkBook = {
SheetNames: [filename], SheetNames: [sheetName],
Sheets: { Sheets: {
[filename]: worksheet, [sheetName]: worksheet,
}, },
}; };
/* output format determined by filename */ /* output format determined by filename */
@ -79,3 +82,67 @@ export function aoaToSheetXlsx<T = any>({
writeFile(workbook, filename, write2excelOpts); writeFile(workbook, filename, write2excelOpts);
/* at this point, out.xlsb will have been downloaded */ /* at this point, out.xlsb will have been downloaded */
} }
/**
* json导出多Sheet的Xlsx
* @param sheetList sheet配置
* @param filename ()
* @param write2excelOpts
*/
export function jsonToMultipleSheetXlsx<T = any>({
sheetList,
filename = DEF_FILE_NAME,
write2excelOpts = { bookType: 'xlsx' },
}: JsonToMultipleSheet<T>) {
const workbook: WorkBook = {
SheetNames: [],
Sheets: {},
};
sheetList.forEach((p, index) => {
const arrData = [...p.data];
if (p.header) {
arrData.unshift(p.header);
p.json2sheetOpts = p.json2sheetOpts || {};
p.json2sheetOpts.skipHeader = true;
}
const worksheet = utils.json_to_sheet(arrData, p.json2sheetOpts);
setColumnWidth(arrData, worksheet);
p.sheetName = p.sheetName || `${DEF_SHEET_NAME}${index}`;
workbook.SheetNames.push(p.sheetName);
workbook.Sheets[p.sheetName] = worksheet;
});
writeFile(workbook, filename, write2excelOpts);
}
/**
* aoa导出多Sheet的Xlsx
* @param sheetList sheet配置
* @param filename ()
* @param write2excelOpts
*/
export function aoaToMultipleSheetXlsx<T = any>({
sheetList,
filename = DEF_FILE_NAME,
write2excelOpts = { bookType: 'xlsx' },
}: AoaToMultipleSheet<T>) {
const workbook: WorkBook = {
SheetNames: [],
Sheets: {},
};
sheetList.forEach((p, index) => {
const arrData = [...p.data];
if (p.header) {
arrData.unshift(p.header);
}
const worksheet = utils.aoa_to_sheet(arrData);
p.sheetName = p.sheetName || `${DEF_SHEET_NAME}${index}`;
workbook.SheetNames.push(p.sheetName);
workbook.Sheets[p.sheetName] = worksheet;
});
/* output format determined by filename */
writeFile(workbook, filename, write2excelOpts);
/* at this point, out.xlsb will have been downloaded */
}

14
apps/vue/src/components/Excel/src/typing.ts

@ -10,6 +10,7 @@ export interface JsonToSheet<T = any> {
data: T[]; data: T[];
header?: T; header?: T;
filename?: string; filename?: string;
sheetName?: string;
json2sheetOpts?: JSON2SheetOpts; json2sheetOpts?: JSON2SheetOpts;
write2excelOpts?: WritingOptions; write2excelOpts?: WritingOptions;
} }
@ -18,6 +19,7 @@ export interface AoAToSheet<T = any> {
data: T[][]; data: T[][];
header?: T[]; header?: T[];
filename?: string; filename?: string;
sheetName?: string;
write2excelOpts?: WritingOptions; write2excelOpts?: WritingOptions;
} }
@ -25,3 +27,15 @@ export interface ExportModalResult {
filename: string; filename: string;
bookType: BookType; bookType: BookType;
} }
export interface JsonToMultipleSheet<T = any> {
sheetList: JsonToSheet<T>[];
filename?: string;
write2excelOpts?: WritingOptions;
}
export interface AoaToMultipleSheet<T = any> {
sheetList: AoAToSheet<T>[];
filename?: string;
write2excelOpts?: WritingOptions;
}

4
apps/vue/src/components/Form/src/components/ApiSelect.vue

@ -76,10 +76,10 @@
return unref(options).reduce((prev, next: Recordable) => { return unref(options).reduce((prev, next: Recordable) => {
if (next) { if (next) {
const value = next[valueField]; const value = get(next, valueField);
prev.push({ prev.push({
...omit(next, [labelField, valueField]), ...omit(next, [labelField, valueField]),
label: next[labelField], label: get(next, labelField),
value: numberToString ? `${value}` : value, value: numberToString ? `${value}` : value,
}); });
} }

3
apps/vue/src/components/Form/src/components/ApiTransfer.vue

@ -76,6 +76,9 @@
if (Array.isArray(props.value)) { if (Array.isArray(props.value)) {
return props.value; return props.value;
} }
if (Array.isArray(props.targetKeys)){
return props.targetKeys;
}
return []; return [];
}); });
function handleChange(keys: string[], direction: TransferDirection, moveKeys: string[]) { function handleChange(keys: string[], direction: TransferDirection, moveKeys: string[]) {

88
apps/vue/src/components/Form/src/hooks/useFormEvents.ts

@ -14,7 +14,7 @@ import {
import { deepMerge } from '/@/utils'; import { deepMerge } from '/@/utils';
import { dateItemType, handleInputNumberValue, defaultValueComponents } from '../helper'; import { dateItemType, handleInputNumberValue, defaultValueComponents } from '../helper';
import { dateUtil } from '/@/utils/dateUtil'; import { dateUtil } from '/@/utils/dateUtil';
import { cloneDeep, uniqBy } from 'lodash-es'; import { cloneDeep, set, uniqBy } from 'lodash-es';
import { error } from '/@/utils/log'; import { error } from '/@/utils/log';
interface UseFormActionContext { interface UseFormActionContext {
@ -27,6 +27,47 @@ interface UseFormActionContext {
schemaRef: Ref<FormSchema[]>; schemaRef: Ref<FormSchema[]>;
handleFormValues: Fn; handleFormValues: Fn;
} }
function tryConstructArray(field: string, values: Recordable = {}): any[] | undefined {
const pattern = /^\[(.+)\]$/;
if (pattern.test(field)) {
const match = field.match(pattern);
if (match && match[1]) {
const keys = match[1].split(',');
if (!keys.length) {
return undefined;
}
const result = [];
keys.forEach((k, index) => {
set(result, index, values[k.trim()]);
});
return result.length ? result : undefined;
}
}
}
function tryConstructObject(field: string, values: Recordable = {}): Recordable | undefined {
const pattern = /^\{(.+)\}$/;
if (pattern.test(field)) {
const match = field.match(pattern);
if (match && match[1]) {
const keys = match[1].split(',');
if (!keys.length) {
return;
}
const result = {};
keys.forEach((k) => {
set(result, k.trim(), values[k.trim()]);
});
return Object.values(result).filter(Boolean).length ? result : undefined;
}
}
}
export function useFormEvents({ export function useFormEvents({
emit, emit,
getProps, getProps,
@ -67,51 +108,61 @@ export function useFormEvents({
// key 支持 a.b.c 的嵌套写法 // key 支持 a.b.c 的嵌套写法
const delimiter = '.'; const delimiter = '.';
const nestKeyArray = fields.filter((item) => item.indexOf(delimiter) >= 0); const nestKeyArray = fields.filter((item) => String(item).indexOf(delimiter) >= 0);
const validKeys: string[] = []; const validKeys: string[] = [];
Object.keys(values).forEach((key) => { fields.forEach((key) => {
const schema = unref(getSchema).find((item) => item.field === key); const schema = unref(getSchema).find((item) => item.field === key);
let value = values[key]; let value = values[key];
const hasKey = Reflect.has(values, key); const hasKey = Reflect.has(values, key);
value = handleInputNumberValue(schema?.component, value); value = handleInputNumberValue(schema?.component, value);
const { componentProps } = schema || {};
let _props = componentProps as any;
if (typeof componentProps === 'function') {
_props = _props({ formModel: unref(formModel) });
}
const constructValue = tryConstructArray(key, values) || tryConstructObject(key, values);
// 0| '' is allow // 0| '' is allow
if (hasKey && fields.includes(key)) { if (hasKey || !!constructValue) {
const fieldValue = constructValue || value;
// time type // time type
if (itemIsDateType(key)) { if (itemIsDateType(key)) {
if (Array.isArray(value)) { if (Array.isArray(fieldValue)) {
const arr: any[] = []; const arr: any[] = [];
for (const ele of value) { for (const ele of fieldValue) {
arr.push(ele ? dateUtil(ele) : null); arr.push(ele ? dateUtil(ele) : null);
} }
formModel[key] = arr; unref(formModel)[key] = arr;
} else { } else {
const { componentProps } = schema || {}; unref(formModel)[key] = fieldValue
let _props = componentProps as any; ? _props?.valueFormat
if (typeof componentProps === 'function') { ? fieldValue
_props = _props({ formModel }); : dateUtil(fieldValue)
} : null;
formModel[key] = value ? (_props?.valueFormat ? value : dateUtil(value)) : null;
} }
} else { } else {
formModel[key] = value; unref(formModel)[key] = fieldValue;
} }
// if (_props?.onChange) {
// _props?.onChange(fieldValue);
// }
validKeys.push(key); validKeys.push(key);
} else { } else {
nestKeyArray.forEach((nestKey: string) => { nestKeyArray.forEach((nestKey: string) => {
try { try {
const value = nestKey.split('.').reduce((out, item) => out[item], values); const value = nestKey.split('.').reduce((out, item) => out[item], values);
if (isDef(value)) { if (isDef(value)) {
formModel[nestKey] = value; unref(formModel)[nestKey] = unref(value);
validKeys.push(nestKey); validKeys.push(nestKey);
} }
} catch (e) { } catch (e) {
// key not exist // key not exist
if (isDef(defaultValueRef.value[nestKey])) { if (isDef(defaultValueRef.value[nestKey])) {
//formModel[nestKey] = defaultValueRef.value[nestKey]; unref(formModel)[nestKey] = cloneDeep(unref(defaultValueRef.value[nestKey]));
formModel[nestKey] = cloneDeep(defaultValueRef.value[nestKey]);
} }
} }
}); });
@ -313,6 +364,9 @@ export function useFormEvents({
const res = handleFormValues(values); const res = handleFormValues(values);
emit('submit', res); emit('submit', res);
} catch (error: any) { } catch (error: any) {
if (error?.outOfDate === false && error?.errorFields) {
return;
}
throw new Error(error); throw new Error(error);
} }
} }

2
apps/vue/src/components/Form/src/types/form.ts

@ -26,7 +26,7 @@ export interface ButtonProps extends AntdButtonProps {
export interface FormActionType { export interface FormActionType {
submit: () => Promise<void>; submit: () => Promise<void>;
setFieldsValue: <T>(values: T) => Promise<void>; setFieldsValue: (values: Recordable) => Promise<void>;
resetFields: () => Promise<void>; resetFields: () => Promise<void>;
getFieldsValue: () => Recordable; getFieldsValue: () => Recordable;
clearValidate: (name?: string | string[]) => Promise<void>; clearValidate: (name?: string | string[]) => Promise<void>;

63
apps/vue/src/components/FormDesign/src/components/VFormDesign/modules/CollapseItem.vue

@ -1,5 +1,5 @@
<template> <template>
<div> <div :class="prefixCls">
<draggable <draggable
tag="ul" tag="ul"
:model-value="list" :model-value="list"
@ -36,6 +36,7 @@
import draggable from 'vuedraggable'; import draggable from 'vuedraggable';
// import { toRefs } from '@vueuse/core'; // import { toRefs } from '@vueuse/core';
import { Icon } from '/@/components/Icon'; import { Icon } from '/@/components/Icon';
import { useDesign } from '/@/hooks/web/useDesign';
export default defineComponent({ export default defineComponent({
name: 'CollapseItem', name: 'CollapseItem',
components: { draggable, Icon }, components: { draggable, Icon },
@ -50,6 +51,7 @@
}, },
}, },
setup(props, { emit }) { setup(props, { emit }) {
const { prefixCls } = useDesign('form-design-collapse-item');
const state = reactive({}); const state = reactive({});
const handleStart = (e: any, list1: IVFormComponent[]) => { const handleStart = (e: any, list1: IVFormComponent[]) => {
emit('start', list1[e.oldIndex].component); emit('start', list1[e.oldIndex].component);
@ -62,40 +64,45 @@
const cloneItem = (one) => { const cloneItem = (one) => {
return props.handleListPush(one); return props.handleListPush(one);
}; };
return { state, handleStart, handleAdd, cloneItem }; return { prefixCls, state, handleStart, handleAdd, cloneItem };
}, },
}); });
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@prefix-cls: ~'@{namespace}-form-design-collapse-item';
@import url(../styles/variable.less); @import url(../styles/variable.less);
ul { .@{prefix-cls} {
padding: 5px; ul {
list-style: none; padding: 5px;
display: flex; list-style: none;
margin-bottom: 0; display: flex;
flex-wrap: wrap; margin-bottom: 0;
// background: #efefef; flex-wrap: wrap;
li { // background: #efefef;
padding: 8px 12px; li {
transition: all 0.3s; padding: 8px 12px;
width: calc(50% - 6px); transition: all 0.3s;
margin: 2.7px; width: calc(50% - 6px);
height: 36px; margin: 2.7px;
line-height: 20px; height: 36px;
cursor: move; line-height: 20px;
border: 1px solid @border-color; cursor: move;
border-radius: 3px; border: 1px solid @border-color;
&:hover { border-radius: 3px;
color: @primary-color;
border: 1px solid @primary-color; &:hover {
position: relative; color: @primary-color;
// z-index: 1; border: 1px solid @primary-color;
box-shadow: 0 2px 6px @primary-color; position: relative;
// z-index: 1;
box-shadow: 0 2px 6px @primary-color;
}
} }
} }
}
svg { svg {
display: inline !important; display: inline !important;
}
} }
</style> </style>

1
apps/vue/src/components/Modal/src/BasicModal.vue

@ -141,6 +141,7 @@
visible: unref(visibleRef), visible: unref(visibleRef),
wrapClassName: unref(getWrapClassName), wrapClassName: unref(getWrapClassName),
}; };
attr['wrapClassName'] = `${attr?.['wrapClassName'] || ''} ${unref(getWrapClassName)}`;
if (unref(fullScreenRef)) { if (unref(fullScreenRef)) {
return omit(attr, ['height', 'title']); return omit(attr, ['height', 'title']);
} }

8
apps/vue/src/components/Table/src/BasicTable.vue

@ -97,7 +97,7 @@
import { warn } from '/@/utils/log'; import { warn } from '/@/utils/log';
export default defineComponent({ export default defineComponent({
name:'BasicTable', name: 'BasicTable',
components: { components: {
Table, Table,
BasicForm, BasicForm,
@ -454,8 +454,10 @@
margin-bottom: 16px; margin-bottom: 16px;
} }
.ant-tag { .ant-table-cell {
margin-right: 0; .ant-tag {
margin-right: 0;
}
} }
.ant-table-wrapper { .ant-table-wrapper {

41
apps/vue/src/components/Table/src/components/AdvancedSearch.vue

@ -24,9 +24,8 @@
style="width: 100%;" style="width: 100%;"
show-search show-search
v-model:value="record.field" v-model:value="record.field"
:options="getAvailableParams" :options="getAvailableOptions"
:filter-option="filterOption" :filter-option="filterOption"
:field-names="{ label: 'description', value: 'name' }"
@change="(field) => handleFieldChange(field, record)" @change="(field) => handleFieldChange(field, record)"
/> />
</template> </template>
@ -43,13 +42,13 @@
v-else-if="record.javaScriptType==='number' && record.options && record.options.length > 0" v-else-if="record.javaScriptType==='number' && record.options && record.options.length > 0"
style="width: 100%;" style="width: 100%;"
v-model:value="record.value" v-model:value="record.value"
:options="getAvailableOptions" :options="record.options"
/> :field-names="{
<InputNumber label: 'key',
v-else-if="record.javaScriptType==='number'" value: 'value'
style="width: 100%;" }"
v-model:value="record.value"
/> />
<InputNumber v-else-if="record.javaScriptType==='number'" style="width: 100%;" v-model:value="record.value" />
<Switch v-else-if="record.javaScriptType==='boolean'" v-model:checked="record.value" /> <Switch v-else-if="record.javaScriptType==='boolean'" v-model:checked="record.value" />
<DatePicker <DatePicker
v-else-if="record.javaScriptType==='Date'" v-else-if="record.javaScriptType==='Date'"
@ -250,6 +249,19 @@
return defineParams.filter(dp => !formMdel.paramters.some(fp => fp.field === dp.name)); return defineParams.filter(dp => !formMdel.paramters.some(fp => fp.field === dp.name));
}); });
const getAvailableOptions = computed(() => {
const availableParams = unref(getAvailableParams);
if (!availableParams.length) return[];
return availableParams
.map((item) => {
return {
label: item.description,
value: item.name,
children: [],
}
});
});
const getAvailableComparisonOptions = computed(() => { const getAvailableComparisonOptions = computed(() => {
return (paramter: DynamicParamter) => { return (paramter: DynamicParamter) => {
const defineParams = unref(defineParamsRef); const defineParams = unref(defineParamsRef);
@ -266,18 +278,6 @@
.filter(c => availableComparator.includes(c.value)); .filter(c => availableComparator.includes(c.value));
} }
}); });
const getAvailableOptions = computed(() => {
const availableParams = unref(getAvailableParams);
if (!availableParams.length) return[];
return availableParams
.map((item) => {
return {
label: item.description,
value: item.name,
children: [],
}
});
});
const filterOption = (input: string, option: any) => { const filterOption = (input: string, option: any) => {
return option.description.toLowerCase().indexOf(input.toLowerCase()) >= 0; return option.description.toLowerCase().indexOf(input.toLowerCase()) >= 0;
@ -300,6 +300,7 @@
const isArrayResult = Array.isArray(res); const isArrayResult = Array.isArray(res);
resultItems = isArrayResult ? res : get(res, listField || 'items'); resultItems = isArrayResult ? res : get(res, listField || 'items');
} }
console.log(resultItems);
defineParamsRef.value = resultItems; defineParamsRef.value = resultItems;
}).finally(() => { }).finally(() => {
setLoading(false); setLoading(false);

4
apps/vue/src/components/Table/src/components/settings/ColumnSetting.vue

@ -350,7 +350,9 @@
function handleColumnFixed(item: BasicColumn, fixed?: 'left' | 'right') { function handleColumnFixed(item: BasicColumn, fixed?: 'left' | 'right') {
if (!state.checkedList.includes(item.dataIndex as string)) return; if (!state.checkedList.includes(item.dataIndex as string)) return;
const columns = getColumns() as BasicColumn[]; const columns = getColumns().filter((c: BasicColumn) =>
state.checkedList.includes(c.dataIndex as string),
) as BasicColumn[];
const isFixed = item.fixed === fixed ? false : fixed; const isFixed = item.fixed === fixed ? false : fixed;
const index = columns.findIndex((col) => col.dataIndex === item.dataIndex); const index = columns.findIndex((col) => col.dataIndex === item.dataIndex);
if (index !== -1) { if (index !== -1) {

2
apps/vue/src/components/Table/src/hooks/useTableForm.ts

@ -11,7 +11,7 @@ export function useTableForm(
slots: Slots, slots: Slots,
fetch: (opt?: FetchParams | undefined) => Promise<void>, fetch: (opt?: FetchParams | undefined) => Promise<void>,
getLoading: ComputedRef<boolean | undefined>, getLoading: ComputedRef<boolean | undefined>,
setFieldsValue: <T>(values: T) => Promise<void>, setFieldsValue: (values: Recordable) => Promise<void>,
) { ) {
const getFormProps = computed((): Partial<FormProps> => { const getFormProps = computed((): Partial<FormProps> => {
const { formConfig, advancedSearchConfig } = unref(propsRef); const { formConfig, advancedSearchConfig } = unref(propsRef);

8
apps/vue/src/components/Tree/src/hooks/useTree.ts

@ -181,14 +181,16 @@ export function useTree(treeDataRef: Ref<TreeDataItem[]>, getFieldNames: Compute
function getSelectedNode(key: KeyType, list?: TreeItem[], selectedNode?: TreeItem | null) { function getSelectedNode(key: KeyType, list?: TreeItem[], selectedNode?: TreeItem | null) {
if (!key && key !== 0) return null; if (!key && key !== 0) return null;
const treeData = list || unref(treeDataRef); const treeData = list || unref(treeDataRef);
const { key: keyField, children: childrenField } = unref(getFieldNames);
if (!keyField) return;
treeData.forEach((item) => { treeData.forEach((item) => {
if (selectedNode?.key || selectedNode?.key === 0) return selectedNode; if (selectedNode?.key || selectedNode?.key === 0) return selectedNode;
if (item.key === key) { if (item[keyField] === key) {
selectedNode = item; selectedNode = item;
return; return;
} }
if (item.children && item.children.length) { if (item[childrenField!] && item[childrenField!].length) {
selectedNode = getSelectedNode(key, item.children, selectedNode); selectedNode = getSelectedNode(key, item[childrenField!], selectedNode);
} }
}); });
return selectedNode || null; return selectedNode || null;

2
apps/vue/src/components/Upload/src/helper.ts

@ -11,7 +11,7 @@ export function checkImgType(file: File) {
} }
export function isImgTypeByName(name: string) { export function isImgTypeByName(name: string) {
return /\.(jpg|jpeg|png|gif)$/i.test(name); return /\.(jpg|jpeg|png|gif|webp)$/i.test(name);
} }
export function getBase64WithFile(file: File) { export function getBase64WithFile(file: File) {

33
apps/vue/src/hooks/web/useECharts.ts

@ -60,23 +60,26 @@ export function useECharts(
function setOptions(options: EChartsOption, clear = true) { function setOptions(options: EChartsOption, clear = true) {
cacheOptions.value = options; cacheOptions.value = options;
if (unref(elRef)?.offsetHeight === 0) { return new Promise((resolve) => {
useTimeoutFn(() => { if (unref(elRef)?.offsetHeight === 0) {
setOptions(unref(getOptions)); useTimeoutFn(() => {
}, 30); setOptions(unref(getOptions));
return; resolve(null);
} }, 30);
nextTick(() => { }
useTimeoutFn(() => { nextTick(() => {
if (!chartInstance) { useTimeoutFn(() => {
initCharts(getDarkMode.value as 'default'); if (!chartInstance) {
initCharts(getDarkMode.value as 'default');
if (!chartInstance) return; if (!chartInstance) return;
} }
clear && chartInstance?.clear(); clear && chartInstance?.clear();
chartInstance?.setOption(unref(getOptions)); chartInstance?.setOption(unref(getOptions));
}, 30); resolve(null);
}, 30);
});
}); });
} }

6
apps/vue/src/hooks/web/useWatermark.ts

@ -4,10 +4,15 @@ import { addResizeListener, removeResizeListener } from '/@/utils/event';
import { isDef } from '/@/utils/is'; import { isDef } from '/@/utils/is';
const domSymbol = Symbol('watermark-dom'); const domSymbol = Symbol('watermark-dom');
const sourceMap = new WeakMap<HTMLElement, {}>();
export function useWatermark( export function useWatermark(
appendEl: Ref<HTMLElement | null> = ref(document.body) as Ref<HTMLElement>, appendEl: Ref<HTMLElement | null> = ref(document.body) as Ref<HTMLElement>,
) { ) {
const appendElRaw = unref(appendEl);
if (appendElRaw && sourceMap.has(appendElRaw)) {
return sourceMap.get(appendElRaw);
}
const func = useRafThrottle(function () { const func = useRafThrottle(function () {
const el = unref(appendEl); const el = unref(appendEl);
if (!el) return; if (!el) return;
@ -82,6 +87,7 @@ export function useWatermark(
const { clientHeight: height, clientWidth: width } = el; const { clientHeight: height, clientWidth: width } = el;
updateWatermark({ str, width, height }); updateWatermark({ str, width, height });
el.appendChild(div); el.appendChild(div);
sourceMap.set(el, { setWatermark, clear });
return id; return id;
}; };

2
apps/vue/src/layouts/default/setting/components/SettingFooter.vue

@ -38,6 +38,7 @@
import { updateColorWeak } from '/@/logics/theme/updateColorWeak'; import { updateColorWeak } from '/@/logics/theme/updateColorWeak';
import { updateGrayMode } from '/@/logics/theme/updateGrayMode'; import { updateGrayMode } from '/@/logics/theme/updateGrayMode';
import { updateSidebarBgColor } from '/@/logics/theme/updateBackground';
import { changeTheme } from '/@/logics/theme'; import { changeTheme } from '/@/logics/theme';
import defaultSetting from '/@/settings/projectSetting'; import defaultSetting from '/@/settings/projectSetting';
@ -72,6 +73,7 @@
appStore.setProjectConfig(defaultSetting); appStore.setProjectConfig(defaultSetting);
const { colorWeak, grayMode, themeColor } = defaultSetting; const { colorWeak, grayMode, themeColor } = defaultSetting;
changeTheme(themeColor); changeTheme(themeColor);
updateSidebarBgColor();
updateColorWeak(colorWeak); updateColorWeak(colorWeak);
updateGrayMode(grayMode); updateGrayMode(grayMode);
createMessage.success(t('layout.setting.resetSuccess')); createMessage.success(t('layout.setting.resetSuccess'));

16
apps/vue/src/store/modules/app.ts

@ -38,19 +38,19 @@ export const useAppStore = defineStore({
beforeMiniInfo: {}, beforeMiniInfo: {},
}), }),
getters: { getters: {
getPageLoading(): boolean { getPageLoading(state): boolean {
return this.pageLoading; return state.pageLoading;
}, },
getDarkMode(): 'light' | 'dark' | string { getDarkMode(state): 'light' | 'dark' | string {
return this.darkMode || localStorage.getItem(APP_DARK_MODE_KEY_) || darkMode; return state.darkMode || localStorage.getItem(APP_DARK_MODE_KEY_) || darkMode;
}, },
getBeforeMiniInfo(): BeforeMiniState { getBeforeMiniInfo(state): BeforeMiniState {
return this.beforeMiniInfo; return state.beforeMiniInfo;
}, },
getProjectConfig(): ProjectConfig { getProjectConfig(state): ProjectConfig {
return this.projectConfig || ({} as ProjectConfig); return state.projectConfig || ({} as ProjectConfig);
}, },
getHeaderSetting(): HeaderSetting { getHeaderSetting(): HeaderSetting {

8
apps/vue/src/store/modules/errorLog.ts

@ -20,11 +20,11 @@ export const useErrorLogStore = defineStore({
errorLogListCount: 0, errorLogListCount: 0,
}), }),
getters: { getters: {
getErrorLogInfoList(): ErrorLogInfo[] { getErrorLogInfoList(state): ErrorLogInfo[] {
return this.errorLogInfoList || []; return state.errorLogInfoList || [];
}, },
getErrorLogListCount(): number { getErrorLogListCount(state): number {
return this.errorLogListCount; return state.errorLogListCount;
}, },
}, },
actions: { actions: {

8
apps/vue/src/store/modules/locale.ts

@ -21,11 +21,11 @@ export const useLocaleStore = defineStore({
localInfo: lsLocaleSetting, localInfo: lsLocaleSetting,
}), }),
getters: { getters: {
getShowPicker(): boolean { getShowPicker(state): boolean {
return !!this.localInfo?.showPicker; return !!state.localInfo?.showPicker;
}, },
getLocale(): LocaleType { getLocale(state): LocaleType {
return this.localInfo?.locale ?? 'zh_CN'; return state.localInfo?.locale ?? 'zh_CN';
}, },
}, },
actions: { actions: {

4
apps/vue/src/store/modules/lock.ts

@ -16,8 +16,8 @@ export const useLockStore = defineStore({
lockInfo: Persistent.getLocal(LOCK_INFO_KEY), lockInfo: Persistent.getLocal(LOCK_INFO_KEY),
}), }),
getters: { getters: {
getLockInfo(): Nullable<LockInfo> { getLockInfo(state): Nullable<LockInfo> {
return this.lockInfo; return state.lockInfo;
}, },
}, },
actions: { actions: {

12
apps/vue/src/store/modules/multipleTab.ts

@ -48,14 +48,14 @@ export const useMultipleTabStore = defineStore({
lastDragEndIndex: 0, lastDragEndIndex: 0,
}), }),
getters: { getters: {
getTabList(): RouteLocationNormalized[] { getTabList(state): RouteLocationNormalized[] {
return this.tabList; return state.tabList;
}, },
getCachedTabList(): string[] { getCachedTabList(state): string[] {
return Array.from(this.cacheTabList); return Array.from(state.cacheTabList);
}, },
getLastDragEndIndex(): number { getLastDragEndIndex(state): number {
return this.lastDragEndIndex; return state.lastDragEndIndex;
}, },
}, },
actions: { actions: {

20
apps/vue/src/store/modules/permission.ts

@ -50,20 +50,20 @@ export const usePermissionStore = defineStore({
frontMenuList: [], frontMenuList: [],
}), }),
getters: { getters: {
getPermCodeList(): string[] | number[] { getPermCodeList(state): string[] | number[] {
return this.permCodeList; return state.permCodeList;
}, },
getBackMenuList(): Menu[] { getBackMenuList(state): Menu[] {
return this.backMenuList; return state.backMenuList;
}, },
getFrontMenuList(): Menu[] { getFrontMenuList(state): Menu[] {
return this.frontMenuList; return state.frontMenuList;
}, },
getLastBuildMenuTime(): number { getLastBuildMenuTime(state): number {
return this.lastBuildMenuTime; return state.lastBuildMenuTime;
}, },
getIsDynamicAddedRoute(): boolean { getIsDynamicAddedRoute(state): boolean {
return this.isDynamicAddedRoute; return state.isDynamicAddedRoute;
}, },
}, },
actions: { actions: {

24
apps/vue/src/store/modules/user.ts

@ -46,23 +46,23 @@ export const useUserStore = defineStore({
lastUpdateTime: 0, lastUpdateTime: 0,
}), }),
getters: { getters: {
getSso(): boolean { getSso(state): boolean {
return this.sso === true; return state.sso === true;
}, },
getUserInfo(): GetUserInfoModel { getUserInfo(state): GetUserInfoModel {
return this.userInfo || getAuthCache<GetUserInfoModel>(USER_INFO_KEY) || {}; return state.userInfo || getAuthCache<GetUserInfoModel>(USER_INFO_KEY) || {};
}, },
getToken(): string { getToken(state): string {
return this.token || getAuthCache<string>(TOKEN_KEY); return state.token || getAuthCache<string>(TOKEN_KEY);
}, },
getRoleList(): RoleEnum[] { getRoleList(state): RoleEnum[] {
return this.roleList.length > 0 ? this.roleList : getAuthCache<RoleEnum[]>(ROLES_KEY); return state.roleList.length > 0 ? state.roleList : getAuthCache<RoleEnum[]>(ROLES_KEY);
}, },
getSessionTimeout(): boolean { getSessionTimeout(state): boolean {
return !!this.sessionTimeout; return !!state.sessionTimeout;
}, },
getLastUpdateTime(): number { getLastUpdateTime(state): number {
return this.lastUpdateTime; return state.lastUpdateTime;
}, },
}, },
actions: { actions: {

68
apps/vue/src/views/webhooks/send-attempts/components/SendAttemptModal.vue

@ -30,7 +30,7 @@
<Input readonly :value="getDateTime(modelRef.creationTime)" /> <Input readonly :value="getDateTime(modelRef.creationTime)" />
</FormItem> </FormItem>
<FormItem :label="L('DisplayName:RequestHeaders')"> <FormItem :label="L('DisplayName:RequestHeaders')">
<CodeEditorX readonly :mode="MODE.JSON" v-model="modelRef.requestHeaders" /> <CodeEditor readonly :mode="MODE.JSON" :value="getJsonValue(modelRef.requestHeaders)" />
</FormItem> </FormItem>
<FormItem :label="L('DisplayName:ResponseStatusCode')"> <FormItem :label="L('DisplayName:ResponseStatusCode')">
<Tag <Tag
@ -40,10 +40,10 @@
> >
</FormItem> </FormItem>
<FormItem :label="L('DisplayName:ResponseHeaders')"> <FormItem :label="L('DisplayName:ResponseHeaders')">
<CodeEditorX readonly :mode="MODE.JSON" v-model="modelRef.responseHeaders" /> <CodeEditor readonly :mode="MODE.JSON" :value="getJsonValue(modelRef.responseHeaders)" />
</FormItem> </FormItem>
<FormItem :label="L('DisplayName:Response')"> <FormItem :label="L('DisplayName:Response')">
<CodeEditorX readonly v-model="modelRef.response" /> <CodeEditor readonly :value="getJsonValue(modelRef.response)" />
</FormItem> </FormItem>
</TabPane> </TabPane>
@ -51,17 +51,17 @@
<FormItem :label="L('DisplayName:TenantId')"> <FormItem :label="L('DisplayName:TenantId')">
<Input readonly :value="getTenant" /> <Input readonly :value="getTenant" />
</FormItem> </FormItem>
<FormItem :label="L('DisplayName:WebhookEventId')"> <FormItem name="webhookEventId" :label="L('DisplayName:WebhookEventId')">
<Input readonly :value="modelRef.webhookEventId" /> <Input readonly :value="modelRef.webhookEventId" />
</FormItem> </FormItem>
<FormItem :label="L('DisplayName:WebhookName')"> <FormItem :name="['webhookEvent', 'webhookName']" :label="L('DisplayName:WebhookName')">
<Input readonly :value="modelRef.webhookEvent.webhookName" /> <Input readonly :value="modelRef.webhookEvent.webhookName" />
</FormItem> </FormItem>
<FormItem :label="L('DisplayName:CreationTime')"> <FormItem :name="['webhookEvent', 'creationTime']" :label="L('DisplayName:CreationTime')">
<Input readonly :value="getDateTime(modelRef.webhookEvent.creationTime)" /> <Input readonly :value="getDateTime(modelRef.webhookEvent.creationTime)" />
</FormItem> </FormItem>
<FormItem :label="L('DisplayName:Data')"> <FormItem :name="['webhookEvent', 'data']" :label="L('DisplayName:Data')">
<CodeEditorX readonly :mode="MODE.JSON" v-model="modelRef.webhookEvent.data" /> <CodeEditor readonly :mode="MODE.JSON" :value="modelRef.webhookEvent.data" />
</FormItem> </FormItem>
</TabPane> </TabPane>
@ -100,7 +100,7 @@
</template> </template>
</FormItem> </FormItem>
<FormItem name="headers" :label="L('DisplayName:Headers')"> <FormItem name="headers" :label="L('DisplayName:Headers')">
<CodeEditorX readonly :mode="MODE.JSON" v-model="subscriptionRef.headers" /> <CodeEditor readonly :mode="MODE.JSON" :value="getJsonValue(subscriptionRef.headers)" />
</FormItem> </FormItem>
</TabPane> </TabPane>
</Tabs> </Tabs>
@ -113,7 +113,7 @@
import { useTabsStyle } from '/@/hooks/component/useStyles'; import { useTabsStyle } from '/@/hooks/component/useStyles';
import { useLocalization } from '/@/hooks/abp/useLocalization'; import { useLocalization } from '/@/hooks/abp/useLocalization';
import { Checkbox, Form, Tabs, Tag, Input, InputPassword, Textarea } from 'ant-design-vue'; import { Checkbox, Form, Tabs, Tag, Input, InputPassword, Textarea } from 'ant-design-vue';
import { CodeEditorX, MODE } from '/@/components/CodeEditor'; import { CodeEditor, MODE } from '/@/components/CodeEditor';
import { BasicModal, useModalInner } from '/@/components/Modal'; import { BasicModal, useModalInner } from '/@/components/Modal';
import { findTenantById } from '/@/api/multi-tenancy/tenants'; import { findTenantById } from '/@/api/multi-tenancy/tenants';
import { getById } from '/@/api/webhooks/send-attempts'; import { getById } from '/@/api/webhooks/send-attempts';
@ -122,6 +122,7 @@
import { WebhookSubscription } from '/@/api/webhooks/model/subscriptionsModel'; import { WebhookSubscription } from '/@/api/webhooks/model/subscriptionsModel';
import { httpStatusCodeMap, getHttpStatusColor } from '../../typing'; import { httpStatusCodeMap, getHttpStatusColor } from '../../typing';
import { formatToDateTime } from '/@/utils/dateUtil'; import { formatToDateTime } from '/@/utils/dateUtil';
import { isString } from '/@/utils/is';
const FormItem = Form.Item; const FormItem = Form.Item;
const TabPane = Tabs.TabPane; const TabPane = Tabs.TabPane;
@ -131,10 +132,12 @@
const activeKey = ref('basic'); const activeKey = ref('basic');
const tenantName = ref(''); const tenantName = ref('');
const tabsStyle = useTabsStyle(); const tabsStyle = useTabsStyle();
const modelRef = ref<WebhookSendAttempt>(getDefaultModel()); const modelRef = ref<WebhookSendAttempt>({} as WebhookSendAttempt);
const subscriptionRef = ref<WebhookSubscription>(getDefaultSubscription()); const subscriptionRef = ref<WebhookSubscription>({} as WebhookSubscription);
const [registerModal] = useModalInner((model) => { const [registerModal] = useModalInner((model) => {
activeKey.value = 'basic'; activeKey.value = 'basic';
modelRef.value = {} as WebhookSendAttempt;
subscriptionRef.value = {} as WebhookSubscription;
fetchModel(model.id); fetchModel(model.id);
}); });
const getDateTime = computed(() => { const getDateTime = computed(() => {
@ -145,6 +148,13 @@
const getTenant = computed(() => { const getTenant = computed(() => {
return tenantName.value ?? modelRef.value.tenantId; return tenantName.value ?? modelRef.value.tenantId;
}); });
const getJsonValue = computed(() => {
return (value?: Recordable | string) => {
if (!value) return '{}';
if (isString(value)) return value;
return JSON.stringify(value);
};
});
watch( watch(
() => modelRef.value.tenantId, () => modelRef.value.tenantId,
@ -173,38 +183,4 @@
subscriptionRef.value = res; subscriptionRef.value = res;
}); });
} }
function getDefaultModel(): WebhookSendAttempt {
return {
id: '',
webhookEventId: '',
webhookSubscriptionId: '',
webhookEvent: {
tenantId: undefined,
webhookName: '',
data: '{}',
creationTime: new Date(),
},
response: '',
responseStatusCode: undefined,
creationTime: new Date(),
lastModificationTime: undefined,
requestHeaders: {},
responseHeaders: {},
sendExactSameData: false,
};
}
function getDefaultSubscription(): WebhookSubscription {
return {
id: '',
webhooks: [],
webhookUri: '',
headers: {},
secret: '',
isActive: true,
creatorId: '',
creationTime: new Date(),
};
}
</script> </script>

14
apps/vue/src/views/webhooks/send-attempts/components/SendAttemptTable.vue

@ -109,15 +109,16 @@
openModal(true, record); openModal(true, record);
} }
function handleDelete(record) { function handleDeleteMany() {
createConfirm({ createConfirm({
iconType: 'warning', iconType: 'warning',
title: L('AreYouSure'), title: L('AreYouSure'),
content: L('ItemWillBeDeletedMessage'), content: L('ItemWillBeDeletedMessageWithFormat', { 0: L('SelectedItems') }),
okCancel: true, okCancel: true,
onOk: () => { onOk: () => {
const selectKeys = getSelectRowKeys();
setLoading(true); setLoading(true);
return deleteById(record.id).then(() => { return deleteMany(selectKeys).then(() => {
createMessage.success(L('SuccessfullyDeleted')); createMessage.success(L('SuccessfullyDeleted'));
clearSelectedRowKeys(); clearSelectedRowKeys();
reload(); reload();
@ -128,16 +129,15 @@
}); });
} }
function handleDeleteMany() { function handleDelete(record) {
createConfirm({ createConfirm({
iconType: 'warning', iconType: 'warning',
title: L('AreYouSure'), title: L('AreYouSure'),
content: L('ItemWillBeDeletedMessageWithFormat', { 0: L('SelectedItems') }), content: L('ItemWillBeDeletedMessage'),
okCancel: true, okCancel: true,
onOk: () => { onOk: () => {
const selectKeys = getSelectRowKeys();
setLoading(true); setLoading(true);
return deleteMany(selectKeys).then(() => { return deleteById(record.id).then(() => {
createMessage.success(L('SuccessfullyDeleted')); createMessage.success(L('SuccessfullyDeleted'));
clearSelectedRowKeys(); clearSelectedRowKeys();
reload(); reload();

19
apps/vue/src/views/webhooks/subscriptions/components/SubscriptionModal.vue

@ -57,7 +57,7 @@
</Select> </Select>
</FormItem> </FormItem>
<FormItem name="headers" :label="L('DisplayName:Headers')"> <FormItem name="headers" :label="L('DisplayName:Headers')">
<CodeEditorX style="height: 300px" :mode="MODE.JSON" v-model="modelRef.headers" /> <CodeEditor style="height: 300px" :mode="MODE.JSON" v-model:value="modelRef.headers" />
</FormItem> </FormItem>
</Form> </Form>
</BasicModal> </BasicModal>
@ -70,7 +70,7 @@
import { useMessage } from '/@/hooks/web/useMessage'; import { useMessage } from '/@/hooks/web/useMessage';
import { Checkbox, Form, Select, Tooltip, Input, InputPassword, Textarea } from 'ant-design-vue'; import { Checkbox, Form, Select, Tooltip, Input, InputPassword, Textarea } from 'ant-design-vue';
import { isString } from '/@/utils/is'; import { isString } from '/@/utils/is';
import { CodeEditorX, MODE } from '/@/components/CodeEditor'; import { CodeEditor, MODE } from '/@/components/CodeEditor';
import { BasicModal, useModalInner } from '/@/components/Modal'; import { BasicModal, useModalInner } from '/@/components/Modal';
import { TenantDto } from '/@/api/saas/tenant/model'; import { TenantDto } from '/@/api/saas/tenant/model';
import { GetListAsyncByInput as getTenants } from '/@/api/saas/tenant'; import { GetListAsyncByInput as getTenants } from '/@/api/saas/tenant';
@ -133,6 +133,19 @@
length: 128, length: 128,
type: 'string', type: 'string',
}), }),
// headers: ruleCreator.defineValidator({
// trigger: 'change',
// validator: (_, value: any) => {
// console.log(String(value));
// if (!value) {
// return Promise.resolve();
// }
// if (isJson(value)) {
// return Promise.resolve();
// }
// return Promise.reject(L('InvalidHeaders'));
// },
// }),
}); });
onMounted(() => { onMounted(() => {
@ -169,11 +182,11 @@
function handleSubmit() { function handleSubmit() {
const formEl = unref(formElRef); const formEl = unref(formElRef);
formEl?.validate().then(() => { formEl?.validate().then(() => {
changeOkLoading(true);
const model = unref(modelRef); const model = unref(modelRef);
if (isString(model.headers)) { if (isString(model.headers)) {
model.headers = JSON.parse(model.headers); model.headers = JSON.parse(model.headers);
} }
changeOkLoading(true);
const api = isEditModal.value const api = isEditModal.value
? update(model.id, Object.assign(model)) ? update(model.id, Object.assign(model))
: create(Object.assign(model)); : create(Object.assign(model));

17
apps/vue/src/views/webhooks/subscriptions/components/SubscriptionTable.vue

@ -69,7 +69,7 @@
const { createConfirm, createMessage } = useMessage(); const { createConfirm, createMessage } = useMessage();
const { L } = useLocalization(['WebhooksManagement', 'AbpUi']); const { L } = useLocalization(['WebhooksManagement', 'AbpUi']);
const [registerModal, { openModal }] = useModal(); const [registerModal, { openModal }] = useModal();
const [registerTable, { reload, setLoading, clearSelectedRowKeys, getSelectRowKeys }] = useTable({ const [registerTable, { reload, setLoading, getSelectRowKeys, clearSelectedRowKeys }] = useTable({
rowKey: 'id', rowKey: 'id',
title: L('Subscriptions'), title: L('Subscriptions'),
columns: getDataColumns(), columns: getDataColumns(),
@ -107,15 +107,16 @@
openModal(true, record); openModal(true, record);
} }
function handleDelete(record) { function handleDeleteMany() {
createConfirm({ createConfirm({
iconType: 'warning', iconType: 'warning',
title: L('AreYouSure'), title: L('AreYouSure'),
content: L('ItemWillBeDeletedMessage'), content: L('ItemWillBeDeletedMessageWithFormat', { 0: L('SelectedItems') }),
okCancel: true, okCancel: true,
onOk: () => { onOk: () => {
const selectKeys = getSelectRowKeys();
setLoading(true); setLoading(true);
return deleteById(record.id).then(() => { return deleteMany(selectKeys).then(() => {
createMessage.success(L('SuccessfullyDeleted')); createMessage.success(L('SuccessfullyDeleted'));
clearSelectedRowKeys(); clearSelectedRowKeys();
reload(); reload();
@ -126,19 +127,19 @@
}); });
} }
function handleDeleteMany() { function handleDelete(record) {
createConfirm({ createConfirm({
iconType: 'warning', iconType: 'warning',
title: L('AreYouSure'), title: L('AreYouSure'),
content: L('ItemWillBeDeletedMessageWithFormat', { 0: L('SelectedItems') }), content: L('ItemWillBeDeletedMessage'),
okCancel: true, okCancel: true,
onOk: () => { onOk: () => {
const selectKeys = getSelectRowKeys();
setLoading(true); setLoading(true);
return deleteMany(selectKeys).then(() => { return deleteById(record.id).then(() => {
createMessage.success(L('SuccessfullyDeleted')); createMessage.success(L('SuccessfullyDeleted'));
clearSelectedRowKeys(); clearSelectedRowKeys();
reload(); reload();
reload();
}).finally(() => { }).finally(() => {
setLoading(false); setLoading(false);
}); });

Loading…
Cancel
Save