af-mobile-client-vue3 1.3.30 → 1.3.31

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 (283) hide show
  1. package/.claude/settings.local.json +10 -0
  2. package/.cursorrules +60 -60
  3. package/.editorconfig +9 -9
  4. package/.env +10 -10
  5. package/.env.development +1 -1
  6. package/.env.production +1 -1
  7. package/.node-version +1 -1
  8. package/.vscode/extensions.json +12 -12
  9. package/.vscode/settings.json +68 -66
  10. package/CLAUDE.md +218 -189
  11. package/README.md +182 -182
  12. package/af-example-mobile-vue-web.iml +9 -9
  13. package/build/vite/index.ts +98 -98
  14. package/build/vite/optimize.ts +34 -34
  15. package/build/vite/vconsole.ts +47 -47
  16. package/commitlint.config.ts +32 -32
  17. package/compress.js +36 -36
  18. package/eslint.config.ts +31 -30
  19. package/index.html +23 -23
  20. package/mock/data.ts +20 -20
  21. package/mock/index.ts +7 -7
  22. package/mock/modules/prose.mock.ts +13 -13
  23. package/mock/modules/user.mock.ts +95 -152
  24. package/mock/util.ts +19 -19
  25. package/netlify.toml +12 -12
  26. package/package.json +114 -114
  27. package/postcss.config.ts +27 -27
  28. package/public/favicon.svg +4 -4
  29. package/public/safari-pinned-tab.svg +4 -4
  30. package/scripts/verifyCommit.js +19 -19
  31. package/src/App.vue +79 -79
  32. package/src/api/auth/index.ts +77 -0
  33. package/src/api/auth/types.ts +200 -0
  34. package/src/api/mock/index.ts +30 -30
  35. package/src/api/user/index.ts +40 -40
  36. package/src/assets/img/user/login/background-shadow-1.svg +20 -20
  37. package/src/assets/img/user/login/logo-background.svg +20 -20
  38. package/src/bootstrap.ts +26 -26
  39. package/src/components/core/BeautifulLoading/index.vue +52 -52
  40. package/src/components/core/ImageUploader/index.vue +251 -251
  41. package/src/components/core/NavBar/index.vue +53 -53
  42. package/src/components/core/Tabbar/index.vue +32 -32
  43. package/src/components/core/Uploader/index.vue +124 -124
  44. package/src/components/core/XGridDropOption/index.vue +154 -154
  45. package/src/components/core/XMultiSelect/index.vue +183 -183
  46. package/src/components/core/XSelect/index.vue +149 -149
  47. package/src/components/data/CardContainer/CardContainer.vue +118 -118
  48. package/src/components/data/CardContainer/CardHeader.vue +99 -99
  49. package/src/components/data/InfoDisplay/index.vue +132 -132
  50. package/src/components/data/UserDetail/api.ts +24 -24
  51. package/src/components/data/UserDetail/index.vue +620 -620
  52. package/src/components/data/UserDetail/recordEntries.ts +159 -159
  53. package/src/components/data/UserDetail/types.ts +26 -26
  54. package/src/components/data/XBadge/index.vue +82 -82
  55. package/src/components/data/XCellDetail/index.vue +105 -105
  56. package/src/components/data/XCellList/XCellList.md +432 -432
  57. package/src/components/data/XCellList/index.vue +1436 -1436
  58. package/src/components/data/XCellListFilter/QrScanner/index.vue +207 -207
  59. package/src/components/data/XCellListFilter/QrScanner/startScanAnimation.ts +53 -53
  60. package/src/components/data/XCellListFilter/VpnRecognition/index.vue +119 -119
  61. package/src/components/data/XCellListFilter/index.vue +705 -705
  62. package/src/components/data/XForm/index.vue +659 -659
  63. package/src/components/data/XFormGroup/doc/DeviceForm.vue +122 -122
  64. package/src/components/data/XFormGroup/doc/FormGroupDemo.vue +56 -56
  65. package/src/components/data/XFormGroup/doc/README.md +286 -286
  66. package/src/components/data/XFormGroup/doc/UserForm.vue +102 -102
  67. package/src/components/data/XFormGroup/index.vue +240 -240
  68. package/src/components/data/XFormItem/index.vue +1310 -1310
  69. package/src/components/data/XOlMap/README.md +227 -227
  70. package/src/components/data/XOlMap/XLocationPicker/index.vue +226 -226
  71. package/src/components/data/XOlMap/index.vue +1490 -1490
  72. package/src/components/data/XOlMap/types.ts +149 -149
  73. package/src/components/data/XOlMap/utils/{wgs84ToGcj02.js → wgs84ToGcj02.ts} +171 -154
  74. package/src/components/data/XReportForm/DateTimeSecondsPicker.vue +208 -208
  75. package/src/components/data/XReportForm/XReportFormJsonRender.vue +220 -220
  76. package/src/components/data/XReportForm/index.vue +1393 -1393
  77. package/src/components/data/XReportGrid/XAddReport/XAddReport.vue +198 -198
  78. package/src/components/data/XReportGrid/XAddReport/index.js +3 -3
  79. package/src/components/data/XReportGrid/XAddReport/index.md +53 -53
  80. package/src/components/data/XReportGrid/XAddReport/index.ts +10 -10
  81. package/src/components/data/XReportGrid/XReport.vue +960 -960
  82. package/src/components/data/XReportGrid/XReportDemo.vue +33 -33
  83. package/src/components/data/XReportGrid/XReportDesign.vue +597 -597
  84. package/src/components/data/XReportGrid/XReportDrawer/XReportDrawer.vue +148 -148
  85. package/src/components/data/XReportGrid/XReportDrawer/index.js +3 -3
  86. package/src/components/data/XReportGrid/XReportDrawer/index.ts +10 -10
  87. package/src/components/data/XReportGrid/XReportJsonRender.vue +399 -399
  88. package/src/components/data/XReportGrid/XReportTrGroup.vue +592 -592
  89. package/src/components/data/XReportGrid/index.md +46 -46
  90. package/src/components/data/XReportGrid/print.js +184 -184
  91. package/src/components/data/XSignature/index.vue +284 -284
  92. package/src/components/data/XTag/index.vue +10 -10
  93. package/src/components/layout/NormalDataLayout/index.vue +69 -69
  94. package/src/components/layout/TabBarLayout/index.vue +40 -40
  95. package/src/composables/dark.ts +5 -5
  96. package/src/config/routes.ts +9 -9
  97. package/src/constants/index.ts +2 -2
  98. package/src/enums/requestEnum.ts +25 -25
  99. package/src/expression/ExpressionRunner.ts +28 -28
  100. package/src/expression/TestExpression.ts +510 -510
  101. package/src/expression/core/Delegate.ts +116 -116
  102. package/src/expression/core/Expression.ts +1359 -1359
  103. package/src/expression/core/Program.ts +985 -985
  104. package/src/expression/core/Token.ts +29 -29
  105. package/src/expression/enums/ExpressionType.ts +81 -81
  106. package/src/expression/enums/TokenType.ts +11 -11
  107. package/src/expression/exception/BreakWayException.ts +2 -2
  108. package/src/expression/exception/ContinueWayException.ts +2 -2
  109. package/src/expression/exception/ExpressionException.ts +29 -29
  110. package/src/expression/exception/ReturnWayException.ts +14 -14
  111. package/src/expression/exception/ServiceException.ts +22 -22
  112. package/src/expression/instances/JSONArray.ts +52 -52
  113. package/src/expression/instances/JSONObject.ts +118 -118
  114. package/src/expression/instances/LogicConsole.ts +31 -31
  115. package/src/font-style/font.css +4 -4
  116. package/src/hooks/useBoolean.ts +26 -26
  117. package/src/hooks/useCommon.ts +9 -9
  118. package/src/hooks/useLoading.ts +16 -16
  119. package/src/hooks/useLogin.ts +97 -97
  120. package/src/icons/svg/check-in.svg +32 -32
  121. package/src/icons/svg/dark.svg +4 -4
  122. package/src/icons/svg/github.svg +4 -4
  123. package/src/icons/svg/light.svg +4 -4
  124. package/src/icons/svg/link.svg +4 -4
  125. package/src/icons/svgo.yml +22 -22
  126. package/src/layout/GridView/index.vue +16 -16
  127. package/src/layout/PageLayout.vue +9 -9
  128. package/src/layout/SingleLayout.vue +9 -9
  129. package/src/locales/en-US.json +128 -128
  130. package/src/locales/zh-CN.json +128 -128
  131. package/src/logic/LogicRunner.ts +67 -67
  132. package/src/logic/TestLogic.ts +13 -13
  133. package/src/logic/plugins/common/DateTools.ts +35 -35
  134. package/src/logic/plugins/common/VueTools.ts +30 -30
  135. package/src/logic/plugins/index.ts +7 -7
  136. package/src/main.ts +44 -44
  137. package/src/plugins/AppData.ts +38 -38
  138. package/src/plugins/GetLoginInfoService.ts +10 -10
  139. package/src/plugins/collectIcons.ts +10 -10
  140. package/src/plugins/index.ts +11 -11
  141. package/src/router/README.md +8 -8
  142. package/src/router/external-routes.ts +60 -0
  143. package/src/router/guards.ts +131 -59
  144. package/src/router/index.ts +35 -35
  145. package/src/router/invoiceRoutes.ts +33 -33
  146. package/src/router/routes.ts +426 -347
  147. package/src/services/api/Login.ts +6 -6
  148. package/src/services/api/common.ts +109 -109
  149. package/src/services/api/index.ts +7 -7
  150. package/src/services/api/manage.ts +8 -8
  151. package/src/services/api/search.ts +16 -16
  152. package/src/services/api/user.ts +17 -17
  153. package/src/services/restTools.ts +56 -56
  154. package/src/services/v3Api.ts +147 -147
  155. package/src/stores/index.ts +13 -13
  156. package/src/stores/modules/counter.ts +19 -19
  157. package/src/stores/modules/homeApp.ts +55 -55
  158. package/src/stores/modules/routeCache.ts +22 -23
  159. package/src/stores/modules/setting.ts +87 -87
  160. package/src/stores/modules/user.ts +326 -235
  161. package/src/stores/mutation-type.ts +12 -7
  162. package/src/styles/app.less +36 -36
  163. package/src/styles/login.less +109 -109
  164. package/src/styles/var.less +25 -25
  165. package/src/types/auth.ts +85 -0
  166. package/src/types/env.d.ts +16 -16
  167. package/src/types/platform.ts +194 -0
  168. package/src/types/settings.ts +1 -1
  169. package/src/types/vue-router.d.ts +13 -9
  170. package/src/utils/Storage.ts +124 -124
  171. package/src/utils/authority-utils.ts +84 -84
  172. package/src/utils/common.ts +41 -41
  173. package/src/utils/crypto.ts +39 -39
  174. package/src/utils/dataUtil.ts +42 -42
  175. package/src/utils/dictUtil.ts +52 -52
  176. package/src/utils/http/index.ts +201 -199
  177. package/src/utils/i18n.ts +72 -72
  178. package/src/utils/indexedDB.ts +195 -195
  179. package/src/utils/inline-px-to-vw.ts +28 -28
  180. package/src/utils/mobileUtil.ts +33 -34
  181. package/src/utils/platform-auth.ts +134 -0
  182. package/src/utils/progress.ts +19 -19
  183. package/src/utils/routerUtil.ts +271 -271
  184. package/src/utils/runEvalFunction.ts +13 -13
  185. package/src/utils/secureStorage.ts +70 -71
  186. package/src/utils/set-page-title.ts +5 -5
  187. package/src/utils/validate.ts +6 -6
  188. package/src/views/chat/index.vue +153 -153
  189. package/src/views/common/Forbidden.vue +97 -0
  190. package/src/views/common/LoadError.vue +63 -63
  191. package/src/views/common/NotFound.vue +67 -67
  192. package/src/views/component/EvaluateRecordView/index.vue +40 -40
  193. package/src/views/component/IconifyView/index.vue +504 -504
  194. package/src/views/component/UserDetailView/UserDetailPage.vue +77 -77
  195. package/src/views/component/UserDetailView/index.vue +234 -234
  196. package/src/views/component/XCellDetailView/index.vue +217 -217
  197. package/src/views/component/XCellListView/index.vue +108 -129
  198. package/src/views/component/XFormAppraiseView/index.vue +174 -174
  199. package/src/views/component/XFormGroupView/index.vue +78 -82
  200. package/src/views/component/XFormView/index.vue +27 -27
  201. package/src/views/component/XOlMapView/XLocationPicker/index.vue +118 -118
  202. package/src/views/component/XOlMapView/index.vue +434 -434
  203. package/src/views/component/XOlMapView/testData.ts +64 -64
  204. package/src/views/component/XReportFormIframeView/index.vue +47 -47
  205. package/src/views/component/XReportFormView/index.vue +13 -13
  206. package/src/views/component/XReportGridView/index.vue +17 -17
  207. package/src/views/component/XRequestView/index.vue +234 -234
  208. package/src/views/component/XSignatureView/index.vue +50 -50
  209. package/src/views/component/index.vue +181 -181
  210. package/src/views/component/menu.vue +117 -117
  211. package/src/views/component/notice.vue +46 -46
  212. package/src/views/component/topNav.vue +36 -36
  213. package/src/views/external/index.vue +152 -0
  214. package/src/views/invoiceShow/index.vue +61 -61
  215. package/src/views/loading/AuthLoading.vue +345 -0
  216. package/src/views/user/login/ForgetPasswordForm.vue +94 -94
  217. package/src/views/user/login/LoginForm.vue +350 -347
  218. package/src/views/user/login/LoginTitle.vue +76 -76
  219. package/src/views/user/login/LoginWave.vue +109 -109
  220. package/src/views/user/login/index.vue +22 -22
  221. package/src/views/user/my/comm/ModifyPassword.vue +346 -346
  222. package/src/views/user/my/index.vue +507 -507
  223. package/src/views/user/register/index.vue +952 -952
  224. package/src/views/userRecords/AbnormalAlarmRecords.vue +21 -21
  225. package/src/views/userRecords/CardReplacementRecords.vue +21 -21
  226. package/src/views/userRecords/ChangeRecords.vue +19 -19
  227. package/src/views/userRecords/CommandViewRecords.vue +20 -20
  228. package/src/views/userRecords/GasCompensationRecords.vue +20 -20
  229. package/src/views/userRecords/InstrumentCollectionRecords.vue +21 -21
  230. package/src/views/userRecords/MeterRecords.vue +20 -20
  231. package/src/views/userRecords/OperateRecords.vue +51 -51
  232. package/src/views/userRecords/OtherChargeRecords.vue +19 -19
  233. package/src/views/userRecords/PaymentRecords.vue +28 -28
  234. package/src/views/userRecords/PriceAdjustmentRecords.vue +19 -19
  235. package/src/views/userRecords/ReplacementRecords.vue +19 -19
  236. package/src/views/userRecords/SafetyRecords.vue +19 -19
  237. package/src/views/userRecords/TransactionRecords.vue +21 -21
  238. package/src/views/userRecords/TransferRecords.vue +19 -19
  239. package/src/views/userRecords/operateRecordDetail/index.vue +316 -316
  240. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/AddUserDetail.vue +124 -124
  241. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/AdvanceDeliveryDetail.vue +88 -88
  242. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/AutoAccountsCancelDetail.vue +205 -205
  243. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/AutoAccountsDetail.vue +192 -192
  244. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/BankDkDetail.vue +192 -192
  245. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/BankPayDetail.vue +192 -192
  246. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/BlacklistDetail.vue +153 -153
  247. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/CancellationDetail.vue +101 -101
  248. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/CardMeterCenterCancelDetail.vue +127 -127
  249. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/CardMeterCenterDetail.vue +153 -153
  250. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/CardOverUserDetail.vue +153 -153
  251. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/ChangeMeterCancelDetail.vue +166 -166
  252. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/ChangeMeterDetail.vue +205 -205
  253. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/DisableManageDetail.vue +127 -127
  254. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/EnableManageDetail.vue +114 -114
  255. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/FaZheChangeDetail.vue +124 -124
  256. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/FeeDeductionDetail.vue +153 -153
  257. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/GasPriceChangeDetail.vue +126 -126
  258. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/InputtorChangeDetail.vue +126 -126
  259. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/IotMeterCenterCancelDetail.vue +114 -114
  260. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/IotMeterCenterDetail.vue +127 -127
  261. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/IotOpenDetail.vue +88 -88
  262. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/MachineCardDetail.vue +101 -101
  263. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/MachineMeterCenterCancelDetail.vue +218 -218
  264. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/MachineMeterCenterDetail.vue +153 -153
  265. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/OffGasAddGasDetail.vue +140 -140
  266. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/OtherChargeCancelDetail.vue +127 -127
  267. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/OtherChargeDetail.vue +114 -114
  268. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/OverUserChangeDetail.vue +127 -127
  269. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/ReBillDetail.vue +127 -127
  270. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/RefundDetail.vue +114 -114
  271. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/ReplaceCardManageCancelDetail.vue +127 -127
  272. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/ReplaceCardManageDetail.vue +114 -114
  273. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/SaleCardGasDetail.vue +140 -140
  274. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/TransferManageCancelDetail.vue +152 -152
  275. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/TransferManageDetail.vue +178 -178
  276. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/UserChangeDetail.vue +123 -123
  277. package/src/views/userRecords/operateRecordDetail/operateRecordDetails/WechatPayDetail.vue +192 -192
  278. package/src/views/userRecords/types.ts +66 -66
  279. package/tsconfig.json +39 -39
  280. package/uno.config.ts +82 -82
  281. package/vite.config.ts +119 -118
  282. package/src/router/types.ts +0 -7
  283. package/src/utils/wechatUtil.ts +0 -9
