@skyfox2000/webui 1.4.21 → 1.4.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/assets/modules/{baseLayout-Da4Ox7Lj.js → baseLayout-BcSEYvus.js} +3 -3
- package/lib/assets/modules/{file-upload-Bu6FkNjZ.js → file-upload-D11e2io7.js} +1 -1
- package/lib/assets/modules/{index-BYVerdEw.js → index-CO9_YadW.js} +2 -2
- package/lib/assets/modules/{index-Ch3meKe4.js → index-ClMWx3tg.js} +1 -1
- package/lib/assets/modules/{index-BysCt107.js → index-voAmrZ30.js} +2 -2
- package/lib/assets/modules/{menuTabs-BqLT-YbD.js → menuTabs-C9wkt-m9.js} +2 -2
- package/lib/assets/modules/{toolIcon-Dd58W0UM.js → toolIcon-9zQ4jiFD.js} +1 -1
- package/lib/assets/modules/{upload-template-Csccple9.js → upload-template-CM0O990W.js} +386 -369
- package/lib/assets/modules/uploadList-DhkFSkqE.js +466 -0
- package/lib/components/content/index.d.ts +4 -0
- package/lib/components/content/list/index.vue.d.ts +126 -0
- package/lib/components/content/list/listOperate.vue.d.ts +18 -0
- package/lib/components/form/switch/index.vue.d.ts +11 -1
- package/lib/components/form/upload/uploadList.vue.d.ts +448 -0
- package/lib/components/index.d.ts +1 -1
- package/lib/const/options.d.ts +4 -2
- package/lib/es/AceEditor/index.js +3 -3
- package/lib/es/BasicLayout/index.js +2 -2
- package/lib/es/Error403/index.js +1 -1
- package/lib/es/Error404/index.js +1 -1
- package/lib/es/ExcelForm/index.js +5 -5
- package/lib/es/MenuLayout/index.js +2 -2
- package/lib/es/TemplateFile/index.js +4 -4
- package/lib/es/UploadForm/index.js +70 -56
- package/lib/index.d.ts +1 -1
- package/lib/typings/upload.d.ts +10 -0
- package/lib/webui.css +1 -1
- package/lib/webui.es.js +1418 -1167
- package/package.json +1 -1
- package/src/components/content/dialog/uploadForm.vue +96 -13
- package/src/components/content/index.ts +5 -0
- package/src/components/content/list/index.vue +198 -0
- package/src/components/content/list/listOperate.vue +122 -0
- package/src/components/content/table/index.vue +1 -1
- package/src/components/content/table/tableOperate.vue +19 -37
- package/src/components/form/switch/index.vue +27 -14
- package/src/components/form/upload/uploadList.vue +46 -3
- package/src/components/index.ts +2 -0
- package/src/const/options.ts +11 -1
- package/src/index.ts +2 -0
- package/src/typings/upload.d.ts +10 -0
- package/lib/assets/modules/uploadList-D8scq04c.js +0 -423
package/package.json
CHANGED
|
@@ -9,19 +9,10 @@ import message from 'vue-m-message';
|
|
|
9
9
|
import { AsyncUploader } from '@/utils/file-upload';
|
|
10
10
|
|
|
11
11
|
const props = defineProps<{
|
|
12
|
-
/**
|
|
13
|
-
* 文件后缀限制
|
|
14
|
-
*/
|
|
15
|
-
fileExt?: string[];
|
|
16
12
|
/**
|
|
17
13
|
* 表格控制器
|
|
18
14
|
*/
|
|
19
15
|
gridCtrl: GridControl<AnyData>;
|
|
20
|
-
/**
|
|
21
|
-
* 最大文件数
|
|
22
|
-
* 默认1个
|
|
23
|
-
*/
|
|
24
|
-
maxCount?: number;
|
|
25
16
|
/**
|
|
26
17
|
* 并发上传文件数
|
|
27
18
|
* 默认3个
|
|
@@ -39,19 +30,90 @@ const props = defineProps<{
|
|
|
39
30
|
* 下载地址和参数
|
|
40
31
|
*/
|
|
41
32
|
downloadUrl?: IUrlInfo;
|
|
33
|
+
/**
|
|
34
|
+
* 删除Url
|
|
35
|
+
*/
|
|
36
|
+
deleteUrl?: IUrlInfo;
|
|
37
|
+
/**
|
|
38
|
+
* 文件列表
|
|
39
|
+
*/
|
|
40
|
+
fileList: UploadFile[];
|
|
41
|
+
|
|
42
42
|
/**
|
|
43
43
|
* 部分错误上传是否继续保存
|
|
44
44
|
*/
|
|
45
45
|
continueOnError?: boolean;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 预览Url
|
|
49
|
+
*/
|
|
50
|
+
previewUrl?: IUrlInfo;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Upload配置参数
|
|
54
|
+
*/
|
|
55
|
+
upload?: {
|
|
56
|
+
/**
|
|
57
|
+
* 是否自动上传
|
|
58
|
+
*/
|
|
59
|
+
autoUpload?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* 提示文字
|
|
62
|
+
*/
|
|
63
|
+
placeholder?: string;
|
|
64
|
+
/**
|
|
65
|
+
* 文件后缀列表
|
|
66
|
+
*/
|
|
67
|
+
fileExt?: string[];
|
|
68
|
+
/**
|
|
69
|
+
* 最大文件大小
|
|
70
|
+
*/
|
|
71
|
+
maxFileSize?: number;
|
|
72
|
+
/**
|
|
73
|
+
* 最大数量
|
|
74
|
+
*/
|
|
75
|
+
maxCount?: number;
|
|
76
|
+
/**
|
|
77
|
+
* 最大数量提示
|
|
78
|
+
*/
|
|
79
|
+
maxCountTip?: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* 文件大小提示
|
|
82
|
+
*/
|
|
83
|
+
maxFileSizeTip?: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* 文件类型提示
|
|
86
|
+
*/
|
|
87
|
+
fileExtTip?: boolean;
|
|
88
|
+
/**
|
|
89
|
+
* 文件路径
|
|
90
|
+
*/
|
|
91
|
+
parentPath?: string;
|
|
92
|
+
/**
|
|
93
|
+
* 显示操作文字
|
|
94
|
+
*/
|
|
95
|
+
showActionText?: boolean;
|
|
96
|
+
/**
|
|
97
|
+
* 是否显示上线或下线
|
|
98
|
+
*/
|
|
99
|
+
showOnlineSwitch?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* 是否显示删除
|
|
102
|
+
*/
|
|
103
|
+
showDelete?: boolean;
|
|
104
|
+
/**
|
|
105
|
+
* 是否显示目录上传按钮
|
|
106
|
+
*/
|
|
107
|
+
showFolderUpload?: boolean;
|
|
108
|
+
};
|
|
46
109
|
}>();
|
|
47
110
|
|
|
48
111
|
const uploadFormCtrl = props.uploadForm;
|
|
49
112
|
const open = ref<boolean>(false);
|
|
50
113
|
|
|
51
|
-
const maxCount = props.maxCount ?? 1;
|
|
52
114
|
const maxConcurrent = props.maxConcurrent ?? 3;
|
|
53
115
|
|
|
54
|
-
const fileList = ref<UploadFile[]>([]);
|
|
116
|
+
const fileList = ref<UploadFile[]>(props.fileList ?? []);
|
|
55
117
|
const emit = defineEmits<{
|
|
56
118
|
/**
|
|
57
119
|
* 显示预处理
|
|
@@ -80,6 +142,22 @@ watch(
|
|
|
80
142
|
const uploadUrl = ref(props.uploadUrl);
|
|
81
143
|
const downloadUrl = ref(props.downloadUrl);
|
|
82
144
|
|
|
145
|
+
// Upload默认配置
|
|
146
|
+
const uploadConfig = ref({
|
|
147
|
+
autoUpload: false,
|
|
148
|
+
placeholder: '',
|
|
149
|
+
maxFileSize: 20,
|
|
150
|
+
maxCount: 5,
|
|
151
|
+
maxCountTip: false,
|
|
152
|
+
maxFileSizeTip: true,
|
|
153
|
+
fileExtTip: true,
|
|
154
|
+
showActionText: true,
|
|
155
|
+
showOnlineSwitch: false,
|
|
156
|
+
showDelete: true,
|
|
157
|
+
showFolderUpload: false,
|
|
158
|
+
...props.upload
|
|
159
|
+
});
|
|
160
|
+
|
|
83
161
|
const dialogSave = async () => {
|
|
84
162
|
emit('before:upload', fileList.value);
|
|
85
163
|
const uploader = new AsyncUploader(uploadUrl.value!, maxConcurrent);
|
|
@@ -139,8 +217,13 @@ const dialogClose = () => {
|
|
|
139
217
|
<Modal title="文件上传" v-model:open="open"
|
|
140
218
|
:wrapClassName="'modal mx-auto ' + ($attrs.width ? 'w-[' + $attrs.width + ']' : 'w-[500px]')"
|
|
141
219
|
@close="dialogClose">
|
|
142
|
-
<UploadList
|
|
143
|
-
|
|
220
|
+
<UploadList
|
|
221
|
+
v-model:file-list="fileList"
|
|
222
|
+
:upload-url="uploadUrl!"
|
|
223
|
+
:download-url="downloadUrl"
|
|
224
|
+
:preview-url="props.previewUrl"
|
|
225
|
+
v-bind="uploadConfig"
|
|
226
|
+
/>
|
|
144
227
|
<template #footer>
|
|
145
228
|
<Space>
|
|
146
229
|
<Button @click="dialogClose">取消</Button>
|
|
@@ -13,6 +13,11 @@ export { Form };
|
|
|
13
13
|
import FormItem from './form/formItem.vue';
|
|
14
14
|
export { FormItem };
|
|
15
15
|
|
|
16
|
+
import List from './list/index.vue';
|
|
17
|
+
export { List };
|
|
18
|
+
import ListOperate from './list/listOperate.vue';
|
|
19
|
+
export { ListOperate };
|
|
20
|
+
|
|
16
21
|
import Search from './search/index.vue';
|
|
17
22
|
export { Search };
|
|
18
23
|
import SearchItem from './search/searchItem.vue';
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { onMounted, Ref, ref, watch, provide, useAttrs, onActivated, computed } from 'vue';
|
|
3
|
+
import { Card, List, ListItem, PaginationProps, ListProps } from 'ant-design-vue';
|
|
4
|
+
import {
|
|
5
|
+
AppRouter,
|
|
6
|
+
gridQueryFind,
|
|
7
|
+
gridStatusUpdate,
|
|
8
|
+
OPTIONS,
|
|
9
|
+
gridQueryList,
|
|
10
|
+
GridControl,
|
|
11
|
+
} from '@/index';
|
|
12
|
+
import ListOperate from './listOperate.vue';
|
|
13
|
+
import Toolbar from '../toolbar/index.vue';
|
|
14
|
+
import Switch from '../../form/switch/index.vue';
|
|
15
|
+
import { AnyData } from '@skyfox2000/fapi';
|
|
16
|
+
import { ProviderKeys } from '@/index';
|
|
17
|
+
|
|
18
|
+
const props = withDefaults(defineProps<{
|
|
19
|
+
/**
|
|
20
|
+
* 列表数据控制
|
|
21
|
+
*/
|
|
22
|
+
gridCtrl: GridControl<AnyData>;
|
|
23
|
+
/**
|
|
24
|
+
* 主键字段名
|
|
25
|
+
*/
|
|
26
|
+
primaryKey?: string;
|
|
27
|
+
/**
|
|
28
|
+
* 自定义列表数据
|
|
29
|
+
*/
|
|
30
|
+
listData?: Record<string, AnyData>[];
|
|
31
|
+
/**
|
|
32
|
+
* 网格配置
|
|
33
|
+
*/
|
|
34
|
+
grid?: ListProps['grid'];
|
|
35
|
+
/**
|
|
36
|
+
* 自定义分页控制
|
|
37
|
+
*/
|
|
38
|
+
pagination?: false | PaginationProps;
|
|
39
|
+
/**
|
|
40
|
+
* 卡片标题字段
|
|
41
|
+
*/
|
|
42
|
+
titleField?: string;
|
|
43
|
+
/**
|
|
44
|
+
* 是否禁用启用状态
|
|
45
|
+
*/
|
|
46
|
+
statusDisabled?: Function;
|
|
47
|
+
}>(), {
|
|
48
|
+
grid: () => ({ gutter: 16, column: 4 }),
|
|
49
|
+
titleField: 'Title',
|
|
50
|
+
pagination: undefined,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// 关闭自动继承属性到根元素
|
|
54
|
+
defineOptions({
|
|
55
|
+
inheritAttrs: false,
|
|
56
|
+
});
|
|
57
|
+
const attrs = useAttrs(); // 手动获取 $attrs
|
|
58
|
+
|
|
59
|
+
const gridCtrl = props.gridCtrl;
|
|
60
|
+
|
|
61
|
+
// 响应式获取当前路由路径
|
|
62
|
+
const currentPath = computed(() => AppRouter.currentRoute.value.path);
|
|
63
|
+
|
|
64
|
+
if (gridCtrl) {
|
|
65
|
+
gridCtrl.pageNo.value = 1;
|
|
66
|
+
gridCtrl.total.value = 0;
|
|
67
|
+
gridCtrl.pageSize.value = gridCtrl.pageSize.value;
|
|
68
|
+
}
|
|
69
|
+
const curPageSize = ref(gridCtrl.pageSize.value);
|
|
70
|
+
const curPageNo = ref(gridCtrl.pageNo.value);
|
|
71
|
+
|
|
72
|
+
const dataList = ref<Record<string, AnyData>[]>([]);
|
|
73
|
+
const pagination: Ref<false | PaginationProps> = ref<false | PaginationProps>({
|
|
74
|
+
...{
|
|
75
|
+
total: 0,
|
|
76
|
+
current: 1,
|
|
77
|
+
pageSize: curPageSize.value,
|
|
78
|
+
showTotal: (total: number) => {
|
|
79
|
+
return `共 ${total} 条记录`;
|
|
80
|
+
},
|
|
81
|
+
onChange: (page: number, pageSize: number) => {
|
|
82
|
+
if (pagination.value !== false) {
|
|
83
|
+
pagination.value.current = page;
|
|
84
|
+
pagination.value.pageSize = pageSize;
|
|
85
|
+
}
|
|
86
|
+
curPageSize.value = pageSize;
|
|
87
|
+
curPageNo.value = page;
|
|
88
|
+
if (gridCtrl) {
|
|
89
|
+
gridCtrl.pageNo.value = page;
|
|
90
|
+
gridCtrl.pageSize.value = pageSize;
|
|
91
|
+
if (gridCtrl.remotePage) gridQueryFind(gridCtrl);
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
...(props.pagination === false ? {} : props.pagination),
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
if (props.pagination === false) {
|
|
99
|
+
pagination.value = false;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
watch(
|
|
103
|
+
() => gridCtrl.tableData.value,
|
|
104
|
+
(newVal) => {
|
|
105
|
+
if (newVal) {
|
|
106
|
+
dataList.value = newVal;
|
|
107
|
+
if (pagination.value !== false) {
|
|
108
|
+
pagination.value.total = gridCtrl.total.value ?? 0;
|
|
109
|
+
pagination.value.current = gridCtrl.pageNo.value ?? 1;
|
|
110
|
+
pagination.value.pageSize = gridCtrl.pageSize.value ?? 10;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
{ immediate: true },
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
watch(
|
|
118
|
+
() => props.listData,
|
|
119
|
+
(newVal) => {
|
|
120
|
+
if (newVal) {
|
|
121
|
+
dataList.value = newVal;
|
|
122
|
+
if (pagination.value !== false) {
|
|
123
|
+
pagination.value.total = newVal.length;
|
|
124
|
+
pagination.value.current = gridCtrl.pageNo.value ?? 1;
|
|
125
|
+
pagination.value.pageSize = gridCtrl.pageSize.value ?? 10;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
{ immediate: true },
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
const visible = ref(false);
|
|
133
|
+
onActivated(() => {
|
|
134
|
+
if (visible.value && gridCtrl && gridCtrl.autoload) gridCtrl.reload.value = true;
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
onMounted(async () => {
|
|
138
|
+
provide(ProviderKeys.GridControl, gridCtrl);
|
|
139
|
+
|
|
140
|
+
if (gridCtrl.page && gridCtrl.gridUrl?.url) {
|
|
141
|
+
if (gridCtrl.gridUrl?.url === gridCtrl.page.urls.list?.url) {
|
|
142
|
+
gridCtrl.remotePage = false;
|
|
143
|
+
}
|
|
144
|
+
if (gridCtrl.gridUrl?.url === gridCtrl.page.urls.find?.url) {
|
|
145
|
+
gridCtrl.remotePage = true;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (gridCtrl.tableData.value) {
|
|
150
|
+
dataList.value = gridCtrl.tableData.value;
|
|
151
|
+
gridCtrl.total.value = dataList.value.length;
|
|
152
|
+
if (pagination.value !== false) {
|
|
153
|
+
pagination.value.total = gridCtrl.total.value ?? 0;
|
|
154
|
+
}
|
|
155
|
+
} else if (gridCtrl.autoload !== false) {
|
|
156
|
+
if (gridCtrl.remotePage) {
|
|
157
|
+
dataList.value = (await gridQueryFind(gridCtrl)).rows;
|
|
158
|
+
} else {
|
|
159
|
+
dataList.value = await gridQueryList(gridCtrl);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
setTimeout(() => {
|
|
164
|
+
// 延时显示,避免列表无数据显示异常
|
|
165
|
+
visible.value = true;
|
|
166
|
+
}, 50);
|
|
167
|
+
});
|
|
168
|
+
</script>
|
|
169
|
+
<template>
|
|
170
|
+
<Toolbar :grid-ctrl="gridCtrl" :editor-ctrl="gridCtrl.editor!"
|
|
171
|
+
v-if="gridCtrl.buttons?.value.length || gridCtrl.tools?.length" />
|
|
172
|
+
<List v-if="visible" class="w-full min-h-[480px]" :grid="props.grid" :data-source="dataList"
|
|
173
|
+
:loading="gridCtrl.isGridLoading.value" :pagination="pagination" v-bind="attrs">
|
|
174
|
+
<template #renderItem="{ item }">
|
|
175
|
+
<ListItem class="!m-0 !p-0">
|
|
176
|
+
<Card class="!m-0" :head-style="{ fontSize: '14px', padding: '8px', minHeight: '36px', height: '36px' }"
|
|
177
|
+
:body-style="{ padding: '4px' }">
|
|
178
|
+
<template #title>
|
|
179
|
+
<div class="flex items-center justify-between">
|
|
180
|
+
<span>{{ item[props.titleField] }}</span>
|
|
181
|
+
<div class="flex items-center space-x-2">
|
|
182
|
+
<Switch v-model:checked="item[gridCtrl.statusKey]"
|
|
183
|
+
v-auth:disable="{ url: currentPath, role: ['Super', 'Admin'], permit: ':enabled' }"
|
|
184
|
+
:disabled="statusDisabled ? statusDisabled(item) : false" :data="OPTIONS.EnableDisable"
|
|
185
|
+
@click="gridStatusUpdate(gridCtrl, item)" size="small" :class="[
|
|
186
|
+
'relative mt-[3px] transform scale-[1.1]',
|
|
187
|
+
statusDisabled && statusDisabled(item) ? 'cursor-not-allowed disabled' : '',
|
|
188
|
+
]" :loading="item.isLoading" />
|
|
189
|
+
<ListOperate :record="item" :grid-ctrl="gridCtrl" />
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
</template>
|
|
193
|
+
<slot name="cardContent" :record="item"></slot>
|
|
194
|
+
</Card>
|
|
195
|
+
</ListItem>
|
|
196
|
+
</template>
|
|
197
|
+
</List>
|
|
198
|
+
</template>
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
<script setup lang="ts" generic="T">
|
|
2
|
+
import {
|
|
3
|
+
AppRouter,
|
|
4
|
+
ButtonTool,
|
|
5
|
+
getToolGroup,
|
|
6
|
+
getToolVisible,
|
|
7
|
+
getToolStatus,
|
|
8
|
+
onToolClicked,
|
|
9
|
+
onGridRowEdit,
|
|
10
|
+
onGridRowDelete,
|
|
11
|
+
GridControl,
|
|
12
|
+
ToolIcon,
|
|
13
|
+
} from '@/index';
|
|
14
|
+
import { ConfigProvider, Space, DropdownButton, Menu, MenuItem, Popconfirm } from 'ant-design-vue';
|
|
15
|
+
import { computed } from 'vue';
|
|
16
|
+
|
|
17
|
+
const props = defineProps<{
|
|
18
|
+
/**
|
|
19
|
+
* 数据行记录
|
|
20
|
+
*/
|
|
21
|
+
record: Record<string, any>;
|
|
22
|
+
/**
|
|
23
|
+
* 表格数据控制
|
|
24
|
+
*/
|
|
25
|
+
gridCtrl: GridControl<T>;
|
|
26
|
+
}>();
|
|
27
|
+
|
|
28
|
+
const gridCtrl = props.gridCtrl;
|
|
29
|
+
|
|
30
|
+
// 响应式获取当前路由路径
|
|
31
|
+
const currentPath = computed(() => AppRouter.currentRoute.value.path);
|
|
32
|
+
|
|
33
|
+
/// 兼容其它按钮操作参数
|
|
34
|
+
const defaultOperates: ButtonTool[] = [
|
|
35
|
+
{
|
|
36
|
+
key: 'Edit',
|
|
37
|
+
label: '',
|
|
38
|
+
icon: 'icon-edit',
|
|
39
|
+
type: 'text',
|
|
40
|
+
visible: true,
|
|
41
|
+
role: ['Super', 'Admin'],
|
|
42
|
+
permit: ':edit',
|
|
43
|
+
click: () => onGridRowEdit<T>(gridCtrl, props.record as T),
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
key: 'Delete',
|
|
47
|
+
label: '',
|
|
48
|
+
icon: 'icon-delete',
|
|
49
|
+
type: 'text',
|
|
50
|
+
visible: true,
|
|
51
|
+
danger: true,
|
|
52
|
+
role: ['Super', 'Admin'],
|
|
53
|
+
permit: ':delete',
|
|
54
|
+
confirm: true,
|
|
55
|
+
confirmText: '是否删除此记录?',
|
|
56
|
+
click: () => onGridRowDelete<T>(gridCtrl, props.record as T),
|
|
57
|
+
},
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
const { buttons, menus } = getToolGroup(defaultOperates, 0, gridCtrl.operates);
|
|
61
|
+
|
|
62
|
+
const disabled = (item: ButtonTool): boolean => {
|
|
63
|
+
if (typeof item.disabled == 'boolean') {
|
|
64
|
+
return item.disabled;
|
|
65
|
+
}
|
|
66
|
+
if (typeof item.disabled == 'function') {
|
|
67
|
+
return getToolStatus(item, props.record) ?? false;
|
|
68
|
+
}
|
|
69
|
+
if (props.record.hasOwnProperty(gridCtrl.statusKey)) {
|
|
70
|
+
switch (item.key) {
|
|
71
|
+
case 'Edit':
|
|
72
|
+
return props.record[gridCtrl.statusKey] ? false : true;
|
|
73
|
+
case 'Delete':
|
|
74
|
+
return props.record[gridCtrl.statusKey] ? true : false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return false;
|
|
78
|
+
};
|
|
79
|
+
</script>
|
|
80
|
+
<template>
|
|
81
|
+
<ConfigProvider :theme="{
|
|
82
|
+
token: {
|
|
83
|
+
fontSize: 13,
|
|
84
|
+
},
|
|
85
|
+
}">
|
|
86
|
+
<Space>
|
|
87
|
+
<template v-for="item in buttons" :key="item.key">
|
|
88
|
+
<Popconfirm v-if="getToolVisible(item, props.record)" :disabled="disabled(item) || !item.confirm"
|
|
89
|
+
cancelText="否" okText="是" :title="item.confirmText" :okButtonProps="{ size: 'small' }"
|
|
90
|
+
:cancelButtonProps="{ size: 'small' }"
|
|
91
|
+
@confirm="onToolClicked(item, gridCtrl.page, gridCtrl, props.record, true)">
|
|
92
|
+
<ToolIcon :key="item.key" :icon="item.icon" :danger="item.danger"
|
|
93
|
+
v-if="getToolVisible(item, props.record)" :disabled="disabled(item)"
|
|
94
|
+
v-auth="{ url: currentPath, role: item.role, permit: item.permit }"
|
|
95
|
+
@click="!disabled(item) && onToolClicked(item, gridCtrl.page, gridCtrl, props.record)"
|
|
96
|
+
:clickable="!disabled(item)" :class="[
|
|
97
|
+
'w-4 h-4',
|
|
98
|
+
item.danger ? 'text-red-500' : 'text-gray-600',
|
|
99
|
+
disabled(item) ? 'opacity-30 cursor-not-allowed' : 'hover:text-gray-800',
|
|
100
|
+
]" />
|
|
101
|
+
</Popconfirm>
|
|
102
|
+
</template>
|
|
103
|
+
|
|
104
|
+
<ConfigProvider :autoInsertSpaceInButton="false" v-if="record[gridCtrl.statusKey] == 1">
|
|
105
|
+
<DropdownButton v-if="menus.length > 0" size="small">
|
|
106
|
+
更多
|
|
107
|
+
<template #overlay>
|
|
108
|
+
<Menu>
|
|
109
|
+
<template v-for="item in menus" :key="item.key">
|
|
110
|
+
<MenuItem v-if="getToolVisible(item, props.record)" :disabled="disabled(item)"
|
|
111
|
+
v-auth="{ url: currentPath, role: item.role, permit: item.permit }"
|
|
112
|
+
@click="onToolClicked(item, gridCtrl.page, gridCtrl, props.record)">
|
|
113
|
+
{{ item.label }}
|
|
114
|
+
</MenuItem>
|
|
115
|
+
</template>
|
|
116
|
+
</Menu>
|
|
117
|
+
</template>
|
|
118
|
+
</DropdownButton>
|
|
119
|
+
</ConfigProvider>
|
|
120
|
+
</Space>
|
|
121
|
+
</ConfigProvider>
|
|
122
|
+
</template>
|
|
@@ -212,7 +212,7 @@ onMounted(async () => {
|
|
|
212
212
|
<template #bodyCell="bodyCell">
|
|
213
213
|
<slot name="bodyCell" :column="bodyCell?.column" :record="bodyCell?.record"></slot>
|
|
214
214
|
<template v-if="gridCtrl && bodyCell?.column?.dataIndex === 'enabled'">
|
|
215
|
-
<Switch v-model:checked="bodyCell.record.
|
|
215
|
+
<Switch v-model:checked="bodyCell.record[gridCtrl.statusKey]"
|
|
216
216
|
v-auth:disable="{ url: currentPath, role: ['Super', 'Admin'], permit: ':enabled' }"
|
|
217
217
|
:disabled="statusDisabled ? statusDisabled(bodyCell.record) : false" :data="OPTIONS.EnableDisable"
|
|
218
218
|
@click="gridStatusUpdate(gridCtrl, bodyCell.record)" :class="[
|
|
@@ -63,68 +63,50 @@ const disabled = (item: ButtonTool): boolean => {
|
|
|
63
63
|
if (typeof item.disabled == 'function') {
|
|
64
64
|
return getToolStatus(item, props.record) ?? false;
|
|
65
65
|
}
|
|
66
|
-
if (props.record.hasOwnProperty(
|
|
66
|
+
if (props.record.hasOwnProperty(gridCtrl.statusKey)) {
|
|
67
67
|
switch (item.key) {
|
|
68
68
|
case 'Edit':
|
|
69
|
-
return props.record.
|
|
69
|
+
return props.record[gridCtrl.statusKey] ? false : true; // 启用时可编辑,停用时不可编辑
|
|
70
70
|
case 'Delete':
|
|
71
|
-
return props.record.
|
|
71
|
+
return props.record[gridCtrl.statusKey] ? true : false; // 启用时不可删除,停用时可删除
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
return false;
|
|
75
75
|
};
|
|
76
76
|
</script>
|
|
77
77
|
<template>
|
|
78
|
-
<ConfigProvider
|
|
79
|
-
:
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}"
|
|
84
|
-
>
|
|
78
|
+
<ConfigProvider :theme="{
|
|
79
|
+
token: {
|
|
80
|
+
fontSize: 13,
|
|
81
|
+
},
|
|
82
|
+
}">
|
|
85
83
|
<Space>
|
|
86
84
|
<template v-for="item in buttons" :key="item.key">
|
|
87
|
-
<Popconfirm
|
|
88
|
-
|
|
89
|
-
:disabled="disabled(item) || !item.confirm"
|
|
90
|
-
cancelText="否"
|
|
91
|
-
okText="是"
|
|
92
|
-
:title="item.confirmText"
|
|
93
|
-
:okButtonProps="{ size: 'small' }"
|
|
85
|
+
<Popconfirm v-if="getToolVisible(item, props.record)" :disabled="disabled(item) || !item.confirm"
|
|
86
|
+
cancelText="否" okText="是" :title="item.confirmText" :okButtonProps="{ size: 'small' }"
|
|
94
87
|
:cancelButtonProps="{ size: 'small' }"
|
|
95
|
-
@confirm="onToolClicked(item, gridCtrl.page, gridCtrl, props.record, true)"
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
:key="item.key"
|
|
99
|
-
:type="item.type ?? 'text'"
|
|
100
|
-
:danger="item.danger"
|
|
101
|
-
v-if="getToolVisible(item, props.record)"
|
|
102
|
-
:disabled="disabled(item)"
|
|
88
|
+
@confirm="onToolClicked(item, gridCtrl.page, gridCtrl, props.record, true)">
|
|
89
|
+
<Button :key="item.key" :type="item.type ?? 'text'" :danger="item.danger"
|
|
90
|
+
v-if="getToolVisible(item, props.record)" :disabled="disabled(item)"
|
|
103
91
|
v-auth="{ url: currentPath, role: item.role, permit: item.permit }"
|
|
104
|
-
@click="onToolClicked(item, gridCtrl.page, gridCtrl, props.record)"
|
|
105
|
-
size="small"
|
|
106
|
-
:style="{
|
|
92
|
+
@click="onToolClicked(item, gridCtrl.page, gridCtrl, props.record)" size="small" :style="{
|
|
107
93
|
padding: item.type ?? '0px 4px',
|
|
108
|
-
}"
|
|
109
|
-
>
|
|
94
|
+
}">
|
|
110
95
|
{{ item.label }}
|
|
111
96
|
</Button>
|
|
112
97
|
</Popconfirm>
|
|
113
98
|
</template>
|
|
114
99
|
|
|
115
|
-
<ConfigProvider :autoInsertSpaceInButton="false" v-if="record.
|
|
100
|
+
<ConfigProvider :autoInsertSpaceInButton="false" v-if="record[gridCtrl.statusKey] == 1">
|
|
116
101
|
<DropdownButton v-if="menus.length > 0" size="small">
|
|
117
102
|
更多
|
|
118
103
|
<template #overlay>
|
|
119
104
|
<Menu>
|
|
120
105
|
<template v-for="item in menus" :key="item.key">
|
|
121
|
-
<MenuItem
|
|
122
|
-
v-if="getToolVisible(item, props.record)"
|
|
123
|
-
:disabled="disabled(item)"
|
|
106
|
+
<MenuItem v-if="getToolVisible(item, props.record)" :disabled="disabled(item)"
|
|
124
107
|
v-auth="{ url: currentPath, role: item.role, permit: item.permit }"
|
|
125
|
-
@click="onToolClicked(item, gridCtrl.page, gridCtrl, props.record)"
|
|
126
|
-
|
|
127
|
-
{{ item.label }}
|
|
108
|
+
@click="onToolClicked(item, gridCtrl.page, gridCtrl, props.record)">
|
|
109
|
+
{{ item.label }}
|
|
128
110
|
</MenuItem>
|
|
129
111
|
</template>
|
|
130
112
|
</Menu>
|
|
@@ -4,6 +4,7 @@ import { formValidate, useInputFactory, OptionItemProps, loadOption, unloadOptio
|
|
|
4
4
|
import { Switch } from 'ant-design-vue';
|
|
5
5
|
import message from 'vue-m-message';
|
|
6
6
|
import { useOptionFactory } from '@/utils/page';
|
|
7
|
+
import { computed } from 'vue';
|
|
7
8
|
|
|
8
9
|
const props = defineProps({
|
|
9
10
|
...OptionCommProps,
|
|
@@ -14,6 +15,10 @@ const props = defineProps({
|
|
|
14
15
|
type: Array as PropType<OptionItemProps[]>,
|
|
15
16
|
required: true,
|
|
16
17
|
},
|
|
18
|
+
size: {
|
|
19
|
+
type: String as PropType<'small' | 'default' | undefined>,
|
|
20
|
+
default: 'default',
|
|
21
|
+
},
|
|
17
22
|
});
|
|
18
23
|
|
|
19
24
|
const inputFactory = useInputFactory();
|
|
@@ -42,6 +47,15 @@ const emit = defineEmits<{
|
|
|
42
47
|
}>();
|
|
43
48
|
|
|
44
49
|
const { editorCtrl, errInfo } = useInputFactory();
|
|
50
|
+
|
|
51
|
+
const customSize = computed(() => {
|
|
52
|
+
switch (props.size) {
|
|
53
|
+
case 'small':
|
|
54
|
+
return 'w-[46px]';
|
|
55
|
+
default:
|
|
56
|
+
return 'w-[58px]';
|
|
57
|
+
}
|
|
58
|
+
});
|
|
45
59
|
const onChange = (checked: boolean | string | number) => {
|
|
46
60
|
if (errInfo?.value.errClass && editorCtrl) {
|
|
47
61
|
/// 重新开始验证
|
|
@@ -63,18 +77,17 @@ onUnmounted(() => {
|
|
|
63
77
|
});
|
|
64
78
|
</script>
|
|
65
79
|
<template>
|
|
66
|
-
<Switch
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
:checkedChildren="switchOptions[0].label"
|
|
74
|
-
:checkedValue="switchOptions[0].value"
|
|
75
|
-
:unCheckedChildren="switchOptions[1].label"
|
|
76
|
-
:unCheckedValue="switchOptions[1].value"
|
|
77
|
-
@change="onChange"
|
|
78
|
-
v-bind="$attrs"
|
|
79
|
-
/>
|
|
80
|
+
<Switch v-if="switchOptions.length === 2" :size="size" :class="[
|
|
81
|
+
errInfo?.errClass === 'error' ? 'error !border-red-300 shadow-[0_0_3px_0px_#ff4d4f]' : '',
|
|
82
|
+
'bg-blue-300',
|
|
83
|
+
customSize,
|
|
84
|
+
]" :checkedChildren="switchOptions[0].label" :checkedValue="switchOptions[0].value"
|
|
85
|
+
:unCheckedChildren="switchOptions[1].label" :unCheckedValue="switchOptions[1].value" @change="onChange"
|
|
86
|
+
v-bind="$attrs" />
|
|
80
87
|
</template>
|
|
88
|
+
<style>
|
|
89
|
+
.ant-switch-small .ant-switch-inner-checked,
|
|
90
|
+
.ant-switch-small .ant-switch-inner-unchecked {
|
|
91
|
+
font-size: 10px !important;
|
|
92
|
+
}
|
|
93
|
+
</style>
|