@skyfox2000/webui 0.1.0
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/.eslintrc.js +23 -0
- package/.prettierrc +11 -0
- package/.vscode/settings.json +25 -0
- package/README.md +104 -0
- package/env.d.ts +11 -0
- package/index.html +19 -0
- package/lib/AceEditor.d.ts +4 -0
- package/lib/BasicLayout.d.ts +4 -0
- package/lib/Error403.d.ts +4 -0
- package/lib/Error404.d.ts +4 -0
- package/lib/ExcelForm.d.ts +4 -0
- package/lib/UploadForm.d.ts +4 -0
- package/lib/assets/modules/basicLayout-YP_-EySb.js +726 -0
- package/lib/assets/modules/error403-Bi0E2twj.js +33 -0
- package/lib/assets/modules/error404-BF7vasR_.js +33 -0
- package/lib/assets/modules/excelForm-Dzndz-SG.js +109 -0
- package/lib/assets/modules/excelForm-WJVQmaDT.js +317 -0
- package/lib/assets/modules/index-FzWSvscZ.js +107 -0
- package/lib/assets/modules/index-ekkaExvB.js +49 -0
- package/lib/assets/modules/uploadForm-BahGnrAq.js +415 -0
- package/lib/assets/modules/uploadForm-DEnOjhwc.js +308 -0
- package/lib/components/common/button/index.vue.d.ts +42 -0
- package/lib/components/common/button/index.vue.d.ts.map +1 -0
- package/lib/components/common/icon/appicon.vue.d.ts +12 -0
- package/lib/components/common/icon/appicon.vue.d.ts.map +1 -0
- package/lib/components/common/icon/fullscreen.vue.d.ts +4 -0
- package/lib/components/common/icon/fullscreen.vue.d.ts.map +1 -0
- package/lib/components/common/icon/helper.vue.d.ts +23 -0
- package/lib/components/common/icon/helper.vue.d.ts.map +1 -0
- package/lib/components/common/icon/index.vue.d.ts +244 -0
- package/lib/components/common/icon/index.vue.d.ts.map +1 -0
- package/lib/components/common/icon/layoutIcon.vue.d.ts +44 -0
- package/lib/components/common/icon/layoutIcon.vue.d.ts.map +1 -0
- package/lib/components/common/icon/projectIcon.vue.d.ts +60 -0
- package/lib/components/common/icon/projectIcon.vue.d.ts.map +1 -0
- package/lib/components/common/icon/toolIcon.vue.d.ts +44 -0
- package/lib/components/common/icon/toolIcon.vue.d.ts.map +1 -0
- package/lib/components/common/index.d.ts +19 -0
- package/lib/components/common/index.d.ts.map +1 -0
- package/lib/components/common/tooltip/index.vue.d.ts +22 -0
- package/lib/components/common/tooltip/index.vue.d.ts.map +1 -0
- package/lib/components/content/dialog/excelForm.vue.d.ts +31 -0
- package/lib/components/content/dialog/excelForm.vue.d.ts.map +1 -0
- package/lib/components/content/dialog/index.vue.d.ts +35 -0
- package/lib/components/content/dialog/index.vue.d.ts.map +1 -0
- package/lib/components/content/dialog/uploadForm.vue.d.ts +25 -0
- package/lib/components/content/dialog/uploadForm.vue.d.ts.map +1 -0
- package/lib/components/content/drawer/index.vue.d.ts +27 -0
- package/lib/components/content/drawer/index.vue.d.ts.map +1 -0
- package/lib/components/content/form/formItem.vue.d.ts +26 -0
- package/lib/components/content/form/formItem.vue.d.ts.map +1 -0
- package/lib/components/content/form/index.vue.d.ts +26 -0
- package/lib/components/content/form/index.vue.d.ts.map +1 -0
- package/lib/components/content/index.d.ts +27 -0
- package/lib/components/content/index.d.ts.map +1 -0
- package/lib/components/content/search/index.vue.d.ts +30 -0
- package/lib/components/content/search/index.vue.d.ts.map +1 -0
- package/lib/components/content/search/searchItem.vue.d.ts +24 -0
- package/lib/components/content/search/searchItem.vue.d.ts.map +1 -0
- package/lib/components/content/table/index.vue.d.ts +37 -0
- package/lib/components/content/table/index.vue.d.ts.map +1 -0
- package/lib/components/content/table/tableOperate.vue.d.ts +19 -0
- package/lib/components/content/table/tableOperate.vue.d.ts.map +1 -0
- package/lib/components/content/toolbar/icontool.vue.d.ts +8 -0
- package/lib/components/content/toolbar/icontool.vue.d.ts.map +1 -0
- package/lib/components/content/toolbar/index.vue.d.ts +19 -0
- package/lib/components/content/toolbar/index.vue.d.ts.map +1 -0
- package/lib/components/content/tree/index.vue.d.ts +47 -0
- package/lib/components/content/tree/index.vue.d.ts.map +1 -0
- package/lib/components/error/error403.vue.d.ts +4 -0
- package/lib/components/error/error403.vue.d.ts.map +1 -0
- package/lib/components/error/error404.vue.d.ts +4 -0
- package/lib/components/error/error404.vue.d.ts.map +1 -0
- package/lib/components/form/aceEditor/aceConfig.d.ts +9 -0
- package/lib/components/form/aceEditor/aceConfig.d.ts.map +1 -0
- package/lib/components/form/aceEditor/index.vue.d.ts +13 -0
- package/lib/components/form/aceEditor/index.vue.d.ts.map +1 -0
- package/lib/components/form/autoComplete/index.vue.d.ts +140 -0
- package/lib/components/form/autoComplete/index.vue.d.ts.map +1 -0
- package/lib/components/form/cascader/index.vue.d.ts +110 -0
- package/lib/components/form/cascader/index.vue.d.ts.map +1 -0
- package/lib/components/form/checkbox/index.vue.d.ts +129 -0
- package/lib/components/form/checkbox/index.vue.d.ts.map +1 -0
- package/lib/components/form/datePicker/index.vue.d.ts +7 -0
- package/lib/components/form/datePicker/index.vue.d.ts.map +1 -0
- package/lib/components/form/index.d.ts +41 -0
- package/lib/components/form/index.d.ts.map +1 -0
- package/lib/components/form/input/index.vue.d.ts +27 -0
- package/lib/components/form/input/index.vue.d.ts.map +1 -0
- package/lib/components/form/input/inputIcon.vue.d.ts +11 -0
- package/lib/components/form/input/inputIcon.vue.d.ts.map +1 -0
- package/lib/components/form/input/inputNumber.vue.d.ts +4 -0
- package/lib/components/form/input/inputNumber.vue.d.ts.map +1 -0
- package/lib/components/form/input/inputPassword.vue.d.ts +4 -0
- package/lib/components/form/input/inputPassword.vue.d.ts.map +1 -0
- package/lib/components/form/propEditor/index.vue.d.ts +13 -0
- package/lib/components/form/propEditor/index.vue.d.ts.map +1 -0
- package/lib/components/form/radio/index.vue.d.ts +134 -0
- package/lib/components/form/radio/index.vue.d.ts.map +1 -0
- package/lib/components/form/radio/radioStatus.vue.d.ts +32 -0
- package/lib/components/form/radio/radioStatus.vue.d.ts.map +1 -0
- package/lib/components/form/rangePicker/index.vue.d.ts +17 -0
- package/lib/components/form/rangePicker/index.vue.d.ts.map +1 -0
- package/lib/components/form/select/index.vue.d.ts +143 -0
- package/lib/components/form/select/index.vue.d.ts.map +1 -0
- package/lib/components/form/switch/index.vue.d.ts +44 -0
- package/lib/components/form/switch/index.vue.d.ts.map +1 -0
- package/lib/components/form/textarea/index.vue.d.ts +4 -0
- package/lib/components/form/textarea/index.vue.d.ts.map +1 -0
- package/lib/components/form/transfer/index.vue.d.ts +39 -0
- package/lib/components/form/transfer/index.vue.d.ts.map +1 -0
- package/lib/components/form/transfer/transferTable.vue.d.ts +39 -0
- package/lib/components/form/transfer/transferTable.vue.d.ts.map +1 -0
- package/lib/components/form/treeSelect/index.vue.d.ts +39 -0
- package/lib/components/form/treeSelect/index.vue.d.ts.map +1 -0
- package/lib/components/form/upload/uploadList.vue.d.ts +477 -0
- package/lib/components/form/upload/uploadList.vue.d.ts.map +1 -0
- package/lib/components/index.d.ts +9 -0
- package/lib/components/index.d.ts.map +1 -0
- package/lib/components/layout/breadcrumb/index.vue.d.ts +4 -0
- package/lib/components/layout/breadcrumb/index.vue.d.ts.map +1 -0
- package/lib/components/layout/content/index.vue.d.ts +23 -0
- package/lib/components/layout/content/index.vue.d.ts.map +1 -0
- package/lib/components/layout/datetime/index.vue.d.ts +4 -0
- package/lib/components/layout/datetime/index.vue.d.ts.map +1 -0
- package/lib/components/layout/header/headerExits.vue.d.ts +4 -0
- package/lib/components/layout/header/headerExits.vue.d.ts.map +1 -0
- package/lib/components/layout/header/index.vue.d.ts +4 -0
- package/lib/components/layout/header/index.vue.d.ts.map +1 -0
- package/lib/components/layout/index.d.ts +17 -0
- package/lib/components/layout/index.d.ts.map +1 -0
- package/lib/components/layout/menu/index.vue.d.ts +7 -0
- package/lib/components/layout/menu/index.vue.d.ts.map +1 -0
- package/lib/components/layout/menu/menuTabs.vue.d.ts +4 -0
- package/lib/components/layout/menu/menuTabs.vue.d.ts.map +1 -0
- package/lib/components/layout/page/basicLayout.vue.d.ts +7 -0
- package/lib/components/layout/page/basicLayout.vue.d.ts.map +1 -0
- package/lib/es/AceEditor/index.js +168 -0
- package/lib/es/BasicLayout/index.js +4 -0
- package/lib/es/Error403/index.js +4 -0
- package/lib/es/Error404/index.js +4 -0
- package/lib/es/ExcelForm/index.js +5 -0
- package/lib/es/UploadForm/index.js +5 -0
- package/lib/index.d.ts +2 -0
- package/lib/webui.css +1 -0
- package/lib/webui.es.js +3349 -0
- package/package.json +66 -0
- package/plugins/vite-plugin-auto-generate-vue.ts +105 -0
- package/postcss.config.ts +6 -0
- package/src/assets/global.css +9 -0
- package/src/components/common/button/index.vue +126 -0
- package/src/components/common/icon/appicon.vue +28 -0
- package/src/components/common/icon/fullscreen.vue +13 -0
- package/src/components/common/icon/helper.vue +30 -0
- package/src/components/common/icon/index.vue +426 -0
- package/src/components/common/icon/layoutIcon.vue +33 -0
- package/src/components/common/icon/projectIcon.vue +41 -0
- package/src/components/common/icon/toolIcon.vue +33 -0
- package/src/components/common/index.ts +19 -0
- package/src/components/common/tooltip/index.vue +25 -0
- package/src/components/content/dialog/excelForm.vue +479 -0
- package/src/components/content/dialog/index.vue +149 -0
- package/src/components/content/dialog/uploadForm.vue +228 -0
- package/src/components/content/drawer/index.vue +93 -0
- package/src/components/content/form/formItem.vue +76 -0
- package/src/components/content/form/index.vue +48 -0
- package/src/components/content/index.ts +32 -0
- package/src/components/content/search/index.vue +135 -0
- package/src/components/content/search/searchItem.vue +52 -0
- package/src/components/content/table/index.vue +215 -0
- package/src/components/content/table/tableOperate.vue +131 -0
- package/src/components/content/toolbar/icontool.vue +151 -0
- package/src/components/content/toolbar/index.vue +107 -0
- package/src/components/content/tree/index.vue +140 -0
- package/src/components/error/error403.vue +14 -0
- package/src/components/error/error404.vue +14 -0
- package/src/components/form/aceEditor/aceConfig.ts +90 -0
- package/src/components/form/aceEditor/index.vue +175 -0
- package/src/components/form/autoComplete/index.vue +171 -0
- package/src/components/form/cascader/index.vue +110 -0
- package/src/components/form/checkbox/index.vue +108 -0
- package/src/components/form/datePicker/index.vue +29 -0
- package/src/components/form/index.ts +54 -0
- package/src/components/form/input/index.vue +70 -0
- package/src/components/form/input/inputIcon.vue +39 -0
- package/src/components/form/input/inputNumber.vue +23 -0
- package/src/components/form/input/inputPassword.vue +22 -0
- package/src/components/form/propEditor/index.vue +81 -0
- package/src/components/form/radio/index.vue +132 -0
- package/src/components/form/radio/radioStatus.vue +42 -0
- package/src/components/form/rangePicker/index.vue +64 -0
- package/src/components/form/select/index.vue +186 -0
- package/src/components/form/switch/index.vue +58 -0
- package/src/components/form/textarea/index.vue +23 -0
- package/src/components/form/transfer/index.vue +95 -0
- package/src/components/form/transfer/transferTable.vue +124 -0
- package/src/components/form/treeSelect/index.vue +108 -0
- package/src/components/form/upload/uploadList.vue +235 -0
- package/src/components/index.ts +97 -0
- package/src/components/layout/breadcrumb/index.vue +38 -0
- package/src/components/layout/content/index.vue +28 -0
- package/src/components/layout/datetime/index.vue +16 -0
- package/src/components/layout/header/headerExits.vue +28 -0
- package/src/components/layout/header/index.vue +43 -0
- package/src/components/layout/index.ts +16 -0
- package/src/components/layout/menu/index.vue +64 -0
- package/src/components/layout/menu/menuTabs.vue +56 -0
- package/src/components/layout/page/basicLayout.vue +67 -0
- package/src/vite-env.d.ts +8 -0
- package/tailwind.config.ts +11 -0
- package/tsconfig.json +53 -0
- package/vite.config.ts +117 -0
- package//344/273/243/347/240/201/350/247/204/350/214/203/345/217/212/351/243/216/346/240/274/346/214/207/345/215/227.md +116 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { watch, ref, onMounted } from 'vue';
|
|
3
|
+
import { Button } from '../../common';
|
|
4
|
+
import { Modal, Space } from 'ant-design-vue';
|
|
5
|
+
import { AsyncUploader, EditorControl, GridControl, gridRowUpdate } from '@skyfox2000/webbase';
|
|
6
|
+
import { AnyData, ApiResponse, IUrlInfo, ResStatus } from '@skyfox2000/fapi';
|
|
7
|
+
import { UploadList } from '../../form';
|
|
8
|
+
import { UploadFile } from '@skyfox2000/webbase';
|
|
9
|
+
import message from 'vue-m-message';
|
|
10
|
+
import { UploadStatus } from '@skyfox2000/webbase';
|
|
11
|
+
|
|
12
|
+
const props = defineProps<{
|
|
13
|
+
/**
|
|
14
|
+
* #### 使用模式
|
|
15
|
+
* - Row 数据行
|
|
16
|
+
* - Page 页面
|
|
17
|
+
*/
|
|
18
|
+
mode: 'Row' | 'Page';
|
|
19
|
+
/**
|
|
20
|
+
* 文件后缀限制
|
|
21
|
+
*/
|
|
22
|
+
fileExt?: string[];
|
|
23
|
+
/**
|
|
24
|
+
* 表格控制器
|
|
25
|
+
*/
|
|
26
|
+
gridCtrl: GridControl<AnyData>;
|
|
27
|
+
/**
|
|
28
|
+
* 最大文件数
|
|
29
|
+
* 默认1个
|
|
30
|
+
*/
|
|
31
|
+
maxCount?: number;
|
|
32
|
+
/**
|
|
33
|
+
* 并发上传文件数
|
|
34
|
+
* 默认3个
|
|
35
|
+
*/
|
|
36
|
+
maxConcurrent?: number;
|
|
37
|
+
/**
|
|
38
|
+
* 弹窗控制器
|
|
39
|
+
*/
|
|
40
|
+
uploadForm: EditorControl<AnyData>;
|
|
41
|
+
/**
|
|
42
|
+
* 上传地址和参数
|
|
43
|
+
*/
|
|
44
|
+
uploadUrl?: IUrlInfo;
|
|
45
|
+
/**
|
|
46
|
+
* 下载地址和参数
|
|
47
|
+
*/
|
|
48
|
+
downloadUrl?: IUrlInfo;
|
|
49
|
+
/**
|
|
50
|
+
* 部分错误上传是否继续保存
|
|
51
|
+
*/
|
|
52
|
+
continueOnError?: boolean;
|
|
53
|
+
}>();
|
|
54
|
+
|
|
55
|
+
const uploadFormCtrl = props.uploadForm;
|
|
56
|
+
const open = ref<boolean>(false);
|
|
57
|
+
|
|
58
|
+
const maxCount = props.maxCount ?? 1;
|
|
59
|
+
const maxConcurrent = props.maxConcurrent ?? 3;
|
|
60
|
+
|
|
61
|
+
const fileList = ref<UploadFile[]>([]);
|
|
62
|
+
const emit = defineEmits<{
|
|
63
|
+
/**
|
|
64
|
+
* 显示预处理
|
|
65
|
+
*/
|
|
66
|
+
'before:file-list': [EditorControl<AnyData>, UploadFile[]];
|
|
67
|
+
/**
|
|
68
|
+
* 上传前预处理
|
|
69
|
+
*/
|
|
70
|
+
'before:upload': [UploadFile[]];
|
|
71
|
+
/**
|
|
72
|
+
* 上传结束,处理上传后的文件
|
|
73
|
+
*/
|
|
74
|
+
'after:upload': [UploadFile[]];
|
|
75
|
+
}>();
|
|
76
|
+
|
|
77
|
+
watch(
|
|
78
|
+
() => uploadFormCtrl.visible.value,
|
|
79
|
+
() => {
|
|
80
|
+
open.value = uploadFormCtrl.visible.value;
|
|
81
|
+
},
|
|
82
|
+
);
|
|
83
|
+
const uploadUrl = ref(props.uploadUrl);
|
|
84
|
+
const downloadUrl = ref(props.downloadUrl);
|
|
85
|
+
|
|
86
|
+
const dialogUpload = async () => {
|
|
87
|
+
const url = uploadUrl.value;
|
|
88
|
+
if (!url) {
|
|
89
|
+
message.error('未配置文件上传地址!');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
emit('before:upload', fileList.value);
|
|
94
|
+
const uploader = new AsyncUploader(url, maxConcurrent);
|
|
95
|
+
|
|
96
|
+
uploadFormCtrl.isFormLoading.value = true;
|
|
97
|
+
try {
|
|
98
|
+
if (fileList.value.length === 0) {
|
|
99
|
+
message.warning('请选择上传的文件!');
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// 开始上传文件
|
|
104
|
+
await uploader.uploadFiles(
|
|
105
|
+
fileList.value,
|
|
106
|
+
(_) => { },
|
|
107
|
+
(files) => {
|
|
108
|
+
uploadFormCtrl.isFormLoading.value = false;
|
|
109
|
+
let err_count = 0;
|
|
110
|
+
for (const file of files) {
|
|
111
|
+
if (file.status === UploadStatus.Error) {
|
|
112
|
+
err_count++;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (!err_count) {
|
|
116
|
+
message.success('全部文件上传成功!');
|
|
117
|
+
emit('after:upload', files);
|
|
118
|
+
dialogSave();
|
|
119
|
+
} else if (err_count < files.length) {
|
|
120
|
+
if (props.continueOnError) {
|
|
121
|
+
message.error('上传结束,部分文件上传失败!');
|
|
122
|
+
message.warning('保存上传成功的文件!');
|
|
123
|
+
emit('after:upload', files);
|
|
124
|
+
dialogSave();
|
|
125
|
+
} else {
|
|
126
|
+
message.error('上传结束,部分文件上传失败,取消保存!');
|
|
127
|
+
}
|
|
128
|
+
} else message.error('上传结束,所有文件上传失败!');
|
|
129
|
+
},
|
|
130
|
+
);
|
|
131
|
+
} catch (error) {
|
|
132
|
+
uploadFormCtrl.isFormLoading.value = false;
|
|
133
|
+
console.error('上传错误:', error);
|
|
134
|
+
message.error('上传错误,请稍后再试!');
|
|
135
|
+
emit('after:upload', fileList.value);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const dialogSave = async () => {
|
|
140
|
+
switch (props.mode) {
|
|
141
|
+
case 'Row':
|
|
142
|
+
if (uploadFormCtrl.formData.value) {
|
|
143
|
+
// 仅修改上传相关字段
|
|
144
|
+
const result: ApiResponse<any> = await gridRowUpdate(props.gridCtrl, uploadFormCtrl.formData.value);
|
|
145
|
+
if (result.status === ResStatus.SUCCESS) {
|
|
146
|
+
uploadFormCtrl.visible.value = false;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
break;
|
|
150
|
+
case 'Page':
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
onMounted(() => {
|
|
156
|
+
const pageCtrl = props.gridCtrl.page;
|
|
157
|
+
uploadUrl.value = uploadUrl.value ?? pageCtrl.urls.upload;
|
|
158
|
+
downloadUrl.value = downloadUrl.value ?? pageCtrl.urls.download;
|
|
159
|
+
if (!uploadUrl.value) {
|
|
160
|
+
message.error('未配置文件上传地址!');
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (!uploadUrl.value.api) uploadUrl.value.api = pageCtrl.api;
|
|
164
|
+
if (uploadUrl.value.authorize === undefined) uploadUrl.value.authorize = pageCtrl.authorize;
|
|
165
|
+
|
|
166
|
+
if (!downloadUrl.value) {
|
|
167
|
+
message.error('未配置文件下载地址!');
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (!downloadUrl.value.api) downloadUrl.value.api = pageCtrl.api;
|
|
171
|
+
if (downloadUrl.value.authorize === undefined) downloadUrl.value.authorize = pageCtrl.authorize;
|
|
172
|
+
|
|
173
|
+
for (const key in uploadFormCtrl.formData.value) {
|
|
174
|
+
if (props.gridCtrl.rowData.value) uploadFormCtrl.formData.value[key] = props.gridCtrl.rowData.value[key];
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const list: UploadFile[] = [];
|
|
178
|
+
emit('before:file-list', uploadFormCtrl, list);
|
|
179
|
+
fileList.value.push(...list);
|
|
180
|
+
open.value = uploadFormCtrl.visible.value;
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const dialogClose = () => {
|
|
184
|
+
uploadFormCtrl.visible.value = false;
|
|
185
|
+
};
|
|
186
|
+
</script>
|
|
187
|
+
<template>
|
|
188
|
+
<Modal title="文件上传" v-model:open="open"
|
|
189
|
+
:wrapClassName="'modal mx-auto ' + ($attrs.width ? 'w-[' + $attrs.width + ']' : 'w-[430px]')"
|
|
190
|
+
@close="dialogClose">
|
|
191
|
+
<UploadList v-model:file-list="fileList" :download-url="downloadUrl!" :max-count="maxCount" :file-ext="fileExt" />
|
|
192
|
+
<template #footer>
|
|
193
|
+
<Space>
|
|
194
|
+
<Button @click="dialogClose">取消</Button>
|
|
195
|
+
<Button @click="dialogUpload" type="primary" :loading="uploadFormCtrl.isFormSaving.value">
|
|
196
|
+
上传文件并保存
|
|
197
|
+
</Button>
|
|
198
|
+
</Space>
|
|
199
|
+
</template>
|
|
200
|
+
</Modal>
|
|
201
|
+
</template>
|
|
202
|
+
<style>
|
|
203
|
+
.modal {
|
|
204
|
+
.ant-modal-content {
|
|
205
|
+
padding: 16px;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.full-modal {
|
|
210
|
+
.ant-modal {
|
|
211
|
+
width: 100% !important;
|
|
212
|
+
max-width: 100%;
|
|
213
|
+
top: 0;
|
|
214
|
+
padding-bottom: 0;
|
|
215
|
+
margin: 0;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.ant-modal-content {
|
|
219
|
+
display: flex;
|
|
220
|
+
flex-direction: column;
|
|
221
|
+
height: calc(100vh);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.ant-modal-body {
|
|
225
|
+
flex: 1;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
</style>
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, watch, onMounted, provide } from 'vue';
|
|
3
|
+
import { Button } from '../../common';
|
|
4
|
+
import { Drawer, Space, theme } from 'ant-design-vue';
|
|
5
|
+
const { useToken } = theme;
|
|
6
|
+
const { token } = useToken();
|
|
7
|
+
import { EditorControl, onFormSave, onFormSaveAs, onFormClose, ProviderKeys } from '@skyfox2000/webbase';
|
|
8
|
+
import { AnyData } from '@skyfox2000/fapi';
|
|
9
|
+
import { ToolIcon } from '../../common';
|
|
10
|
+
|
|
11
|
+
const open = ref<boolean>(false);
|
|
12
|
+
|
|
13
|
+
// interface RuleItem {
|
|
14
|
+
// key: string[]; // 使用字符串数组来表示嵌套属性的路径
|
|
15
|
+
// validate: (value: any) => boolean; //
|
|
16
|
+
// message: string
|
|
17
|
+
// }
|
|
18
|
+
|
|
19
|
+
const props = defineProps<{
|
|
20
|
+
/**
|
|
21
|
+
* 确认按钮文字,空字符串则不显示
|
|
22
|
+
*/
|
|
23
|
+
saveText?: string;
|
|
24
|
+
/**
|
|
25
|
+
* 另存为按钮文字,空字符串则不显示
|
|
26
|
+
*/
|
|
27
|
+
saveAsText?: string;
|
|
28
|
+
/**
|
|
29
|
+
* 取消按钮文字,空字符则不显示
|
|
30
|
+
*/
|
|
31
|
+
cancelText?: string;
|
|
32
|
+
/**
|
|
33
|
+
* 保存数据请求配置
|
|
34
|
+
*/
|
|
35
|
+
editorCtrl: EditorControl<AnyData>;
|
|
36
|
+
}>();
|
|
37
|
+
|
|
38
|
+
const editorCtrl = props.editorCtrl;
|
|
39
|
+
provide(ProviderKeys.EditorControl, editorCtrl);
|
|
40
|
+
|
|
41
|
+
watch(
|
|
42
|
+
() => editorCtrl.visible.value,
|
|
43
|
+
(newVal) => {
|
|
44
|
+
open.value = newVal ?? false;
|
|
45
|
+
},
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
onMounted(() => {
|
|
49
|
+
open.value = editorCtrl.visible.value ?? false;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const drawerClose = () => {
|
|
53
|
+
onFormClose(editorCtrl);
|
|
54
|
+
};
|
|
55
|
+
</script>
|
|
56
|
+
<template>
|
|
57
|
+
<Drawer v-model:open="open" :get-container="false" :closable="false" :header-style="{
|
|
58
|
+
height: '40px',
|
|
59
|
+
padding: '10px 6px 10px 16px',
|
|
60
|
+
backgroundColor: token.colorBgLayout,
|
|
61
|
+
}" :body-style="{
|
|
62
|
+
padding: '10px 16px',
|
|
63
|
+
}" :footer-style="{
|
|
64
|
+
textAlign: 'right',
|
|
65
|
+
}" :style="{
|
|
66
|
+
position: 'absolute',
|
|
67
|
+
boxShadow: 'rgba(0, 0, 0, 0.3) -2px 0px 8px',
|
|
68
|
+
}" width="420px" @close="drawerClose">
|
|
69
|
+
<template #extra>
|
|
70
|
+
<div class="hover:bg-gray-200 w-[24px] h-[24px] rounded-md">
|
|
71
|
+
<ToolIcon class="top-[-2px] left-[2px] w-6 h-6" icon="icon-new" :angle="45" fontsize="24px" clickable
|
|
72
|
+
color="#666" :position="[0, 0]" @click="() => onFormClose(editorCtrl)" />
|
|
73
|
+
</div>
|
|
74
|
+
</template>
|
|
75
|
+
<template #default>
|
|
76
|
+
<slot></slot>
|
|
77
|
+
</template>
|
|
78
|
+
<template #footer>
|
|
79
|
+
<Space>
|
|
80
|
+
<Button @click="() => onFormClose(editorCtrl)" v-if="cancelText !== ''">{{ cancelText ?? '取消' }}</Button>
|
|
81
|
+
<Button @click="() => onFormSaveAs(editorCtrl)"
|
|
82
|
+
v-if="saveAsText !== '' && editorCtrl.saveAsBtnVisible !== false" type="primary"
|
|
83
|
+
:loading="editorCtrl.isFormSaving.value">
|
|
84
|
+
{{ saveAsText ?? '另存为' }}
|
|
85
|
+
</Button>
|
|
86
|
+
<Button @click="() => onFormSave(editorCtrl)" v-if="saveText !== '' && editorCtrl.saveBtnVisible !== false"
|
|
87
|
+
type="primary" :loading="editorCtrl.isFormSaving.value">
|
|
88
|
+
{{ saveText ?? '保存' }}
|
|
89
|
+
</Button>
|
|
90
|
+
</Space>
|
|
91
|
+
</template>
|
|
92
|
+
</Drawer>
|
|
93
|
+
</template>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { EditorControl, ProviderKeys, useFormItemFactory } from '@skyfox2000/webbase';
|
|
3
|
+
import { FormItem } from 'ant-design-vue';
|
|
4
|
+
import { Helper } from '../../common';
|
|
5
|
+
import { inject, ref, useAttrs } from 'vue';
|
|
6
|
+
import { AnyData } from '@skyfox2000/fapi';
|
|
7
|
+
|
|
8
|
+
const props = defineProps<{
|
|
9
|
+
/**
|
|
10
|
+
* 标签文字
|
|
11
|
+
*/
|
|
12
|
+
label?: string;
|
|
13
|
+
/**
|
|
14
|
+
* 验证规则
|
|
15
|
+
*/
|
|
16
|
+
rule?: string;
|
|
17
|
+
/**
|
|
18
|
+
* 帮助文字
|
|
19
|
+
*/
|
|
20
|
+
helper?: string;
|
|
21
|
+
/**
|
|
22
|
+
* 宽度
|
|
23
|
+
*/
|
|
24
|
+
width?: string;
|
|
25
|
+
}>();
|
|
26
|
+
|
|
27
|
+
// 关闭自动继承属性到根元素
|
|
28
|
+
defineOptions({
|
|
29
|
+
inheritAttrs: false,
|
|
30
|
+
});
|
|
31
|
+
const attrs = useAttrs(); // 手动获取 $attrs
|
|
32
|
+
|
|
33
|
+
const editorCtrl = inject(ProviderKeys.EditorControl, undefined) as EditorControl<AnyData> | undefined;
|
|
34
|
+
const errInfo = useFormItemFactory(props, editorCtrl);
|
|
35
|
+
|
|
36
|
+
const visible = ref(false);
|
|
37
|
+
setTimeout(() => {
|
|
38
|
+
// 延迟显示,提高性能
|
|
39
|
+
visible.value = true;
|
|
40
|
+
}, 30);
|
|
41
|
+
|
|
42
|
+
// 参考代码
|
|
43
|
+
// this.$parent.$el.scrollIntoView({
|
|
44
|
+
// //滚动到指定节点
|
|
45
|
+
// block: "center", //值有start,center,end,nearest,当前显示在视图区域中间
|
|
46
|
+
// behavior: "smooth" //值有auto、instant,smooth,缓动动画(当前是慢速的)
|
|
47
|
+
// });
|
|
48
|
+
</script>
|
|
49
|
+
<template>
|
|
50
|
+
<div :class="['w-full relative mb-1', width]">
|
|
51
|
+
<FormItem
|
|
52
|
+
v-if="visible"
|
|
53
|
+
:required="!!rule && editorCtrl?.formRules?.value?.[rule]?.required"
|
|
54
|
+
class="!w-[95%] relative"
|
|
55
|
+
v-bind="attrs"
|
|
56
|
+
:class="[rule ? '' : 'mb-3']"
|
|
57
|
+
>
|
|
58
|
+
<template #label>
|
|
59
|
+
<span :class="[errInfo.errClass ? 'text-[#ff4d4f]' : '', 'w-full']"> {{ label }}</span>
|
|
60
|
+
</template>
|
|
61
|
+
<div class="w-full flex items-center">
|
|
62
|
+
<div class="flex-grow">
|
|
63
|
+
<slot></slot>
|
|
64
|
+
</div>
|
|
65
|
+
<div class="w-8 mt-[-2px]">
|
|
66
|
+
<slot name="helper">
|
|
67
|
+
<Helper v-if="helper" :text="helper" />
|
|
68
|
+
</slot>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
</FormItem>
|
|
72
|
+
<span class="absolute bottom-[3px] left-[85px] text-[12px] text-[#ff4d4fcc] block" v-if="errInfo.errClass">
|
|
73
|
+
{{ errInfo.msg }}
|
|
74
|
+
</span>
|
|
75
|
+
</div>
|
|
76
|
+
</template>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { EditorControl, ProviderKeys, onFormSave } from '@skyfox2000/webbase';
|
|
3
|
+
import { AnyData } from '@skyfox2000/fapi';
|
|
4
|
+
import { Form } from 'ant-design-vue';
|
|
5
|
+
import { inject } from 'vue';
|
|
6
|
+
// 使用以下统一控制表单显示
|
|
7
|
+
// :label-col="{ flex: '60px' }"
|
|
8
|
+
// :wrapper-col="{ flex: '200px' }"
|
|
9
|
+
// 单独项使用FormItem控制
|
|
10
|
+
const props = defineProps<{
|
|
11
|
+
/**
|
|
12
|
+
* 快速配置表单标签宽度
|
|
13
|
+
*/
|
|
14
|
+
labelWidth?: string;
|
|
15
|
+
/**
|
|
16
|
+
* 快速配置表单项宽度
|
|
17
|
+
*/
|
|
18
|
+
wrapperWidth?: string;
|
|
19
|
+
/**
|
|
20
|
+
* 表单配置信息
|
|
21
|
+
*/
|
|
22
|
+
editorCtrl?: EditorControl<AnyData>;
|
|
23
|
+
}>();
|
|
24
|
+
|
|
25
|
+
const editorCtrl =
|
|
26
|
+
props.editorCtrl ?? (inject(ProviderKeys.EditorControl, undefined) as EditorControl<AnyData> | undefined);
|
|
27
|
+
</script>
|
|
28
|
+
<template>
|
|
29
|
+
<Form
|
|
30
|
+
:label-col="{ flex: props.labelWidth ?? '85px' }"
|
|
31
|
+
:wrapper-col="{
|
|
32
|
+
flex: props.wrapperWidth ?? '1',
|
|
33
|
+
}"
|
|
34
|
+
:style="{
|
|
35
|
+
display: 'flex',
|
|
36
|
+
flexWrap: 'wrap',
|
|
37
|
+
}"
|
|
38
|
+
v-submit="
|
|
39
|
+
() => {
|
|
40
|
+
if (editorCtrl) {
|
|
41
|
+
onFormSave(editorCtrl);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
"
|
|
45
|
+
>
|
|
46
|
+
<slot></slot>
|
|
47
|
+
</Form>
|
|
48
|
+
</template>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import Dialog from './dialog/index.vue';
|
|
2
|
+
export { Dialog };
|
|
3
|
+
import UploadForm from './dialog/uploadForm.vue';
|
|
4
|
+
export { UploadForm };
|
|
5
|
+
import ExcelForm from './dialog/excelForm.vue';
|
|
6
|
+
export { ExcelForm };
|
|
7
|
+
|
|
8
|
+
import Drawer from './drawer/index.vue';
|
|
9
|
+
export { Drawer };
|
|
10
|
+
|
|
11
|
+
import Form from './form/index.vue';
|
|
12
|
+
export { Form };
|
|
13
|
+
import FormItem from './form/formItem.vue';
|
|
14
|
+
export { FormItem };
|
|
15
|
+
|
|
16
|
+
import Search from './search/index.vue';
|
|
17
|
+
export { Search };
|
|
18
|
+
import SearchItem from './search/searchItem.vue';
|
|
19
|
+
export { SearchItem };
|
|
20
|
+
|
|
21
|
+
import Table from './table/index.vue';
|
|
22
|
+
export { Table };
|
|
23
|
+
import TableOperate from './table/tableOperate.vue';
|
|
24
|
+
export { TableOperate };
|
|
25
|
+
|
|
26
|
+
import Toolbar from './toolbar/index.vue';
|
|
27
|
+
export { Toolbar };
|
|
28
|
+
import Icontool from './toolbar/icontool.vue';
|
|
29
|
+
export { Icontool };
|
|
30
|
+
|
|
31
|
+
import Tree from './tree/index.vue';
|
|
32
|
+
export { Tree };
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { onMounted, ref, watch, useSlots, VNode } from 'vue';
|
|
3
|
+
import { Form, Space } from 'ant-design-vue';
|
|
4
|
+
import SearchItem from './searchItem.vue';
|
|
5
|
+
import { Button } from '../../common';
|
|
6
|
+
import { GridControl } from '@skyfox2000/webbase';
|
|
7
|
+
import { AnyData } from '@skyfox2000/fapi';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 搜索表单BUG
|
|
11
|
+
* 添加ref="searchForm" 后打包报错
|
|
12
|
+
*/
|
|
13
|
+
// ref="searchForm"
|
|
14
|
+
// The inferred type of '__VLS_template' cannot be named without a reference to '.pnpm/vue-types@3.0.2_vue@3.5.16_typescript@5.8.3_/node_modules/vue-types'. This is likely not portable. A type annotation is necessary.
|
|
15
|
+
// 225 function __VLS_template() {
|
|
16
|
+
//
|
|
17
|
+
//
|
|
18
|
+
|
|
19
|
+
// 使用以下统一控制表单显示
|
|
20
|
+
// :label-col="{ flex: '60px' }"
|
|
21
|
+
// :wrapper-col="{ flex: '200px' }"
|
|
22
|
+
// 单独项使用FormItem控制
|
|
23
|
+
const props = defineProps<{
|
|
24
|
+
/**
|
|
25
|
+
* 搜索条件
|
|
26
|
+
*/
|
|
27
|
+
search: Record<string, any>;
|
|
28
|
+
/**
|
|
29
|
+
* 表格控制对象
|
|
30
|
+
*/
|
|
31
|
+
gridCtrl: GridControl<AnyData>;
|
|
32
|
+
}>();
|
|
33
|
+
|
|
34
|
+
// const pageData = props.gridData.page;
|
|
35
|
+
|
|
36
|
+
const emits = defineEmits<{
|
|
37
|
+
(e: 'update:search', val: Record<string, any>): void;
|
|
38
|
+
}>();
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 搜索按钮前的占位数量,1或者2
|
|
42
|
+
*/
|
|
43
|
+
const holderSize = ref(0);
|
|
44
|
+
const defaultSlots = ref(0);
|
|
45
|
+
const controlSlots = ref(0);
|
|
46
|
+
const getSlotLen = (items: VNode[]): number => {
|
|
47
|
+
let count = 0;
|
|
48
|
+
for (let i = 0; i < items.length; i++) {
|
|
49
|
+
if (typeof items[i].type === 'object') count++;
|
|
50
|
+
}
|
|
51
|
+
return count;
|
|
52
|
+
};
|
|
53
|
+
const slots = useSlots();
|
|
54
|
+
const updateHolderSize = () => {
|
|
55
|
+
defaultSlots.value = 0;
|
|
56
|
+
controlSlots.value = 0;
|
|
57
|
+
if (slots.default) defaultSlots.value = getSlotLen(slots.default({}));
|
|
58
|
+
if (props.gridCtrl.searchBar && slots.control) controlSlots.value = getSlotLen(slots.control({}));
|
|
59
|
+
|
|
60
|
+
holderSize.value = 2 - ((defaultSlots.value + controlSlots.value) % 3);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
watch(
|
|
64
|
+
() => props.gridCtrl.searchBar,
|
|
65
|
+
() => {
|
|
66
|
+
updateHolderSize();
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const defaultData: Record<string, any> = JSON.parse(JSON.stringify(props.search));
|
|
71
|
+
|
|
72
|
+
onMounted(() => {
|
|
73
|
+
updateHolderSize();
|
|
74
|
+
let search = { ...props.search };
|
|
75
|
+
props.gridCtrl.gridQuery = {
|
|
76
|
+
...props.gridCtrl.gridQuery,
|
|
77
|
+
Query: {
|
|
78
|
+
...props.gridCtrl.gridQuery?.Query,
|
|
79
|
+
...search,
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const onSearch = () => {
|
|
85
|
+
let search = { ...props.search };
|
|
86
|
+
props.gridCtrl.gridQuery = {
|
|
87
|
+
...props.gridCtrl.gridQuery,
|
|
88
|
+
Query: {
|
|
89
|
+
...props.gridCtrl.gridQuery?.Query,
|
|
90
|
+
...search,
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
props.gridCtrl.reload.value = true;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const onReset = () => {
|
|
97
|
+
const data = JSON.parse(JSON.stringify(defaultData));
|
|
98
|
+
for (const key in props.search) {
|
|
99
|
+
if (data[key] === undefined) {
|
|
100
|
+
data[key] = undefined;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
emits('update:search', data);
|
|
104
|
+
};
|
|
105
|
+
</script>
|
|
106
|
+
<template>
|
|
107
|
+
<Form
|
|
108
|
+
v-if="defaultSlots + controlSlots > 0"
|
|
109
|
+
:label-col="{ flex: '60px' }"
|
|
110
|
+
:style="{
|
|
111
|
+
flexWrap: 'wrap',
|
|
112
|
+
borderBottom: '1px solid #e9e9e9',
|
|
113
|
+
}"
|
|
114
|
+
class="flex mb-[10px]"
|
|
115
|
+
v-submit="onSearch"
|
|
116
|
+
>
|
|
117
|
+
<!-- 默认插槽 -->
|
|
118
|
+
<slot></slot>
|
|
119
|
+
<!-- 受控插槽 -->
|
|
120
|
+
<slot name="control" v-if="gridCtrl.searchBar"></slot>
|
|
121
|
+
<!-- 表单操作按钮 占位数量 -->
|
|
122
|
+
<SearchItem class="w-1/3" v-if="holderSize >= 1"> </SearchItem>
|
|
123
|
+
<SearchItem class="w-1/3" v-if="holderSize >= 2"> </SearchItem>
|
|
124
|
+
<SearchItem
|
|
125
|
+
v-if="defaultSlots || gridCtrl.searchBar"
|
|
126
|
+
class="w-1/3 flex justify-end text-right pr-5"
|
|
127
|
+
:wrapper-col="{ flex: 'auto' }"
|
|
128
|
+
>
|
|
129
|
+
<Space>
|
|
130
|
+
<Button type="primary" @click="onSearch" icon="icon-search">搜索</Button>
|
|
131
|
+
<Button @click="onReset" icon="icon-reset">重置</Button>
|
|
132
|
+
</Space>
|
|
133
|
+
</SearchItem>
|
|
134
|
+
</Form>
|
|
135
|
+
</template>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { inject, useAttrs } from 'vue';
|
|
3
|
+
import { ProviderKeys, EditorControl, useFormItemFactory } from '@skyfox2000/webbase';
|
|
4
|
+
import { FormItem } from 'ant-design-vue';
|
|
5
|
+
import { AnyData } from '@skyfox2000/fapi';
|
|
6
|
+
|
|
7
|
+
const props = defineProps<{
|
|
8
|
+
/**
|
|
9
|
+
* 标签文字
|
|
10
|
+
*/
|
|
11
|
+
label?: string;
|
|
12
|
+
/**
|
|
13
|
+
* 宽度
|
|
14
|
+
*/
|
|
15
|
+
width?: string;
|
|
16
|
+
/**
|
|
17
|
+
* 验证规则
|
|
18
|
+
*/
|
|
19
|
+
rule?: string;
|
|
20
|
+
}>();
|
|
21
|
+
// 关闭自动继承属性到根元素
|
|
22
|
+
defineOptions({
|
|
23
|
+
inheritAttrs: false,
|
|
24
|
+
});
|
|
25
|
+
const attrs = useAttrs(); // 手动获取 $attrs
|
|
26
|
+
|
|
27
|
+
const editorCtrl = inject(ProviderKeys.EditorControl, undefined) as EditorControl<AnyData> | undefined;
|
|
28
|
+
const errInfo = useFormItemFactory(props, editorCtrl);
|
|
29
|
+
</script>
|
|
30
|
+
<template>
|
|
31
|
+
<div class="w-1/3 relative mb-1">
|
|
32
|
+
<FormItem
|
|
33
|
+
:required="rule !== undefined"
|
|
34
|
+
class="w-[90%] relative"
|
|
35
|
+
v-bind="attrs"
|
|
36
|
+
:class="[rule ? '' : 'mb-3', width]"
|
|
37
|
+
:labelCol="{ span: 6 }"
|
|
38
|
+
>
|
|
39
|
+
<template #label v-if="label">
|
|
40
|
+
<span :class="[errInfo.errClass ? 'text-[#ff4d4f]' : '', 'w-full']"> {{ label }}</span>
|
|
41
|
+
</template>
|
|
42
|
+
<div class="flex items-center">
|
|
43
|
+
<div class="flex-grow pl-1">
|
|
44
|
+
<slot></slot>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</FormItem>
|
|
48
|
+
<span class="absolute bottom-[3px] left-[85px] text-[12px] text-[#ff4d4fcc] block" v-if="errInfo.msg">
|
|
49
|
+
{{ errInfo.msg }}
|
|
50
|
+
</span>
|
|
51
|
+
</div>
|
|
52
|
+
</template>
|