mooho-base-admin-plus 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. package/.env +5 -0
  2. package/.env.development +0 -0
  3. package/.env.production +0 -0
  4. package/.eslintignore +11 -0
  5. package/.eslintrc.js +47 -0
  6. package/.prettierrc +15 -0
  7. package/README.md +18 -0
  8. package/dist/favicon.ico +0 -0
  9. package/dist/mooho-base-admin-plus.min.esm.js +131746 -0
  10. package/dist/mooho-base-admin-plus.min.js +279 -0
  11. package/dist/setting.js +31 -0
  12. package/dist/static/images/app-barcode.png +0 -0
  13. package/dist/static/images/login/bg.png +0 -0
  14. package/dist/static/images/login/logo.png +0 -0
  15. package/dist/static/images/login/password-active.png +0 -0
  16. package/dist/static/images/login/password-default.png +0 -0
  17. package/dist/static/images/login/signIn-img.png +0 -0
  18. package/dist/static/images/login/user-active.png +0 -0
  19. package/dist/static/images/login/user-default.png +0 -0
  20. package/dist/static/images/logo-dark.png +0 -0
  21. package/dist/static/images/logo-small.png +0 -0
  22. package/dist/static/images/logo.png +0 -0
  23. package/dist/static/images/logo.svg +510 -0
  24. package/dist/static/images/no-image.png +0 -0
  25. package/dist/style.css +4 -0
  26. package/index.html +18 -0
  27. package/other/pda.vue +28 -0
  28. package/package.json +59 -0
  29. package/public/favicon.ico +0 -0
  30. package/public/setting.js +31 -0
  31. package/public/static/images/app-barcode.png +0 -0
  32. package/public/static/images/login/bg.png +0 -0
  33. package/public/static/images/login/logo.png +0 -0
  34. package/public/static/images/login/password-active.png +0 -0
  35. package/public/static/images/login/password-default.png +0 -0
  36. package/public/static/images/login/signIn-img.png +0 -0
  37. package/public/static/images/login/user-active.png +0 -0
  38. package/public/static/images/login/user-default.png +0 -0
  39. package/public/static/images/logo-dark.png +0 -0
  40. package/public/static/images/logo-small.png +0 -0
  41. package/public/static/images/logo.png +0 -0
  42. package/public/static/images/logo.svg +510 -0
  43. package/public/static/images/no-image.png +0 -0
  44. package/src/App.vue +60 -0
  45. package/src/api/application.js +35 -0
  46. package/src/api/customModel.js +187 -0
  47. package/src/api/customPage.js +15 -0
  48. package/src/api/customTable.js +24 -0
  49. package/src/api/dataSource.js +93 -0
  50. package/src/api/dataView.js +199 -0
  51. package/src/api/dictType.js +23 -0
  52. package/src/api/entityView.js +13 -0
  53. package/src/api/enum.js +15 -0
  54. package/src/api/filterColumn.js +16 -0
  55. package/src/api/model.js +244 -0
  56. package/src/api/movePlan.js +29 -0
  57. package/src/api/notification.js +28 -0
  58. package/src/api/openApiPermission.js +25 -0
  59. package/src/api/permission.js +51 -0
  60. package/src/api/planJob.js +15 -0
  61. package/src/api/process.js +23 -0
  62. package/src/api/processDef.js +36 -0
  63. package/src/api/processInst.js +16 -0
  64. package/src/api/rolePermission.js +17 -0
  65. package/src/api/roleProperty.js +36 -0
  66. package/src/api/shortcut.js +20 -0
  67. package/src/api/system.js +23 -0
  68. package/src/api/task.js +56 -0
  69. package/src/api/taskQueue.js +24 -0
  70. package/src/api/user.js +45 -0
  71. package/src/api/viewColumn.js +16 -0
  72. package/src/assets/svg/body.svg +17 -0
  73. package/src/assets/svg/header-theme-dark.svg +40 -0
  74. package/src/assets/svg/header-theme-primary.svg +40 -0
  75. package/src/assets/svg/header-top.svg +40 -0
  76. package/src/assets/svg/icon-happy.svg +1 -0
  77. package/src/assets/svg/icon-sad.svg +1 -0
  78. package/src/assets/svg/icon-social-bilibili.svg +1 -0
  79. package/src/assets/svg/icon-social-dingding.svg +1 -0
  80. package/src/assets/svg/icon-social-facebook.svg +1 -0
  81. package/src/assets/svg/icon-social-juejin.svg +1 -0
  82. package/src/assets/svg/icon-social-qq.svg +1 -0
  83. package/src/assets/svg/icon-social-twitter.svg +1 -0
  84. package/src/assets/svg/icon-social-wechat.svg +1 -0
  85. package/src/assets/svg/icon-social-weibo.svg +1 -0
  86. package/src/assets/svg/icon-social-zhihu.svg +1 -0
  87. package/src/assets/svg/nav-theme-dark.svg +40 -0
  88. package/src/assets/svg/nav-theme-light.svg +40 -0
  89. package/src/components/copyright/index.vue +28 -0
  90. package/src/components/home/notice-list.vue +62 -0
  91. package/src/components/home/shortcut.vue +125 -0
  92. package/src/components/input/dialog-select.vue +301 -0
  93. package/src/components/input/item-select.vue +195 -0
  94. package/src/components/link/index.vue +54 -0
  95. package/src/components/richEditor/index.vue +86 -0
  96. package/src/components/upload/file-upload.vue +84 -0
  97. package/src/components/upload/upload-attachment.vue +119 -0
  98. package/src/components/upload/upload-image.vue +212 -0
  99. package/src/components/view/column-check.vue +223 -0
  100. package/src/components/view/column-edit.vue +850 -0
  101. package/src/components/view/column-select.vue +206 -0
  102. package/src/components/view/condition-edit.vue +164 -0
  103. package/src/components/view/filter-edit.vue +633 -0
  104. package/src/components/view/filter-setting.vue +126 -0
  105. package/src/components/view/form-setting-layout.vue +375 -0
  106. package/src/components/view/form-setting.vue +247 -0
  107. package/src/components/view/group-column.vue +104 -0
  108. package/src/components/view/group-method.vue +104 -0
  109. package/src/components/view/mixin.js +72 -0
  110. package/src/components/view/modal-form-filter.vue +319 -0
  111. package/src/components/view/modal-form-sort.vue +248 -0
  112. package/src/components/view/modal-form.vue +453 -0
  113. package/src/components/view/modal-table.vue +471 -0
  114. package/src/components/view/table-filter.vue +702 -0
  115. package/src/components/view/table-setting.vue +533 -0
  116. package/src/components/view/view-chart.vue +423 -0
  117. package/src/components/view/view-form-draggable.vue +837 -0
  118. package/src/components/view/view-form.vue +1444 -0
  119. package/src/components/view/view-table.vue +2261 -0
  120. package/src/components/workflow/flow-chart.vue +846 -0
  121. package/src/directive/focus.js +10 -0
  122. package/src/directive/tabHide.js +9 -0
  123. package/src/i18n/index.js +15 -0
  124. package/src/i18n/locale/en-US.js +1 -0
  125. package/src/i18n/locale/lang.js +1 -0
  126. package/src/i18n/locale/zh-CN.js +1 -0
  127. package/src/i18n/locale.js +102 -0
  128. package/src/index.js +222 -0
  129. package/src/layouts/basic-layout/header-breadcrumb/index.vue +122 -0
  130. package/src/layouts/basic-layout/header-collapse/index.vue +44 -0
  131. package/src/layouts/basic-layout/header-fullscreen/index.vue +19 -0
  132. package/src/layouts/basic-layout/header-i18n/index.vue +45 -0
  133. package/src/layouts/basic-layout/header-log/index.vue +41 -0
  134. package/src/layouts/basic-layout/header-logo/index.vue +23 -0
  135. package/src/layouts/basic-layout/header-notice/index.vue +218 -0
  136. package/src/layouts/basic-layout/header-reload/index.vue +21 -0
  137. package/src/layouts/basic-layout/header-search/index.vue +37 -0
  138. package/src/layouts/basic-layout/header-setting/index.vue +219 -0
  139. package/src/layouts/basic-layout/header-user/index.vue +175 -0
  140. package/src/layouts/basic-layout/i18n.js +50 -0
  141. package/src/layouts/basic-layout/index.vue +280 -0
  142. package/src/layouts/basic-layout/menu-head/index.vue +120 -0
  143. package/src/layouts/basic-layout/menu-head/title.vue +48 -0
  144. package/src/layouts/basic-layout/menu-side/index.vue +113 -0
  145. package/src/layouts/basic-layout/menu-side/menu-collapse.vue +76 -0
  146. package/src/layouts/basic-layout/menu-side/menu-item.vue +31 -0
  147. package/src/layouts/basic-layout/menu-side/menu-title.vue +56 -0
  148. package/src/layouts/basic-layout/menu-side/submenu.vue +31 -0
  149. package/src/layouts/basic-layout/mixins/click-item.js +21 -0
  150. package/src/layouts/basic-layout/mixins/sider-menu-badge.js +13 -0
  151. package/src/layouts/basic-layout/mixins/translate-title.js +11 -0
  152. package/src/layouts/basic-layout/tabs/index.vue +192 -0
  153. package/src/layouts/basic-layout/water-mark/index.vue +29 -0
  154. package/src/libs/lodop/index.js +145 -0
  155. package/src/libs/random_str.js +10 -0
  156. package/src/libs/request/index.js +158 -0
  157. package/src/libs/system/index.js +234 -0
  158. package/src/libs/util.cookies.js +44 -0
  159. package/src/libs/util.db.js +13 -0
  160. package/src/libs/util.js +55 -0
  161. package/src/libs/util.log.js +88 -0
  162. package/src/libs/water-mark.js +44 -0
  163. package/src/menu/header.js +20 -0
  164. package/src/menu/modules/dashboard.js +23 -0
  165. package/src/menu/sider.js +12 -0
  166. package/src/mixins/app.js +9 -0
  167. package/src/mixins/page.js +643 -0
  168. package/src/pages/account/login.vue +101 -0
  169. package/src/pages/common/home.vue +169 -0
  170. package/src/pages/common/task-form.vue +350 -0
  171. package/src/pages/common/todo.vue +31 -0
  172. package/src/pages/system/apiLog.vue +79 -0
  173. package/src/pages/system/applicationType.vue +182 -0
  174. package/src/pages/system/customPage.vue +62 -0
  175. package/src/pages/system/customTable.vue +98 -0
  176. package/src/pages/system/dict.vue +36 -0
  177. package/src/pages/system/dictType.vue +58 -0
  178. package/src/pages/system/entityView.vue +38 -0
  179. package/src/pages/system/error/404.vue +6 -0
  180. package/src/pages/system/extendColumn.vue +99 -0
  181. package/src/pages/system/formView.vue +136 -0
  182. package/src/pages/system/log.vue +55 -0
  183. package/src/pages/system/notice.vue +26 -0
  184. package/src/pages/system/openApi.vue +26 -0
  185. package/src/pages/system/openUser.vue +66 -0
  186. package/src/pages/system/organization.vue +98 -0
  187. package/src/pages/system/organizationType.vue +26 -0
  188. package/src/pages/system/permission.vue +175 -0
  189. package/src/pages/system/planJob.vue +40 -0
  190. package/src/pages/system/printTemplate.vue +48 -0
  191. package/src/pages/system/process.vue +79 -0
  192. package/src/pages/system/processType.vue +26 -0
  193. package/src/pages/system/role.vue +395 -0
  194. package/src/pages/system/rolePropertyEdit.vue +480 -0
  195. package/src/pages/system/sequenceSetting.vue +26 -0
  196. package/src/pages/system/systemData.vue +52 -0
  197. package/src/pages/system/tableView.vue +386 -0
  198. package/src/pages/system/taskQueue.vue +48 -0
  199. package/src/pages/system/user.vue +250 -0
  200. package/src/pages/template/processPage.vue +243 -0
  201. package/src/pages/template/reportPage.vue +66 -0
  202. package/src/pages/template/viewPage.vue +139 -0
  203. package/src/plugins/auth/index.js +21 -0
  204. package/src/plugins/error/index.js +31 -0
  205. package/src/plugins/index.js +24 -0
  206. package/src/plugins/sweetalert2/index.js +20 -0
  207. package/src/router/dynamic.js +183 -0
  208. package/src/router/index.js +84 -0
  209. package/src/setting.js +202 -0
  210. package/src/store/index.js +9 -0
  211. package/src/store/modules/admin/index.js +16 -0
  212. package/src/store/modules/admin/modules/account.js +103 -0
  213. package/src/store/modules/admin/modules/cache.js +119 -0
  214. package/src/store/modules/admin/modules/dataView.js +112 -0
  215. package/src/store/modules/admin/modules/db.js +231 -0
  216. package/src/store/modules/admin/modules/i18n.js +87 -0
  217. package/src/store/modules/admin/modules/layout.js +115 -0
  218. package/src/store/modules/admin/modules/loader.js +44 -0
  219. package/src/store/modules/admin/modules/log.js +77 -0
  220. package/src/store/modules/admin/modules/menu.js +338 -0
  221. package/src/store/modules/admin/modules/page.js +466 -0
  222. package/src/store/modules/admin/modules/user.js +96 -0
  223. package/src/store/modules/admin/modules/viewPage.js +34 -0
  224. package/src/styles/common.less +47 -0
  225. package/src/styles/css/default.css +510 -0
  226. package/src/styles/css/login.css +1217 -0
  227. package/src/styles/default/index.less +6 -0
  228. package/src/styles/font/demo.css +539 -0
  229. package/src/styles/font/demo_index.html +372 -0
  230. package/src/styles/font/icon-demo/demo.css +539 -0
  231. package/src/styles/font/icon-demo/demo_index.html +423 -0
  232. package/src/styles/font/icon-demo/iconfont.css +61 -0
  233. package/src/styles/font/icon-demo/iconfont.eot +0 -0
  234. package/src/styles/font/icon-demo/iconfont.js +1 -0
  235. package/src/styles/font/icon-demo/iconfont.svg +59 -0
  236. package/src/styles/font/icon-demo/iconfont.ttf +0 -0
  237. package/src/styles/font/icon-demo/iconfont.woff +0 -0
  238. package/src/styles/font/icon-demo/iconfont.woff2 +0 -0
  239. package/src/styles/font/iconfont.css +47 -0
  240. package/src/styles/font/iconfont.js +1 -0
  241. package/src/styles/font/iconfont.json +65 -0
  242. package/src/styles/font/iconfont.ttf +0 -0
  243. package/src/styles/font/iconfont.woff +0 -0
  244. package/src/styles/font/iconfont.woff2 +0 -0
  245. package/src/styles/font/ionicons.svg +870 -0
  246. package/src/styles/font/ionicons.ttf +0 -0
  247. package/src/styles/font/ionicons.woff +0 -0
  248. package/src/styles/font/ionicons.woff2 +0 -0
  249. package/src/styles/index.less +7 -0
  250. package/src/styles/layout/basic-layout/layout.less +527 -0
  251. package/src/styles/layout/basic-layout/menu.less +274 -0
  252. package/src/styles/layout/index.less +2 -0
  253. package/src/styles/setting.less +6 -0
  254. package/styleguide.config.js +22 -0
  255. package/test/api/barcode.js +50 -0
  256. package/test/api/inbound.js +47 -0
  257. package/test/api/interfaceLog.js +15 -0
  258. package/test/api/interfaceQueue.js +15 -0
  259. package/test/api/interfaceServer.js +29 -0
  260. package/test/api/movePlan.js +50 -0
  261. package/test/api/movePlanItem.js +13 -0
  262. package/test/api/moveType.js +22 -0
  263. package/test/api/openApiPermission.js +25 -0
  264. package/test/api/outbound.js +40 -0
  265. package/test/api/permission.js +34 -0
  266. package/test/api/rolePermission.js +17 -0
  267. package/test/api/user.js +40 -0
  268. package/test/api/viewColumn.js +16 -0
  269. package/test/api/warehouse.js +13 -0
  270. package/test/api/warehouseMoveType.js +18 -0
  271. package/test/main.js +55 -0
  272. package/test/package.js +33 -0
  273. package/test/pages/home/index.vue +22 -0
  274. package/test/pages/task/test.vue +28 -0
  275. package/test/pages/test/dataViewTest.vue +28 -0
  276. package/test/pages/test/logReport.vue +25 -0
  277. package/test/pages/test/testPage.vue +38 -0
  278. package/test/router/routes.js +88 -0
  279. package/test/setting.env.js +22 -0
  280. package/test/styles/css/custom.css +0 -0
  281. package/test/styles/css/login.css +1217 -0
  282. package/vite.config.js +72 -0
  283. package/vue.config.js +20 -0
