cloud-web-corejs 1.0.281 → 1.1.0-dev.10

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.
Files changed (192) hide show
  1. package/package.json +6 -2
  2. package/src/components/VabUpload/image-viewer.vue +442 -442
  3. package/src/components/VabUpload/index.vue +45 -3
  4. package/src/components/VabUpload/mixins.js +126 -19
  5. package/src/components/VabUpload/view.vue +248 -209
  6. package/src/components/baseTabs/mixins.js +181 -181
  7. package/src/components/bizTab/BizBillActions.vue +129 -0
  8. package/src/components/bizTab/BizTabListPage.vue +391 -0
  9. package/src/components/bizTab/README.md +378 -0
  10. package/src/components/bizTab/billTableUtil.js +48 -0
  11. package/src/components/bizTab/billValidators.js +136 -0
  12. package/src/components/bizTab/bizBillDetailMixin.js +705 -0
  13. package/src/components/bizTab/index.js +24 -0
  14. package/src/components/excelExport/exportFieldDialog.vue +23 -12
  15. package/src/components/excelExport/exportItemConfigUtil.js +30 -0
  16. package/src/components/excelExport/mixins.js +3 -3
  17. package/src/components/excelImport/index.vue +156 -156
  18. package/src/components/jsonImport/index.vue +1 -1
  19. package/src/components/langImport/index.vue +1 -1
  20. package/src/components/mobile/statusTag/mixins.js +1 -61
  21. package/src/components/mobile/wf/addTaskUserdialog.vue +23 -3
  22. package/src/components/mobile/wf/content.vue +1705 -1556
  23. package/src/components/mobile/wf/deleteTaskUserDialog.vue +22 -3
  24. package/src/components/mobile/wf/mixins/wfModifyDialogMixin.js +8 -6
  25. package/src/components/mobile/wf/selectUserDialog.vue +122 -0
  26. package/src/components/mobile/wf/setCandidateDialog.vue +25 -4
  27. package/src/components/mobile/wf/urgingDialog.vue +26 -3
  28. package/src/components/mobile/wf/wfModifyDialog.vue +4 -0
  29. package/src/components/obsUpload/index.vue +1 -1
  30. package/src/components/table/config.js +78 -78
  31. package/src/components/table/index.js +1276 -1276
  32. package/src/components/table/plugins/cell-area/index.js +1055 -0
  33. package/src/components/table/plugins/cell-area/index.scss +77 -0
  34. package/src/components/table/plugins/cell-area/util.js +224 -0
  35. package/src/components/table/tableForm.vue +330 -330
  36. package/src/components/table/tableFormMixin.js +318 -318
  37. package/src/components/table/vxeFilter/index.js +163 -163
  38. package/src/components/table/vxeFilter/mixin.js +316 -316
  39. package/src/components/wf/content.vue +1188 -1188
  40. package/src/components/wf/wf.js +40 -20
  41. package/src/components/wf/wfActionDropdown.vue +1 -1
  42. package/src/components/wf/wfActionItems.js +1 -1
  43. package/src/components/xform/docs/2026-08 xform H5 P0 /345/256/236/347/216/260/350/247/204/346/240/274.md" +528 -0
  44. package/src/components/xform/docs/2026-08 xform H5 P1 /345/256/236/347/216/260/350/247/204/346/240/274.md" +412 -0
  45. package/src/components/xform/docs/2026-08 xform H5 P2 /345/256/236/347/216/260/350/247/204/346/240/274.md" +287 -0
  46. package/src/components/xform/docs/2026-08 xform /347/247/273/345/212/250/347/253/257/345/270/203/345/261/200/345/257/271/351/275/220 bill_setting /346/226/271/346/241/210.md" +400 -0
  47. package/src/components/xform/form-designer/designer.js +51 -52
  48. package/src/components/xform/form-designer/form-widget/container-widget/data-table-widget.vue +269 -269
  49. package/src/components/xform/form-designer/form-widget/container-widget/detail-h5-widget.vue +18 -2
  50. package/src/components/xform/form-designer/form-widget/container-widget/detail-temp-widget.vue +132 -0
  51. package/src/components/xform/form-designer/form-widget/container-widget/detail-widget.vue +250 -250
  52. package/src/components/xform/form-designer/form-widget/container-widget/h5-card-pane-widget.vue +23 -2
  53. package/src/components/xform/form-designer/form-widget/container-widget/h5-card-widget.vue +30 -1
  54. package/src/components/xform/form-designer/form-widget/dialog/fileReferenceDialog.vue +319 -320
  55. package/src/components/xform/form-designer/form-widget/dialog/formDialog.vue +365 -365
  56. package/src/components/xform/form-designer/form-widget/dialog/importDialog.vue +185 -185
  57. package/src/components/xform/form-designer/form-widget/dialog/searchFormDialog.vue +554 -555
  58. package/src/components/xform/form-designer/form-widget/dialog/vabSearchDialog.vue +409 -409
  59. package/src/components/xform/form-designer/form-widget/field-widget/a-link-widget.vue +150 -132
  60. package/src/components/xform/form-designer/form-widget/field-widget/date-range-widget.vue +114 -114
  61. package/src/components/xform/form-designer/form-widget/field-widget/date-widget.vue +154 -154
  62. package/src/components/xform/form-designer/form-widget/field-widget/form-item-wrapper.vue +47 -1
  63. package/src/components/xform/form-designer/form-widget/field-widget/mixins/date-limit-mixin.js +178 -178
  64. package/src/components/xform/form-designer/form-widget/field-widget/mixins/time-limit-mixin.js +77 -77
  65. package/src/components/xform/form-designer/form-widget/field-widget/select-export-item-button-widget.vue +6 -0
  66. package/src/components/xform/form-designer/form-widget/field-widget/select-widget.vue +139 -139
  67. package/src/components/xform/form-designer/form-widget/field-widget/singleUpload-widget.vue +1 -1
  68. package/src/components/xform/form-designer/form-widget/field-widget/time-range-widget.vue +106 -106
  69. package/src/components/xform/form-designer/form-widget/field-widget/time-widget.vue +134 -134
  70. package/src/components/xform/form-designer/form-widget/field-widget/vabUpload-widget.vue +3 -2
  71. package/src/components/xform/form-designer/indexMixin.js +35 -1
  72. package/src/components/xform/form-designer/setting-panel/form-setting.vue +39 -39
  73. package/src/components/xform/form-designer/setting-panel/property-editor/container-data-table/data-table-editor.vue +10 -10
  74. package/src/components/xform/form-designer/setting-panel/property-editor/container-data-table/exportItemColumns-dialog.vue +438 -432
  75. package/src/components/xform/form-designer/setting-panel/property-editor/container-data-table/table-column-dialog.vue +2103 -2103
  76. package/src/components/xform/form-designer/setting-panel/property-editor/container-detail/detail-temp-edito.vue +90 -0
  77. package/src/components/xform/form-designer/setting-panel/property-editor/container-grid/gutter-editor.vue +82 -82
  78. package/src/components/xform/form-designer/setting-panel/property-editor/container-list-h5/list-h5-editor.vue +833 -846
  79. package/src/components/xform/form-designer/setting-panel/property-editor/container-table/table-dynamicField-editor.vue +8 -8
  80. package/src/components/xform/form-designer/setting-panel/property-editor/dropdownFlag-editor.vue +137 -137
  81. package/src/components/xform/form-designer/setting-panel/property-editor/field-button/search-dialog-event-editor.vue +237 -237
  82. package/src/components/xform/form-designer/setting-panel/property-editor/field-date/date-defaultValue-editor.vue +43 -43
  83. package/src/components/xform/form-designer/setting-panel/property-editor/field-date-range/date-range-defaultValue-editor.vue +43 -43
  84. package/src/components/xform/form-designer/setting-panel/property-editor/field-import-button/import2-button-editor.vue +96 -96
  85. package/src/components/xform/form-designer/setting-panel/property-editor/field-table-export-button/select-export-item-button-editor.vue +51 -0
  86. package/src/components/xform/form-designer/setting-panel/property-editor/field-time/time-defaultValue-editor.vue +42 -42
  87. package/src/components/xform/form-designer/setting-panel/property-editor/field-time-range/time-range-defaultValue-editor.vue +43 -43
  88. package/src/components/xform/form-designer/setting-panel/property-editor/formScriptEnabled-editor.vue +158 -158
  89. package/src/components/xform/form-designer/setting-panel/property-editor/h5Span-editor.vue +51 -0
  90. package/src/components/xform/form-designer/setting-panel/property-editor/itemStyle-editor.vue +39 -0
  91. package/src/components/xform/form-designer/setting-panel/property-editor/name-editor.vue +188 -188
  92. package/src/components/xform/form-designer/setting-panel/property-editor/styleTempClass-editor.vue +51 -0
  93. package/src/components/xform/form-designer/setting-panel/property-editor/textFlag-editor.vue +347 -347
  94. package/src/components/xform/form-designer/setting-panel/propertyRegister.js +12 -0
  95. package/src/components/xform/form-designer/toolbar-panel/index.vue +884 -874
  96. package/src/components/xform/form-designer/toolbar-panel/indexMixin.js +14 -0
  97. package/src/components/xform/form-designer/widget-panel/index.vue +11 -7
  98. package/src/components/xform/form-designer/widget-panel/indexMixin.js +30 -6
  99. package/src/components/xform/form-designer/widget-panel/widgetsConfig.js +112 -4
  100. package/src/components/xform/form-render/container-item/data-table-mixin.js +151 -93
  101. package/src/components/xform/form-render/container-item/detail-h5-item.vue +204 -34
  102. package/src/components/xform/form-render/container-item/detail-temp-item.vue +110 -0
  103. package/src/components/xform/form-render/container-item/h5-card-pane-item.vue +160 -140
  104. package/src/components/xform/form-render/container-item/list-h5-item.vue +1913 -1699
  105. package/src/components/xform/form-render/index.vue +153 -147
  106. package/src/components/xform/form-render/indexMixin.js +35 -3
  107. package/src/components/xform/lang/en-US.js +14 -0
  108. package/src/components/xform/lang/zh-CN.js +17 -0
  109. package/src/components/xform/mixins/defaultHandle.js +707 -707
  110. package/src/components/xform/styles/h5.scss +2238 -0
  111. package/src/components/xform/utils/textMaskUtil.js +182 -179
  112. package/src/components/xform/utils/treeTableUtil.js +1292 -1265
  113. package/src/components/xform/utils/util.js +56 -11
  114. package/src/directive/append-to-body/index.js +48 -0
  115. package/src/index.js +13 -4
  116. package/src/layout/components/Sidebar/default.vue +1655 -1655
  117. package/src/layout/components/extractedCode/viewDialog.vue +7 -7
  118. package/src/router/index.js +48 -27
  119. package/src/router/modules/customer.js +71 -14
  120. package/src/store/modules/permission.js +17 -18
  121. package/src/utils/assetUrl.js +19 -0
  122. package/src/utils/pdfUtil.js +429 -429
  123. package/src/utils/resolveViewComponent.js +142 -16
  124. package/src/utils/vab.js +1283 -1279
  125. package/src/views/bd/project/branch/bd_branch/edit.vue +145 -0
  126. package/src/views/bd/project/branch/bd_branch/list.vue +72 -0
  127. package/src/views/bd/project/branch/bd_branch/menuKindDialog.vue +106 -0
  128. package/src/views/bd/project/branch/bd_branch/mixins/edit.js +189 -0
  129. package/src/views/bd/project/branch/bd_branch/mixins/list.js +124 -0
  130. package/src/views/bd/project/branch/bd_branch/mixins/menuKindDialog.js +85 -0
  131. package/src/views/bd/project/branch/form_script/list.vue +31 -0
  132. package/src/views/bd/project/branch/form_template/list.vue +30 -0
  133. package/src/views/bd/project/branch/menu_kind/list.vue +31 -0
  134. package/src/views/bd/project/common/form_script/list.vue +16 -0
  135. package/src/views/bd/project/common/form_template/list.vue +15 -0
  136. package/src/views/bd/project/common/menu_kind/list.vue +15 -0
  137. package/src/views/bd/project/core/branchContext.js +100 -0
  138. package/src/views/bd/project/core/branchPage.js +78 -0
  139. package/src/views/bd/project/core/branchPageWrap.vue +225 -0
  140. package/src/views/bd/project/core/branchScope.js +44 -0
  141. package/src/views/bd/project/core/branchSearchPage.js +285 -0
  142. package/src/views/bd/project/core/branchSelect.vue +85 -0
  143. package/src/views/bd/project/core/branchTreeBar.vue +81 -0
  144. package/src/views/bd/project/core/httpBranchPatch.js +58 -0
  145. package/src/views/bd/project/datatable/menu_kind/list.vue +15 -0
  146. package/src/views/bd/project/datatable/table_model/list.vue +15 -0
  147. package/src/views/bd/setting/bd_company_env/dialog.vue +174 -174
  148. package/src/views/bd/setting/form_template/edit.vue +378 -356
  149. package/src/views/bd/setting/form_template/formDesignerDialog.vue +6 -0
  150. package/src/views/bd/setting/form_template/formTemplateType.js +43 -0
  151. package/src/views/bd/setting/form_template/list.vue +304 -303
  152. package/src/views/bd/setting/form_template/mixins/edit.js +344 -280
  153. package/src/views/bd/setting/form_template/mixins/list.js +748 -721
  154. package/src/views/bd/setting/table_model/edit.vue +1066 -1066
  155. package/src/views/bd/setting/table_model/mixins/edit.js +1455 -1455
  156. package/src/views/bd/setting/table_model/mixins/zdDialog.js +148 -148
  157. package/src/views/demo/bizTab/bill/billConfig.js +41 -0
  158. package/src/views/demo/bizTab/bill/detail.vue +436 -0
  159. package/src/views/demo/bizTab/bill/list.vue +288 -0
  160. package/src/views/demo/bizTab/bill/productDialog.vue +176 -0
  161. package/src/views/demo/bizTab/simple/billApi.js +123 -0
  162. package/src/views/demo/bizTab/simple/detail.vue +407 -0
  163. package/src/views/demo/bizTab/simple/list.vue +217 -0
  164. package/src/views/demo/bizTab/standalone/index.vue +121 -0
  165. package/src/views/demo/bizTab/wf/billConfig.js +44 -0
  166. package/src/views/demo/bizTab/wf/detail.vue +661 -0
  167. package/src/views/demo/bizTab/wf/list.vue +242 -0
  168. package/src/views/support/form-dialog-demo/demoPickerDialog.vue +72 -0
  169. package/src/views/support/form-dialog-demo/index.vue +537 -0
  170. package/src/views/user/file_view_ins/list.vue +970 -970
  171. package/src/views/user/form/vform/designer.vue +823 -821
  172. package/src/views/user/home/default.vue +1117 -1117
  173. package/src/views/user/home/default2.vue +1 -1
  174. package/src/views/user/home/index.vue +103 -101
  175. package/src/views/user/home/wjl/content.vue +1569 -0
  176. package/src/views/user/notify_message/dialog.vue +139 -137
  177. package/src/views/user/outLink/cc_form_view.vue +188 -0
  178. package/src/views/user/outLink/form_view.vue +202 -202
  179. package/src/views/user/outLink/index.vue +110 -110
  180. package/src/views/user/outLink/view.vue +3 -3
  181. package/src/views/user/role/edit.vue +632 -632
  182. package/src/views/user/role/list.vue +260 -260
  183. package/src/views/user/wf/iframe/index.vue +51 -51
  184. package/src/views/user/wf/iframe/index2.vue +64 -64
  185. package/src/views/user/wf/wf_manage/list.vue +1112 -1116
  186. package/src/views/user/wf/wf_manage/list2.vue +871 -875
  187. package/src/views/user/wf/wf_manage/wfContentDialog.vue +134 -131
  188. package/src/views/user/wf/wf_obj_config/importItemDialog.vue +1 -1
  189. package/src/components/xform/form-designer/form-widget/field-widget/dropdown-menu-widget.vue +0 -106
  190. package/src/components/xform/form-designer/form-widget/field-widget/tableexportbuttonwidget.vue +0 -99
  191. package/src/components/xform/form-render/container-item/list-h5-item2.vue +0 -1340
  192. package/src/utils/wf.js +0 -766