@@ -1,960 +1,960 @@
1
- <script setup lang="ts">
2
- import XReportDesign from '@af-mobile-client-vue3/components/data/XReportGrid/XReportDesign.vue'
3
- import { getConfigByName, runLogic } from '@af-mobile-client-vue3/services/api/common'
4
- import { useUserStore } from '@af-mobile-client-vue3/stores/modules/user'
5
- import { executeStrFunctionByContext } from '@af-mobile-client-vue3/utils/runEvalFunction'
6
- import {
7
- showDialog,
8
- Button as VanButton,
9
- Card as VanCard,
10
- Radio as VanRadio,
11
- RadioGroup as VanRadioGroup,
12
- Row as VanRow,
13
- Skeleton as VanSkeleton,
14
- Space as VanSpace,
15
- } from 'vant'
16
- import { computed, nextTick, onBeforeMount, onBeforeUnmount, onMounted, provide, ref, watch } from 'vue'
17
-
18
- // import HtmlToPdf from '@/utils/htmlToPDF'
19
-
20
- // Props
21
- const props = defineProps({
22
- files: {
23
- type: Array,
24
- default: () => [],
25
- },
26
- authority: {
27
- type: String,
28
- default: 'user',
29
- },
30
- editMode: {
31
- type: Boolean,
32
- default: true,
33
- },
34
- configName: {
35
- type: String,
36
- required: true,
37
- },
38
- activatedSlotName: {
39
- type: String,
40
- default: undefined,
41
- },
42
- localConfig: {
43
- type: Object,
44
- default: undefined,
45
- },
46
- dontFormat: {
47
- type: Boolean,
48
- default: true,
49
- },
50
- showImgInCell: {
51
- type: Boolean,
52
- default: false,
53
- },
54
- configData: {
55
- type: Object,
56
- default: undefined,
57
- },
58
- serverName: {
59
- type: String,
60
- default: '',
61
- },
62
- env: {
63
- type: String,
64
- default: 'prod',
65
- },
66
- displayOnly: {
67
- type: Boolean,
68
- default: true,
69
- },
70
- noPadding: {
71
- type: Boolean,
72
- default: true,
73
- },
74
- noTopBorder: {
75
- type: Boolean,
76
- default: false,
77
- },
78
- showTitle: {
79
- type: Boolean,
80
- default: true,
81
- },
82
- showSaveButton: {
83
- type: Boolean,
84
- default: false,
85
- },
86
- registerMap: {
87
- type: Array,
88
- default: undefined,
89
- },
90
- isWidget: {
91
- type: Boolean,
92
- default: true,
93
- },
94
- useOssForImg: {
95
- type: Boolean,
96
- default: true,
97
- },
98
- imgPrefix: {
99
- type: String,
100
- default: undefined,
101
- },
102
- })
103
-
104
- // Emits
105
- const emit = defineEmits(['updateImg', 'selectRow', 'cancel', 'register'])
106
-
107
- // Store
108
- const userStore = useUserStore()
109
- // const { user: currUser } = storeToRefs(userStore)
110
-
111
- // Refs
112
- // const XReportDesign = ref()
113
- const xAddReport = ref()
114
- const xReportDrawer = ref()
115
-
116
- // 状态
117
- const showSkeleton = ref(true)
118
- const config = ref()
119
- const type = ref('design')
120
- const onlyDisplay = ref(false)
121
- const _maxColSpan = ref(12)
122
- const scanFinish = ref(false)
123
- const activeConfig = ref(null)
124
- const originalConfig = ref(null)
125
- const configFromWeb = ref({})
126
- const timer = ref()
127
- const hasImages = ref(false)
128
- const imageList = ref([])
129
- const dataCache = ref()
130
- const diff = ref([])
131
- const globalData = ref({})
132
-
133
- // Computed
134
- const widget = computed(() => props.isWidget)
135
-
136
- // 在provide之前定义getGlobalData函数
137
- const getGlobalData = () => globalData.value
138
-
139
- function setGlobalData(obj: any) {
140
- globalData.value = obj
141
- }
142
-
143
- // 然后再进行provide
144
- provide('runLogic', runLogic)
145
- provide('openDialog', openDialog)
146
- provide('registerComponent', registerComponent)
147
- provide('getComponentByName', getComponentByName)
148
- provide('getParentComponentByName', getComponentByName)
149
- provide('getConfigByName', getConfigByName)
150
- provide('isWidget', widget)
151
- // provide('currUser', currUser)
152
- provide('setGlobalData', setGlobalData)
153
- provide('getGlobalData', getGlobalData)
154
-
155
- // Methods
156
- function slotRendered() {
157
- if (config.value?.mountedFunction) {
158
- let func = config.value.mountedFunction
159
- if (func && func.startsWith('function')) {
160
- func = func.replace('function', 'async function')
161
- executeStrFunctionByContext(null, func, [])
162
- }
163
- }
164
- }
165
-
166
- function registerComponent(componentName: string, component: any) {
167
- if (XReportDesign.value)
168
- XReportDesign.value[componentName] = component
169
- }
170
-
171
- // 数据处理方法
172
- function transformArray(inputList: any[]) {
173
- let operationIndex = 0
174
- let operationList = []
175
- const outputList = []
176
- for (const lst of inputList) {
177
- if (lst.length >= 1 && !lst.every(x => Array.isArray(x) || Array.isArray(lst[0]) || x.rowSpan === lst[0].rowSpan)) {
178
- operationList = lst
179
- break
180
- }
181
- else {
182
- operationIndex += 1
183
- }
184
- }
185
-
186
- let maxMergeRow = 0
187
-
188
- if (operationList.length === 0) {
189
- return inputList
190
- }
191
- else {
192
- const maxRow = Math.max(...operationList.map(item => item.rowSpan))
193
- let mergeIndexCol = 0
194
- for (let index = 0; index < operationList.length; index++) {
195
- const row = operationList[index]
196
- let rowSpan = row.rowSpan
197
- let mergeIndexRow = operationIndex + 1
198
- const rows = []
199
- if (rowSpan < maxRow && mergeIndexRow < inputList.length)
200
- rows.push([row])
201
-
202
- while (rowSpan < maxRow && mergeIndexRow < inputList.length) {
203
- rowSpan += inputList[mergeIndexRow][mergeIndexCol].rowSpan
204
- rows.push([inputList[mergeIndexRow][mergeIndexCol]])
205
- if (mergeIndexRow > maxMergeRow)
206
- maxMergeRow = mergeIndexRow
207
-
208
- mergeIndexRow++
209
- }
210
- if (rows.length !== 0)
211
- operationList[index] = rows
212
-
213
- if (row.rowSpan !== maxRow)
214
- mergeIndexCol++
215
- }
216
- }
217
-
218
- let putindex = 0
219
- while (operationIndex > 0) {
220
- outputList.push(inputList[putindex])
221
- putindex++
222
- operationIndex -= 1
223
- }
224
-
225
- outputList.push(operationList)
226
-
227
- while (maxMergeRow < inputList.length - 1) {
228
- outputList.push(inputList[maxMergeRow + 1])
229
- maxMergeRow += 1
230
- }
231
-
232
- return transformArray(outputList)
233
- }
234
-
235
- // 组件操作方法
236
- function getComponentByName(componentName: string) {
237
- return XReportDesign.value?.[componentName]
238
- }
239
-
240
- // 对话框操作
241
- function openDialog(configName: string, selectedId: any, mixinData: any, outEnv = {}, attr = {}) {
242
- xAddReport.value?.init({
243
- configName,
244
- selectedId,
245
- mixinData,
246
- outEnv,
247
- attr,
248
- })
249
- }
250
-
251
- function openDrawer(configName: string, selectedId: any, mixinData: any, outEnv = {}, attr = {}) {
252
- xReportDrawer.value?.init({
253
- configName,
254
- selectedId,
255
- mixinData,
256
- outEnv,
257
- attr,
258
- })
259
- }
260
-
261
- // 数据导出和打印
262
- function updateImg(data: any) {
263
- emit('updateImg', data)
264
- }
265
-
266
- function exportData() {
267
- let tempData
268
- if (!activeConfig.value) {
269
- tempData = originalConfig.value.data
270
- }
271
- else {
272
- const tempDataKeys = Object.keys(activeConfig.value.tempData)
273
- tempDataKeys.forEach((key) => {
274
- changeDeepObject(activeConfig.value.data, key, activeConfig.value.tempData[key])
275
- })
276
- tempData = activeConfig.value.data
277
- }
278
-
279
- diff.value = []
280
- compareProps(tempData, dataCache.value)
281
-
282
- diff.value.forEach((eachDiff) => {
283
- const arr = eachDiff.split('.')
284
- let targetData = tempData[arr[0]]
285
- if (arr.length !== 1) {
286
- for (let i = 1; i < arr.length - 1; i++) {
287
- const path = arr[i]
288
- targetData = targetData[path]
289
- }
290
- }
291
- targetData.update = true
292
- })
293
-
294
- return tempData
295
- }
296
-
297
- function printDocument() {
298
- const printContent = (window as any).rawDocument.getElementById('printReady')
299
- // printElement(printContent)
300
- showDialog({ message: '操作成功!' })
301
- }
302
-
303
- function exportPDF() {
304
- const date = getDate()
305
- let title = config.value.title
306
- title = title.replace(/<[^>]+>/g, '')
307
- const fileName = `${date}${title}`
308
- // HtmlToPdf.getPdf(fileName, '#printReady')
309
- }
310
-
311
- // 配置处理方法
312
- function configInit() {
313
- originalConfig.value = Object.assign({}, config.value)
314
- if (!props.dontFormat)
315
- formatConfigRow(config.value)
316
-
317
- activeConfig.value = config.value
318
- showSkeleton.value = false
319
-
320
- // 处理动态Index
321
- activeConfig.value.columns.forEach((row: any[]) => {
322
- row.forEach((cell) => {
323
- if (cell.dynamicDataIndex === true) {
324
- // eslint-disable-next-line no-new-func
325
- const func = new Function(`return ${cell.customFunctionForDynamicDataIndex}`)()
326
- cell.dataIndex = func(config.value)
327
- }
328
- if (['action', 'click'].includes(cell.eventType) && cell.customFunction && !cell.events) {
329
- cell.events = []
330
- cell.events.push({
331
- type: cell.eventType,
332
- customFunction: cell.customFunction,
333
- })
334
- }
335
- })
336
- })
337
-
338
- activeConfig.value.tempData = {}
339
- activeConfig.value.columns.forEach((row: any[]) => {
340
- row.forEach((cell) => {
341
- if (cell.dataIndex?.includes('@@@'))
342
- activeConfig.value.tempData[cell.dataIndex] = getDeepObject(activeConfig.value.data, cell.dataIndex)
343
- })
344
- })
345
-
346
- originalConfig.value.columns = transformArray(JSON.parse(JSON.stringify(config.value.columns)))
347
-
348
- scanFinish.value = true
349
- }
350
-
351
- // 格式化配置行方法
352
- function formatConfigRow(config: any) {
353
- for (let i = 0; i < config.columns.length; i++) {
354
- // 对原始数组进行递归,依次将该位置拆分为三个部分,当前处理位置之前的,当前处理位置,当前处理位置之后的
355
- const before = config.columns.slice(0, i)
356
- const after = config.columns.slice(i + 1, config.columns.length)
357
-
358
- // 将当前处理的数组交给处理的方法
359
- const x = checkRow(config.columns[i])
360
-
361
- const newArr = []
362
-
363
- // 拼接之前的数组
364
- if (before.length > 0) {
365
- if (before.length >= 1) {
366
- before.forEach((item) => {
367
- newArr.push(item)
368
- })
369
- }
370
- else {
371
- newArr.push(before)
372
- }
373
- }
374
-
375
- // 拼接不需要更改当前节点处理完成的数组
376
- newArr.push(x.old)
377
-
378
- // 如果处理了新加的数据,拼接
379
- if (x.add.length > 0) {
380
- for (let j = 0; j < x.add.length; j++) {
381
- if (x.add[j]) {
382
- newArr.push(x.add[j])
383
- i++
384
- }
385
- }
386
- }
387
-
388
- // 拼接之后的数组
389
- if (after.length > 0) {
390
- if (after.length >= 1) {
391
- after.forEach((item) => {
392
- newArr.push(item)
393
- })
394
- }
395
- else {
396
- newArr.push(after)
397
- }
398
- }
399
-
400
- config.columns = newArr
401
- }
402
- }
403
-
404
- // 处理行数据
405
- function checkRow(rowArr: any[]) {
406
- // 不需要更改的数据
407
- const original = []
408
- // 需要更改新加的数据
409
- const addArr = []
410
- // 统计rowspan出现的总和
411
- let count = 0
412
- // 统计声明列需要的rowspan总数
413
- let total = 0
414
- // 是否为声明行
415
- let titleCellFlag = false
416
- // 是否为声明行后第一行
417
- let firstSubLine = false
418
- // 需要处理的行,新的index值
419
- let subRowIndex = 0
420
- // 新生成的行,临时存储
421
- const waitForAddArr = []
422
- // 用于记录声明行的colspan避免格式错误
423
- let preColSpan = 0
424
- // 用于统计循环次数,判断是否是最后一次
425
- let forEachCount = 0
426
-
427
- // 标记所有数据
428
- rowArr.forEach((cell) => {
429
- forEachCount++
430
- // 如果该行没有rowspan则默认其为1,不要影响统计结果
431
- if (!cell.rowSpan)
432
- cell.rowSpan = 0
433
-
434
- if (cell.text && total !== 0) { // 如果遇到了下一个声明行,证明rowspan少了一行,需要补充一个占位格
435
- const nullObj = {
436
- type: 'placeHolderColumn',
437
- order: subRowIndex,
438
- noBoarder: true,
439
- needSplit: true,
440
- colSpan: preColSpan,
441
- dontShowRow: true,
442
- }
443
- subRowIndex++
444
- waitForAddArr.push(nullObj)
445
- total = 0
446
- count = 0
447
- titleCellFlag = false
448
- firstSubLine = false
449
- }
450
- else if ((total !== count + cell.rowSpan) && forEachCount === rowArr.length) {
451
- // 如果没有遇到了下一个声明行,但已经是当前行最后一个数据,也证明rowspan少了一行,需要补充一个占位格
452
- const nullObj = {
453
- type: 'placeHolderColumn',
454
- order: subRowIndex,
455
- noBoarder: true,
456
- needSplit: true,
457
- colSpan: preColSpan,
458
- dontShowRow: true,
459
- }
460
- subRowIndex++
461
- waitForAddArr.push(nullObj)
462
- total = 0
463
- count = 0
464
- titleCellFlag = false
465
- firstSubLine = false
466
- }
467
-
468
- // 判断是否为声明行
469
- if (cell.text && total === 0) {
470
- // 将声明行声明的rowspan作为总数,判断下方rowspan相加是否等于声明行声明的数量
471
- total = cell.rowSpan
472
- titleCellFlag = false
473
- firstSubLine = true
474
- subRowIndex = 1
475
- cell.show = true
476
- cell.showRowSpan = total
477
- }
478
- else if (cell.rowSpan > 0 && !titleCellFlag && firstSubLine) { // 判断是否为声明行后首行,因为首行不需要移动
479
- count += cell.rowSpan
480
- firstSubLine = false
481
- cell.noBoarder = true
482
- cell.show = true
483
- cell.showRowSpan = total
484
- }
485
- else if (cell.rowSpan > 0 && !titleCellFlag && !firstSubLine) { // 既非声明行,也非首行,需要移动
486
- count += cell.rowSpan
487
- cell.needSplit = true
488
- cell.order = subRowIndex
489
- cell.dontShowRow = true
490
- subRowIndex++
491
-
492
- // 如果之前添加过空行补充位置,刚好最后一位还有内容,将其互换
493
- if (forEachCount === rowArr.length && !waitForAddArr[waitForAddArr.length - 1].dataIndex) {
494
- waitForAddArr[waitForAddArr.length - 1].order += 1
495
- cell.order -= 1
496
- waitForAddArr.push(cell)
497
- }
498
- else {
499
- waitForAddArr.push(cell)
500
- }
501
- }
502
-
503
- // 如果count和total相等了,证明已经处理完成。将计数器还原
504
- if (count === total) {
505
- total = 0
506
- count = 0
507
- titleCellFlag = false
508
- firstSubLine = false
509
- }
510
- // 保存上一个的colspan,保持生成的格子与原格式一致
511
- preColSpan = cell.colSpan
512
- })
513
-
514
- // 将所有不需要移动的放入original
515
- rowArr.forEach((cell) => {
516
- if (cell.needSplit !== true)
517
- original.push(cell)
518
- })
519
-
520
- // 增加新的数组
521
- waitForAddArr.forEach((cell) => {
522
- const target = cell.order
523
- cell.noBoarder = true
524
- if (addArr[target] === undefined) {
525
- const temp = []
526
- temp.push(cell)
527
- addArr[target] = temp
528
- }
529
- else if (addArr[target].length > 0) {
530
- addArr[target].push(cell)
531
- }
532
- })
533
-
534
- // 如果没有新增,将单元格边框设置为显示
535
- if (addArr.length < 1) {
536
- original.forEach((cell) => {
537
- if (cell.type === 'input' || cell.type === 'inputs')
538
- cell.noBoarder = false
539
- })
540
- }
541
-
542
- return {
543
- old: original,
544
- add: addArr,
545
- }
546
- }
547
-
548
- // 配置扫描方法
549
- function checkSlotDefine(config: any) {
550
- const slotsDeclare = config.slotsDeclare
551
- const total = slotsDeclare.length
552
- let count = 0
553
- slotsDeclare.forEach((declare: string) => {
554
- config.columns.forEach((row: any[]) => {
555
- row.forEach((cell) => {
556
- if (cell.slotConfig === declare) {
557
- count++
558
- }
559
- })
560
- })
561
- })
562
- return count === total
563
- }
564
-
565
- function scanConfigName(config: any, result: string[]) {
566
- if (config.slotsDeclare) {
567
- config.slotsDeclare.forEach((name: string) => {
568
- result.push(name)
569
- })
570
- }
571
- }
572
-
573
- function scanConfigSlot(config: any) {
574
- const columnsArr = config.columns
575
- for (let i = 0; i < columnsArr.length; i++) {
576
- for (let j = 0; j < columnsArr[i].length; j++) {
577
- if (columnsArr[i][j].type === 'slot') {
578
- const targetName = columnsArr[i][j].slotConfig
579
- if (!configFromWeb.value[targetName] || !configFromWeb.value[targetName].columns) {
580
- console.error('无法找到目标插槽的配置!')
581
- return
582
- }
583
-
584
- config.columns[i] = []
585
- const before = config.columns.slice(0, i)
586
- let after = config.columns.slice(i + 1, config.columns.length)
587
-
588
- const addArr = []
589
- for (let k = 0; k < configFromWeb.value[targetName].columns.length; k++) {
590
- const temp = []
591
- configFromWeb.value[targetName].columns[k].forEach((cell: any) => {
592
- temp.push(cell)
593
- })
594
- addArr.push(temp)
595
- }
596
-
597
- const newArr = []
598
- if (before.length > 0) {
599
- before.forEach((item) => {
600
- newArr.push(item)
601
- })
602
- }
603
-
604
- addArr.forEach((arr) => {
605
- newArr.push(arr)
606
- })
607
-
608
- if (after.length === 1) {
609
- if (after[0].type === 'slot' || after[0][0].type === 'slot')
610
- after = []
611
- }
612
- if (after.length > 0) {
613
- after.forEach((item) => {
614
- newArr.push(item)
615
- })
616
- }
617
-
618
- config.columns = newArr
619
- config.slotsDeclare = configFromWeb.value[targetName].slotsDeclare || []
620
-
621
- if (config.data.images && configFromWeb.value[targetName].data.images) {
622
- config.data.images = { ...config.data.images, ...configFromWeb.value[targetName].data.images }
623
- delete configFromWeb.value[targetName].data.images
624
- }
625
- config.data = { ...config.data, ...configFromWeb.value[targetName].data }
626
- }
627
- }
628
- }
629
- config.value = config
630
- }
631
-
632
- // 数据比较方法
633
- function compareProps(obj1: any, obj2: any, path = '') {
634
- for (const key in obj1) {
635
- if (typeof obj2[key] === 'undefined') {
636
- diff.value.push(path + key)
637
- }
638
- else if (Array.isArray(obj1) && Array.isArray(obj2)) {
639
- if (obj1[key].length !== obj2[key].length)
640
- diff.value.push(path + key)
641
- }
642
- else if (typeof obj1[key] === 'object' && typeof obj2[key] === 'object') {
643
- compareProps(obj1[key], obj2[key], `${path + key}.`)
644
- }
645
- else if (obj1[key] !== obj2[key]) {
646
- diff.value.push(path + key)
647
- }
648
- }
649
- }
650
-
651
- // 数据处理辅助方法
652
- function getDeepObject(obj: any, strPath: string) {
653
- const arr = strPath.split('@@@')
654
- let result = obj[arr[0]]
655
- arr.shift()
656
- try {
657
- while (arr.length > 0) {
658
- result = result[arr[0]]
659
- arr.shift()
660
- }
661
- }
662
- catch (e) {
663
- result = undefined
664
- }
665
- return result
666
- }
667
-
668
- function changeDeepObject(obj: any, strPath: string, newVal: any) {
669
- const arr = strPath.split('@@@')
670
- if (obj[arr[0]] === undefined)
671
- obj = obj.images
672
-
673
- if (arr.length === 1) {
674
- obj[arr[0]] = newVal
675
- }
676
- else {
677
- let result = obj[arr[0]]
678
- arr.shift()
679
- while (arr.length > 1) {
680
- result = result[arr[0]]
681
- arr.shift()
682
- }
683
- if (result)
684
- result[arr[0]] = newVal
685
- }
686
- }
687
-
688
- // 日期处理方法
689
- function getDate() {
690
- const currentDate = new Date()
691
- const year = currentDate.getFullYear()
692
- const month = String(currentDate.getMonth() + 1).padStart(2, '0')
693
- const day = String(currentDate.getDate()).padStart(2, '0')
694
- return `${year}_${month}_${day}`
695
- }
696
-
697
- // 表格操作方法
698
- function tabChanged(key: string) {
699
- scanFinish.value = false
700
- originalConfig.value.data = { ...originalConfig.value.data, ...config.value.data }
701
- config.value.data = originalConfig.value.data
702
-
703
- if (type.value === 'display') {
704
- const tempDataKeys = Object.keys(activeConfig.value.tempData)
705
- tempDataKeys.forEach((key) => {
706
- changeDeepObject(activeConfig.value.data, key, activeConfig.value.tempData[key])
707
- })
708
-
709
- let count = 0
710
- imageList.value = []
711
- const keys = Object.keys(config.value.data.images)
712
- keys.forEach((key) => {
713
- if (config.value.data.images[key].length > 0) {
714
- imageList.value = [...imageList.value, ...config.value.data.images[key]]
715
- count++
716
- }
717
- })
718
- hasImages.value = count > 0
719
- }
720
- else {
721
- hasImages.value = false
722
- }
723
-
724
- scanFinish.value = true
725
- }
726
-
727
- function saveConfig() {
728
- const funcStr = config.value.confirmFunction
729
- executeStrFunctionByContext(null, funcStr, [])
730
- }
731
-
732
- function cancelConfig() {
733
- emit('cancel')
734
- }
735
-
736
- // 在其他方法后面添加
737
- function jsonConfigInit() {
738
- if (props.configData === undefined) {
739
- console.error('未找到数据!')
740
- return
741
- }
742
-
743
- originalConfig.value = Object.assign({}, config.value)
744
- originalConfig.value.data = JSON.parse(JSON.stringify(props.configData))
745
- type.value = 'display'
746
- // onlyDisplay.value = true
747
- showSkeleton.value = false
748
-
749
- nextTick(() => {
750
- scanFinish.value = true
751
- })
752
- }
753
-
754
- // 生命周期
755
- onBeforeMount(() => {
756
- if (props.displayOnly) {
757
- onlyDisplay.value = true
758
- type.value = 'display'
759
- }
760
-
761
- if (props.localConfig) {
762
- if (props.localConfig.designMode === 'json') {
763
- config.value = props.localConfig
764
- if (props.configData !== undefined)
765
- config.value.data = props.configData
766
-
767
- jsonConfigInit()
768
- }
769
- else {
770
- config.value = props.localConfig
771
- if (props.configData !== undefined)
772
- config.value.data = props.configData
773
-
774
- if (config.value.data.images === undefined)
775
- config.value.data.images = {}
776
-
777
- configInit()
778
- }
779
- }
780
- else {
781
- getConfigByName(props.configName, (res: any) => {
782
- config.value = JSON.parse(JSON.stringify(res))
783
- if (config.value.designMode === 'json') {
784
- if (props.configData !== undefined)
785
- config.value.data = props.configData
786
-
787
- jsonConfigInit()
788
- }
789
- else {
790
- if (props.configData !== undefined)
791
- config.value.data = props.configData
792
-
793
- if (config.value.data.images === undefined)
794
- config.value.data.images = {}
795
-
796
- configInit()
797
- }
798
- }, props.serverName)
799
- }
800
- })
801
-
802
- onMounted(() => {
803
- if (props.registerMap !== undefined) {
804
- // eslint-disable-next-line vue/no-mutating-props
805
- props.registerMap.push({
806
- exportData,
807
- printDocument,
808
- exportPDF,
809
- })
810
- }
811
-
812
- if (props.configData)
813
- dataCache.value = JSON.parse(JSON.stringify(props.configData))
814
- else if (config.value?.data)
815
- dataCache.value = JSON.parse(JSON.stringify(config.value.data))
816
- })
817
-
818
- onBeforeUnmount(() => {
819
- clearInterval(timer.value)
820
- })
821
-
822
- // Watch
823
- watch(() => props.configName, (val) => {
824
- if (val) {
825
- getConfigByName(props.configName, (res: any) => {
826
- config.value = res
827
- configInit()
828
- }, props.serverName)
829
- }
830
- })
831
-
832
- watch(() => props.localConfig, (val) => {
833
- if (val) {
834
- config.value = val
835
- configInit()
836
- }
837
- })
838
-
839
- // 暴露方法
840
- defineExpose({
841
- exportData,
842
- printDocument,
843
- exportPDF,
844
- getComponentByName,
845
- })
846
-
847
- // 选择行方法
848
- function selectRow(selectedRowKeys: any[], selectedRows: any[]) {
849
- emit('selectRow', selectedRowKeys, selectedRows)
850
- }
851
- </script>
852
-
853
- <template>
854
- <div>
855
- <!-- 骨架屏 -->
856
- <VanCard v-if="showSkeleton">
857
- <VanSkeleton active />
858
- </VanCard>
859
- <template v-if="noPadding">
860
- <!-- 主体表格 -->
861
- <XReportDesign
862
- v-if="scanFinish"
863
- ref="XReportDesign"
864
- :show-img-in-cell="showImgInCell"
865
- :img-prefix="imgPrefix"
866
- :use-oss-for-img="useOssForImg"
867
- :display-only="displayOnly"
868
- :config="type === 'display' ? originalConfig : activeConfig"
869
- :slot-config-name="type === 'display' ? undefined : activatedSlotName"
870
- :for-display="type === 'display'"
871
- :server-name="serverName"
872
- :env="env"
873
- :show-title="showTitle"
874
- :no-padding="noPadding"
875
- :no-top-border="noTopBorder"
876
- :show-images="hasImages"
877
- :image-list="imageList"
878
- @update-img="updateImg"
879
- @select-row="selectRow"
880
- @slot-rendered="slotRendered"
881
- />
882
-
883
- <VanRow v-if="showSaveButton" type="flex" justify="end">
884
- <VanSpace>
885
- <VanButton @click="saveConfig">
886
- 提交
887
- </VanButton>
888
- <VanButton @click="cancelConfig">
889
- 取消
890
- </VanButton>
891
- </VanSpace>
892
- </VanRow>
893
- </template>
894
- <template v-else>
895
- <!-- 用以包裹整个页面 -->
896
- <div v-if="!showSkeleton">
897
- <!-- 切换菜单 -->
898
- <VanRadioGroup
899
- v-show="!onlyDisplay && editMode"
900
- v-model="type"
901
- default-value="a"
902
- button-style="solid"
903
- @change="tabChanged"
904
- >
905
- <VanRadio v-if="!onlyDisplay" name="design">
906
- 设计
907
- </VanRadio>
908
- <VanRadio name="display" style="border-radius: 0">
909
- 预览
910
- </VanRadio>
911
- </VanRadioGroup>
912
-
913
- <!-- 主体表格 -->
914
- <XReportDesign
915
- v-if="scanFinish"
916
- ref="XReportDesign"
917
- :show-img-in-cell="showImgInCell"
918
- :img-prefix="imgPrefix"
919
- :use-oss-for-img="useOssForImg"
920
- :display-only="displayOnly"
921
- :config="type === 'display' ? originalConfig : activeConfig"
922
- :slot-config-name="type === 'display' ? undefined : activatedSlotName"
923
- :for-display="type === 'display'"
924
- :no-padding="noPadding"
925
- :no-top-border="noTopBorder"
926
- :show-title="showTitle"
927
- :server-name="serverName"
928
- :env="env"
929
- :show-images="hasImages"
930
- :image-list="imageList"
931
- @update-img="updateImg"
932
- @select-row="selectRow"
933
- @slot-rendered="slotRendered"
934
- />
935
- </div>
936
- </template>
937
-
938
- <!-- 弹出框 -->
939
- <!-- <x-add-report
940
- ref="xAddReport"
941
- :env="env"
942
- /> -->
943
- <!-- 弹出框 -->
944
- <!-- <x-report-drawer
945
- ref="xReportDrawer"
946
- :env="env"
947
- /> -->
948
- </div>
949
- </template>
950
-
951
- <style lang="less" scoped>
952
- .tools {
953
- text-align: center;
954
- cursor: pointer;
955
-
956
- .toolsItem {
957
- display: inline-block;
958
- }
959
- }
960
- </style>
1
+ <script setup lang="ts">
2
+ import XReportDesign from '@af-mobile-client-vue3/components/data/XReportGrid/XReportDesign.vue'
3
+ import { getConfigByName, runLogic } from '@af-mobile-client-vue3/services/api/common'
4
+ import { useUserStore } from '@af-mobile-client-vue3/stores/modules/user'
5
+ import { executeStrFunctionByContext } from '@af-mobile-client-vue3/utils/runEvalFunction'
6
+ import {
7
+ showDialog,
8
+ Button as VanButton,
9
+ Card as VanCard,
10
+ Radio as VanRadio,
11
+ RadioGroup as VanRadioGroup,
12
+ Row as VanRow,
13
+ Skeleton as VanSkeleton,
14
+ Space as VanSpace,
15
+ } from 'vant'
16
+ import { computed, nextTick, onBeforeMount, onBeforeUnmount, onMounted, provide, ref, watch } from 'vue'
17
+
18
+ // import HtmlToPdf from '@/utils/htmlToPDF'
19
+
20
+ // Props
21
+ const props = defineProps({
22
+ files: {
23
+ type: Array,
24
+ default: () => [],
25
+ },
26
+ authority: {
27
+ type: String,
28
+ default: 'user',
29
+ },
30
+ editMode: {
31
+ type: Boolean,
32
+ default: true,
33
+ },
34
+ configName: {
35
+ type: String,
36
+ required: true,
37
+ },
38
+ activatedSlotName: {
39
+ type: String,
40
+ default: undefined,
41
+ },
42
+ localConfig: {
43
+ type: Object,
44
+ default: undefined,
45
+ },
46
+ dontFormat: {
47
+ type: Boolean,
48
+ default: true,
49
+ },
50
+ showImgInCell: {
51
+ type: Boolean,
52
+ default: false,
53
+ },
54
+ configData: {
55
+ type: Object,
56
+ default: undefined,
57
+ },
58
+ serverName: {
59
+ type: String,
60
+ default: '',
61
+ },
62
+ env: {
63
+ type: String,
64
+ default: 'prod',
65
+ },
66
+ displayOnly: {
67
+ type: Boolean,
68
+ default: true,
69
+ },
70
+ noPadding: {
71
+ type: Boolean,
72
+ default: true,
73
+ },
74
+ noTopBorder: {
75
+ type: Boolean,
76
+ default: false,
77
+ },
78
+ showTitle: {
79
+ type: Boolean,
80
+ default: true,
81
+ },
82
+ showSaveButton: {
83
+ type: Boolean,
84
+ default: false,
85
+ },
86
+ registerMap: {
87
+ type: Array,
88
+ default: undefined,
89
+ },
90
+ isWidget: {
91
+ type: Boolean,
92
+ default: true,
93
+ },
94
+ useOssForImg: {
95
+ type: Boolean,
96
+ default: true,
97
+ },
98
+ imgPrefix: {
99
+ type: String,
100
+ default: undefined,
101
+ },
102
+ })
103
+
104
+ // Emits
105
+ const emit = defineEmits(['updateImg', 'selectRow', 'cancel', 'register'])
106
+
107
+ // Store
108
+ const userStore = useUserStore()
109
+ // const { user: currUser } = storeToRefs(userStore)
110
+
111
+ // Refs
112
+ // const XReportDesign = ref()
113
+ const xAddReport = ref()
114
+ const xReportDrawer = ref()
115
+
116
+ // 状态
117
+ const showSkeleton = ref(true)
118
+ const config = ref()
119
+ const type = ref('design')
120
+ const onlyDisplay = ref(false)
121
+ const _maxColSpan = ref(12)
122
+ const scanFinish = ref(false)
123
+ const activeConfig = ref(null)
124
+ const originalConfig = ref(null)
125
+ const configFromWeb = ref({})
126
+ const timer = ref()
127
+ const hasImages = ref(false)
128
+ const imageList = ref([])
129
+ const dataCache = ref()
130
+ const diff = ref([])
131
+ const globalData = ref({})
132
+
133
+ // Computed
134
+ const widget = computed(() => props.isWidget)
135
+
136
+ // 在provide之前定义getGlobalData函数
137
+ const getGlobalData = () => globalData.value
138
+
139
+ function setGlobalData(obj: any) {
140
+ globalData.value = obj
141
+ }
142
+
143
+ // 然后再进行provide
144
+ provide('runLogic', runLogic)
145
+ provide('openDialog', openDialog)
146
+ provide('registerComponent', registerComponent)
147
+ provide('getComponentByName', getComponentByName)
148
+ provide('getParentComponentByName', getComponentByName)
149
+ provide('getConfigByName', getConfigByName)
150
+ provide('isWidget', widget)
151
+ // provide('currUser', currUser)
152
+ provide('setGlobalData', setGlobalData)
153
+ provide('getGlobalData', getGlobalData)
154
+
155
+ // Methods
156
+ function slotRendered() {
157
+ if (config.value?.mountedFunction) {
158
+ let func = config.value.mountedFunction
159
+ if (func && func.startsWith('function')) {
160
+ func = func.replace('function', 'async function')
161
+ executeStrFunctionByContext(null, func, [])
162
+ }
163
+ }
164
+ }
165
+
166
+ function registerComponent(componentName: string, component: any) {
167
+ if (XReportDesign.value)
168
+ XReportDesign.value[componentName] = component
169
+ }
170
+
171
+ // 数据处理方法
172
+ function transformArray(inputList: any[]) {
173
+ let operationIndex = 0
174
+ let operationList = []
175
+ const outputList = []
176
+ for (const lst of inputList) {
177
+ if (lst.length >= 1 && !lst.every(x => Array.isArray(x) || Array.isArray(lst[0]) || x.rowSpan === lst[0].rowSpan)) {
178
+ operationList = lst
179
+ break
180
+ }
181
+ else {
182
+ operationIndex += 1
183
+ }
184
+ }
185
+
186
+ let maxMergeRow = 0
187
+
188
+ if (operationList.length === 0) {
189
+ return inputList
190
+ }
191
+ else {
192
+ const maxRow = Math.max(...operationList.map(item => item.rowSpan))
193
+ let mergeIndexCol = 0
194
+ for (let index = 0; index < operationList.length; index++) {
195
+ const row = operationList[index]
196
+ let rowSpan = row.rowSpan
197
+ let mergeIndexRow = operationIndex + 1
198
+ const rows = []
199
+ if (rowSpan < maxRow && mergeIndexRow < inputList.length)
200
+ rows.push([row])
201
+
202
+ while (rowSpan < maxRow && mergeIndexRow < inputList.length) {
203
+ rowSpan += inputList[mergeIndexRow][mergeIndexCol].rowSpan
204
+ rows.push([inputList[mergeIndexRow][mergeIndexCol]])
205
+ if (mergeIndexRow > maxMergeRow)
206
+ maxMergeRow = mergeIndexRow
207
+
208
+ mergeIndexRow++
209
+ }
210
+ if (rows.length !== 0)
211
+ operationList[index] = rows
212
+
213
+ if (row.rowSpan !== maxRow)
214
+ mergeIndexCol++
215
+ }
216
+ }
217
+
218
+ let putindex = 0
219
+ while (operationIndex > 0) {
220
+ outputList.push(inputList[putindex])
221
+ putindex++
222
+ operationIndex -= 1
223
+ }
224
+
225
+ outputList.push(operationList)
226
+
227
+ while (maxMergeRow < inputList.length - 1) {
228
+ outputList.push(inputList[maxMergeRow + 1])
229
+ maxMergeRow += 1
230
+ }
231
+
232
+ return transformArray(outputList)
233
+ }
234
+
235
+ // 组件操作方法
236
+ function getComponentByName(componentName: string) {
237
+ return XReportDesign.value?.[componentName]
238
+ }
239
+
240
+ // 对话框操作
241
+ function openDialog(configName: string, selectedId: any, mixinData: any, outEnv = {}, attr = {}) {
242
+ xAddReport.value?.init({
243
+ configName,
244
+ selectedId,
245
+ mixinData,
246
+ outEnv,
247
+ attr,
248
+ })
249
+ }
250
+
251
+ function openDrawer(configName: string, selectedId: any, mixinData: any, outEnv = {}, attr = {}) {
252
+ xReportDrawer.value?.init({
253
+ configName,
254
+ selectedId,
255
+ mixinData,
256
+ outEnv,
257
+ attr,
258
+ })
259
+ }
260
+
261
+ // 数据导出和打印
262
+ function updateImg(data: any) {
263
+ emit('updateImg', data)
264
+ }
265
+
266
+ function exportData() {
267
+ let tempData
268
+ if (!activeConfig.value) {
269
+ tempData = originalConfig.value.data
270
+ }
271
+ else {
272
+ const tempDataKeys = Object.keys(activeConfig.value.tempData)
273
+ tempDataKeys.forEach((key) => {
274
+ changeDeepObject(activeConfig.value.data, key, activeConfig.value.tempData[key])
275
+ })
276
+ tempData = activeConfig.value.data
277
+ }
278
+
279
+ diff.value = []
280
+ compareProps(tempData, dataCache.value)
281
+
282
+ diff.value.forEach((eachDiff) => {
283
+ const arr = eachDiff.split('.')
284
+ let targetData = tempData[arr[0]]
285
+ if (arr.length !== 1) {
286
+ for (let i = 1; i < arr.length - 1; i++) {
287
+ const path = arr[i]
288
+ targetData = targetData[path]
289
+ }
290
+ }
291
+ targetData.update = true
292
+ })
293
+
294
+ return tempData
295
+ }
296
+
297
+ function printDocument() {
298
+ const printContent = (window as any).rawDocument.getElementById('printReady')
299
+ // printElement(printContent)
300
+ showDialog({ message: '操作成功!' })
301
+ }
302
+
303
+ function exportPDF() {
304
+ const date = getDate()
305
+ let title = config.value.title
306
+ title = title.replace(/<[^>]+>/g, '')
307
+ const fileName = `${date}${title}`
308
+ // HtmlToPdf.getPdf(fileName, '#printReady')
309
+ }
310
+
311
+ // 配置处理方法
312
+ function configInit() {
313
+ originalConfig.value = Object.assign({}, config.value)
314
+ if (!props.dontFormat)
315
+ formatConfigRow(config.value)
316
+
317
+ activeConfig.value = config.value
318
+ showSkeleton.value = false
319
+
320
+ // 处理动态Index
321
+ activeConfig.value.columns.forEach((row: any[]) => {
322
+ row.forEach((cell) => {
323
+ if (cell.dynamicDataIndex === true) {
324
+ // eslint-disable-next-line no-new-func
325
+ const func = new Function(`return ${cell.customFunctionForDynamicDataIndex}`)()
326
+ cell.dataIndex = func(config.value)
327
+ }
328
+ if (['action', 'click'].includes(cell.eventType) && cell.customFunction && !cell.events) {
329
+ cell.events = []
330
+ cell.events.push({
331
+ type: cell.eventType,
332
+ customFunction: cell.customFunction,
333
+ })
334
+ }
335
+ })
336
+ })
337
+
338
+ activeConfig.value.tempData = {}
339
+ activeConfig.value.columns.forEach((row: any[]) => {
340
+ row.forEach((cell) => {
341
+ if (cell.dataIndex?.includes('@@@'))
342
+ activeConfig.value.tempData[cell.dataIndex] = getDeepObject(activeConfig.value.data, cell.dataIndex)
343
+ })
344
+ })
345
+
346
+ originalConfig.value.columns = transformArray(JSON.parse(JSON.stringify(config.value.columns)))
347
+
348
+ scanFinish.value = true
349
+ }
350
+
351
+ // 格式化配置行方法
352
+ function formatConfigRow(config: any) {
353
+ for (let i = 0; i < config.columns.length; i++) {
354
+ // 对原始数组进行递归,依次将该位置拆分为三个部分,当前处理位置之前的,当前处理位置,当前处理位置之后的
355
+ const before = config.columns.slice(0, i)
356
+ const after = config.columns.slice(i + 1, config.columns.length)
357
+
358
+ // 将当前处理的数组交给处理的方法
359
+ const x = checkRow(config.columns[i])
360
+
361
+ const newArr = []
362
+
363
+ // 拼接之前的数组
364
+ if (before.length > 0) {
365
+ if (before.length >= 1) {
366
+ before.forEach((item) => {
367
+ newArr.push(item)
368
+ })
369
+ }
370
+ else {
371
+ newArr.push(before)
372
+ }
373
+ }
374
+
375
+ // 拼接不需要更改当前节点处理完成的数组
376
+ newArr.push(x.old)
377
+
378
+ // 如果处理了新加的数据,拼接
379
+ if (x.add.length > 0) {
380
+ for (let j = 0; j < x.add.length; j++) {
381
+ if (x.add[j]) {
382
+ newArr.push(x.add[j])
383
+ i++
384
+ }
385
+ }
386
+ }
387
+
388
+ // 拼接之后的数组
389
+ if (after.length > 0) {
390
+ if (after.length >= 1) {
391
+ after.forEach((item) => {
392
+ newArr.push(item)
393
+ })
394
+ }
395
+ else {
396
+ newArr.push(after)
397
+ }
398
+ }
399
+
400
+ config.columns = newArr
401
+ }
402
+ }
403
+
404
+ // 处理行数据
405
+ function checkRow(rowArr: any[]) {
406
+ // 不需要更改的数据
407
+ const original = []
408
+ // 需要更改新加的数据
409
+ const addArr = []
410
+ // 统计rowspan出现的总和
411
+ let count = 0
412
+ // 统计声明列需要的rowspan总数
413
+ let total = 0
414
+ // 是否为声明行
415
+ let titleCellFlag = false
416
+ // 是否为声明行后第一行
417
+ let firstSubLine = false
418
+ // 需要处理的行,新的index值
419
+ let subRowIndex = 0
420
+ // 新生成的行,临时存储
421
+ const waitForAddArr = []
422
+ // 用于记录声明行的colspan避免格式错误
423
+ let preColSpan = 0
424
+ // 用于统计循环次数,判断是否是最后一次
425
+ let forEachCount = 0
426
+
427
+ // 标记所有数据
428
+ rowArr.forEach((cell) => {
429
+ forEachCount++
430
+ // 如果该行没有rowspan则默认其为1,不要影响统计结果
431
+ if (!cell.rowSpan)
432
+ cell.rowSpan = 0
433
+
434
+ if (cell.text && total !== 0) { // 如果遇到了下一个声明行,证明rowspan少了一行,需要补充一个占位格
435
+ const nullObj = {
436
+ type: 'placeHolderColumn',
437
+ order: subRowIndex,
438
+ noBoarder: true,
439
+ needSplit: true,
440
+ colSpan: preColSpan,
441
+ dontShowRow: true,
442
+ }
443
+ subRowIndex++
444
+ waitForAddArr.push(nullObj)
445
+ total = 0
446
+ count = 0
447
+ titleCellFlag = false
448
+ firstSubLine = false
449
+ }
450
+ else if ((total !== count + cell.rowSpan) && forEachCount === rowArr.length) {
451
+ // 如果没有遇到了下一个声明行,但已经是当前行最后一个数据,也证明rowspan少了一行,需要补充一个占位格
452
+ const nullObj = {
453
+ type: 'placeHolderColumn',
454
+ order: subRowIndex,
455
+ noBoarder: true,
456
+ needSplit: true,
457
+ colSpan: preColSpan,
458
+ dontShowRow: true,
459
+ }
460
+ subRowIndex++
461
+ waitForAddArr.push(nullObj)
462
+ total = 0
463
+ count = 0
464
+ titleCellFlag = false
465
+ firstSubLine = false
466
+ }
467
+
468
+ // 判断是否为声明行
469
+ if (cell.text && total === 0) {
470
+ // 将声明行声明的rowspan作为总数,判断下方rowspan相加是否等于声明行声明的数量
471
+ total = cell.rowSpan
472
+ titleCellFlag = false
473
+ firstSubLine = true
474
+ subRowIndex = 1
475
+ cell.show = true
476
+ cell.showRowSpan = total
477
+ }
478
+ else if (cell.rowSpan > 0 && !titleCellFlag && firstSubLine) { // 判断是否为声明行后首行,因为首行不需要移动
479
+ count += cell.rowSpan
480
+ firstSubLine = false
481
+ cell.noBoarder = true
482
+ cell.show = true
483
+ cell.showRowSpan = total
484
+ }
485
+ else if (cell.rowSpan > 0 && !titleCellFlag && !firstSubLine) { // 既非声明行,也非首行,需要移动
486
+ count += cell.rowSpan
487
+ cell.needSplit = true
488
+ cell.order = subRowIndex
489
+ cell.dontShowRow = true
490
+ subRowIndex++
491
+
492
+ // 如果之前添加过空行补充位置,刚好最后一位还有内容,将其互换
493
+ if (forEachCount === rowArr.length && !waitForAddArr[waitForAddArr.length - 1].dataIndex) {
494
+ waitForAddArr[waitForAddArr.length - 1].order += 1
495
+ cell.order -= 1
496
+ waitForAddArr.push(cell)
497
+ }
498
+ else {
499
+ waitForAddArr.push(cell)
500
+ }
501
+ }
502
+
503
+ // 如果count和total相等了,证明已经处理完成。将计数器还原
504
+ if (count === total) {
505
+ total = 0
506
+ count = 0
507
+ titleCellFlag = false
508
+ firstSubLine = false
509
+ }
510
+ // 保存上一个的colspan,保持生成的格子与原格式一致
511
+ preColSpan = cell.colSpan
512
+ })
513
+
514
+ // 将所有不需要移动的放入original
515
+ rowArr.forEach((cell) => {
516
+ if (cell.needSplit !== true)
517
+ original.push(cell)
518
+ })
519
+
520
+ // 增加新的数组
521
+ waitForAddArr.forEach((cell) => {
522
+ const target = cell.order
523
+ cell.noBoarder = true
524
+ if (addArr[target] === undefined) {
525
+ const temp = []
526
+ temp.push(cell)
527
+ addArr[target] = temp
528
+ }
529
+ else if (addArr[target].length > 0) {
530
+ addArr[target].push(cell)
531
+ }
532
+ })
533
+
534
+ // 如果没有新增,将单元格边框设置为显示
535
+ if (addArr.length < 1) {
536
+ original.forEach((cell) => {
537
+ if (cell.type === 'input' || cell.type === 'inputs')
538
+ cell.noBoarder = false
539
+ })
540
+ }
541
+
542
+ return {
543
+ old: original,
544
+ add: addArr,
545
+ }
546
+ }
547
+
548
+ // 配置扫描方法
549
+ function checkSlotDefine(config: any) {
550
+ const slotsDeclare = config.slotsDeclare
551
+ const total = slotsDeclare.length
552
+ let count = 0
553
+ slotsDeclare.forEach((declare: string) => {
554
+ config.columns.forEach((row: any[]) => {
555
+ row.forEach((cell) => {
556
+ if (cell.slotConfig === declare) {
557
+ count++
558
+ }
559
+ })
560
+ })
561
+ })
562
+ return count === total
563
+ }
564
+
565
+ function scanConfigName(config: any, result: string[]) {
566
+ if (config.slotsDeclare) {
567
+ config.slotsDeclare.forEach((name: string) => {
568
+ result.push(name)
569
+ })
570
+ }
571
+ }
572
+
573
+ function scanConfigSlot(config: any) {
574
+ const columnsArr = config.columns
575
+ for (let i = 0; i < columnsArr.length; i++) {
576
+ for (let j = 0; j < columnsArr[i].length; j++) {
577
+ if (columnsArr[i][j].type === 'slot') {
578
+ const targetName = columnsArr[i][j].slotConfig
579
+ if (!configFromWeb.value[targetName] || !configFromWeb.value[targetName].columns) {
580
+ console.error('无法找到目标插槽的配置!')
581
+ return
582
+ }
583
+
584
+ config.columns[i] = []
585
+ const before = config.columns.slice(0, i)
586
+ let after = config.columns.slice(i + 1, config.columns.length)
587
+
588
+ const addArr = []
589
+ for (let k = 0; k < configFromWeb.value[targetName].columns.length; k++) {
590
+ const temp = []
591
+ configFromWeb.value[targetName].columns[k].forEach((cell: any) => {
592
+ temp.push(cell)
593
+ })
594
+ addArr.push(temp)
595
+ }
596
+
597
+ const newArr = []
598
+ if (before.length > 0) {
599
+ before.forEach((item) => {
600
+ newArr.push(item)
601
+ })
602
+ }
603
+
604
+ addArr.forEach((arr) => {
605
+ newArr.push(arr)
606
+ })
607
+
608
+ if (after.length === 1) {
609
+ if (after[0].type === 'slot' || after[0][0].type === 'slot')
610
+ after = []
611
+ }
612
+ if (after.length > 0) {
613
+ after.forEach((item) => {
614
+ newArr.push(item)
615
+ })
616
+ }
617
+
618
+ config.columns = newArr
619
+ config.slotsDeclare = configFromWeb.value[targetName].slotsDeclare || []
620
+
621
+ if (config.data.images && configFromWeb.value[targetName].data.images) {
622
+ config.data.images = { ...config.data.images, ...configFromWeb.value[targetName].data.images }
623
+ delete configFromWeb.value[targetName].data.images
624
+ }
625
+ config.data = { ...config.data, ...configFromWeb.value[targetName].data }
626
+ }
627
+ }
628
+ }
629
+ config.value = config
630
+ }
631
+
632
+ // 数据比较方法
633
+ function compareProps(obj1: any, obj2: any, path = '') {
634
+ for (const key in obj1) {
635
+ if (typeof obj2[key] === 'undefined') {
636
+ diff.value.push(path + key)
637
+ }
638
+ else if (Array.isArray(obj1) && Array.isArray(obj2)) {
639
+ if (obj1[key].length !== obj2[key].length)
640
+ diff.value.push(path + key)
641
+ }
642
+ else if (typeof obj1[key] === 'object' && typeof obj2[key] === 'object') {
643
+ compareProps(obj1[key], obj2[key], `${path + key}.`)
644
+ }
645
+ else if (obj1[key] !== obj2[key]) {
646
+ diff.value.push(path + key)
647
+ }
648
+ }
649
+ }
650
+
651
+ // 数据处理辅助方法
652
+ function getDeepObject(obj: any, strPath: string) {
653
+ const arr = strPath.split('@@@')
654
+ let result = obj[arr[0]]
655
+ arr.shift()
656
+ try {
657
+ while (arr.length > 0) {
658
+ result = result[arr[0]]
659
+ arr.shift()
660
+ }
661
+ }
662
+ catch (e) {
663
+ result = undefined
664
+ }
665
+ return result
666
+ }
667
+
668
+ function changeDeepObject(obj: any, strPath: string, newVal: any) {
669
+ const arr = strPath.split('@@@')
670
+ if (obj[arr[0]] === undefined)
671
+ obj = obj.images
672
+
673
+ if (arr.length === 1) {
674
+ obj[arr[0]] = newVal
675
+ }
676
+ else {
677
+ let result = obj[arr[0]]
678
+ arr.shift()
679
+ while (arr.length > 1) {
680
+ result = result[arr[0]]
681
+ arr.shift()
682
+ }
683
+ if (result)
684
+ result[arr[0]] = newVal
685
+ }
686
+ }
687
+
688
+ // 日期处理方法
689
+ function getDate() {
690
+ const currentDate = new Date()
691
+ const year = currentDate.getFullYear()
692
+ const month = String(currentDate.getMonth() + 1).padStart(2, '0')
693
+ const day = String(currentDate.getDate()).padStart(2, '0')
694
+ return `${year}_${month}_${day}`
695
+ }
696
+
697
+ // 表格操作方法
698
+ function tabChanged(key: string) {
699
+ scanFinish.value = false
700
+ originalConfig.value.data = { ...originalConfig.value.data, ...config.value.data }
701
+ config.value.data = originalConfig.value.data
702
+
703
+ if (type.value === 'display') {
704
+ const tempDataKeys = Object.keys(activeConfig.value.tempData)
705
+ tempDataKeys.forEach((key) => {
706
+ changeDeepObject(activeConfig.value.data, key, activeConfig.value.tempData[key])
707
+ })
708
+
709
+ let count = 0
710
+ imageList.value = []
711
+ const keys = Object.keys(config.value.data.images)
712
+ keys.forEach((key) => {
713
+ if (config.value.data.images[key].length > 0) {
714
+ imageList.value = [...imageList.value, ...config.value.data.images[key]]
715
+ count++
716
+ }
717
+ })
718
+ hasImages.value = count > 0
719
+ }
720
+ else {
721
+ hasImages.value = false
722
+ }
723
+
724
+ scanFinish.value = true
725
+ }
726
+
727
+ function saveConfig() {
728
+ const funcStr = config.value.confirmFunction
729
+ executeStrFunctionByContext(null, funcStr, [])
730
+ }
731
+
732
+ function cancelConfig() {
733
+ emit('cancel')
734
+ }
735
+
736
+ // 在其他方法后面添加
737
+ function jsonConfigInit() {
738
+ if (props.configData === undefined) {
739
+ console.error('未找到数据!')
740
+ return
741
+ }
742
+
743
+ originalConfig.value = Object.assign({}, config.value)
744
+ originalConfig.value.data = JSON.parse(JSON.stringify(props.configData))
745
+ type.value = 'display'
746
+ // onlyDisplay.value = true
747
+ showSkeleton.value = false
748
+
749
+ nextTick(() => {
750
+ scanFinish.value = true
751
+ })
752
+ }
753
+
754
+ // 生命周期
755
+ onBeforeMount(() => {
756
+ if (props.displayOnly) {
757
+ onlyDisplay.value = true
758
+ type.value = 'display'
759
+ }
760
+
761
+ if (props.localConfig) {
762
+ if (props.localConfig.designMode === 'json') {
763
+ config.value = props.localConfig
764
+ if (props.configData !== undefined)
765
+ config.value.data = props.configData
766
+
767
+ jsonConfigInit()
768
+ }
769
+ else {
770
+ config.value = props.localConfig
771
+ if (props.configData !== undefined)
772
+ config.value.data = props.configData
773
+
774
+ if (config.value.data.images === undefined)
775
+ config.value.data.images = {}
776
+
777
+ configInit()
778
+ }
779
+ }
780
+ else {
781
+ getConfigByName(props.configName, (res: any) => {
782
+ config.value = JSON.parse(JSON.stringify(res))
783
+ if (config.value.designMode === 'json') {
784
+ if (props.configData !== undefined)
785
+ config.value.data = props.configData
786
+
787
+ jsonConfigInit()
788
+ }
789
+ else {
790
+ if (props.configData !== undefined)
791
+ config.value.data = props.configData
792
+
793
+ if (config.value.data.images === undefined)
794
+ config.value.data.images = {}
795
+
796
+ configInit()
797
+ }
798
+ }, props.serverName)
799
+ }
800
+ })
801
+
802
+ onMounted(() => {
803
+ if (props.registerMap !== undefined) {
804
+ // eslint-disable-next-line vue/no-mutating-props
805
+ props.registerMap.push({
806
+ exportData,
807
+ printDocument,
808
+ exportPDF,
809
+ })
810
+ }
811
+
812
+ if (props.configData)
813
+ dataCache.value = JSON.parse(JSON.stringify(props.configData))
814
+ else if (config.value?.data)
815
+ dataCache.value = JSON.parse(JSON.stringify(config.value.data))
816
+ })
817
+
818
+ onBeforeUnmount(() => {
819
+ clearInterval(timer.value)
820
+ })
821
+
822
+ // Watch
823
+ watch(() => props.configName, (val) => {
824
+ if (val) {
825
+ getConfigByName(props.configName, (res: any) => {
826
+ config.value = res
827
+ configInit()
828
+ }, props.serverName)
829
+ }
830
+ })
831
+
832
+ watch(() => props.localConfig, (val) => {
833
+ if (val) {
834
+ config.value = val
835
+ configInit()
836
+ }
837
+ })
838
+
839
+ // 暴露方法
840
+ defineExpose({
841
+ exportData,
842
+ printDocument,
843
+ exportPDF,
844
+ getComponentByName,
845
+ })
846
+
847
+ // 选择行方法
848
+ function selectRow(selectedRowKeys: any[], selectedRows: any[]) {
849
+ emit('selectRow', selectedRowKeys, selectedRows)
850
+ }
851
+ </script>
852
+
853
+ <template>
854
+ <div>
855
+ <!-- 骨架屏 -->
856
+ <VanCard v-if="showSkeleton">
857
+ <VanSkeleton active />
858
+ </VanCard>
859
+ <template v-if="noPadding">
860
+ <!-- 主体表格 -->
861
+ <XReportDesign
862
+ v-if="scanFinish"
863
+ ref="XReportDesign"
864
+ :show-img-in-cell="showImgInCell"
865
+ :img-prefix="imgPrefix"
866
+ :use-oss-for-img="useOssForImg"
867
+ :display-only="displayOnly"
868
+ :config="type === 'display' ? originalConfig : activeConfig"
869
+ :slot-config-name="type === 'display' ? undefined : activatedSlotName"
870
+ :for-display="type === 'display'"
871
+ :server-name="serverName"
872
+ :env="env"
873
+ :show-title="showTitle"
874
+ :no-padding="noPadding"
875
+ :no-top-border="noTopBorder"
876
+ :show-images="hasImages"
877
+ :image-list="imageList"
878
+ @update-img="updateImg"
879
+ @select-row="selectRow"
880
+ @slot-rendered="slotRendered"
881
+ />
882
+
883
+ <VanRow v-if="showSaveButton" type="flex" justify="end">
884
+ <VanSpace>
885
+ <VanButton @click="saveConfig">
886
+ 提交
887
+ </VanButton>
888
+ <VanButton @click="cancelConfig">
889
+ 取消
890
+ </VanButton>
891
+ </VanSpace>
892
+ </VanRow>
893
+ </template>
894
+ <template v-else>
895
+ <!-- 用以包裹整个页面 -->
896
+ <div v-if="!showSkeleton">
897
+ <!-- 切换菜单 -->
898
+ <VanRadioGroup
899
+ v-show="!onlyDisplay && editMode"
900
+ v-model="type"
901
+ default-value="a"
902
+ button-style="solid"
903
+ @change="tabChanged"
904
+ >
905
+ <VanRadio v-if="!onlyDisplay" name="design">
906
+ 设计
907
+ </VanRadio>
908
+ <VanRadio name="display" style="border-radius: 0">
909
+ 预览
910
+ </VanRadio>
911
+ </VanRadioGroup>
912
+
913
+ <!-- 主体表格 -->
914
+ <XReportDesign
915
+ v-if="scanFinish"
916
+ ref="XReportDesign"
917
+ :show-img-in-cell="showImgInCell"
918
+ :img-prefix="imgPrefix"
919
+ :use-oss-for-img="useOssForImg"
920
+ :display-only="displayOnly"
921
+ :config="type === 'display' ? originalConfig : activeConfig"
922
+ :slot-config-name="type === 'display' ? undefined : activatedSlotName"
923
+ :for-display="type === 'display'"
924
+ :no-padding="noPadding"
925
+ :no-top-border="noTopBorder"
926
+ :show-title="showTitle"
927
+ :server-name="serverName"
928
+ :env="env"
929
+ :show-images="hasImages"
930
+ :image-list="imageList"
931
+ @update-img="updateImg"
932
+ @select-row="selectRow"
933
+ @slot-rendered="slotRendered"
934
+ />
935
+ </div>
936
+ </template>
937
+
938
+ <!-- 弹出框 -->
939
+ <!-- <x-add-report
940
+ ref="xAddReport"
941
+ :env="env"
942
+ /> -->
943
+ <!-- 弹出框 -->
944
+ <!-- <x-report-drawer
945
+ ref="xReportDrawer"
946
+ :env="env"
947
+ /> -->
948
+ </div>
949
+ </template>
950
+
951
+ <style lang="less" scoped>
952
+ .tools {
953
+ text-align: center;
954
+ cursor: pointer;
955
+
956
+ .toolsItem {
957
+ display: inline-block;
958
+ }
959
+ }
960
+ </style>