@@ -0,0 +1,1444 @@
1
+ <template>
2
+ <div>
3
+ <!--
4
+ @slot 顶部
5
+ -->
6
+ <slot name="top" :form="this" />
7
+ <Form ref="form" :model="data" label-position="top" label-colon=":" class="ivu-mt" :rules="rules" @submit.prevent>
8
+ <!-- <Tabs v-model="tabName" v-tab-hide="tabs.length == 1">
9
+ <TabPane v-for="(tab, tabIndex) in tabs" :key="tabIndex" :label="tab" :name="tab"> -->
10
+ <Row :gutter="24" type="flex">
11
+ <template v-for="(column, index) in columns">
12
+ <div :key="'newLine' + index" v-if="column.newLine" style="width: 100%"></div>
13
+ <Col :key="index" v-if="column.isShow || column.controlType === 'Table' || column.controlType === 'List'" v-show="column.isShow" v-bind="getGrid(column.columnWidth)">
14
+ <div :key="column.code" v-if="column.controlType === 'Placeholder'" style="margin-bottom: 0px"></div>
15
+ <div :key="column.code" v-if="column.controlType === 'Title'">
16
+ <div class="form-title" :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }" v-html="column.name"></div>
17
+ </div>
18
+ <div v-if="column.controlType === 'Table'">
19
+ <Divider :plain="true" dashed orientation="left" size="small">
20
+ <span class="title">{{ column.name }}</span>
21
+ </Divider>
22
+ <view-table
23
+ :ref="'table_' + column.code"
24
+ :static="true"
25
+ :view-code="column.source"
26
+ :readonly="readonly || column.isReadonly"
27
+ :embedded="true"
28
+ :parent-data="data"
29
+ @on-change="onDataChange(column)"
30
+ >
31
+ <template #column="{ row, index, column, code }">
32
+ <!--
33
+ @slot 内嵌表格自定义列
34
+ @binding {object} table 表格对象
35
+ @binding {object} tableData 表格数据对象
36
+ @binding {object} tableColumn 表格列对象
37
+ @binding {string} tableCode 表格列代码
38
+ @binding {object} row 行对象
39
+ @binding {int} index 行序号
40
+ @binding {object} column 列对象
41
+ @binding {string} code 列代码
42
+ -->
43
+ <slot
44
+ name="tableColumn"
45
+ :table="$refs['table_' + column.code][0]"
46
+ :tableData="data"
47
+ :tableColumn="column"
48
+ :tableCode="column.code"
49
+ :row="row"
50
+ :index="index"
51
+ :column="column"
52
+ :code="code"
53
+ ></slot>
54
+ </template>
55
+ </view-table>
56
+ </div>
57
+ <div v-if="column.controlType === 'List'">
58
+ <Divider :plain="true" dashed orientation="left" size="small">
59
+ <span class="title">{{ column.name }}</span>
60
+ </Divider>
61
+ <view-table :ref="'list_' + column.code" :static="true" :view-code="column.source" :readonly="true" :pageEnable="false" :embedded="true"></view-table>
62
+ </div>
63
+ <FormItem
64
+ :label="column.name"
65
+ :prop="column.code"
66
+ :key="column.code"
67
+ :rules="getRules(column)"
68
+ v-if="column.controlType !== 'Placeholder' && column.controlType !== 'Title' && column.controlType !== 'Table' && column.controlType !== 'List'"
69
+ >
70
+ <template v-if="column.controlType === 'Custom'">
71
+ <!--
72
+ @slot 自定义列
73
+ @binding {object} form 表单对象
74
+ @binding {object} data 数据对象
75
+ @binding {object} column 列对象
76
+ @binding {string} code 列代码
77
+ -->
78
+ <slot name="column" :form="this" :data="data" :column="column" :code="column.code"></slot>
79
+ </template>
80
+ <template v-else-if="column.controlType === 'Label'">
81
+ <div class="label" :title="compareData == null ? showData(data, column) : showData(compareData, column)">
82
+ <div :class="{ error: compareData != null && parseData(data, column.code) != parseData(compareData, column.code) }" v-html="showData(data, column)"></div>
83
+ </div>
84
+ </template>
85
+ <template v-if="column.controlType === 'Hyperlink'">
86
+ <a :href="getHyperlink(data, column.hyperlink)" :target="column.isNewWindow ? '_blank' : ''">
87
+ <span v-html="showData(data, column)"></span>
88
+ </a>
89
+ </template>
90
+ <template v-else-if="column.controlType === 'TextInput'">
91
+ <Input
92
+ type="text"
93
+ :model-value="parseData(data, column.code)"
94
+ @update:model-value="$event => setData(data, column.code, $event)"
95
+ :readonly="readonly || column.isReadonly"
96
+ :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
97
+ :maxlength="column.maxLength"
98
+ :placeholder="column.description"
99
+ @on-change="onDataChange(column)"
100
+ @on-blur="onBlur(column)"
101
+ />
102
+ </template>
103
+ <template v-else-if="column.controlType === 'NumberInput'">
104
+ <Input
105
+ type="number"
106
+ number
107
+ :model-value="parseData(data, column.code)"
108
+ @update:model-value="$event => setData(data, column.code, $event)"
109
+ :readonly="readonly || column.isReadonly"
110
+ :style="{ width: column.controlWidth == null ? '100px' : column.controlWidth + 'px' }"
111
+ :placeholder="column.description"
112
+ :max="column.maxValue"
113
+ :min="column.minValue"
114
+ @on-change="onDataChange(column)"
115
+ @on-blur="onBlur(column)"
116
+ />
117
+ </template>
118
+ <template v-else-if="column.controlType === 'Select'">
119
+ <Select
120
+ :model-value="parseData(data, column.code)"
121
+ @update:model-value="$event => setData(data, column.code, $event)"
122
+ :disabled="readonly || column.isReadonly"
123
+ :clearable="true"
124
+ :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
125
+ :placeholder="column.description"
126
+ :transfer="true"
127
+ @on-change="selected => onSelectDataChange(column, selected)"
128
+ >
129
+ <Option v-for="item in getDataSource(data, column)" :key="item.id" :value="item.id">{{ item.name }}</Option>
130
+ </Select>
131
+ </template>
132
+ <template v-else-if="column.controlType === 'MultiSelect'">
133
+ <Select
134
+ :model-value="parseArrayData(data, column.code)"
135
+ @update:model-value="$event => setArrayData(data, column.code, $event)"
136
+ :disabled="readonly || column.isReadonly"
137
+ :multiple="true"
138
+ :clearable="true"
139
+ :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
140
+ :placeholder="column.description"
141
+ :transfer="true"
142
+ @on-change="selected => onSelectDataChange(column, selected)"
143
+ >
144
+ <Option v-for="item in getDataSource(data, column)" :key="item.id" :value="item.id">{{ item.name }}</Option>
145
+ </Select>
146
+ </template>
147
+ <template v-else-if="column.controlType === 'TreeSelect'">
148
+ <TreeSelect
149
+ :model-value="parseTreeData(data, column.code)"
150
+ @update:model-value="$event => setData(data, column.code, $event)"
151
+ :data="getDataSource(data, column)"
152
+ :disabled="readonly || column.isReadonly"
153
+ :clearable="true"
154
+ :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
155
+ :placeholder="column.description"
156
+ :transfer="true"
157
+ @on-change="selected => onSelectDataChange(column, selected)"
158
+ ></TreeSelect>
159
+ </template>
160
+ <template v-else-if="column.controlType === 'MultiTreeSelect'">
161
+ <TreeSelect
162
+ :model-value="parseArrayData(data, column.code)"
163
+ @update:model-value="$event => setArrayData(data, column.code, $event)"
164
+ :data="getDataSource(data, column)"
165
+ :disabled="readonly || column.isReadonly"
166
+ :multiple="true"
167
+ :show-checkbox="true"
168
+ :clearable="true"
169
+ :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
170
+ :placeholder="column.description"
171
+ :transfer="true"
172
+ @on-change="selected => onSelectDataChange(column, selected)"
173
+ ></TreeSelect>
174
+ </template>
175
+ <!-- <template v-else-if="column.controlType === 'AutoComplete'">
176
+ <AutoComplete :value="parseData(data, column.code) ? parseData(data, column.code) : ''"
177
+ @update:model-value="$event => setData(data, column.code, $event)"
178
+ :disabled="readonly || column.isReadonly"
179
+ :clearable="true"
180
+ @on-search="search => loadOption(data, column, search)"
181
+ @on-clear="() => loadOption(data, column)"
182
+ :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
183
+ :placeholder="column.description"
184
+ :transfer="true"
185
+ @on-change="(selected) => onDataChange(column, selected)">
186
+ <Option v-for="item in getDataSource(data, column)"
187
+ :key="item.id"
188
+ :value="item.name">{{ item.name }}</Option>
189
+ </AutoComplete>
190
+ </template> -->
191
+ <template v-else-if="column.controlType === 'ComboSelect'">
192
+ <Select
193
+ :model-value="parseData(data, column.code)"
194
+ @update:model-value="$event => setData(data, column.code, $event)"
195
+ :disabled="readonly || column.isReadonly"
196
+ :clearable="true"
197
+ filterable
198
+ :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
199
+ :placeholder="column.description"
200
+ :transfer="true"
201
+ @on-change="selected => onSelectDataChange(column, selected)"
202
+ >
203
+ <Option v-for="item in getDataSource(data, column)" :key="item.id" :value="item.id">{{ item.name }}</Option>
204
+ </Select>
205
+ </template>
206
+ <template v-else-if="column.controlType === 'DialogSelect'">
207
+ <dialog-select
208
+ :model-value="parseData(data, column.code)"
209
+ @update:model-value="$event => setData(data, column.code, $event)"
210
+ :readonly="readonly || column.isReadonly"
211
+ :source="column.source"
212
+ :source-data-code="column.sourceDataCode"
213
+ :source-display-code="column.sourceDisplayCode"
214
+ :param="getParam(data, column)"
215
+ :controlWidth="column.controlWidth"
216
+ @on-change="selected => onSelectDataChange(column, selected)"
217
+ ></dialog-select>
218
+ </template>
219
+ <template v-else-if="column.controlType === 'MultiDialogSelect'">
220
+ <dialog-select
221
+ :model-value="parseData(data, column.code)"
222
+ @update:model-value="$event => setData(data, column.code, $event)"
223
+ :multi="true"
224
+ :readonly="readonly || column.isReadonly"
225
+ :source="column.source"
226
+ :source-data-code="column.sourceDataCode"
227
+ :source-display-code="column.sourceDisplayCode"
228
+ :param="getParam(data, column)"
229
+ :controlWidth="column.controlWidth"
230
+ @on-change="selected => onSelectDataChange(column, selected)"
231
+ ></dialog-select>
232
+ </template>
233
+ <template v-else-if="column.controlType === 'SelectWithOther'">
234
+ <Select
235
+ :model-value="parseDataWithOther(data, column)"
236
+ @update:model-value="$event => setDataWithOther(data, column.code, $event)"
237
+ :disabled="readonly || column.isReadonly"
238
+ :clearable="true"
239
+ :style="{ width: column.controlWidth == null ? '40%' : column.controlWidth + 'px' }"
240
+ :placeholder="column.description"
241
+ :transfer="true"
242
+ @on-change="selected => onSelectDataChange(column, selected)"
243
+ >
244
+ <Option v-for="item in getDataSource(data, column)" :key="item.id" :value="item.id">{{ item.name }}</Option>
245
+ <Option key="__Other" value="__Other">其他</Option>
246
+ </Select>
247
+ <Input
248
+ type="text"
249
+ v-show="parseDataWithOther(data, column) == '__Other'"
250
+ :model-value="parseData(data, column.code)"
251
+ @update:model-value="$event => setData(data, column.code, $event)"
252
+ :readonly="readonly || column.isReadonly"
253
+ :style="{ width: column.controlWidth == null ? '40%' : column.controlWidth + 'px' }"
254
+ style="margin-left: 4px"
255
+ :maxlength="column.maxLength"
256
+ :placeholder="column.description"
257
+ @on-change="selected => onDataChange(column, selected)"
258
+ @on-blur="onBlur(column)"
259
+ />
260
+ </template>
261
+ <template v-else-if="column.controlType === 'Date' || column.controlType === 'DateTime' || column.controlType === 'Year' || column.controlType === 'Month'">
262
+ <DatePicker
263
+ :type="column.controlType.toLowerCase()"
264
+ :model-value="parseDateTimeData(data, column.code)"
265
+ @update:model-value="$event => setData(data, column.code, $event)"
266
+ :readonly="readonly || column.isReadonly"
267
+ :placeholder="column.description"
268
+ :transfer="true"
269
+ :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
270
+ @on-change="onDataChange(column)"
271
+ ></DatePicker>
272
+ </template>
273
+ <template v-else-if="column.controlType === 'DateRange'">
274
+ <DatePicker
275
+ :type="column.controlType.toLowerCase()"
276
+ :model-value="parseDateRangeData(data, column.code)"
277
+ @update:model-value="$event => setArrayData(data, column.code, $event)"
278
+ :readonly="readonly || column.isReadonly"
279
+ :placeholder="column.description"
280
+ :transfer="true"
281
+ :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
282
+ @on-change="onDataChange(column)"
283
+ ></DatePicker>
284
+ </template>
285
+ <template v-else-if="column.controlType === 'Time'">
286
+ <TimePicker
287
+ type="time"
288
+ :model-value="parseDateTimeData(data, column.code)"
289
+ @update:model-value="$event => setData(data, column.code, $event)"
290
+ :readonly="readonly || column.isReadonly"
291
+ :placeholder="column.description"
292
+ :transfer="true"
293
+ :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
294
+ @on-change="onDataChange(column)"
295
+ ></TimePicker>
296
+ </template>
297
+ <template v-else-if="column.controlType === 'Check'">
298
+ <Checkbox
299
+ :model-value="!!parseData(data, column.code)"
300
+ @update:model-value="$event => setData(data, column.code, $event)"
301
+ :disabled="readonly || column.isReadonly"
302
+ size="large"
303
+ @on-change="onDataChange(column)"
304
+ />
305
+ </template>
306
+ <template v-else-if="column.controlType === 'Switch'">
307
+ <Switch
308
+ :model-value="!!parseData(data, column.code)"
309
+ @update:model-value="$event => setData(data, column.code, $event)"
310
+ :disabled="readonly || column.isReadonly"
311
+ @on-change="onDataChange(column)"
312
+ />
313
+ </template>
314
+ <template v-else-if="column.controlType === 'Radio'">
315
+ <RadioGroup
316
+ :model-value="parseData(data, column.code)"
317
+ @update:model-value="$event => setData(data, column.code, $event)"
318
+ @on-change="selected => onSelectDataChange(column, selected)"
319
+ >
320
+ <Radio v-for="item in getDataSource(data, column)" :key="item.id" :label="item.id" :disabled="readonly || column.isReadonly">
321
+ <span>{{ item.name }}</span>
322
+ </Radio>
323
+ </RadioGroup>
324
+ </template>
325
+ <template v-else-if="column.controlType === 'CheckGroup'">
326
+ <CheckboxGroup
327
+ :model-value="parseArrayData(data, column.code)"
328
+ @update:model-value="$event => setArrayData(data, column.code, $event)"
329
+ @on-change="selected => onSelectDataChange(column, selected)"
330
+ >
331
+ <Checkbox v-for="item in getDataSource(data, column)" :key="item.id" :label="item.id" :disabled="readonly || column.isReadonly">
332
+ <span>{{ item.name }}</span>
333
+ </Checkbox>
334
+ </CheckboxGroup>
335
+ </template>
336
+ <template v-else-if="column.controlType === 'TextArea'">
337
+ <Input
338
+ type="textarea"
339
+ :model-value="parseData(data, column.code)"
340
+ @update:model-value="$event => setData(data, column.code, $event)"
341
+ :readonly="readonly || column.isReadonly"
342
+ :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
343
+ :rows="column.controlHeight / 20"
344
+ :maxlength="column.maxLength"
345
+ :placeholder="column.description"
346
+ />
347
+ </template>
348
+ <template v-else-if="column.controlType === 'RichEditor'">
349
+ <rich-editor
350
+ :model-value="parseData(data, column.code)"
351
+ @update:model-value="$event => setData(data, column.code, $event)"
352
+ :readonly="readonly || column.isReadonly"
353
+ :height="column.controlHeight"
354
+ :width="column.controlWidth"
355
+ />
356
+ </template>
357
+ <template v-else-if="column.controlType === 'Attachment'">
358
+ <upload-attachment
359
+ v-if="!readonly && !column.isReadonly"
360
+ :model-value="parseData(data, column.code)"
361
+ @update:model-value="$event => setData(data, column.code, $event)"
362
+ :maxCount="column.maxLength"
363
+ :accept="column.pattern"
364
+ />
365
+ <template v-if="(readonly || column.isReadonly) && !!(parseData(data, column.code) || '').trim()">
366
+ <a
367
+ :href="getAttachmentUrl(attachment.file, attachment.name)"
368
+ :key="attachmentIndex"
369
+ v-for="(attachment, attachmentIndex) in JSON.parse(parseData(data, column.code))"
370
+ >
371
+ <div>
372
+ <Icon type="ios-document" />
373
+ {{ attachment.name }}
374
+ </div>
375
+ </a>
376
+ </template>
377
+ </template>
378
+ <template v-else-if="column.controlType === 'Image'">
379
+ <upload-image
380
+ :model-value="parseData(data, column.code)"
381
+ @update:model-value="$event => setData(data, column.code, $event)"
382
+ :readonly="readonly || column.isReadonly"
383
+ :maxCount="column.maxLength"
384
+ :height="column.controlHeight"
385
+ :width="column.controlWidth"
386
+ />
387
+ </template>
388
+ <template v-else-if="column.controlType === 'Slider'">
389
+ <Slider
390
+ v-if="!readonly && !column.isReadonly"
391
+ :model-value="parseData(data, column.code)"
392
+ @update:model-value="$event => setData(data, column.code, $event)"
393
+ show-input
394
+ :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
395
+ :max="column.maxValue"
396
+ :min="column.minValue"
397
+ />
398
+ <Input
399
+ v-if="readonly || column.isReadonly"
400
+ type="number"
401
+ number
402
+ readonly
403
+ :model-value="parseData(data, column.code)"
404
+ :style="{ width: column.controlWidth == null ? '100px' : column.controlWidth + 'px' }"
405
+ :placeholder="column.description"
406
+ />
407
+ </template>
408
+ </FormItem>
409
+ </Col>
410
+ </template>
411
+ </Row>
412
+ <!-- </TabPane>
413
+ </Tabs> -->
414
+ <!--
415
+ @slot 底部
416
+ @binding {object} form 表单对象
417
+ -->
418
+ <slot name="bottom" :form="this" />
419
+ </Form>
420
+ <!-- <FooterToolbar>
421
+ <Button type="primary" size="large">提交</Button>
422
+ </FooterToolbar>-->
423
+ </div>
424
+ </template>
425
+ <script>
426
+ import mixinPage from '../../mixins/page';
427
+ import mixin from './mixin';
428
+ import { mapActions } from 'vuex';
429
+ import modelApi from '../../api/model';
430
+ import customModelApi from '../../api/customModel';
431
+ import richEditor from '../richEditor';
432
+ import uploadAttachment from '../upload/upload-attachment';
433
+ import uploadImage from '../upload/upload-image';
434
+ import dateFormat from 'date-fns/format';
435
+
436
+ /**
437
+ * @displayName view-form 表单视图
438
+ */
439
+ export default {
440
+ mixins: [mixin, mixinPage],
441
+ components: { richEditor, uploadAttachment, uploadImage },
442
+ data() {
443
+ return {
444
+ formView: {},
445
+ tabs: [],
446
+ tabName: '',
447
+ columns: [],
448
+ rules: {},
449
+ data: null,
450
+ compareData: null,
451
+ dataBefore: null
452
+ };
453
+ },
454
+ async created() {
455
+ // 默认视图代码
456
+ if (this.viewCode) {
457
+ // 初始化
458
+ await this.init(this.viewCode);
459
+ }
460
+ },
461
+ props: {
462
+ /**
463
+ * 视图代码
464
+ */
465
+ viewCode: {
466
+ type: String
467
+ },
468
+ /**
469
+ * 只读
470
+ */
471
+ readonly: {
472
+ type: Boolean,
473
+ default: false
474
+ },
475
+ /**
476
+ * 预设默认值
477
+ */
478
+ defaultData: {
479
+ type: Object,
480
+ default() {
481
+ return {};
482
+ }
483
+ },
484
+ /**
485
+ * 显示工具栏
486
+ */
487
+ commandEnable: {
488
+ type: Boolean,
489
+ default: true
490
+ },
491
+ /**
492
+ * 是否允许配置界面
493
+ */
494
+ settingEnable: {
495
+ type: Boolean,
496
+ default: true
497
+ }
498
+ },
499
+ computed: {},
500
+ watch: {
501
+ data() {
502
+ if (this.data && Object.keys(this.data).length > 0) {
503
+ this.columns.forEach(async column => {
504
+ if (column.controlType == 'Table' && this.$refs['table_' + column.code]) {
505
+ setTimeout(async () => {
506
+ if (column.tableStoreType == 'Inner') {
507
+ // 表内存储
508
+ let json = this.parseData(this.data, column.code);
509
+
510
+ if (json) {
511
+ this.$refs['table_' + column.code][0].loadData(JSON.parse(json));
512
+ } else {
513
+ this.$refs['table_' + column.code][0].loadData([]);
514
+ }
515
+ } else {
516
+ // 关联表
517
+ if (this.data.id) {
518
+ // 参数完整,查询数据
519
+ let res;
520
+ let param = {};
521
+
522
+ let tableView = this.$refs['table_' + column.code][0].tableView;
523
+
524
+ let filtering = tableView.filtering;
525
+
526
+ if (!!(filtering || '').trim()) {
527
+ param = JSON.parse(filtering);
528
+ }
529
+
530
+ param[column.sourceDataCode] = this.data.id;
531
+
532
+ if (column.isSourceCustom) {
533
+ res = await customModelApi.query(column.sourceModel, param);
534
+ } else {
535
+ res = await modelApi.query(column.sourceModel, param, tableView.functionName, tableView.functionType);
536
+ }
537
+
538
+ this.$refs['table_' + column.code][0].loadData(res.data);
539
+ }
540
+ }
541
+ });
542
+ }
543
+ });
544
+ }
545
+
546
+ //this.changed = false;
547
+ }
548
+ // staticData() {
549
+ // // 设置选中项
550
+ // if (typeof this.selectFunc === 'function') {
551
+ // let selected = this.staticData.filter(this.selectFunc);
552
+ // this.setSelected(selected);
553
+ // }
554
+ // }
555
+ },
556
+ methods: {
557
+ ...mapActions('admin/dataView', { loadDataView: 'load' }),
558
+ /**
559
+ * 初始化
560
+ *
561
+ * @param {string} viewCode 视图代码
562
+ * @param {function} callback 完成后回调方法
563
+ * @param {function} onFail 失败后回调方法
564
+ * @public
565
+ */
566
+ async init(viewCode, callback, onFail) {
567
+ // 加载表格视图
568
+ let view = await this.loadDataView(viewCode);
569
+
570
+ if (view == null && viewCode.indexOf('_') >= 0) {
571
+ view = await this.loadDataView(viewCode.split('_')[0]);
572
+ }
573
+
574
+ if (view == null) {
575
+ if (typeof onFail === 'function') {
576
+ onFail();
577
+ } else {
578
+ this.error('视图代码不存在!' + viewCode);
579
+ }
580
+ return;
581
+ }
582
+
583
+ this.loadView(view);
584
+
585
+ setTimeout(() => {
586
+ if (typeof callback === 'function') {
587
+ callback(view);
588
+ }
589
+ });
590
+ },
591
+ /**
592
+ * 加载视图
593
+ *
594
+ * @param {object} view 视图
595
+ * @public
596
+ */
597
+ loadView(view) {
598
+ // 加载表格视图
599
+ this.formView = view.dataView;
600
+ this.formView.columns = view.viewColumns;
601
+
602
+ /**
603
+ * 视图获取完成事件
604
+ * @property {object} formView 表单视图
605
+ */
606
+ this.$emit('on-ready', this.formView);
607
+ this.columns = view.viewColumns;
608
+
609
+ // 设置初始值
610
+ this.data = this.getDefaultData();
611
+
612
+ // 初始化校验规则
613
+ //this.initRule();
614
+
615
+ setTimeout(() => {
616
+ // 初始化板块
617
+ this.initTab();
618
+
619
+ // 初始化静态选项
620
+ this.initStaticItem();
621
+
622
+ // 初始化触发规则
623
+ this.initTrigger();
624
+
625
+ this.onDataChange();
626
+ });
627
+ },
628
+ /**
629
+ * 获取默认值
630
+ *
631
+ * @public
632
+ */
633
+ getDefaultData() {
634
+ let data = {};
635
+ this.columns.forEach(item => {
636
+ if (item.defaultValue) {
637
+ if (item.defaultValue == '{today}') {
638
+ // 当前日期
639
+ let date = new Date();
640
+ let value = date.toISOString().replace(/T.*/, '');
641
+ this.setData(data, item.code, new Date(value));
642
+ } else if (item.defaultValue.startsWith('{today(') && item.defaultValue.endsWith(')}')) {
643
+ // 当前时间转字符串
644
+ let format = item.defaultValue.substr(7, item.defaultValue.length - 9);
645
+ this.setData(data, item.code, dateFormat(new Date(), format));
646
+ } else if (item.defaultValue == '{currentUser}') {
647
+ // 当前用户
648
+ this.setData(data, item.code, this.info.name);
649
+ } else {
650
+ if (item.dataType === 'Integer') {
651
+ this.setData(data, item.code, parseInt(item.defaultValue));
652
+ } else if (item.dataType === 'Decimal') {
653
+ this.setData(data, item.code, parseFloat(item.defaultValue));
654
+ } else if (item.dataType === 'Boolean' && item.defaultValue.toUpperCase == 'TRUE') {
655
+ this.setData(data, item.code, true);
656
+ } else if (item.dataType === 'Boolean' && item.defaultValue.toUpperCase == 'FALSE') {
657
+ this.setData(data, item.code, false);
658
+ } else {
659
+ this.setData(data, item.code, item.defaultValue);
660
+ }
661
+ }
662
+ } else {
663
+ if (item.dataType === 'Boolean') {
664
+ this.setData(data, item.code, false);
665
+ } else {
666
+ this.setData(data, item.code, null);
667
+ }
668
+ }
669
+ });
670
+
671
+ for (let key in this.defaultData) {
672
+ this.setData(data, key, this.defaultData[key]);
673
+ }
674
+
675
+ return data;
676
+ },
677
+ /**
678
+ * 重置
679
+ *
680
+ * @public
681
+ */
682
+ reset() {
683
+ // 清空表格控件数据;
684
+ this.columns.forEach(column => {
685
+ if (column.controlType == 'Table') {
686
+ this.$refs['table_' + column.code][0].loadData([]);
687
+ }
688
+ });
689
+
690
+ this.data = {};
691
+
692
+ this.clearValidate();
693
+ },
694
+ /**
695
+ * 清空验证信息
696
+ *
697
+ * @public
698
+ */
699
+ async clearValidate() {
700
+ this.$refs.form.fields.forEach(field => {
701
+ field.validateState = '';
702
+ field.validateMessage = '';
703
+ });
704
+ },
705
+ /**
706
+ * 设为默认值
707
+ *
708
+ * @param {object} data 默认值
709
+ * @public
710
+ */
711
+ setDefault(data) {
712
+ //this.$refs.form.resetFields();
713
+
714
+ // 清空表格控件数据
715
+ // this.columns.forEach(column => {
716
+ // if (column.controlType == 'Table') {
717
+ // this.$refs['table_' + column.code][0].loadData([]);
718
+ // }
719
+ // });
720
+
721
+ this.data = this.getDefaultData();
722
+ if (data) {
723
+ for (let key in data) {
724
+ this.data[key] = data[key];
725
+ }
726
+ }
727
+
728
+ this.clearValidate();
729
+ },
730
+ /**
731
+ * 验证
732
+ *
733
+ * @public
734
+ */
735
+ validate() {
736
+ return this.$refs.form.validate();
737
+ },
738
+ /**
739
+ * 获取完整数据
740
+ *
741
+ * @public
742
+ */
743
+ getFullData() {
744
+ let data = this.copy(this.data);
745
+ data.tableData = [];
746
+
747
+ for (let column of this.columns) {
748
+ if (column.controlType == 'Table' && !column.isReadonly && column.isShow) {
749
+ let tableData = this.$refs['table_' + column.code][0].getData();
750
+
751
+ if (column.isRequired && tableData.length == 0) {
752
+ this.error(column.name + ' 不能为空!');
753
+ return false;
754
+ }
755
+
756
+ if (!this.$refs['table_' + column.code][0].validate()) {
757
+ return false;
758
+ }
759
+
760
+ if (column.tableStoreType == 'Inner') {
761
+ // 表内存储
762
+ data[column.code] = JSON.stringify(tableData);
763
+ } else {
764
+ // 外部关联表
765
+ data.tableData.push({
766
+ model: column.sourceModel,
767
+ sourceDataCode: column.sourceDataCode,
768
+ filtering: this.$refs['table_' + column.code][0].tableView.filtering,
769
+ data: tableData
770
+ });
771
+ }
772
+ }
773
+ }
774
+
775
+ return data;
776
+ },
777
+ /**
778
+ * 设置表格字段内容
779
+ *
780
+ * @param {string} code 字段
781
+ * @param {object} value 值
782
+ * @public
783
+ */
784
+ setTableData(code, value) {
785
+ let column = this.columns.find(x => x.code == code);
786
+
787
+ if (value == null) {
788
+ this.setData(this.data, column.code, null);
789
+ value = [];
790
+ } else {
791
+ this.setData(this.data, column.code, JSON.stringify(value));
792
+ }
793
+
794
+ if (column.controlType == 'Table' && this.$refs['table_' + column.code]) {
795
+ this.$refs['table_' + column.code][0].loadData(value);
796
+ }
797
+ },
798
+ /**
799
+ * 刷新
800
+ *
801
+ * @public
802
+ */
803
+ refresh() {
804
+ this.onDataChange();
805
+ },
806
+ // 根据选项卡序号返回列
807
+ tabColumns(index) {
808
+ return this.columns.filter(item => {
809
+ return item.tabIndex === index || item.tabIndex == null;
810
+ });
811
+ },
812
+ getRules(column) {
813
+ if (!column.isShow) {
814
+ return [];
815
+ }
816
+
817
+ let rules = [];
818
+
819
+ if (column.isRequired) {
820
+ if (
821
+ column.controlType == 'Date' ||
822
+ column.controlType == 'DateTime' ||
823
+ column.controlType == 'Year' ||
824
+ column.controlType == 'Month' ||
825
+ column.controlType == 'DateRange'
826
+ ) {
827
+ rules.push({
828
+ pattern: /.+/,
829
+ required: true,
830
+ message: '请输入' + column.name,
831
+ trigger: this.getTrigger(column)
832
+ });
833
+ } else {
834
+ rules.push({
835
+ type: this.getDataType(column),
836
+ required: true,
837
+ message: '请输入' + column.name,
838
+ trigger: this.getTrigger(column)
839
+ });
840
+ }
841
+ }
842
+
843
+ if (column.pattern) {
844
+ rules.push({
845
+ type: this.getDataType(column),
846
+ pattern: column.pattern,
847
+ message: column.name + '不符合要求',
848
+ trigger: this.getTrigger(column)
849
+ });
850
+ }
851
+
852
+ if (column.maxValue != null) {
853
+ rules.push({
854
+ type: this.getDataType(column),
855
+ max: column.maxValue,
856
+ message: column.name + '不能大于' + column.maxValue,
857
+ trigger: this.getTrigger(column)
858
+ });
859
+ }
860
+
861
+ if (column.minValue != null) {
862
+ rules.push({
863
+ type: this.getDataType(column),
864
+ min: column.minValue,
865
+ message: column.name + '不能小于' + column.minValue,
866
+ trigger: this.getTrigger(column)
867
+ });
868
+ }
869
+
870
+ if (column.maxLength != null) {
871
+ rules.push({
872
+ type: this.getDataType(column),
873
+ length: column.maxLength,
874
+ message: column.name + '不能超过' + column.maxLength + '个字符',
875
+ trigger: this.getTrigger(column)
876
+ });
877
+ }
878
+
879
+ return rules;
880
+ },
881
+ // 初始化校验规则
882
+ // initRule() {
883
+ // // 重置验证信息
884
+ // setTimeout(() => {
885
+ // this.clearValidate();
886
+ // });
887
+ // },
888
+ // 初始化板块
889
+ initTab() {
890
+ if (!!(this.formView.tab || '').trim()) {
891
+ this.tabs = this.formView.tab.split(',');
892
+ } else {
893
+ this.tabs = [this.formView.name];
894
+ }
895
+
896
+ this.tabName = this.tabs[0];
897
+ },
898
+ // 初始化静态选项
899
+ initStaticItem() {
900
+ this.columns.forEach(column => {
901
+ if (column.isStaticItem) {
902
+ column.dataSource = [];
903
+
904
+ if (!!(column.itemData || '').trim()) {
905
+ column.itemData.split(/[\n]/).forEach(item => {
906
+ if (!!(item || '').trim()) {
907
+ if (item.split(':').length > 1) {
908
+ let key = item.split(':')[0];
909
+ let value = item.split(':')[1];
910
+
911
+ column.dataSource.push({
912
+ id: key,
913
+ name: value
914
+ });
915
+ } else {
916
+ column.dataSource.push({
917
+ id: item,
918
+ name: item
919
+ });
920
+ }
921
+ }
922
+ });
923
+ }
924
+ }
925
+ });
926
+
927
+ //this.$forceUpdate();
928
+ },
929
+ // 初始化触发规则
930
+ initTrigger() {
931
+ // 触发规则
932
+ this.columns.forEach(column => {
933
+ column.triggers = [];
934
+ });
935
+
936
+ // 数据源中包含变量需要刷新
937
+ this.columns
938
+ .filter(column => {
939
+ return !column.isStaticItem && !!(column.source || '').trim() && !!(column.param || '').trim();
940
+ })
941
+ .forEach(column => {
942
+ let param = JSON.parse(column.param);
943
+ for (let key in param) {
944
+ this.columns
945
+ .filter(item => {
946
+ return param[key] == item.code || param[key].split('.')[0] + 'ID' == item.code;
947
+ })
948
+ .forEach(item => {
949
+ item.triggers.push(this.copy(column));
950
+ });
951
+ }
952
+ });
953
+
954
+ // 公式中包含变量需要刷新
955
+ // this.columns
956
+ // .filter(column => {
957
+ // return !!(column.calculate || '').trim();
958
+ // })
959
+ // .forEach(column => {
960
+ // let triggers = this.getTriggers(column.calculate);
961
+
962
+ // this.columns
963
+ // .filter(item => {
964
+ // return triggers.some(i => {
965
+ // return i == item.code;
966
+ // });
967
+ // })
968
+ // .forEach(item => {
969
+ // item.triggers.push(column);
970
+ // });
971
+ // });
972
+ },
973
+ // 填充数据源
974
+ async fillDataSource(data, column, param) {
975
+ let value;
976
+ if (column.controlType === 'TreeSelect' || column.controlType === 'MultiTreeSelect') {
977
+ // 树选择框重新加载数据源时,需要先清空数据源,否则无法直接点击清空按钮清除数据。
978
+ value = this.parseTreeData(data, column.code);
979
+ column.dataSource = null;
980
+ }
981
+
982
+ // 参数完整,查询数据
983
+ let res;
984
+ if (column.isSourceCustom) {
985
+ res = await customModelApi.query(column.source, param);
986
+ } else {
987
+ res = await modelApi.query(column.source, param);
988
+ }
989
+
990
+ column.rawData = res.data;
991
+
992
+ if (column.controlType === 'TreeSelect' || column.controlType === 'MultiTreeSelect') {
993
+ let treeData = res.data.map(item => {
994
+ return {
995
+ id: !(column.sourceDataCode || '').trim() ? item.id : this.parseData(item, column.sourceDataCode),
996
+ name: this.parseData(item, column.sourceDisplayCode),
997
+ parentID: item.parentID
998
+ };
999
+ });
1000
+
1001
+ column.dataSource = this.getTreeDataSource(treeData, column, null);
1002
+ this.setData(data, column.code, value);
1003
+ } else {
1004
+ column.dataSource = res.data.map(item => {
1005
+ return {
1006
+ id: !(column.sourceDataCode || '').trim() ? item.id : this.parseData(item, column.sourceDataCode),
1007
+ name: this.parseData(item, column.sourceDisplayCode)
1008
+ };
1009
+ });
1010
+
1011
+ // 默认第一项
1012
+ if (data) {
1013
+ if (this.parseData(data, column.code) == null && column.isDefaultFirst && res.data.length > 0) {
1014
+ this.setData(data, column.code, this.parseData(res.data[0], column.sourceDataCode));
1015
+
1016
+ if (column.sourceDataCode == 'id' && column.code.length > 2) {
1017
+ let code = column.code.substr(0, column.code.length - 2);
1018
+ let model = column.rawData.find(item => {
1019
+ return item.id == this.parseData(data, column.code);
1020
+ });
1021
+
1022
+ this.setData(data, code, model);
1023
+ }
1024
+ }
1025
+ }
1026
+ }
1027
+
1028
+ //this.$forceUpdate();
1029
+
1030
+ // 级联更新时清空数据
1031
+ if (column.controlType == 'Select' || column.controlType == 'ComboSelect' || column.controlType == 'Radio') {
1032
+ if (
1033
+ !column.dataSource.some(item => {
1034
+ return item.id == this.parseData(data, column.code);
1035
+ })
1036
+ ) {
1037
+ // 数据不存在于此数据源,清空数据
1038
+ this.setData(data, column.code, null);
1039
+
1040
+ // 触发
1041
+ column.triggers.forEach(item => {
1042
+ item.needClear = true;
1043
+ });
1044
+ }
1045
+ }
1046
+ },
1047
+ // 获取树结构数据源
1048
+ getTreeDataSource(treeData, column, parentID) {
1049
+ let result = treeData
1050
+ .filter(item => {
1051
+ return item.parentID == parentID;
1052
+ })
1053
+ .map(item => {
1054
+ return {
1055
+ value: !(column.sourceDataCode || '').trim() ? item.id : this.parseData(item, column.sourceDataCode),
1056
+ title: this.parseData(item, column.sourceDisplayCode),
1057
+ selected: false,
1058
+ checked: false
1059
+ };
1060
+ });
1061
+
1062
+ if (result.length > 0) {
1063
+ for (let item of result) {
1064
+ item.expand = true;
1065
+ item.children = this.getTreeDataSource(treeData, column, item.value);
1066
+ }
1067
+ }
1068
+
1069
+ return result;
1070
+ },
1071
+ // 获取数据源
1072
+ getDataSource(data, column) {
1073
+ if (!column.isStaticItem && column.dataType.indexOf('Enum:') === 0) {
1074
+ // 枚举
1075
+ return this.getEnumList(column.dataType.split(':')[1]);
1076
+ } else {
1077
+ return column.dataSource == null ? [] : column.dataSource;
1078
+ }
1079
+ },
1080
+ // // 可筛选下拉框加载数据
1081
+ // loadOption(data, column, keyword) {
1082
+ // let param = this.getParam(data, column);
1083
+
1084
+ // if (param != null) {
1085
+ // if (!(keyword || '').trim() && this.parseData(data, column.code) != null && column.controlType !== 'AutoComplete') {
1086
+ // param[column.sourceDataCode] = this.parseData(data, column.code);
1087
+ // } else {
1088
+ // param.keyword = keyword;
1089
+ // }
1090
+ // param.per = 20;
1091
+
1092
+ // this.fillDataSource(data, column, param);
1093
+ // } else {
1094
+ // // 参数不完整,清空数据
1095
+ // column.dataSource = [];
1096
+ // this.setData(data, column.code, null);
1097
+ // // column.displayValue = null;
1098
+
1099
+ // // 触发
1100
+ // column.triggers.forEach(item => {
1101
+ // item.needClear = true;
1102
+ // });
1103
+ // }
1104
+ // },
1105
+ // 选项变化事件
1106
+ onSelectDataChange(sender, selected) {
1107
+ let code;
1108
+ if (sender.code.endsWith('ID')) {
1109
+ code = sender.code.substr(0, sender.code.length - 2);
1110
+ }
1111
+ let model = null;
1112
+ if (typeof selected == 'object') {
1113
+ if (selected instanceof Array) {
1114
+ model = [];
1115
+
1116
+ for (let item of selected) {
1117
+ if (typeof item == 'object') {
1118
+ model.push(item);
1119
+ } else {
1120
+ if (sender.rawData) {
1121
+ model.push(
1122
+ sender.rawData.find(rawData => {
1123
+ return this.parseData(rawData, sender.sourceDataCode) == item;
1124
+ })
1125
+ );
1126
+ } else {
1127
+ model.push(item);
1128
+ }
1129
+ }
1130
+ }
1131
+ } else {
1132
+ model = selected;
1133
+ }
1134
+ } else {
1135
+ if (sender.rawData) {
1136
+ model = sender.rawData.find(rawData => {
1137
+ return this.parseData(rawData, sender.sourceDataCode) == selected;
1138
+ });
1139
+ } else {
1140
+ model = selected;
1141
+ }
1142
+ }
1143
+
1144
+ if (code) {
1145
+ this.setData(this.data, code, model);
1146
+ }
1147
+
1148
+ this.onDataChange(sender, model);
1149
+ },
1150
+ // 数据变化事件
1151
+ async onDataChange(sender, selected) {
1152
+ for (let column of this.columns) {
1153
+ // 判断是否需要显示
1154
+ if (!!(column.showJson || '').trim()) {
1155
+ let setting = JSON.parse(column.showJson);
1156
+
1157
+ if (setting.type == 'Condition' || setting.type == 'Expression') {
1158
+ column.isShow = this.judgeCondition(setting, this.data);
1159
+ }
1160
+ }
1161
+
1162
+ // 判断是否只读
1163
+ if (!!(column.readonlyJson || '').trim()) {
1164
+ let setting = JSON.parse(column.readonlyJson);
1165
+
1166
+ if (setting.type == 'Condition' || setting.type == 'Expression') {
1167
+ column.isReadonly = this.judgeCondition(setting, this.data);
1168
+ }
1169
+ }
1170
+
1171
+ // 判断是否必填
1172
+ if (!!(column.requiredJson || '').trim()) {
1173
+ let setting = JSON.parse(column.requiredJson);
1174
+
1175
+ if (setting.type == 'Condition' || setting.type == 'Expression') {
1176
+ let before = column.isRequired;
1177
+ column.isRequired = this.judgeCondition(setting, this.data);
1178
+
1179
+ if (before != column.isRequired) {
1180
+ // 必填有变化
1181
+ let field = this.$refs.form.fields.find(field => {
1182
+ return field.prop == column.code;
1183
+ });
1184
+
1185
+ if (field != null) {
1186
+ field.isRequired = column.isRequired;
1187
+
1188
+ if (!column.isRequired) {
1189
+ field.validateState = '';
1190
+ field.validateMessage = '';
1191
+ }
1192
+ }
1193
+ }
1194
+ }
1195
+ }
1196
+ }
1197
+
1198
+ if (sender != null && sender.controlType == 'Table') {
1199
+ /**
1200
+ * 数据变化事件
1201
+ * @property {object} sender 触发的列对象
1202
+ * @property {object} oldValue 原数据
1203
+ * @property {object} newValue 新数据
1204
+ * @property {object} selected 选中对象(弹出选择框等有效)
1205
+ * @property {boolean} loading 加载数据时触发
1206
+ */
1207
+ this.$emit('on-change', sender, null, null, this.$refs['table_' + sender.code][0].data);
1208
+ } else if (sender != null) {
1209
+ let oldValue = this.parseData(this.dataBefore, sender.code);
1210
+ let newValue = this.parseData(this.data, sender.code);
1211
+ if (oldValue !== newValue) {
1212
+ setTimeout(() => {
1213
+ this.$emit('on-change', sender, oldValue, newValue, selected);
1214
+ });
1215
+ }
1216
+ } else {
1217
+ this.$emit('on-change', sender, null, null, selected);
1218
+ }
1219
+
1220
+ this.dataBefore = this.copy(this.data);
1221
+
1222
+ // 公式计算
1223
+ for (let column of this.columns) {
1224
+ if (!!(column.calculate || '').trim()) {
1225
+ let triggers = this.getTriggers(column.calculate);
1226
+
1227
+ if (!sender || triggers.some(item => item == sender.code)) {
1228
+ // 包含在公式中,需要刷新
1229
+ let result = this.calculate(column.calculate, this.data);
1230
+
1231
+ // 保留小数
1232
+ if (column.digit != null) {
1233
+ result = this.keepDecimal(result, column.digit, column.fixedDigit);
1234
+ }
1235
+
1236
+ this.setData(this.data, column.code, result);
1237
+ }
1238
+ }
1239
+ }
1240
+
1241
+ // 计算需要刷新的字段
1242
+ if (sender == null || sender.triggers !== []) {
1243
+ this.columns.forEach(function (column) {
1244
+ if (
1245
+ !column.isStaticItem &&
1246
+ !!(column.source || '').trim() &&
1247
+ (sender == null ||
1248
+ sender.triggers.some(item => {
1249
+ return item.code == column.code;
1250
+ }))
1251
+ ) {
1252
+ column.needRefresh = true;
1253
+ // if (column.controlType == 'Table') {
1254
+ // this.$refs['table_' + sender.code][0];
1255
+ // } else {
1256
+ // }
1257
+ }
1258
+ });
1259
+ }
1260
+
1261
+ // 刷新数据源
1262
+ while (true) {
1263
+ let column = this.columns.filter(item => {
1264
+ return item.needRefresh == true || item.needClear == true;
1265
+ })[0];
1266
+
1267
+ if (column == null) {
1268
+ // 没有需要刷新的字段
1269
+ break;
1270
+ }
1271
+
1272
+ // 重新加载数据源
1273
+ if (column.needClear && this.parseData(this.data, column.code) != null) {
1274
+ this.setData(this.data, column.code, null);
1275
+ // 触发
1276
+ column.triggers.forEach(item => {
1277
+ item.needClear = true;
1278
+ });
1279
+ } else if (column.needRefresh && !!(column.source || '').trim()) {
1280
+ let param = this.getParam(this.data, column);
1281
+
1282
+ if (
1283
+ column.controlType === 'Select' ||
1284
+ column.controlType === 'MultiSelect' ||
1285
+ column.controlType === 'TreeSelect' ||
1286
+ column.controlType === 'MultiTreeSelect' ||
1287
+ column.controlType === 'SelectWithOther' ||
1288
+ column.controlType === 'ComboSelect' ||
1289
+ column.controlType === 'Radio' ||
1290
+ column.controlType === 'CheckGroup'
1291
+ // column.controlType === 'AutoComplete'
1292
+ ) {
1293
+ // 选择框、单选框组
1294
+ if (param != null) {
1295
+ // if (column.controlType === 'TreeSelect' || column.controlType === 'MultiTreeSelect') {
1296
+ // if (column.dataSource == null) {
1297
+ // this.fillDataSource(this.data, column, param);
1298
+ // }
1299
+ // } else {
1300
+ this.fillDataSource(this.data, column, param);
1301
+ // }
1302
+ } else {
1303
+ // 参数不完整,清空数据
1304
+ column.dataSource = [];
1305
+ this.setData(this.data, column.code, null);
1306
+ // column.displayValue = null;
1307
+
1308
+ // 触发
1309
+ column.triggers.forEach(item => {
1310
+ item.needClear = true;
1311
+ });
1312
+ }
1313
+ } else if (column.controlType === 'List') {
1314
+ if (param != null) {
1315
+ // 参数完整,查询数据
1316
+ let res;
1317
+
1318
+ let tableView = this.$refs['list_' + column.code][0].tableView;
1319
+
1320
+ let filtering = tableView.filtering;
1321
+
1322
+ if (!!(filtering || '').trim()) {
1323
+ param = {
1324
+ ...param,
1325
+ ...JSON.parse(filtering)
1326
+ };
1327
+ }
1328
+
1329
+ if (column.isSourceCustom) {
1330
+ res = await customModelApi.query(column.sourceModel, param);
1331
+ } else {
1332
+ res = await modelApi.query(column.sourceModel, param, tableView.functionName, tableView.functionType);
1333
+ }
1334
+
1335
+ this.$refs['list_' + column.code][0].loadData(res.data);
1336
+ }
1337
+ }
1338
+ }
1339
+
1340
+ // 重新加载公式
1341
+ // if (!!(column.calculate || '').trim()) {
1342
+ // let data = this.calculate(column.calculate, this.data);
1343
+ // this.setData(this.data, column.code, data);
1344
+ // }
1345
+
1346
+ column.needClear = false;
1347
+ column.needRefresh = false;
1348
+ }
1349
+ },
1350
+ // 输入框失去焦点事件
1351
+ onBlur(data, sender) {
1352
+ /**
1353
+ * 数据变化事件
1354
+ * @property {object} sender 触发的列对象
1355
+ */
1356
+ this.$emit('on-blur', sender);
1357
+ },
1358
+ // 获取数据类型
1359
+ getDataType(column) {
1360
+ if (!(column.dataType || '').trim()) {
1361
+ return null;
1362
+ }
1363
+ if (column.dataType.indexOf('Enum:') === 0) {
1364
+ return 'string';
1365
+ }
1366
+
1367
+ switch (column.dataType) {
1368
+ case 'String':
1369
+ case 'BigInteger':
1370
+ return 'string';
1371
+ case 'Boolean':
1372
+ return 'boolean';
1373
+ case 'DateTime':
1374
+ return 'date';
1375
+ case 'Float':
1376
+ case 'Double':
1377
+ case 'Decimal':
1378
+ return 'number';
1379
+ case 'Short':
1380
+ case 'Integer':
1381
+ return 'integer';
1382
+ }
1383
+ },
1384
+ // 获取触发器
1385
+ getTrigger(column) {
1386
+ if (column.controlType === 'TextInput' || column.controlType === 'NumberInput') {
1387
+ return 'blur,change';
1388
+ } else {
1389
+ return 'blur,change';
1390
+ }
1391
+ },
1392
+ // 根据表达式取值(带其他)
1393
+ parseDataWithOther(model, column) {
1394
+ let expression = column.code;
1395
+ let selectValue = this.parseData(model, expression + '_o');
1396
+
1397
+ let value = this.parseData(model, expression);
1398
+ let dataSource = this.getDataSource(model, column);
1399
+
1400
+ if (selectValue != null) {
1401
+ return selectValue;
1402
+ } else if (value == null) {
1403
+ return null;
1404
+ } else if (
1405
+ dataSource &&
1406
+ dataSource.some(item => {
1407
+ return item.id == value;
1408
+ })
1409
+ ) {
1410
+ return value;
1411
+ } else {
1412
+ return '__Other';
1413
+ }
1414
+ },
1415
+ // 根据表达式赋值(带其他)
1416
+ setDataWithOther(model, expression, value) {
1417
+ this.setData(model, expression + '_o', value);
1418
+ if (value != '__Other') {
1419
+ this.setData(model, expression, value);
1420
+ } else {
1421
+ this.setData(model, expression, null);
1422
+ }
1423
+ },
1424
+ // 转换为日期类型
1425
+ // parseDateTime(value) {
1426
+ // if (value && typeof value === 'string') {
1427
+ // return new Date(value);
1428
+ // } else {
1429
+ // return value;
1430
+ // }
1431
+ // },
1432
+ // 根据表达式取值(树)
1433
+ parseTreeData(data, code) {
1434
+ let value = this.parseData(data, code);
1435
+
1436
+ if (value == null) {
1437
+ return '';
1438
+ } else {
1439
+ return value;
1440
+ }
1441
+ }
1442
+ }
1443
+ };
1444
+ </script>