package/src/utils/vab.js CHANGED
@@ -1,1279 +1,1283 @@
1
- /**version-1.0*/
2
- let install = {};
3
-
4
- import request from "./request";
5
- import * as lodash from "lodash";
6
- import { Loading, Message, MessageBox, Notification, Form } from "element-ui";
7
- import store from "../store";
8
- import ElImageViewer from "../components/VabUpload/image-viewer";
9
-
10
- import { getToken } from "./auth";
11
- import XEUtils from "xe-utils";
12
-
13
- import prefixConfig from "@/prefixConfig.js";
14
- import moment from "moment";
15
- import { openView } from "./repeatOpen";
16
-
17
- let imFun = {
18
- request,
19
- lodash,
20
- Loading,
21
- Message,
22
- MessageBox,
23
- Notification,
24
- Form,
25
- store,
26
- getToken,
27
- prefixConfig,
28
- };
29
-
30
- function reqImg(a) {
31
- return require("@/resources/images/" + a);
32
- }
33
-
34
- const FILE_ICON_NAME_MAP = {
35
- word: "ico-wrod.svg",
36
- excel: "ico-excel.svg",
37
- ppt: "ico-ppt.svg",
38
- pdf: "ico-pdf.svg",
39
- picture: "ico-photo.svg",
40
- video: "ico-video.svg",
41
- audio: "ico-music.svg",
42
- html: "ico-html.svg",
43
- txt: "ico-txt.svg",
44
- java: "ico-java.svg",
45
- vue: "ico-vue.svg",
46
- ftl: "ico-ftl.svg",
47
- xml: "ico-xml.svg",
48
- flash: "ico-flash.svg",
49
- zip: "ico-yasuobao.svg",
50
- exe: "ico-ext.svg",
51
- psd: "ico-psd.svg",
52
- folder: "ico-wenjianjia.svg",
53
- other: "ico-default_wenjian.svg",
54
- };
55
-
56
- const FILE_ICON_TYPE_MAP = {
57
- doc: "word",
58
- docx: "word",
59
- xls: "excel",
60
- xlsx: "excel",
61
- ppt: "ppt",
62
- pptx: "ppt",
63
- pdf: "pdf",
64
- jpg: "picture",
65
- jpeg: "picture",
66
- png: "picture",
67
- gif: "picture",
68
- mp3: "video",
69
- mp4: "video",
70
- mpg: "video",
71
- mkv: "video",
72
- rmvb: "video",
73
- avi: "video",
74
- mov: "video",
75
- wav: "audio",
76
- html: "html",
77
- htm: "html",
78
- txt: "txt",
79
- java: "java",
80
- vue: "vue",
81
- ftl: "ftl",
82
- xml: "xml",
83
- swf: "flash",
84
- zip: "zip",
85
- rar: "zip",
86
- "7z": "zip",
87
- // exe: 'exe',
88
- psd: "psd",
89
- };
90
-
91
- let typeList = [
92
- "doc",
93
- "docx",
94
- "xls",
95
- "xlsx",
96
- "ppt",
97
- "pptx",
98
- "csv",
99
- "wps",
100
- "dps",
101
- "et",
102
- "ett",
103
- "wpt",
104
- "vsd",
105
- "vsdx",
106
- "wmf",
107
- "emf",
108
- "psd",
109
- "eps",
110
- "pdf",
111
- "xmind",
112
- "obj",
113
- "3ds",
114
- "stl",
115
- "ply",
116
- "gltf",
117
- "glb",
118
- "off",
119
- "3dm",
120
- "fbx",
121
- "dae",
122
- "wrl",
123
- "3mf",
124
- "ifc",
125
- "brep",
126
- "step",
127
- "iges",
128
- "fcstd",
129
- "bim",
130
- "dwg",
131
- "dxf",
132
- "dwf",
133
- "iges",
134
- "igs",
135
- "dwt",
136
- "dng",
137
- "ifc",
138
- "dwfx",
139
- "stl",
140
- "cf2",
141
- "plt",
142
- "txt",
143
- "xml",
144
- "md",
145
- "java",
146
- "php",
147
- "py",
148
- "js",
149
- "css",
150
- "zip",
151
- "rar",
152
- "jar",
153
- "tar",
154
- "gzip",
155
- "7z",
156
- "mp3",
157
- "wav",
158
- "mp4",
159
- "flv",
160
- "avi",
161
- "mov",
162
- "rm",
163
- "mkv",
164
- "mpeg",
165
- "mpg",
166
- "rmvb",
167
- "wmv",
168
- "3gp",
169
- "swf",
170
- "drawio",
171
- "tif",
172
- "tiff",
173
- "jfif",
174
- "webp",
175
- "tga",
176
- "svg",
177
- "vue",
178
- "ftl",
179
- ];
180
-
181
- const accessToken = imFun.store.getters["user/token"];
182
-
183
- const loadingText = "";
184
- const messageDuration = 3000;
185
-
186
- install = (Vue, opts = {}) => {
187
- /**http请求*/
188
- let $http = async function (option) {
189
- option = option || {};
190
- if (!option.loadingTarget && this.$el) {
191
- option.loadingTarget = this.$el;
192
- }
193
- if (!option.vueTarget) {
194
- option.vueTarget = this;
195
- }
196
- if (option.sync === false) {
197
- return await imFun.request(option);
198
- } else {
199
- return imFun.request(option);
200
- }
201
- };
202
-
203
- Vue.prototype.$commonHttp = function (opts) {
204
- let defaultOption = {
205
- addCreateInfo: true,
206
- queryCreateInfo: window.$vueRoot.$store.getters.queryCreateInfo || "0",
207
- };
208
- let option = Object.assign({}, defaultOption, opts);
209
- if (opts.addCreateInfo === null || opts.addCreateInfo === undefined) {
210
- option.addCreateInfo = defaultOption.addCreateInfo;
211
- }
212
- if (
213
- opts.queryCreateInfo === null ||
214
- opts.queryCreateInfo === undefined ||
215
- opts.queryCreateInfo === true
216
- ) {
217
- option.queryCreateInfo = defaultOption.queryCreateInfo;
218
- }
219
- if (opts.queryCreateInfo === false) {
220
- option.queryCreateInfo = "0";
221
- }
222
- return this.$http(option);
223
- };
224
-
225
- Object.assign($http, imFun.request);
226
- $http.prototype = imFun.request.prototype;
227
- Vue.prototype.$http = $http;
228
-
229
- /* 通用打开菜单/路由:开关开启时以独立标签重复打开,否则按原逻辑跳转
230
- * 用法:this.$openView('/path') 或 this.$openView({ path, query }[, route]) */
231
- Vue.prototype.$openView = function (location, route) {
232
- return openView(this.$router, location, route);
233
- };
234
-
235
- /* 全局accessToken */
236
- Vue.prototype.$baseAccessToken = () => {
237
- return accessToken || imFun.getToken();
238
- };
239
-
240
- /* 全局加载层 */
241
- Vue.prototype.$baseLoading = function (option) {
242
- let d = this.$el;
243
- let loading;
244
- option = option || {};
245
- if (!option.index) {
246
- let opts = {
247
- lock: true,
248
- background: "hsla(0,0%,100%,.8)",
249
- target: d,
250
- };
251
- Object.assign(opts, option);
252
- loading = imFun.Loading.service(opts);
253
- } else {
254
- let opts = {
255
- lock: true,
256
- spinner: "vab-loading-type" + option.index,
257
- background: "hsla(0,0%,100%,.8)",
258
- target: d,
259
- };
260
- Object.assign(opts, option);
261
- loading = imFun.Loading.service(opts);
262
- }
263
- return loading;
264
- };
265
- /* 全局多彩加载层 */
266
- Vue.prototype.$baseColorfullLoading = function (index, text) {
267
- let loading;
268
- if (!index) {
269
- loading = imFun.Loading.service({
270
- lock: true,
271
- text: text || loadingText,
272
- spinner: "dots-loader",
273
- background: "hsla(0,0%,100%,.8)",
274
- target: this.target,
275
- fullscreen: true,
276
- });
277
- } else {
278
- switch (index) {
279
- case 1:
280
- index = "dots";
281
- break;
282
- case 2:
283
- index = "gauge";
284
- break;
285
- case 3:
286
- index = "inner-circles";
287
- break;
288
- case 4:
289
- index = "plus";
290
- break;
291
- }
292
- loading = imFun.Loading.service({
293
- lock: true,
294
- text: text || loadingText,
295
- spinner: index + "-loader",
296
- background: "hsla(0,0%,100%,.8)",
297
- target: this.target,
298
- });
299
- }
300
- return loading;
301
- };
302
- /* 全局Message */
303
- Vue.prototype.$baseMessage = ({ message, type, onClose }) => {
304
- imFun.Message({
305
- offset: 60,
306
- showClose: true,
307
- message: message,
308
- type: type,
309
- dangerouslyUseHTMLString: true,
310
- duration: messageDuration,
311
- onClose: onClose,
312
- });
313
- };
314
-
315
- /* 全局Alert */
316
- Vue.prototype.$baseAlert = function (content, title, callback) {
317
- imFun.MessageBox.alert(content, title || "提示", {
318
- confirmButtonText: "确定",
319
- dangerouslyUseHTMLString: true,
320
- target: this.$el,
321
- confirmButtonClass: "icondui",
322
- customClass: "dialog-style",
323
- callback: (action) => {
324
- if (callback) {
325
- callback();
326
- }
327
- },
328
- });
329
- };
330
-
331
- /* 全局Confirm */
332
- Vue.prototype.$baseConfirm = function (content, title) {
333
- return imFun.MessageBox.confirm(content, title || "提示", {
334
- confirmButtonText: "确定",
335
- cancelButtonText: "取消",
336
- closeOnClickModal: false,
337
- type: "warning",
338
- customClass: "dialog-style",
339
- cancelButtonClass: "iconguanbi",
340
- confirmButtonClass: "icondui",
341
- });
342
- };
343
-
344
- /* 全局Notification */
345
- Vue.prototype.$baseNotify = (message, title, type, position) => {
346
- imFun.Notification({
347
- title: title,
348
- message: message,
349
- position: position || "top-right",
350
- type: type || "success",
351
- duration: messageDuration,
352
- });
353
- };
354
-
355
- /* 全局TableHeight */
356
- Vue.prototype.$baseTableHeight = (formType) => {
357
- let height = window.innerHeight;
358
- let paddingHeight = 400;
359
- const formHeight = 50;
360
-
361
- if (true) {
362
- paddingHeight = 365;
363
- }
364
-
365
- if ("number" === typeof formType) {
366
- height = height - paddingHeight - formHeight * formType;
367
- } else {
368
- height = height - paddingHeight;
369
- }
370
- return height;
371
- };
372
-
373
- /* 全局map图层 */
374
- Vue.prototype.$baseMap = () => {
375
- return new maptalks.Map("map", {
376
- center: [116.41348403785, 39.910843952376],
377
- zoom: 12,
378
- minZoom: 1,
379
- maxZoom: 19,
380
- spatialReference: {
381
- projection: "baidu",
382
- },
383
- attribution: {
384
- content: "© vue-admin-beautiful",
385
- },
386
- baseLayer: new maptalks.TileLayer("base", {
387
- cssFilter: "sepia(100%) invert(90%)",
388
- urlTemplate:
389
- "http://online{s}.map.bdimg.com/onlinelabel/?qt=tile&x={x}&y={y}&z={z}&styles=pl&scaler=1&p=1",
390
- subdomains: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
391
- attribution:
392
- '&copy; <a target="_blank" href="http://map.baidu.com">Baidu</a>',
393
- }),
394
- });
395
- };
396
-
397
- /* 全局lodash */
398
- Vue.prototype.$baseLodash = imFun.lodash;
399
- /* 全局事件总线 */
400
- Vue.prototype.$baseEventBus = new Vue();
401
-
402
- Vue.prototype.$commonFileUtil = {
403
- // 文件类型获取与判断接口
404
- getFileSuffix: function (name) {
405
- let i = name.lastIndexOf(".");
406
- if (i < 0) {
407
- // 默认是文本类型
408
- return "";
409
- }
410
- let suffix = name.substring(i + 1, name.length).toLowerCase();
411
- return suffix;
412
- },
413
- isBinary: function (suffix) {
414
- if (!suffix || suffix === "") {
415
- return false;
416
- }
417
- let fileTypeMap = {
418
- bin: true,
419
- exe: true,
420
- dll: true,
421
- so: true,
422
- lib: true,
423
- war: true,
424
- jar: true,
425
- };
426
- let type = fileTypeMap[suffix];
427
- if (undefined === type) {
428
- return false;
429
- }
430
- return true;
431
- },
432
- isPicture: function (suffix) {
433
- if (!suffix || suffix === "") {
434
- return false;
435
- }
436
-
437
- let fileTypeMap = {
438
- jpg: true,
439
- jpeg: true,
440
- png: true,
441
- gif: true,
442
- bmp: true,
443
- mpg: true,
444
- webp: true,
445
- };
446
-
447
- let type = fileTypeMap[suffix];
448
- if (undefined === type) {
449
- return false;
450
- }
451
-
452
- return true;
453
- },
454
- isVideo: function (suffix) {
455
- if (!suffix || suffix === "") {
456
- return false;
457
- }
458
- let fileTypeMap = {
459
- avi: true,
460
- mov: true,
461
- mpeg: true,
462
- mpg: true,
463
- mp4: true,
464
- rmvb: true,
465
- asf: true,
466
- flv: true,
467
- ogg: true,
468
- };
469
-
470
- let type = fileTypeMap[suffix];
471
- if (undefined === type) {
472
- return false;
473
- }
474
-
475
- return true;
476
- },
477
- isText: function (suffix) {
478
- if (!suffix || suffix === "") {
479
- return false;
480
- }
481
- let fileTypeMap = {
482
- txt: true,
483
- log: true,
484
- md: true,
485
- py: true,
486
- java: true,
487
- cpp: true,
488
- hpp: true,
489
- c: true,
490
- h: true,
491
- json: true,
492
- xml: true,
493
- html: true,
494
- sql: true,
495
- js: true,
496
- css: true,
497
- jsp: true,
498
- php: true,
499
- properties: true,
500
- conf: true,
501
- out: true,
502
- sh: true,
503
- bat: true,
504
- msg: true,
505
- cmake: true,
506
- yaml: true,
507
- yml: true,
508
- };
509
-
510
- let type = fileTypeMap[suffix];
511
- if (undefined === type) {
512
- return false;
513
- }
514
-
515
- return true;
516
- },
517
- isZip: function (suffix) {
518
- if (!suffix || suffix === "") {
519
- return false;
520
- }
521
- let fileTypeMap = {
522
- zip: true,
523
- war: true,
524
- rar: true,
525
- "7z": true,
526
- gz: true,
527
- tgz: true,
528
- xz: true,
529
- txz: true,
530
- bz2: true,
531
- tbz2: true,
532
- tar: true,
533
- };
534
-
535
- let type = fileTypeMap[suffix];
536
- if (undefined === type) {
537
- return false;
538
- }
539
-
540
- return true;
541
- },
542
- isOffice: function (suffix) {
543
- if (!suffix || suffix === "") {
544
- return false;
545
- }
546
- let fileTypeMap = {
547
- doc: true,
548
- docx: true,
549
- ppt: true,
550
- pptx: true,
551
- xls: true,
552
- xlsx: true,
553
- };
554
-
555
- let type = fileTypeMap[suffix];
556
- if (undefined === type) {
557
- return false;
558
- }
559
-
560
- return true;
561
- },
562
- isPdf: function (suffix) {
563
- if (!suffix || suffix === "") {
564
- return false;
565
- }
566
- let fileTypeMap = {
567
- pdf: true,
568
- };
569
-
570
- let type = fileTypeMap[suffix];
571
- if (undefined === type) {
572
- return false;
573
- }
574
-
575
- return true;
576
- },
577
- isPictureFile: function (fileName) {
578
- if (!fileName) return false;
579
- let typeStr = Object.prototype.toString.call(fileName);
580
- let suffix = null;
581
- if (typeStr === "[object Object]") {
582
- suffix = this.getFileSuffix(fileName.name);
583
- } else {
584
- suffix = this.getFileSuffix(fileName);
585
- }
586
- return this.isPicture(suffix);
587
- },
588
- isTextFile: function (fileName) {
589
- let suffix = this.getFileSuffix(fileName);
590
- return this.isText(suffix);
591
- },
592
- getShowUrl(url, showImagePreview) {
593
- let index = url.lastIndexOf("/");
594
- let filename;
595
- if (index >= 0) {
596
- filename = url.substring(url.lastIndexOf("/") + 1);
597
- } else {
598
- filename = url;
599
- }
600
-
601
- if (this.isPictureFile(filename) && showImagePreview !== false) {
602
- return url;
603
- } else {
604
- return this.getFileIconRequire(filename);
605
- }
606
- },
607
- resolveFileIconName: function (name, showType) {
608
- let iconType = this.getDiyFileIconType(name) || "other";
609
- if (showType) {
610
- iconType = showType;
611
- }
612
- return FILE_ICON_NAME_MAP[iconType];
613
- },
614
- getFileIconRequire: function (name, showType) {
615
- return reqImg(this.resolveFileIconName(name, showType));
616
- },
617
- getFileIconPath: function (name, showType) {
618
- return "/resources/images/" + this.resolveFileIconName(name, showType);
619
- },
620
- getDiyFileIconType: function (name) {
621
- let suffix = this.getFileSuffix(name);
622
- if (suffix === "") {
623
- // 默认是文本类型
624
- return "";
625
- }
626
-
627
- let iconType = FILE_ICON_TYPE_MAP[suffix];
628
- if (undefined === iconType) {
629
- return "";
630
- }
631
- return iconType;
632
- },
633
- getFileExtension(urlString) {
634
- if (!urlString) return null;
635
- const url = new URL(urlString);
636
- // 获取路径部分,例如 "/images/photo.jpg"
637
- const pathname = url.pathname;
638
-
639
- // 使用 lastIndexOf 找到最后一个点的位置
640
- const lastDotIndex = pathname.lastIndexOf(".");
641
-
642
- // 如果没有点,或者点在最后一位(即没有后缀),返回空字符串
643
- if (lastDotIndex === -1 || lastDotIndex === pathname.length - 1) {
644
- return "";
645
- }
646
-
647
- // 截取点之后的部分
648
- return pathname.slice(lastDotIndex + 1).toLowerCase();
649
- },
650
- downloadFile: function () {
651
- let filePath, name;
652
- let opts;
653
- if (typeof arguments[0] === "string") {
654
- filePath = arguments[0];
655
- name = arguments[1];
656
- } else {
657
- opts = arguments[0];
658
- filePath = opts.filePath;
659
- name = opts.name;
660
- }
661
- if (filePath) {
662
- let url = null;
663
- if (filePath.indexOf("?") >= 0) {
664
- url = filePath + "&_d=true";
665
- } else {
666
- url = filePath + "?_d=true";
667
- }
668
- if (name) {
669
- let fileSuffix = this.getFileExtension(filePath);
670
- if (fileSuffix && !name.endsWith("." + fileSuffix)) {
671
- name = name + "." + fileSuffix;
672
- }
673
-
674
- url += "&_n=" + encodeURIComponent(name);
675
- }
676
- // window.open(url);
677
- openInNewTab(url);
678
- }
679
- },
680
- isPreviewFile(fileName) {
681
- let fileSuffix = this.getFileSuffix(fileName);
682
- return typeList.includes(fileSuffix);
683
- },
684
- };
685
-
686
- Vue.prototype.$openFilePreview = function () {
687
- let filePath;
688
- let opts;
689
- if (typeof arguments[0] === "string") {
690
- filePath = arguments[0];
691
- } else {
692
- let attachment = arguments[0];
693
- filePath = attachment.domain + attachment.url;
694
- }
695
- let fileSuffix = this.$commonFileUtil.getFileSuffix(filePath);
696
- if (!typeList.includes(fileSuffix)) {
697
- return;
698
- }
699
-
700
- this.$http({
701
- url: USER_PREFIX + "/sf_common/getFilePreviewUrl",
702
- method: `post`,
703
- data: {
704
- url: filePath,
705
- },
706
- isLoading: true,
707
- success: (res) => {
708
- if (res.objx) {
709
- openInNewTab(res.objx);
710
- }
711
- },
712
- });
713
- };
714
-
715
- function openInNewTab(url) {
716
- if (!url) return;
717
- let a = document.createElement("a");
718
- a.href = url;
719
- a.target = "_blank";
720
- document.body.appendChild(a);
721
- a.click();
722
- document.body.removeChild(a);
723
- }
724
-
725
- Vue.prototype.$getFilePreviewUrl = async function (obj, callback) {
726
- let filePath;
727
- let opts;
728
- if (typeof obj === "string") {
729
- filePath = obj;
730
- } else {
731
- let attachment = obj;
732
- filePath = attachment.domain + attachment.url;
733
- }
734
- let fileSuffix = this.$commonFileUtil.getFileSuffix(filePath);
735
- /*if (!typeList.includes(fileSuffix)) {
736
- return;
737
- }*/
738
-
739
- return this.$http({
740
- url: USER_PREFIX + "/sf_common/getFilePreviewUrl",
741
- method: `post`,
742
- data: {
743
- url: filePath,
744
- },
745
- isLoading: true,
746
- success: (res) => {
747
- callback && callback(res.objx);
748
- },
749
- });
750
- };
751
-
752
- Vue.prototype.$baseFilePreview = function (attachment, index) {
753
- let that = this;
754
- let openImagePreView = function (attachments, index) {
755
- let pictureIndex = -1;
756
- let pictureDtoList = [];
757
- index = index || 0;
758
- attachments.forEach((item, i) => {
759
- let typeStr = Object.prototype.toString.call(item);
760
- if (typeStr === "[object Object]") {
761
- if (that.$commonFileUtil.isPictureFile(item.url)) {
762
- if (i <= index) {
763
- pictureIndex++;
764
- }
765
- pictureDtoList.push(item.domain + item.url);
766
- }
767
- } else {
768
- if (that.$commonFileUtil.isPictureFile(item)) {
769
- if (i <= index) {
770
- pictureIndex++;
771
- }
772
- pictureDtoList.push(item);
773
- }
774
- }
775
- });
776
-
777
- let a = Vue.extend(ElImageViewer);
778
- let instance = new a({
779
- propsData: {
780
- onClose: () => {
781
- dom.remove();
782
- },
783
- initialIndex: pictureIndex,
784
- urlList: pictureDtoList,
785
- },
786
- });
787
- let dom = instance.$mount().$el;
788
- document.body.append(dom);
789
- };
790
- let openPreview = function (attachment, index) {
791
- if (Array.isArray(attachment)) {
792
- let currentFile = attachment[index];
793
- let typeStr = Object.prototype.toString.call(currentFile);
794
- let url =
795
- typeStr === "[object Object]"
796
- ? currentFile.domain + currentFile.url
797
- : currentFile;
798
- if (that.$commonFileUtil.isPictureFile(url)) {
799
- openImagePreView(attachment, index);
800
- } else if (that.$commonFileUtil.isPreviewFile(url)) {
801
- that.$openFilePreview(url);
802
- }
803
- } else {
804
- let typeStr = Object.prototype.toString.call(attachment);
805
- let url =
806
- typeStr === "[object Object]"
807
- ? attachment.domain + attachment.url
808
- : attachment;
809
- if (that.$commonFileUtil.isPictureFile(url)) {
810
- openImagePreView([url], 0);
811
- } else if (that.$commonFileUtil.isPreviewFile(url)) {
812
- that.$openFilePreview(url);
813
- }
814
- }
815
- };
816
- openPreview(attachment, index);
817
- };
818
-
819
- Vue.prototype.$openEditView = function (key) {
820
- this[key] = false;
821
- setTimeout(() => {
822
- this[key] = true;
823
- }, 200);
824
- };
825
-
826
- Vue.prototype.$baseReload = function (param) {
827
- this.$emit("reload", this, param);
828
- };
829
-
830
- Vue.prototype.$reloadHandle = function (target, param) {
831
- let visibleKey = target.$attrs["visible-key"] || "showEdit";
832
- let parentTarget = target.$attrs["parent-target"] || target.$parent;
833
- let originTarget = parentTarget.$refs._viewDialog ? parentTarget : target;
834
- let updateParam =
835
- param !== null &&
836
- param !== undefined &&
837
- param.updateParam !== null &&
838
- param.updateParam !== undefined
839
- ? param.updateParam
840
- : {};
841
- for (let key in updateParam) {
842
- originTarget.$emit("update:" + key, updateParam[key]);
843
- }
844
- parentTarget[visibleKey] = false;
845
- return new Promise((resolve) => {
846
- setTimeout(() => {
847
- parentTarget[visibleKey] = true;
848
- parentTarget.$nextTick(resolve);
849
- }, 200);
850
- });
851
- };
852
-
853
- Vue.prototype.$baseStartPickerOptions = function (value, type) {
854
- return {
855
- disabledDate: (time) => {
856
- if (value !== null && value !== undefined && value !== "") {
857
- let date = new Date(value.replace(/-/g, "/"));
858
- if (!type || type === "date") {
859
- date.setDate(date.getDate() + 1);
860
- return time.getTime() >= date.getTime();
861
- } else if (type === "year") {
862
- return time.getYear() > date.getYear();
863
- } else if (type === "month") {
864
- date.setMonth(date.getMonth() + 1);
865
- return time.getTime() >= date.getTime();
866
- }
867
- } else {
868
- return false;
869
- }
870
- },
871
- };
872
- };
873
-
874
- Vue.prototype.$baseEndPickerOptions = function (value, format) {
875
- return {
876
- disabledDate: (time) => {
877
- if (value !== null && value !== undefined && value !== "") {
878
- let date = new Date(value.replace(/-/g, "/"));
879
- return time.getTime() < date.getTime();
880
- } else {
881
- return false;
882
- }
883
- },
884
- };
885
- };
886
-
887
- //除法
888
- function baseDiv() {
889
- let value = 0;
890
- if (arguments.length) {
891
- value = arguments[0];
892
- for (let i = 1; i < arguments.length; i++) {
893
- value = XEUtils.divide(value, arguments[i]);
894
- }
895
- }
896
- return value;
897
- }
898
-
899
- //乘法
900
- function baseMul() {
901
- let value = 0;
902
- if (arguments.length) {
903
- value = arguments[0];
904
- for (let i = 1; i < arguments.length; i++) {
905
- value = XEUtils.multiply(value, arguments[i]);
906
- }
907
- }
908
- return value;
909
- }
910
-
911
- //加法
912
- function baseAdd() {
913
- let value = 0;
914
- if (arguments.length) {
915
- value = arguments[0];
916
- for (let i = 1; i < arguments.length; i++) {
917
- value = XEUtils.add(value, arguments[i]);
918
- }
919
- }
920
- return value;
921
- }
922
-
923
- //减法
924
- function baseSub() {
925
- let value = 0;
926
- if (arguments.length) {
927
- value = arguments[0];
928
- for (let i = 1; i < arguments.length; i++) {
929
- value = XEUtils.subtract(value, arguments[i]);
930
- }
931
- }
932
- return value;
933
- }
934
-
935
- Vue.prototype.$baseAdd = baseAdd;
936
- Vue.prototype.$baseSub = baseSub;
937
- Vue.prototype.$baseMul = baseMul;
938
- Vue.prototype.$baseDiv = baseDiv;
939
-
940
- /**
941
- * 格式化数字为带千分位的字符串。
942
- *
943
- * @param {string | number} value - 输入值
944
- * @param {Object} [options={}] - 配置
945
- * @param {boolean} [options.fixed=false] -
946
- * - `true`: 启用定点精度处理 —— 使用 toFixed(digits) 四舍五入并补零到指定小数位。
947
- * - `false`(默认): 保留原始小数形式(不四舍五入、不补零、保留尾随零)。
948
- * @param {number} [options.digits=2] - 小数位数(仅在 fixed: true 时生效)
949
- * @param {string} [options.thousandsSeparator=','] - 千分位分隔符(始终生效)
950
- * @param {string} [options.decimalSeparator='.'] - 小数点符号
951
- * @returns {string}
952
- *
953
- * @example
954
- * // 默认:保留原始小数
955
- * formatNumber(0.2); // "0.2"
956
- * formatNumber("0.2000"); // "0.2000"
957
- *
958
- * // 启用定点精度处理
959
- * formatNumber(0.2, { fixed: true }); // "0.20"
960
- * formatNumber("123.456", { fixed: true, digits: 1 }); // "123.5"
961
- * formatNumber(1000, { fixed: true, digits: 0 }); // "1,000"
962
- */
963
- function formatNumber(value, options = {}) {
964
- if (value === null || value === undefined || value === "") {
965
- return "";
966
- }
967
-
968
- const {
969
- fixed = false,
970
- digits = 2,
971
- thousandsSeparator = ",",
972
- decimalSeparator = ".",
973
- } = options;
974
-
975
- const isNumber = typeof value === "number";
976
- let str = String(value).trim();
977
-
978
- // Normalize ".123" → "0.123"
979
- if (str.charCodeAt(0) === 46) {
980
- str = "0" + str;
981
- } else if (str.startsWith("-.")) {
982
- str = "-0." + str.slice(2);
983
- }
984
-
985
- let intPart, decPart, isNegative;
986
-
987
- if (fixed) {
988
- // ✅ 启用精度处理:toFixed + 补零
989
- const num = isNumber ? value : parseFloat(str);
990
- if (num !== num) return str;
991
-
992
- const fixedStr = num.toFixed(digits);
993
- const dotIndex = fixedStr.indexOf(".");
994
- intPart = dotIndex === -1 ? fixedStr : fixedStr.slice(0, dotIndex);
995
- decPart = dotIndex === -1 ? "" : fixedStr.slice(dotIndex + 1);
996
- isNegative = intPart.charCodeAt(0) === 45;
997
- if (isNegative) intPart = intPart.slice(1);
998
- } else {
999
- // 保留原始小数
1000
- let s = str;
1001
- isNegative = s.charCodeAt(0) === 45;
1002
- if (isNegative) s = s.slice(1);
1003
-
1004
- const dotIndex = s.indexOf(".");
1005
- intPart = dotIndex === -1 ? s : s.slice(0, dotIndex);
1006
- decPart = dotIndex === -1 ? "" : s.slice(dotIndex + 1);
1007
-
1008
- if (intPart === "") intPart = "0";
1009
- if (!/^\d+$/.test(intPart)) return str;
1010
- }
1011
-
1012
- // 千分位(始终应用)
1013
- let fmtInt = intPart;
1014
- if (intPart !== "0") {
1015
- let out = "";
1016
- for (let i = intPart.length - 1, c = 0; i >= 0; i--, c++) {
1017
- if (c > 0 && c % 3 === 0) out = thousandsSeparator + out;
1018
- out = intPart[i] + out;
1019
- }
1020
- fmtInt = out;
1021
- }
1022
-
1023
- // 拼接
1024
- let result = isNegative ? "-" + fmtInt : fmtInt;
1025
- if (decPart) {
1026
- result += decimalSeparator + decPart;
1027
- } else if (fixed && digits > 0) {
1028
- result += decimalSeparator + "0".repeat(digits);
1029
- }
1030
-
1031
- return result;
1032
- }
1033
- Vue.prototype.$formatNumber = formatNumber;
1034
-
1035
- /**
1036
- * 生成一个符合 RFC4122 标准的随机 UUID (v4)
1037
- * @returns {string} 格式为 "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx" 的 UUID 字符串
1038
- */
1039
- function generateUUID() {
1040
- const buf = new Uint8Array(16);
1041
- crypto.getRandomValues(buf);
1042
- buf[6] = (buf[6] & 0x0f) | 0x40; // version 4
1043
- buf[8] = (buf[8] & 0x3f) | 0x80; // variant RFC4122
1044
- const hex = Array.from(buf, (b) => b.toString(16).padStart(2, "0")).join(
1045
- ""
1046
- );
1047
- return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(
1048
- 12,
1049
- 16
1050
- )}-${hex.slice(16, 20)}-${hex.slice(20)}`;
1051
- }
1052
- Vue.prototype.$generateUUID = generateUUID;
1053
-
1054
- //数字精确位数
1055
- Vue.prototype.$currency = function (value, priceScale, priceRoundType) {
1056
- if (value !== null && value !== undefined) {
1057
- if (priceScale === null || priceScale === undefined) {
1058
- priceScale = 2;
1059
- }
1060
- if (priceRoundType === null || priceRoundType === undefined) {
1061
- priceRoundType = "roundHalfUp";
1062
- }
1063
- let price;
1064
- if (priceRoundType === "roundHalfUp") {
1065
- price = (
1066
- Math.round(value * Math.pow(10, priceScale)) /
1067
- Math.pow(10, priceScale)
1068
- ).toFixed(priceScale);
1069
- } else if (priceRoundType === "roundUp") {
1070
- price = (
1071
- Math.ceil(value * Math.pow(10, priceScale)) / Math.pow(10, priceScale)
1072
- ).toFixed(priceScale);
1073
- } else {
1074
- price = (
1075
- Math.floor(value * Math.pow(10, priceScale)) /
1076
- Math.pow(10, priceScale)
1077
- ).toFixed(priceScale);
1078
- }
1079
- return price;
1080
- }
1081
- };
1082
-
1083
- Vue.prototype.$getBaseDicts = async function (option) {
1084
- let isLoading = option.isLoading || false;
1085
- return this.$http({
1086
- url: USER_PREFIX + "/common_attribute/listItems",
1087
- method: `post`,
1088
- data: {
1089
- code: option.code,
1090
- enabled: true,
1091
- forCompany: true,
1092
- ...option.data,
1093
- },
1094
- isLoading: isLoading,
1095
- modalStrictly: true,
1096
- success: (res) => {
1097
- let dicts = res.objx || [];
1098
- let dictMap = {};
1099
- for (let item of dicts) {
1100
- dictMap[item.sn] = item.value;
1101
- }
1102
- /* dicts.forEach((item) => {
1103
- dictMap[item.sn] = item.value;
1104
- }); */
1105
- option.success &&
1106
- option.success({
1107
- dicts,
1108
- dictMap,
1109
- });
1110
- },
1111
- });
1112
- };
1113
-
1114
- imFun.Form.methods.$baseValidate = function (callback, opt) {
1115
- let that = this;
1116
- that.validate((valid, obj, c, d) => {
1117
- if (!valid && (!opt || opt.errorTip !== false)) {
1118
- this.$message({
1119
- message: this.$t2("必填项不能为空", "system.message.required"),
1120
- type: "error",
1121
- duration: 2000,
1122
- });
1123
- }
1124
- scrollToFirstError(that);
1125
- callback(valid, obj);
1126
- });
1127
- };
1128
-
1129
- function scrollToFirstError(formTarget) {
1130
- // 获取第一个验证失败的字段
1131
- // let formTarget = this.$refs['renderForm'];
1132
- const firstErrorField = Object.keys(formTarget.fields).find((key) => {
1133
- return formTarget.fields[key].validateState === "error";
1134
- });
1135
-
1136
- if (firstErrorField) {
1137
- const field = formTarget.fields[firstErrorField];
1138
-
1139
- let dom = field.$el;
1140
- if (dom) {
1141
- // 滚动到该字段位置
1142
- dom.scrollIntoView({
1143
- behavior: "smooth",
1144
- block: "center",
1145
- });
1146
-
1147
- // 添加高亮效果
1148
- dom.classList.add("highlight");
1149
-
1150
- // 3秒后移除高亮效果
1151
- setTimeout(() => {
1152
- dom.classList.remove("highlight");
1153
- }, 3000);
1154
- }
1155
- }
1156
- }
1157
-
1158
- Vue.prototype.$getBillInfo = async function (option) {
1159
- let defaultOption = {
1160
- url: null,
1161
- method: `post`,
1162
- data: {},
1163
- isLoading: true,
1164
- modalStrictly: true,
1165
- success: null,
1166
- };
1167
- let opt = Object.assign({}, defaultOption, option);
1168
- delete opt.wfConfig;
1169
- return this.$http({
1170
- ...opt,
1171
- success: (res, response) => {
1172
- option.success && option.success(res, response);
1173
- },
1174
- });
1175
- };
1176
-
1177
- Vue.prototype.$downloadByFileWhole = function (fileWhole, fileName) {
1178
- let that = this;
1179
- if (!fileWhole) {
1180
- this.$baseAlert("凭证信息不存在");
1181
- return;
1182
- }
1183
- let getDownloadDomian = function (callback) {
1184
- that.$http({
1185
- method: "post",
1186
- url: USER_PREFIX + "/common/fileDownloadUrl",
1187
- data: {},
1188
- isLoading: true,
1189
- success: (res) => {
1190
- callback(res.objx);
1191
- },
1192
- });
1193
- };
1194
- getDownloadDomian((domain) => {
1195
- if (fileName) {
1196
- fileWhole.fileName = fileName;
1197
- }
1198
- that.$http({
1199
- method: "post",
1200
- url: domain + "/docfile/download",
1201
- data: fileWhole,
1202
- isLoading: true,
1203
- success: (res) => {
1204
- // window.open(res.objx.url);
1205
- let url = res.objx.url;
1206
- openInNewTab(url);
1207
- },
1208
- });
1209
- });
1210
- };
1211
-
1212
- let isDef = function (value) {
1213
- return value !== undefined && value !== null;
1214
- };
1215
-
1216
- Vue.prototype.$t2 = function (defaultValue, path, values) {
1217
- let that = window.$vueRoot;
1218
- if (!that.hasOwnProperty("_i18n")) {
1219
- return defaultValue;
1220
- }
1221
- const i18n = that.$i18n;
1222
- path = path || defaultValue;
1223
- return i18n.te(path) ? i18n.t(path, values) : defaultValue;
1224
- };
1225
-
1226
- Vue.prototype.$t1 = function (path, values) {
1227
- let that = window.$vueRoot;
1228
- if (!that.hasOwnProperty("_i18n")) {
1229
- return path;
1230
- }
1231
- let lang = that.$i18n.locale;
1232
- const i18n = that.$i18n;
1233
- if (lang === "zh") {
1234
- let val = i18n._t(path, lang, { zh: { [path]: path } }, null, values);
1235
- return val;
1236
- } else {
1237
- if (!i18n.te(path)) {
1238
- return i18n._t(path, lang, { zh: { [path]: path } }, null, values);
1239
- } else {
1240
- return (
1241
- i18n.t(path, values) ||
1242
- i18n._t(path, lang, { zh: { [path]: path } }, null, values)
1243
- );
1244
- }
1245
- }
1246
- };
1247
-
1248
- Vue.prototype.$i18nVal = function (zhValue, enValue) {
1249
- let that = window.$vueRoot;
1250
- if (!that.hasOwnProperty("_i18n")) {
1251
- return zhValue;
1252
- }
1253
- let $i18n = that.$i18n;
1254
- let value = zhValue;
1255
- if ($i18n.locale === "zh") {
1256
- value = zhValue;
1257
- } else if ($i18n.locale === "en") {
1258
- value = enValue;
1259
- }
1260
- return value;
1261
- };
1262
-
1263
- Vue.prototype.$utcToLocal = function (utcTime) {
1264
- if (!utcTime) return utcTime;
1265
- let offsetHours = this.$store.getters.utcTransformOffset; // 时区偏移量,单位:小时
1266
- if (!offsetHours || offsetHours === 0) return utcTime;
1267
- let localTime = moment(utcTime).add(offsetHours, "hours");
1268
- return localTime.format("YYYY-MM-DD HH:mm:ss");
1269
- };
1270
-
1271
- Vue.prototype.$window = window;
1272
- };
1273
-
1274
- window && Object.assign(window, imFun.prefixConfig);
1275
- if (typeof window !== "undefined" && window.Vue) {
1276
- install(window.Vue);
1277
- }
1278
-
1279
- export default install;
1
+ /**version-1.0*/
2
+ let install = {};
3
+
4
+ import request from "./request";
5
+ import * as lodash from "lodash";
6
+ import { Loading, Message, MessageBox, Notification, Form } from "element-ui";
7
+ import store from "../store";
8
+ import ElImageViewer from "../components/VabUpload/image-viewer";
9
+
10
+ import { getToken } from "./auth";
11
+ import XEUtils from "xe-utils";
12
+
13
+ import prefixConfig from "@/prefixConfig.js";
14
+ import moment from "moment";
15
+ import { openView } from "./repeatOpen";
16
+ import { assetUrl } from "./assetUrl";
17
+
18
+ let imFun = {
19
+ request,
20
+ lodash,
21
+ Loading,
22
+ Message,
23
+ MessageBox,
24
+ Notification,
25
+ Form,
26
+ store,
27
+ getToken,
28
+ prefixConfig,
29
+ };
30
+
31
+ function reqImg(a) {
32
+ /* webpack5 下 require 返回的是无原型的 Module 对象,直接当 src 用会崩,统一取真实 URL */
33
+ return assetUrl(require("@/resources/images/" + a));
34
+ }
35
+
36
+ const FILE_ICON_NAME_MAP = {
37
+ word: "ico-wrod.svg",
38
+ excel: "ico-excel.svg",
39
+ ppt: "ico-ppt.svg",
40
+ pdf: "ico-pdf.svg",
41
+ picture: "ico-photo.svg",
42
+ video: "ico-video.svg",
43
+ audio: "ico-music.svg",
44
+ html: "ico-html.svg",
45
+ txt: "ico-txt.svg",
46
+ java: "ico-java.svg",
47
+ vue: "ico-vue.svg",
48
+ ftl: "ico-ftl.svg",
49
+ xml: "ico-xml.svg",
50
+ flash: "ico-flash.svg",
51
+ zip: "ico-yasuobao.svg",
52
+ exe: "ico-ext.svg",
53
+ psd: "ico-psd.svg",
54
+ folder: "ico-wenjianjia.svg",
55
+ other: "ico-default_wenjian.svg",
56
+ };
57
+
58
+ const FILE_ICON_TYPE_MAP = {
59
+ doc: "word",
60
+ docx: "word",
61
+ xls: "excel",
62
+ xlsx: "excel",
63
+ ppt: "ppt",
64
+ pptx: "ppt",
65
+ pdf: "pdf",
66
+ jpg: "picture",
67
+ jpeg: "picture",
68
+ png: "picture",
69
+ gif: "picture",
70
+ mp3: "video",
71
+ mp4: "video",
72
+ mpg: "video",
73
+ mkv: "video",
74
+ rmvb: "video",
75
+ avi: "video",
76
+ mov: "video",
77
+ wav: "audio",
78
+ html: "html",
79
+ htm: "html",
80
+ txt: "txt",
81
+ java: "java",
82
+ vue: "vue",
83
+ ftl: "ftl",
84
+ xml: "xml",
85
+ swf: "flash",
86
+ zip: "zip",
87
+ rar: "zip",
88
+ "7z": "zip",
89
+ // exe: 'exe',
90
+ psd: "psd",
91
+ };
92
+
93
+ let typeList = [
94
+ "doc",
95
+ "docx",
96
+ "xls",
97
+ "xlsx",
98
+ "ppt",
99
+ "pptx",
100
+ "csv",
101
+ "wps",
102
+ "dps",
103
+ "et",
104
+ "ett",
105
+ "wpt",
106
+ "vsd",
107
+ "vsdx",
108
+ "wmf",
109
+ "emf",
110
+ "psd",
111
+ "eps",
112
+ "pdf",
113
+ "xmind",
114
+ "obj",
115
+ "3ds",
116
+ "stl",
117
+ "ply",
118
+ "gltf",
119
+ "glb",
120
+ "off",
121
+ "3dm",
122
+ "fbx",
123
+ "dae",
124
+ "wrl",
125
+ "3mf",
126
+ "ifc",
127
+ "brep",
128
+ "step",
129
+ "iges",
130
+ "fcstd",
131
+ "bim",
132
+ "dwg",
133
+ "dxf",
134
+ "dwf",
135
+ "iges",
136
+ "igs",
137
+ "dwt",
138
+ "dng",
139
+ "ifc",
140
+ "dwfx",
141
+ "stl",
142
+ "cf2",
143
+ "plt",
144
+ "txt",
145
+ "xml",
146
+ "md",
147
+ "java",
148
+ "php",
149
+ "py",
150
+ "js",
151
+ "css",
152
+ "zip",
153
+ "rar",
154
+ "jar",
155
+ "tar",
156
+ "gzip",
157
+ "7z",
158
+ "mp3",
159
+ "wav",
160
+ "mp4",
161
+ "flv",
162
+ "avi",
163
+ "mov",
164
+ "rm",
165
+ "mkv",
166
+ "mpeg",
167
+ "mpg",
168
+ "rmvb",
169
+ "wmv",
170
+ "3gp",
171
+ "swf",
172
+ "drawio",
173
+ "tif",
174
+ "tiff",
175
+ "jfif",
176
+ "webp",
177
+ "tga",
178
+ "svg",
179
+ "vue",
180
+ "ftl",
181
+ ];
182
+
183
+ const accessToken = imFun.store.getters["user/token"];
184
+
185
+ const loadingText = "";
186
+ const messageDuration = 3000;
187
+
188
+ install = (Vue, opts = {}) => {
189
+ /**http请求*/
190
+ let $http = async function (option) {
191
+ option = option || {};
192
+ if (!option.loadingTarget && this.$el) {
193
+ option.loadingTarget = this.$el;
194
+ }
195
+ if (!option.vueTarget) {
196
+ option.vueTarget = this;
197
+ }
198
+ if (option.sync === false) {
199
+ return await imFun.request(option);
200
+ } else {
201
+ return imFun.request(option);
202
+ }
203
+ };
204
+
205
+ Vue.prototype.$commonHttp = function (opts) {
206
+ let defaultOption = {
207
+ addCreateInfo: true,
208
+ queryCreateInfo: window.$vueRoot.$store.getters.queryCreateInfo || "0",
209
+ };
210
+ let option = Object.assign({}, defaultOption, opts);
211
+ if (opts.addCreateInfo === null || opts.addCreateInfo === undefined) {
212
+ option.addCreateInfo = defaultOption.addCreateInfo;
213
+ }
214
+ if (
215
+ opts.queryCreateInfo === null ||
216
+ opts.queryCreateInfo === undefined ||
217
+ opts.queryCreateInfo === true
218
+ ) {
219
+ option.queryCreateInfo = defaultOption.queryCreateInfo;
220
+ }
221
+ if (opts.queryCreateInfo === false) {
222
+ option.queryCreateInfo = "0";
223
+ }
224
+ return this.$http(option);
225
+ };
226
+
227
+ Object.assign($http, imFun.request);
228
+ $http.prototype = imFun.request.prototype;
229
+ Vue.prototype.$http = $http;
230
+
231
+ /* 通用打开菜单/路由:开关开启时以独立标签重复打开,否则按原逻辑跳转
232
+ * 用法:this.$openView('/path') 或 this.$openView({ path, query }[, route]) */
233
+ Vue.prototype.$openView = function (location, route) {
234
+ return openView(this.$router, location, route);
235
+ };
236
+
237
+ /* 全局accessToken */
238
+ Vue.prototype.$baseAccessToken = () => {
239
+ return accessToken || imFun.getToken();
240
+ };
241
+
242
+ /* 全局加载层 */
243
+ Vue.prototype.$baseLoading = function (option) {
244
+ let d = this.$el;
245
+ let loading;
246
+ option = option || {};
247
+ if (!option.index) {
248
+ let opts = {
249
+ lock: true,
250
+ background: "hsla(0,0%,100%,.8)",
251
+ target: d,
252
+ };
253
+ Object.assign(opts, option);
254
+ loading = imFun.Loading.service(opts);
255
+ } else {
256
+ let opts = {
257
+ lock: true,
258
+ spinner: "vab-loading-type" + option.index,
259
+ background: "hsla(0,0%,100%,.8)",
260
+ target: d,
261
+ };
262
+ Object.assign(opts, option);
263
+ loading = imFun.Loading.service(opts);
264
+ }
265
+ return loading;
266
+ };
267
+ /* 全局多彩加载层 */
268
+ Vue.prototype.$baseColorfullLoading = function (index, text) {
269
+ let loading;
270
+ if (!index) {
271
+ loading = imFun.Loading.service({
272
+ lock: true,
273
+ text: text || loadingText,
274
+ spinner: "dots-loader",
275
+ background: "hsla(0,0%,100%,.8)",
276
+ target: this.target,
277
+ fullscreen: true,
278
+ });
279
+ } else {
280
+ switch (index) {
281
+ case 1:
282
+ index = "dots";
283
+ break;
284
+ case 2:
285
+ index = "gauge";
286
+ break;
287
+ case 3:
288
+ index = "inner-circles";
289
+ break;
290
+ case 4:
291
+ index = "plus";
292
+ break;
293
+ }
294
+ loading = imFun.Loading.service({
295
+ lock: true,
296
+ text: text || loadingText,
297
+ spinner: index + "-loader",
298
+ background: "hsla(0,0%,100%,.8)",
299
+ target: this.target,
300
+ });
301
+ }
302
+ return loading;
303
+ };
304
+ /* 全局Message */
305
+ Vue.prototype.$baseMessage = ({ message, type, onClose }) => {
306
+ imFun.Message({
307
+ offset: 60,
308
+ showClose: true,
309
+ message: message,
310
+ type: type,
311
+ dangerouslyUseHTMLString: true,
312
+ duration: messageDuration,
313
+ onClose: onClose,
314
+ });
315
+ };
316
+
317
+ /* 全局Alert */
318
+ Vue.prototype.$baseAlert = function (content, title, callback) {
319
+ imFun.MessageBox.alert(content, title || "提示", {
320
+ confirmButtonText: "确定",
321
+ dangerouslyUseHTMLString: true,
322
+ target: this.$el,
323
+ confirmButtonClass: "icondui",
324
+ customClass: "dialog-style",
325
+ callback: (action) => {
326
+ if (callback) {
327
+ callback();
328
+ }
329
+ },
330
+ });
331
+ };
332
+
333
+ /* 全局Confirm */
334
+ Vue.prototype.$baseConfirm = function (content, title) {
335
+ return imFun.MessageBox.confirm(content, title || "提示", {
336
+ confirmButtonText: "确定",
337
+ cancelButtonText: "取消",
338
+ closeOnClickModal: false,
339
+ type: "warning",
340
+ customClass: "dialog-style",
341
+ cancelButtonClass: "iconguanbi",
342
+ confirmButtonClass: "icondui",
343
+ });
344
+ };
345
+
346
+ /* 全局Notification */
347
+ Vue.prototype.$baseNotify = (message, title, type, position) => {
348
+ imFun.Notification({
349
+ title: title,
350
+ message: message,
351
+ position: position || "top-right",
352
+ type: type || "success",
353
+ duration: messageDuration,
354
+ });
355
+ };
356
+
357
+ /* 全局TableHeight */
358
+ Vue.prototype.$baseTableHeight = (formType) => {
359
+ let height = window.innerHeight;
360
+ let paddingHeight = 400;
361
+ const formHeight = 50;
362
+
363
+ if (true) {
364
+ paddingHeight = 365;
365
+ }
366
+
367
+ if ("number" === typeof formType) {
368
+ height = height - paddingHeight - formHeight * formType;
369
+ } else {
370
+ height = height - paddingHeight;
371
+ }
372
+ return height;
373
+ };
374
+
375
+ /* 全局map图层 */
376
+ Vue.prototype.$baseMap = () => {
377
+ return new maptalks.Map("map", {
378
+ center: [116.41348403785, 39.910843952376],
379
+ zoom: 12,
380
+ minZoom: 1,
381
+ maxZoom: 19,
382
+ spatialReference: {
383
+ projection: "baidu",
384
+ },
385
+ attribution: {
386
+ content: "&copy; vue-admin-beautiful",
387
+ },
388
+ baseLayer: new maptalks.TileLayer("base", {
389
+ cssFilter: "sepia(100%) invert(90%)",
390
+ urlTemplate:
391
+ "http://online{s}.map.bdimg.com/onlinelabel/?qt=tile&x={x}&y={y}&z={z}&styles=pl&scaler=1&p=1",
392
+ subdomains: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
393
+ attribution:
394
+ '&copy; <a target="_blank" href="http://map.baidu.com">Baidu</a>',
395
+ }),
396
+ });
397
+ };
398
+
399
+ /* 全局lodash */
400
+ Vue.prototype.$baseLodash = imFun.lodash;
401
+ /* 全局事件总线 */
402
+ Vue.prototype.$baseEventBus = new Vue();
403
+ /* 模板里 :src="$assetUrl(require(...))" 用,见 utils/assetUrl.js */
404
+ Vue.prototype.$assetUrl = assetUrl;
405
+
406
+ Vue.prototype.$commonFileUtil = {
407
+ // 文件类型获取与判断接口
408
+ getFileSuffix: function (name) {
409
+ let i = name.lastIndexOf(".");
410
+ if (i < 0) {
411
+ // 默认是文本类型
412
+ return "";
413
+ }
414
+ let suffix = name.substring(i + 1, name.length).toLowerCase();
415
+ return suffix;
416
+ },
417
+ isBinary: function (suffix) {
418
+ if (!suffix || suffix === "") {
419
+ return false;
420
+ }
421
+ let fileTypeMap = {
422
+ bin: true,
423
+ exe: true,
424
+ dll: true,
425
+ so: true,
426
+ lib: true,
427
+ war: true,
428
+ jar: true,
429
+ };
430
+ let type = fileTypeMap[suffix];
431
+ if (undefined === type) {
432
+ return false;
433
+ }
434
+ return true;
435
+ },
436
+ isPicture: function (suffix) {
437
+ if (!suffix || suffix === "") {
438
+ return false;
439
+ }
440
+
441
+ let fileTypeMap = {
442
+ jpg: true,
443
+ jpeg: true,
444
+ png: true,
445
+ gif: true,
446
+ bmp: true,
447
+ mpg: true,
448
+ webp: true,
449
+ };
450
+
451
+ let type = fileTypeMap[suffix];
452
+ if (undefined === type) {
453
+ return false;
454
+ }
455
+
456
+ return true;
457
+ },
458
+ isVideo: function (suffix) {
459
+ if (!suffix || suffix === "") {
460
+ return false;
461
+ }
462
+ let fileTypeMap = {
463
+ avi: true,
464
+ mov: true,
465
+ mpeg: true,
466
+ mpg: true,
467
+ mp4: true,
468
+ rmvb: true,
469
+ asf: true,
470
+ flv: true,
471
+ ogg: true,
472
+ };
473
+
474
+ let type = fileTypeMap[suffix];
475
+ if (undefined === type) {
476
+ return false;
477
+ }
478
+
479
+ return true;
480
+ },
481
+ isText: function (suffix) {
482
+ if (!suffix || suffix === "") {
483
+ return false;
484
+ }
485
+ let fileTypeMap = {
486
+ txt: true,
487
+ log: true,
488
+ md: true,
489
+ py: true,
490
+ java: true,
491
+ cpp: true,
492
+ hpp: true,
493
+ c: true,
494
+ h: true,
495
+ json: true,
496
+ xml: true,
497
+ html: true,
498
+ sql: true,
499
+ js: true,
500
+ css: true,
501
+ jsp: true,
502
+ php: true,
503
+ properties: true,
504
+ conf: true,
505
+ out: true,
506
+ sh: true,
507
+ bat: true,
508
+ msg: true,
509
+ cmake: true,
510
+ yaml: true,
511
+ yml: true,
512
+ };
513
+
514
+ let type = fileTypeMap[suffix];
515
+ if (undefined === type) {
516
+ return false;
517
+ }
518
+
519
+ return true;
520
+ },
521
+ isZip: function (suffix) {
522
+ if (!suffix || suffix === "") {
523
+ return false;
524
+ }
525
+ let fileTypeMap = {
526
+ zip: true,
527
+ war: true,
528
+ rar: true,
529
+ "7z": true,
530
+ gz: true,
531
+ tgz: true,
532
+ xz: true,
533
+ txz: true,
534
+ bz2: true,
535
+ tbz2: true,
536
+ tar: true,
537
+ };
538
+
539
+ let type = fileTypeMap[suffix];
540
+ if (undefined === type) {
541
+ return false;
542
+ }
543
+
544
+ return true;
545
+ },
546
+ isOffice: function (suffix) {
547
+ if (!suffix || suffix === "") {
548
+ return false;
549
+ }
550
+ let fileTypeMap = {
551
+ doc: true,
552
+ docx: true,
553
+ ppt: true,
554
+ pptx: true,
555
+ xls: true,
556
+ xlsx: true,
557
+ };
558
+
559
+ let type = fileTypeMap[suffix];
560
+ if (undefined === type) {
561
+ return false;
562
+ }
563
+
564
+ return true;
565
+ },
566
+ isPdf: function (suffix) {
567
+ if (!suffix || suffix === "") {
568
+ return false;
569
+ }
570
+ let fileTypeMap = {
571
+ pdf: true,
572
+ };
573
+
574
+ let type = fileTypeMap[suffix];
575
+ if (undefined === type) {
576
+ return false;
577
+ }
578
+
579
+ return true;
580
+ },
581
+ isPictureFile: function (fileName) {
582
+ if (!fileName) return false;
583
+ let typeStr = Object.prototype.toString.call(fileName);
584
+ let suffix = null;
585
+ if (typeStr === "[object Object]") {
586
+ suffix = this.getFileSuffix(fileName.name);
587
+ } else {
588
+ suffix = this.getFileSuffix(fileName);
589
+ }
590
+ return this.isPicture(suffix);
591
+ },
592
+ isTextFile: function (fileName) {
593
+ let suffix = this.getFileSuffix(fileName);
594
+ return this.isText(suffix);
595
+ },
596
+ getShowUrl(url, showImagePreview) {
597
+ let index = url.lastIndexOf("/");
598
+ let filename;
599
+ if (index >= 0) {
600
+ filename = url.substring(url.lastIndexOf("/") + 1);
601
+ } else {
602
+ filename = url;
603
+ }
604
+
605
+ if (this.isPictureFile(filename) && showImagePreview !== false) {
606
+ return url;
607
+ } else {
608
+ return this.getFileIconRequire(filename);
609
+ }
610
+ },
611
+ resolveFileIconName: function (name, showType) {
612
+ let iconType = this.getDiyFileIconType(name) || "other";
613
+ if (showType) {
614
+ iconType = showType;
615
+ }
616
+ return FILE_ICON_NAME_MAP[iconType];
617
+ },
618
+ getFileIconRequire: function (name, showType) {
619
+ return reqImg(this.resolveFileIconName(name, showType));
620
+ },
621
+ getFileIconPath: function (name, showType) {
622
+ return "/resources/images/" + this.resolveFileIconName(name, showType);
623
+ },
624
+ getDiyFileIconType: function (name) {
625
+ let suffix = this.getFileSuffix(name);
626
+ if (suffix === "") {
627
+ // 默认是文本类型
628
+ return "";
629
+ }
630
+
631
+ let iconType = FILE_ICON_TYPE_MAP[suffix];
632
+ if (undefined === iconType) {
633
+ return "";
634
+ }
635
+ return iconType;
636
+ },
637
+ getFileExtension(urlString) {
638
+ if (!urlString) return null;
639
+ const url = new URL(urlString);
640
+ // 获取路径部分,例如 "/images/photo.jpg"
641
+ const pathname = url.pathname;
642
+
643
+ // 使用 lastIndexOf 找到最后一个点的位置
644
+ const lastDotIndex = pathname.lastIndexOf(".");
645
+
646
+ // 如果没有点,或者点在最后一位(即没有后缀),返回空字符串
647
+ if (lastDotIndex === -1 || lastDotIndex === pathname.length - 1) {
648
+ return "";
649
+ }
650
+
651
+ // 截取点之后的部分
652
+ return pathname.slice(lastDotIndex + 1).toLowerCase();
653
+ },
654
+ downloadFile: function () {
655
+ let filePath, name;
656
+ let opts;
657
+ if (typeof arguments[0] === "string") {
658
+ filePath = arguments[0];
659
+ name = arguments[1];
660
+ } else {
661
+ opts = arguments[0];
662
+ filePath = opts.filePath;
663
+ name = opts.name;
664
+ }
665
+ if (filePath) {
666
+ let url = null;
667
+ if (filePath.indexOf("?") >= 0) {
668
+ url = filePath + "&_d=true";
669
+ } else {
670
+ url = filePath + "?_d=true";
671
+ }
672
+ if (name) {
673
+ let fileSuffix = this.getFileExtension(filePath);
674
+ if (fileSuffix && !name.endsWith("." + fileSuffix)) {
675
+ name = name + "." + fileSuffix;
676
+ }
677
+
678
+ url += "&_n=" + encodeURIComponent(name);
679
+ }
680
+ // window.open(url);
681
+ openInNewTab(url);
682
+ }
683
+ },
684
+ isPreviewFile(fileName) {
685
+ let fileSuffix = this.getFileSuffix(fileName);
686
+ return typeList.includes(fileSuffix);
687
+ },
688
+ };
689
+
690
+ Vue.prototype.$openFilePreview = function () {
691
+ let filePath;
692
+ let opts;
693
+ if (typeof arguments[0] === "string") {
694
+ filePath = arguments[0];
695
+ } else {
696
+ let attachment = arguments[0];
697
+ filePath = attachment.domain + attachment.url;
698
+ }
699
+ let fileSuffix = this.$commonFileUtil.getFileSuffix(filePath);
700
+ if (!typeList.includes(fileSuffix)) {
701
+ return;
702
+ }
703
+
704
+ this.$http({
705
+ url: USER_PREFIX + "/sf_common/getFilePreviewUrl",
706
+ method: `post`,
707
+ data: {
708
+ url: filePath,
709
+ },
710
+ isLoading: true,
711
+ success: (res) => {
712
+ if (res.objx) {
713
+ openInNewTab(res.objx);
714
+ }
715
+ },
716
+ });
717
+ };
718
+
719
+ function openInNewTab(url) {
720
+ if (!url) return;
721
+ let a = document.createElement("a");
722
+ a.href = url;
723
+ a.target = "_blank";
724
+ document.body.appendChild(a);
725
+ a.click();
726
+ document.body.removeChild(a);
727
+ }
728
+
729
+ Vue.prototype.$getFilePreviewUrl = async function (obj, callback) {
730
+ let filePath;
731
+ let opts;
732
+ if (typeof obj === "string") {
733
+ filePath = obj;
734
+ } else {
735
+ let attachment = obj;
736
+ filePath = attachment.domain + attachment.url;
737
+ }
738
+ let fileSuffix = this.$commonFileUtil.getFileSuffix(filePath);
739
+ /*if (!typeList.includes(fileSuffix)) {
740
+ return;
741
+ }*/
742
+
743
+ return this.$http({
744
+ url: USER_PREFIX + "/sf_common/getFilePreviewUrl",
745
+ method: `post`,
746
+ data: {
747
+ url: filePath,
748
+ },
749
+ isLoading: true,
750
+ success: (res) => {
751
+ callback && callback(res.objx);
752
+ },
753
+ });
754
+ };
755
+
756
+ Vue.prototype.$baseFilePreview = function (attachment, index) {
757
+ let that = this;
758
+ let openImagePreView = function (attachments, index) {
759
+ let pictureIndex = -1;
760
+ let pictureDtoList = [];
761
+ index = index || 0;
762
+ attachments.forEach((item, i) => {
763
+ let typeStr = Object.prototype.toString.call(item);
764
+ if (typeStr === "[object Object]") {
765
+ if (that.$commonFileUtil.isPictureFile(item.url)) {
766
+ if (i <= index) {
767
+ pictureIndex++;
768
+ }
769
+ pictureDtoList.push(item.domain + item.url);
770
+ }
771
+ } else {
772
+ if (that.$commonFileUtil.isPictureFile(item)) {
773
+ if (i <= index) {
774
+ pictureIndex++;
775
+ }
776
+ pictureDtoList.push(item);
777
+ }
778
+ }
779
+ });
780
+
781
+ let a = Vue.extend(ElImageViewer);
782
+ let instance = new a({
783
+ propsData: {
784
+ onClose: () => {
785
+ dom.remove();
786
+ },
787
+ initialIndex: pictureIndex,
788
+ urlList: pictureDtoList,
789
+ },
790
+ });
791
+ let dom = instance.$mount().$el;
792
+ document.body.append(dom);
793
+ };
794
+ let openPreview = function (attachment, index) {
795
+ if (Array.isArray(attachment)) {
796
+ let currentFile = attachment[index];
797
+ let typeStr = Object.prototype.toString.call(currentFile);
798
+ let url =
799
+ typeStr === "[object Object]"
800
+ ? currentFile.domain + currentFile.url
801
+ : currentFile;
802
+ if (that.$commonFileUtil.isPictureFile(url)) {
803
+ openImagePreView(attachment, index);
804
+ } else if (that.$commonFileUtil.isPreviewFile(url)) {
805
+ that.$openFilePreview(url);
806
+ }
807
+ } else {
808
+ let typeStr = Object.prototype.toString.call(attachment);
809
+ let url =
810
+ typeStr === "[object Object]"
811
+ ? attachment.domain + attachment.url
812
+ : attachment;
813
+ if (that.$commonFileUtil.isPictureFile(url)) {
814
+ openImagePreView([url], 0);
815
+ } else if (that.$commonFileUtil.isPreviewFile(url)) {
816
+ that.$openFilePreview(url);
817
+ }
818
+ }
819
+ };
820
+ openPreview(attachment, index);
821
+ };
822
+
823
+ Vue.prototype.$openEditView = function (key) {
824
+ this[key] = false;
825
+ setTimeout(() => {
826
+ this[key] = true;
827
+ }, 200);
828
+ };
829
+
830
+ Vue.prototype.$baseReload = function (param) {
831
+ this.$emit("reload", this, param);
832
+ };
833
+
834
+ Vue.prototype.$reloadHandle = function (target, param) {
835
+ let visibleKey = target.$attrs["visible-key"] || "showEdit";
836
+ let parentTarget = target.$attrs["parent-target"] || target.$parent;
837
+ let originTarget = parentTarget.$refs._viewDialog ? parentTarget : target;
838
+ let updateParam =
839
+ param !== null &&
840
+ param !== undefined &&
841
+ param.updateParam !== null &&
842
+ param.updateParam !== undefined
843
+ ? param.updateParam
844
+ : {};
845
+ for (let key in updateParam) {
846
+ originTarget.$emit("update:" + key, updateParam[key]);
847
+ }
848
+ parentTarget[visibleKey] = false;
849
+ return new Promise((resolve) => {
850
+ setTimeout(() => {
851
+ parentTarget[visibleKey] = true;
852
+ parentTarget.$nextTick(resolve);
853
+ }, 200);
854
+ });
855
+ };
856
+
857
+ Vue.prototype.$baseStartPickerOptions = function (value, type) {
858
+ return {
859
+ disabledDate: (time) => {
860
+ if (value !== null && value !== undefined && value !== "") {
861
+ let date = new Date(value.replace(/-/g, "/"));
862
+ if (!type || type === "date") {
863
+ date.setDate(date.getDate() + 1);
864
+ return time.getTime() >= date.getTime();
865
+ } else if (type === "year") {
866
+ return time.getYear() > date.getYear();
867
+ } else if (type === "month") {
868
+ date.setMonth(date.getMonth() + 1);
869
+ return time.getTime() >= date.getTime();
870
+ }
871
+ } else {
872
+ return false;
873
+ }
874
+ },
875
+ };
876
+ };
877
+
878
+ Vue.prototype.$baseEndPickerOptions = function (value, format) {
879
+ return {
880
+ disabledDate: (time) => {
881
+ if (value !== null && value !== undefined && value !== "") {
882
+ let date = new Date(value.replace(/-/g, "/"));
883
+ return time.getTime() < date.getTime();
884
+ } else {
885
+ return false;
886
+ }
887
+ },
888
+ };
889
+ };
890
+
891
+ //除法
892
+ function baseDiv() {
893
+ let value = 0;
894
+ if (arguments.length) {
895
+ value = arguments[0];
896
+ for (let i = 1; i < arguments.length; i++) {
897
+ value = XEUtils.divide(value, arguments[i]);
898
+ }
899
+ }
900
+ return value;
901
+ }
902
+
903
+ //乘法
904
+ function baseMul() {
905
+ let value = 0;
906
+ if (arguments.length) {
907
+ value = arguments[0];
908
+ for (let i = 1; i < arguments.length; i++) {
909
+ value = XEUtils.multiply(value, arguments[i]);
910
+ }
911
+ }
912
+ return value;
913
+ }
914
+
915
+ //加法
916
+ function baseAdd() {
917
+ let value = 0;
918
+ if (arguments.length) {
919
+ value = arguments[0];
920
+ for (let i = 1; i < arguments.length; i++) {
921
+ value = XEUtils.add(value, arguments[i]);
922
+ }
923
+ }
924
+ return value;
925
+ }
926
+
927
+ //减法
928
+ function baseSub() {
929
+ let value = 0;
930
+ if (arguments.length) {
931
+ value = arguments[0];
932
+ for (let i = 1; i < arguments.length; i++) {
933
+ value = XEUtils.subtract(value, arguments[i]);
934
+ }
935
+ }
936
+ return value;
937
+ }
938
+
939
+ Vue.prototype.$baseAdd = baseAdd;
940
+ Vue.prototype.$baseSub = baseSub;
941
+ Vue.prototype.$baseMul = baseMul;
942
+ Vue.prototype.$baseDiv = baseDiv;
943
+
944
+ /**
945
+ * 格式化数字为带千分位的字符串。
946
+ *
947
+ * @param {string | number} value - 输入值
948
+ * @param {Object} [options={}] - 配置
949
+ * @param {boolean} [options.fixed=false] -
950
+ * - `true`: 启用定点精度处理 —— 使用 toFixed(digits) 四舍五入并补零到指定小数位。
951
+ * - `false`(默认): 保留原始小数形式(不四舍五入、不补零、保留尾随零)。
952
+ * @param {number} [options.digits=2] - 小数位数(仅在 fixed: true 时生效)
953
+ * @param {string} [options.thousandsSeparator=','] - 千分位分隔符(始终生效)
954
+ * @param {string} [options.decimalSeparator='.'] - 小数点符号
955
+ * @returns {string}
956
+ *
957
+ * @example
958
+ * // 默认:保留原始小数
959
+ * formatNumber(0.2); // "0.2"
960
+ * formatNumber("0.2000"); // "0.2000"
961
+ *
962
+ * // 启用定点精度处理
963
+ * formatNumber(0.2, { fixed: true }); // "0.20"
964
+ * formatNumber("123.456", { fixed: true, digits: 1 }); // "123.5"
965
+ * formatNumber(1000, { fixed: true, digits: 0 }); // "1,000"
966
+ */
967
+ function formatNumber(value, options = {}) {
968
+ if (value === null || value === undefined || value === "") {
969
+ return "";
970
+ }
971
+
972
+ const {
973
+ fixed = false,
974
+ digits = 2,
975
+ thousandsSeparator = ",",
976
+ decimalSeparator = ".",
977
+ } = options;
978
+
979
+ const isNumber = typeof value === "number";
980
+ let str = String(value).trim();
981
+
982
+ // Normalize ".123" "0.123"
983
+ if (str.charCodeAt(0) === 46) {
984
+ str = "0" + str;
985
+ } else if (str.startsWith("-.")) {
986
+ str = "-0." + str.slice(2);
987
+ }
988
+
989
+ let intPart, decPart, isNegative;
990
+
991
+ if (fixed) {
992
+ // 启用精度处理:toFixed + 补零
993
+ const num = isNumber ? value : parseFloat(str);
994
+ if (num !== num) return str;
995
+
996
+ const fixedStr = num.toFixed(digits);
997
+ const dotIndex = fixedStr.indexOf(".");
998
+ intPart = dotIndex === -1 ? fixedStr : fixedStr.slice(0, dotIndex);
999
+ decPart = dotIndex === -1 ? "" : fixedStr.slice(dotIndex + 1);
1000
+ isNegative = intPart.charCodeAt(0) === 45;
1001
+ if (isNegative) intPart = intPart.slice(1);
1002
+ } else {
1003
+ // 保留原始小数
1004
+ let s = str;
1005
+ isNegative = s.charCodeAt(0) === 45;
1006
+ if (isNegative) s = s.slice(1);
1007
+
1008
+ const dotIndex = s.indexOf(".");
1009
+ intPart = dotIndex === -1 ? s : s.slice(0, dotIndex);
1010
+ decPart = dotIndex === -1 ? "" : s.slice(dotIndex + 1);
1011
+
1012
+ if (intPart === "") intPart = "0";
1013
+ if (!/^\d+$/.test(intPart)) return str;
1014
+ }
1015
+
1016
+ // 千分位(始终应用)
1017
+ let fmtInt = intPart;
1018
+ if (intPart !== "0") {
1019
+ let out = "";
1020
+ for (let i = intPart.length - 1, c = 0; i >= 0; i--, c++) {
1021
+ if (c > 0 && c % 3 === 0) out = thousandsSeparator + out;
1022
+ out = intPart[i] + out;
1023
+ }
1024
+ fmtInt = out;
1025
+ }
1026
+
1027
+ // 拼接
1028
+ let result = isNegative ? "-" + fmtInt : fmtInt;
1029
+ if (decPart) {
1030
+ result += decimalSeparator + decPart;
1031
+ } else if (fixed && digits > 0) {
1032
+ result += decimalSeparator + "0".repeat(digits);
1033
+ }
1034
+
1035
+ return result;
1036
+ }
1037
+ Vue.prototype.$formatNumber = formatNumber;
1038
+
1039
+ /**
1040
+ * 生成一个符合 RFC4122 标准的随机 UUID (v4)
1041
+ * @returns {string} 格式为 "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx" 的 UUID 字符串
1042
+ */
1043
+ function generateUUID() {
1044
+ const buf = new Uint8Array(16);
1045
+ crypto.getRandomValues(buf);
1046
+ buf[6] = (buf[6] & 0x0f) | 0x40; // version 4
1047
+ buf[8] = (buf[8] & 0x3f) | 0x80; // variant RFC4122
1048
+ const hex = Array.from(buf, (b) => b.toString(16).padStart(2, "0")).join(
1049
+ ""
1050
+ );
1051
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(
1052
+ 12,
1053
+ 16
1054
+ )}-${hex.slice(16, 20)}-${hex.slice(20)}`;
1055
+ }
1056
+ Vue.prototype.$generateUUID = generateUUID;
1057
+
1058
+ //数字精确位数
1059
+ Vue.prototype.$currency = function (value, priceScale, priceRoundType) {
1060
+ if (value !== null && value !== undefined) {
1061
+ if (priceScale === null || priceScale === undefined) {
1062
+ priceScale = 2;
1063
+ }
1064
+ if (priceRoundType === null || priceRoundType === undefined) {
1065
+ priceRoundType = "roundHalfUp";
1066
+ }
1067
+ let price;
1068
+ if (priceRoundType === "roundHalfUp") {
1069
+ price = (
1070
+ Math.round(value * Math.pow(10, priceScale)) /
1071
+ Math.pow(10, priceScale)
1072
+ ).toFixed(priceScale);
1073
+ } else if (priceRoundType === "roundUp") {
1074
+ price = (
1075
+ Math.ceil(value * Math.pow(10, priceScale)) / Math.pow(10, priceScale)
1076
+ ).toFixed(priceScale);
1077
+ } else {
1078
+ price = (
1079
+ Math.floor(value * Math.pow(10, priceScale)) /
1080
+ Math.pow(10, priceScale)
1081
+ ).toFixed(priceScale);
1082
+ }
1083
+ return price;
1084
+ }
1085
+ };
1086
+
1087
+ Vue.prototype.$getBaseDicts = async function (option) {
1088
+ let isLoading = option.isLoading || false;
1089
+ return this.$http({
1090
+ url: USER_PREFIX + "/common_attribute/listItems",
1091
+ method: `post`,
1092
+ data: {
1093
+ code: option.code,
1094
+ enabled: true,
1095
+ forCompany: true,
1096
+ ...option.data,
1097
+ },
1098
+ isLoading: isLoading,
1099
+ modalStrictly: true,
1100
+ success: (res) => {
1101
+ let dicts = res.objx || [];
1102
+ let dictMap = {};
1103
+ for (let item of dicts) {
1104
+ dictMap[item.sn] = item.value;
1105
+ }
1106
+ /* dicts.forEach((item) => {
1107
+ dictMap[item.sn] = item.value;
1108
+ }); */
1109
+ option.success &&
1110
+ option.success({
1111
+ dicts,
1112
+ dictMap,
1113
+ });
1114
+ },
1115
+ });
1116
+ };
1117
+
1118
+ imFun.Form.methods.$baseValidate = function (callback, opt) {
1119
+ let that = this;
1120
+ that.validate((valid, obj, c, d) => {
1121
+ if (!valid && (!opt || opt.errorTip !== false)) {
1122
+ this.$message({
1123
+ message: this.$t2("必填项不能为空", "system.message.required"),
1124
+ type: "error",
1125
+ duration: 2000,
1126
+ });
1127
+ }
1128
+ scrollToFirstError(that);
1129
+ callback(valid, obj);
1130
+ });
1131
+ };
1132
+
1133
+ function scrollToFirstError(formTarget) {
1134
+ // 获取第一个验证失败的字段
1135
+ // let formTarget = this.$refs['renderForm'];
1136
+ const firstErrorField = Object.keys(formTarget.fields).find((key) => {
1137
+ return formTarget.fields[key].validateState === "error";
1138
+ });
1139
+
1140
+ if (firstErrorField) {
1141
+ const field = formTarget.fields[firstErrorField];
1142
+
1143
+ let dom = field.$el;
1144
+ if (dom) {
1145
+ // 滚动到该字段位置
1146
+ dom.scrollIntoView({
1147
+ behavior: "smooth",
1148
+ block: "center",
1149
+ });
1150
+
1151
+ // 添加高亮效果
1152
+ dom.classList.add("highlight");
1153
+
1154
+ // 3秒后移除高亮效果
1155
+ setTimeout(() => {
1156
+ dom.classList.remove("highlight");
1157
+ }, 3000);
1158
+ }
1159
+ }
1160
+ }
1161
+
1162
+ Vue.prototype.$getBillInfo = async function (option) {
1163
+ let defaultOption = {
1164
+ url: null,
1165
+ method: `post`,
1166
+ data: {},
1167
+ isLoading: true,
1168
+ modalStrictly: true,
1169
+ success: null,
1170
+ };
1171
+ let opt = Object.assign({}, defaultOption, option);
1172
+ delete opt.wfConfig;
1173
+ return this.$http({
1174
+ ...opt,
1175
+ success: (res, response) => {
1176
+ option.success && option.success(res, response);
1177
+ },
1178
+ });
1179
+ };
1180
+
1181
+ Vue.prototype.$downloadByFileWhole = function (fileWhole, fileName) {
1182
+ let that = this;
1183
+ if (!fileWhole) {
1184
+ this.$baseAlert("凭证信息不存在");
1185
+ return;
1186
+ }
1187
+ let getDownloadDomian = function (callback) {
1188
+ that.$http({
1189
+ method: "post",
1190
+ url: USER_PREFIX + "/common/fileDownloadUrl",
1191
+ data: {},
1192
+ isLoading: true,
1193
+ success: (res) => {
1194
+ callback(res.objx);
1195
+ },
1196
+ });
1197
+ };
1198
+ getDownloadDomian((domain) => {
1199
+ if (fileName) {
1200
+ fileWhole.fileName = fileName;
1201
+ }
1202
+ that.$http({
1203
+ method: "post",
1204
+ url: domain + "/docfile/download",
1205
+ data: fileWhole,
1206
+ isLoading: true,
1207
+ success: (res) => {
1208
+ // window.open(res.objx.url);
1209
+ let url = res.objx.url;
1210
+ openInNewTab(url);
1211
+ },
1212
+ });
1213
+ });
1214
+ };
1215
+
1216
+ let isDef = function (value) {
1217
+ return value !== undefined && value !== null;
1218
+ };
1219
+
1220
+ Vue.prototype.$t2 = function (defaultValue, path, values) {
1221
+ let that = window.$vueRoot;
1222
+ if (!that.hasOwnProperty("_i18n")) {
1223
+ return defaultValue;
1224
+ }
1225
+ const i18n = that.$i18n;
1226
+ path = path || defaultValue;
1227
+ return i18n.te(path) ? i18n.t(path, values) : defaultValue;
1228
+ };
1229
+
1230
+ Vue.prototype.$t1 = function (path, values) {
1231
+ let that = window.$vueRoot;
1232
+ if (!that.hasOwnProperty("_i18n")) {
1233
+ return path;
1234
+ }
1235
+ let lang = that.$i18n.locale;
1236
+ const i18n = that.$i18n;
1237
+ if (lang === "zh") {
1238
+ let val = i18n._t(path, lang, { zh: { [path]: path } }, null, values);
1239
+ return val;
1240
+ } else {
1241
+ if (!i18n.te(path)) {
1242
+ return i18n._t(path, lang, { zh: { [path]: path } }, null, values);
1243
+ } else {
1244
+ return (
1245
+ i18n.t(path, values) ||
1246
+ i18n._t(path, lang, { zh: { [path]: path } }, null, values)
1247
+ );
1248
+ }
1249
+ }
1250
+ };
1251
+
1252
+ Vue.prototype.$i18nVal = function (zhValue, enValue) {
1253
+ let that = window.$vueRoot;
1254
+ if (!that.hasOwnProperty("_i18n")) {
1255
+ return zhValue;
1256
+ }
1257
+ let $i18n = that.$i18n;
1258
+ let value = zhValue;
1259
+ if ($i18n.locale === "zh") {
1260
+ value = zhValue;
1261
+ } else if ($i18n.locale === "en") {
1262
+ value = enValue;
1263
+ }
1264
+ return value;
1265
+ };
1266
+
1267
+ Vue.prototype.$utcToLocal = function (utcTime) {
1268
+ if (!utcTime) return utcTime;
1269
+ let offsetHours = this.$store.getters.utcTransformOffset; // 时区偏移量,单位:小时
1270
+ if (!offsetHours || offsetHours === 0) return utcTime;
1271
+ let localTime = moment(utcTime).add(offsetHours, "hours");
1272
+ return localTime.format("YYYY-MM-DD HH:mm:ss");
1273
+ };
1274
+
1275
+ Vue.prototype.$window = window;
1276
+ };
1277
+
1278
+ window && Object.assign(window, imFun.prefixConfig);
1279
+ if (typeof window !== "undefined" && window.Vue) {
1280
+ install(window.Vue);
1281
+ }
1282
+
1283
+ export default install;