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,2261 @@
1
+ <template>
2
+ <div>
3
+ <Divider :plain="true" v-if="title != null" dashed orientation="left" size="small">
4
+ <span class="title">{{ title }}</span>
5
+ </Divider>
6
+ <!--
7
+ @slot 顶部
8
+ -->
9
+ <slot name="top"></slot>
10
+ <Form v-if="tableView.filterEnable && filterEnable" :model="filter" :label-width="125" label-colon=":" label-position="right" class="filter" @submit.prevent>
11
+ <Row :gutter="24" type="flex" justify="end">
12
+ <!--
13
+ @slot 筛选栏
14
+ @binding {object} table 表格对象
15
+ @binding {object} filter 筛选对象
16
+ -->
17
+ <slot name="filter" :table="this" :filter="filter">
18
+ <!--
19
+ @slot 自定义筛选栏
20
+ -->
21
+ <slot name="customFilter"></slot>
22
+ <table-filter
23
+ ref="tableFilter"
24
+ :data="filter"
25
+ :columns="filterColumns"
26
+ :isDataSource="tableView.isDataSource"
27
+ :keywordEnable="tableView.keywordEnable"
28
+ @on-keyup="onKeyup"
29
+ >
30
+ <template #column="{ filter, column }">
31
+ <!--
32
+ @slot 筛选栏自定义列
33
+ @binding {object} filter 筛选条件对象
34
+ @binding {object} column 列对象
35
+ @binding {string} code 列代码
36
+ -->
37
+ <slot name="filterColumn" :filter="filter" :column="column" :code="column.code"></slot>
38
+ </template>
39
+ </table-filter>
40
+ <Col v-bind="getGrid(tableView.filterWidth)" :style="{ 'text-align': tableView.filterAlign == null ? 'left' : tableView.filterAlign.toLowerCase() }">
41
+ <FormItem :label-width="0">
42
+ <Button type="info" v-if="tableView.keywordEnable || filterColumns.length > 0" custom-icon="fa fa-search" @click="search()" size="small">查询</Button>
43
+ <Button type="primary" v-if="tableView.createEnable && createEnable" custom-icon="fa fa-plus" @click="create()" size="small">新建</Button>
44
+ <!--
45
+ @slot 筛选栏按钮
46
+ -->
47
+ <slot name="filterCommand"></slot>
48
+ <Dropdown
49
+ v-if="tableView.exportEnable || tableView.exportPdfEnable || tableView.printEnable || tableView.batchEditEnable"
50
+ style="margin-left: 4px"
51
+ @on-click="moreClick"
52
+ >
53
+ <Button type="info" size="small">
54
+ 更多...
55
+ <Icon type="ios-arrow-down" />
56
+ </Button>
57
+ <template #list>
58
+ <DropdownMenu>
59
+ <DropdownItem v-if="tableView.exportEnable" name="exportExcel">导出 Excel</DropdownItem>
60
+ <DropdownItem v-if="tableView.exportPdfEnable" name="exportPdf">导出 PDF</DropdownItem>
61
+ <DropdownItem v-if="tableView.printEnable" name="print">打印</DropdownItem>
62
+ <DropdownItem v-if="tableView.batchEditEnable" name="batchEdit">批量编辑</DropdownItem>
63
+ </DropdownMenu>
64
+ </template>
65
+ </Dropdown>
66
+ <Button type="error" title="筛选设置" custom-icon="fa fa-filter" size="small" v-if="settingEnable && allow('permission/tableView')" @click="filterSettingOpen" />
67
+ </FormItem>
68
+ </Col>
69
+ </slot>
70
+ </Row>
71
+ </Form>
72
+ <!--
73
+ @slot 中部
74
+ -->
75
+ <slot name="middle"></slot>
76
+ <div :class="{ 'i-table-no-border': !tableView.borderEnable }">
77
+ <Table
78
+ class=""
79
+ ref="table"
80
+ size="small"
81
+ stripe
82
+ row-key="id"
83
+ :indent-size="18"
84
+ :update-show-children="treeEnable"
85
+ :columns="columns"
86
+ :data="data"
87
+ :max-height="maxHeight"
88
+ :load-data="onLoadData"
89
+ :draggable="draggable"
90
+ :sticky="true"
91
+ :span-method="handleSpan"
92
+ :border="tableView.borderEnable"
93
+ :show-summary="tableView.showSummary"
94
+ :summary-method="summaryMethod"
95
+ :page-size-opts="pageSizeOpts"
96
+ no-data-text="暂无数据..."
97
+ @on-column-width-resize="columnWidthResize"
98
+ @on-sort-change="sortChange"
99
+ @on-select="select"
100
+ @on-select-cancel="selectCancel"
101
+ @on-select-all="selectAll"
102
+ @on-select-all-cancel="selectAllCancel"
103
+ @on-drag-drop="dragDrop"
104
+ >
105
+ <template #normal="{ row, column, index }">
106
+ <template v-if="isShow(rowData(row, index), column)">
107
+ <template v-if="column.controlType === 'Custom'">
108
+ <!--
109
+ @slot 自定义列
110
+ @binding {object} row 行对象
111
+ @binding {int} index 行序号
112
+ @binding {int} column 列对象
113
+ @binding {string} code 列代码
114
+ -->
115
+ <slot name="column" :row="rowData(row, index)" :index="index" :column="column" :code="column.code"></slot>
116
+ </template>
117
+ <template v-else-if="column.controlType === 'Label'">
118
+ <div v-html="showData(rowData(row, index), column)"></div>
119
+ </template>
120
+ <template v-else-if="column.controlType === 'Hyperlink'">
121
+ <a :href="getHyperlink(rowData(row, index), column.hyperlink)" :target="column.isNewWindow ? '_blank' : ''">
122
+ <span v-html="showData(rowData(row, index), column)"></span>
123
+ </a>
124
+ </template>
125
+ <template v-else-if="column.controlType === 'TextInput'">
126
+ <Input
127
+ type="text"
128
+ size="small"
129
+ :model-value="parseData(rowData(row, index), column.code)"
130
+ @update:model-value="$event => setData(rowData(row, index), column.code, $event)"
131
+ :readonly="isReadonly(rowData(row, index), column)"
132
+ :style="{ width: column.controlWidth == null ? null : column.controlWidth - 36 + 'px' }"
133
+ :maxlength="column.maxLength"
134
+ :pattern="column.pattern"
135
+ :placeholder="column.description"
136
+ @on-change="onDataChange(rowData(row, index), column)"
137
+ @on-blur="onBlur(rowData(row, index), column)"
138
+ />
139
+ </template>
140
+ <template v-else-if="column.controlType === 'NumberInput'">
141
+ <Input
142
+ type="number"
143
+ size="small"
144
+ number
145
+ :model-value="parseData(rowData(row, index), column.code)"
146
+ @update:model-value="$event => setData(rowData(row, index), column.code, $event)"
147
+ :readonly="isReadonly(rowData(row, index), column)"
148
+ :style="{ width: column.controlWidth == null ? null : column.controlWidth - 36 + 'px' }"
149
+ :placeholder="column.description"
150
+ @on-change="onDataChange(rowData(row, index), column)"
151
+ @on-blur="onBlur(rowData(row, index), column)"
152
+ />
153
+ </template>
154
+ <template v-else-if="column.controlType === 'Select'">
155
+ <Select
156
+ size="small"
157
+ :model-value="parseData(rowData(row, index), column.code)"
158
+ @update:model-value="$event => setData(rowData(row, index), column.code, $event)"
159
+ :disabled="isReadonly(rowData(row, index), column)"
160
+ clearable
161
+ :style="{ width: column.controlWidth == null ? null : column.controlWidth - 36 + 'px' }"
162
+ :placeholder="column.description"
163
+ :transfer="true"
164
+ @on-change="selected => onSelectDataChange(rowData(row, index), column, selected)"
165
+ >
166
+ <Option v-for="item in getDataSource(rowData(row, index), column)" :key="item.id" :value="item.id">{{ item.name }}</Option>
167
+ </Select>
168
+ </template>
169
+ <template v-else-if="column.controlType === 'MultiSelect'">
170
+ <Select
171
+ size="small"
172
+ :model-value="parseArrayData(rowData(row, index), column.code)"
173
+ @update:model-value="$event => setArrayData(rowData(row, index), column.code, $event)"
174
+ :disabled="isReadonly(rowData(row, index), column)"
175
+ :multiple="true"
176
+ clearable
177
+ :style="{ width: column.controlWidth == null ? null : column.controlWidth - 36 + 'px' }"
178
+ :placeholder="column.description"
179
+ :transfer="true"
180
+ @on-change="selected => onSelectDataChange(rowData(row, index), column, selected)"
181
+ >
182
+ <Option v-for="item in getDataSource(rowData(row, index), column)" :key="item.id" :value="item.id">{{ item.name }}</Option>
183
+ </Select>
184
+ </template>
185
+ <template v-else-if="column.controlType === 'ComboSelect'">
186
+ <Select
187
+ size="small"
188
+ :model-value="parseData(rowData(row, index), column.code)"
189
+ @update:model-value="$event => setData(rowData(row, index), column.code, $event)"
190
+ :disabled="isReadonly(rowData(row, index), column)"
191
+ clearable
192
+ filterable
193
+ :style="{ width: column.controlWidth == null ? null : column.controlWidth - 36 + 'px' }"
194
+ :placeholder="column.description"
195
+ :transfer="true"
196
+ @on-change="selected => onSelectDataChange(rowData(row, index), column, selected)"
197
+ >
198
+ <Option v-for="item in getDataSource(rowData(row, index), column)" :key="item.id" :value="item.id">{{ item.name }}</Option>
199
+ </Select>
200
+ </template>
201
+ <template v-else-if="column.controlType === 'DialogSelect'">
202
+ <dialog-select
203
+ :model-value="parseData(rowData(row, index), column.code)"
204
+ size="small"
205
+ @update:model-value="$event => setData(rowData(row, index), column.code, $event)"
206
+ :readonly="isReadonly(rowData(row, index), column)"
207
+ :source="column.source"
208
+ :source-data-code="column.sourceDataCode"
209
+ :source-display-code="column.sourceDisplayCode"
210
+ :param="getParam(rowData(row, index), column)"
211
+ :controlWidth="column.controlWidth"
212
+ @on-change="selected => onSelectDataChange(rowData(row, index), column, selected)"
213
+ ></dialog-select>
214
+ </template>
215
+ <template v-else-if="column.controlType === 'MultiDialogSelect'">
216
+ <dialog-select
217
+ :model-value="parseData(rowData(row, index), column.code)"
218
+ size="small"
219
+ @update:model-value="$event => setData(rowData(row, index), column.code, $event)"
220
+ :multi="true"
221
+ :readonly="isReadonly(rowData(row, index), column)"
222
+ :source="column.source"
223
+ :source-data-code="column.sourceDataCode"
224
+ :source-display-code="column.sourceDisplayCode"
225
+ :param="getParam(rowData(row, index), column)"
226
+ :controlWidth="column.controlWidth"
227
+ @on-change="selected => onSelectDataChange(rowData(row, index), column, selected)"
228
+ ></dialog-select>
229
+ </template>
230
+ <template v-else-if="column.controlType === 'Date' || column.controlType === 'DateTime' || column.controlType === 'Year' || column.controlType === 'Month'">
231
+ <DatePicker
232
+ size="small"
233
+ :type="column.controlType.toLowerCase()"
234
+ :model-value="parseDateTimeData(rowData(row, index), column.code)"
235
+ @update:model-value="$event => setData(rowData(row, index), column.code, $event)"
236
+ :readonly="isReadonly(rowData(row, index), column)"
237
+ :placeholder="column.description"
238
+ :style="{ width: column.controlWidth == null ? null : column.controlWidth - 36 + 'px' }"
239
+ :transfer="true"
240
+ @on-change="onDataChange(rowData(row, index), column)"
241
+ ></DatePicker>
242
+ </template>
243
+ <template v-else-if="column.controlType === 'DateRange'">
244
+ <DatePicker
245
+ size="small"
246
+ :type="column.controlType.toLowerCase()"
247
+ :model-value="parseDateRangeData(rowData(row, index), column.code)"
248
+ @update:model-value="$event => setArrayData(rowData(row, index), column.code, $event)"
249
+ :readonly="isReadonly(rowData(row, index), column)"
250
+ :placeholder="column.description"
251
+ :style="{ width: column.controlWidth == null ? null : column.controlWidth - 36 + 'px' }"
252
+ :transfer="true"
253
+ @on-change="onDataChange(rowData(row, index), column)"
254
+ ></DatePicker>
255
+ </template>
256
+ <template v-else-if="column.controlType === 'Time'">
257
+ <TimePicker
258
+ size="small"
259
+ type="time"
260
+ :model-value="parseDateTimeData(rowData(row, index), column.code)"
261
+ @update:model-value="$event => setData(rowData(row, index), column.code, $event)"
262
+ :readonly="isReadonly(rowData(row, index), column)"
263
+ :placeholder="column.description"
264
+ :style="{ width: column.controlWidth == null ? null : column.controlWidth - 36 + 'px' }"
265
+ :transfer="true"
266
+ @on-change="onDataChange(rowData(row, index), column)"
267
+ ></TimePicker>
268
+ </template>
269
+ <template v-else-if="column.controlType === 'Check'">
270
+ <Checkbox
271
+ :model-value="!!parseData(rowData(row, index), column.code)"
272
+ @update:model-value="$event => setData(rowData(row, index), column.code, $event)"
273
+ :disabled="isReadonly(rowData(row, index), column)"
274
+ @on-change="onDataChange(rowData(row, index), column)"
275
+ />
276
+ </template>
277
+ <template v-else-if="column.controlType === 'Switch'">
278
+ <Switch
279
+ :model-value="!!parseData(rowData(row, index), column.code)"
280
+ @update:model-value="$event => setData(rowData(row, index), column.code, $event)"
281
+ :disabled="isReadonly(rowData(row, index), column)"
282
+ @on-change="onDataChange(rowData(row, index), column)"
283
+ />
284
+ </template>
285
+ <template v-else-if="column.controlType === 'Radio'">
286
+ <RadioGroup
287
+ :model-value="parseData(rowData(row, index), column.code)"
288
+ @update:model-value="$event => setData(rowData(row, index), column.code, $event)"
289
+ @on-change="selected => onSelectDataChange(rowData(row, index), column, selected)"
290
+ >
291
+ <Radio v-for="item in getDataSource(rowData(row, index), column)" :key="item.id" :label="item.id" :disabled="isReadonly(rowData(row, index), column)">
292
+ <span>{{ item.name }}</span>
293
+ </Radio>
294
+ </RadioGroup>
295
+ </template>
296
+ <template v-else-if="column.controlType === 'CheckGroup'">
297
+ <CheckboxGroup
298
+ :model-value="parseArrayData(rowData(row, index), column.code)"
299
+ @update:model-value="$event => setArrayData(rowData(row, index), column.code, $event)"
300
+ @on-change="onDataChange(rowData(row, index), column)"
301
+ >
302
+ <Checkbox v-for="item in getDataSource(rowData(row, index), column)" :key="item.id" :label="item.id" :disabled="isReadonly(rowData(row, index), column)">
303
+ <span>{{ item.name }}</span>
304
+ </Checkbox>
305
+ </CheckboxGroup>
306
+ </template>
307
+ <template v-else-if="column.controlType === 'Attachment'">
308
+ <!-- <upload-attachment :value="parseData(data, column.code)"
309
+ @update:model-value="$event => setData(data, column.code, $event)"
310
+ v-if="!readonly && !column.isReadonly"
311
+ size="small"
312
+ :maxCount="column.maxLength" /> -->
313
+ <template v-if="!!(parseData(rowData(row, index), column.code) || '').trim()">
314
+ <a
315
+ :href="getAttachmentUrl(attachment.file, attachment.name)"
316
+ :key="attachmentIndex"
317
+ v-for="(attachment, attachmentIndex) in JSON.parse(parseData(row, column.code))"
318
+ >
319
+ <span style="margin: auto 4px">
320
+ <Icon type="ios-document" />
321
+ {{ attachment.name }}
322
+ </span>
323
+ </a>
324
+ </template>
325
+ </template>
326
+ <template v-else-if="column.controlType === 'Image'">
327
+ <div class="image-group" :style="{ 'justify-content': column.align ? column.align.toLowerCase() : 'center' }">
328
+ <div class="image" v-for="(item, index) in parseData(row, column.code).split(',')" :key="index">
329
+ <img v-if="item" @click="previewImage(item)" :src="getImgUrl(item)" />
330
+ </div>
331
+ </div>
332
+ </template>
333
+ <template v-else-if="column.controlType === 'Slider'">
334
+ <Slider
335
+ :model-value="parseData(rowData(row, index), column.code)"
336
+ @update:model-value="$event => setData(rowData(row, index), column.code, $event)"
337
+ show-input
338
+ :style="{ width: column.controlWidth == null ? null : column.controlWidth - 36 + 'px' }"
339
+ :max="column.MaxValue"
340
+ :min="column.MinValue"
341
+ />
342
+ <Slider
343
+ v-if="!readonly && !column.isReadonly"
344
+ :model-value="parseData(rowData(row, index), column.code)"
345
+ @update:model-value="$event => setData(rowData(row, index), column.code, $event)"
346
+ show-input
347
+ :style="{ width: column.controlWidth == null ? null : column.controlWidth - 36 + 'px' }"
348
+ :max="column.maxValue"
349
+ :min="column.minValue"
350
+ />
351
+ <Input
352
+ v-if="isReadonly(rowData(row, index), column)"
353
+ type="number"
354
+ number
355
+ readonly
356
+ :model-value="parseData(rowData(row, index), column.code)"
357
+ :style="{ width: column.controlWidth == null ? '100px' : column.controlWidth + 'px' }"
358
+ :placeholder="column.description"
359
+ />
360
+ </template>
361
+ <template v-else-if="column.controlType === 'Placeholder'"></template>
362
+ <template v-else>暂不支持此控件 {{ column.controlType }}</template>
363
+ </template>
364
+ </template>
365
+ <template #command="{ row, index }">
366
+ <div>
367
+ <!--
368
+ @slot 工具栏(编辑按钮前)
369
+ @binding {object} row 行对象
370
+ @binding {int} index 行序号
371
+ -->
372
+ <slot name="commandBefore" :row="rowData(row, index)" :index="index"></slot>
373
+ <Button
374
+ v-if="judge(tableView.editEnable, tableView.editEnableJson, rowData(row, index)) && editEnable && !readonly"
375
+ size="small"
376
+ title="编辑"
377
+ type="primary"
378
+ custom-icon="fa fa-edit"
379
+ @click="edit(rowData(row, index), index)"
380
+ ></Button>
381
+ <Button
382
+ v-if="judge(tableView.removeEnable, tableView.removeEnableJson, rowData(row, index)) && removeEnable && !readonly"
383
+ size="small"
384
+ title="删除"
385
+ type="warning"
386
+ custom-icon="fa fa-trash-alt"
387
+ @click="remove(rowData(row, index), index)"
388
+ ></Button>
389
+ <Button
390
+ v-for="(item, index) in commandButtons"
391
+ :key="index"
392
+ size="small"
393
+ :title="item.title"
394
+ type="info"
395
+ :custom-icon="item.icon"
396
+ @click="clickCommandButton(row, item)"
397
+ ></Button>
398
+ <!--
399
+ @slot 工具栏
400
+ @binding {object} row 行对象
401
+ @binding {int} index 行序号
402
+ -->
403
+ <slot name="command" :row="rowData(row, index)" :index="index"></slot>
404
+ </div>
405
+ </template>
406
+ <template #sn="{ index }">
407
+ <div>
408
+ {{ size * (current - 1) + index + 1 }}
409
+ </div>
410
+ </template>
411
+ </Table>
412
+ <div class="ivu-mt ivu-text-right">
413
+ <Button class="ivu-fr" type="error" title="设置" custom-icon="fa fa-cog" v-if="settingEnable && allow('permission/tableView')" @click="tableSettingOpen"></Button>
414
+ <Page
415
+ show-sizer
416
+ show-total
417
+ v-model="current"
418
+ :page-size="size"
419
+ :page-size-opts="pageSizeOpts == null ? [10, 20, 50, 100] : pageSizeOpts"
420
+ :total="total"
421
+ v-if="tableView.pageEnable && pageEnable"
422
+ @on-change="loadData()"
423
+ @on-page-size-change="pageSizeChange"
424
+ />
425
+ </div>
426
+ <modal-table ref="dialogTable" v-if="dialogActive">
427
+ <template #command="{ row }">
428
+ <Button size="small" title="选择" type="primary" custom-icon="fa fa-check-square-o" @click="dialogCheck(row)"></Button>
429
+ </template>
430
+ </modal-table>
431
+ <table-setting ref="tableSetting" v-if="tableSettingActive" :is-setting="true" @on-change="viewCode => init(viewCode)" />
432
+ <filter-setting ref="filterSetting" v-if="filterSettingActive" @on-change="viewCode => init(viewCode)" />
433
+ <item-select ref="itemSelect" v-if="itemSelectActive" @save="saveItemSelect"></item-select>
434
+ <modal-table ref="modalTable" v-if="inited"></modal-table>
435
+ <modal-form ref="modalForm" :saveEnable="false" v-if="inited"></modal-form>
436
+ <modal-table ref="batchEditTable" :embedded="true" :static="true" :footerEnable="true" v-if="inited">
437
+ <template #footer>
438
+ <Button type="primary" custom-icon="fa fa-save" @click="batchSave()">保存</Button>
439
+ <Button type="default" custom-icon="fa fa-times" @click="$refs.batchEditTable.close()">关闭</Button>
440
+ </template>
441
+ </modal-table>
442
+ <Modal title="预览" v-model="preview" scrollable :mask-closable="layout.maskClosable" :draggable="layout.draggable" :sticky="true" :reset-drag-position="true" width="70%">
443
+ <div style="text-align: center">
444
+ <a href="#" :download="imageUrl" onClick="return false;">
445
+ <img :src="getImgUrl(imageUrl)" v-if="preview" style="max-width: 100%" />
446
+ </a>
447
+ </div>
448
+ <template #footer>
449
+ <Button type="default" custom-icon="fa fa-times" @click="preview = false">关闭</Button>
450
+ </template>
451
+ </Modal>
452
+ </div>
453
+ </div>
454
+ </template>
455
+ <script>
456
+ import { mapActions } from 'vuex';
457
+ import modelApi from '../../api/model';
458
+ import customModelApi from '../../api/customModel';
459
+ import dataSourceApi from '../../api/dataSource';
460
+ import dataViewApi from '../../api/dataView';
461
+ import mixinPage from '../../mixins/page';
462
+ import mixin from './mixin';
463
+ import tableSetting from './table-setting';
464
+ import filterSetting from './filter-setting';
465
+ import tableFilter from './table-filter';
466
+ import dateFormat from 'date-fns/format';
467
+ import { resolveComponent } from 'vue';
468
+
469
+ var getColumns = (view, item) => {
470
+ let children = view.viewColumns.filter(i => {
471
+ return i.parentCode == item.code;
472
+ });
473
+
474
+ if (children.length > 0) {
475
+ // 合并单元格表头
476
+ return {
477
+ ...item,
478
+ title: item.name,
479
+ renderHeader: (h, params) => {
480
+ return h('span', {
481
+ innerHTML: params.column.name.replace('|', '<br/>')
482
+ });
483
+ },
484
+ key: item.code,
485
+ align: item.align ? item.align.toLowerCase() : 'center',
486
+ children:
487
+ children.length > 0
488
+ ? children.map(item => {
489
+ return getColumns(view, item);
490
+ })
491
+ : null
492
+ };
493
+ } else {
494
+ // 普通单元格
495
+ return {
496
+ ...item,
497
+ title: item.name,
498
+ renderHeader: (h, params) => {
499
+ return h('span', {
500
+ innerHTML: params.column.name.replace('|', '<br/>')
501
+ });
502
+ },
503
+ // tree: this.treeEnable && index == 0, // 需要树展开,给第一列添加展开按钮
504
+ key: item.code,
505
+ dataType: item.dataType,
506
+ format: item.displayFormat,
507
+ width: item.controlWidth,
508
+ minWidth: 100,
509
+ align: item.align ? item.align.toLowerCase() : 'center',
510
+ sortable: 'custom',
511
+ resizable: true,
512
+ slot: 'normal'
513
+ };
514
+ }
515
+ };
516
+
517
+ /**
518
+ * @displayName view-table 表格视图
519
+ */
520
+ export default {
521
+ mixins: [mixin, mixinPage],
522
+ components: { tableFilter, tableSetting, filterSetting },
523
+ data() {
524
+ return {
525
+ inited: false,
526
+ size: 10,
527
+ orderBy: null,
528
+ tableView: {},
529
+ columns: [],
530
+ viewFilter: {},
531
+ filterColumns: [],
532
+ data: [],
533
+ staticData: [],
534
+ selectedData: [],
535
+ current: 1,
536
+ total: 0,
537
+ setting: false,
538
+ dialogActive: false,
539
+ tableSettingActive: false,
540
+ filterSettingActive: false,
541
+ itemSelectActive: false,
542
+ commandButtons: [],
543
+ preview: false,
544
+ imageUrl: null
545
+ };
546
+ },
547
+ async created() {
548
+ // 默认视图代码
549
+ if (this.viewCode) {
550
+ // 初始化
551
+ await this.init(this.viewCode);
552
+
553
+ /**
554
+ * 初始化完成事件
555
+ */
556
+ this.$emit('after-init');
557
+ }
558
+
559
+ if (this.viewCode && this.autoLoad) {
560
+ this.loadData();
561
+ }
562
+ },
563
+ activated() {
564
+ if (this.viewCode && this.autoLoad) {
565
+ this.loadData();
566
+ }
567
+ },
568
+ props: {
569
+ /**
570
+ * 标题
571
+ */
572
+ title: {
573
+ type: String
574
+ },
575
+ /**
576
+ * 视图代码
577
+ */
578
+ viewCode: {
579
+ type: String
580
+ },
581
+ /**
582
+ * 只读
583
+ */
584
+ readonly: {
585
+ type: Boolean,
586
+ default: false
587
+ },
588
+ /**
589
+ * 是否内嵌表格
590
+ */
591
+ embedded: {
592
+ type: Boolean,
593
+ default: false
594
+ },
595
+ /**
596
+ * 内嵌表格的父对象
597
+ */
598
+ parentData: {
599
+ type: Object,
600
+ default() {
601
+ return {};
602
+ }
603
+ },
604
+ /**
605
+ * 是否静态数据
606
+ */
607
+ static: {
608
+ type: Boolean,
609
+ default: false
610
+ },
611
+ /**
612
+ * 筛选
613
+ */
614
+ filter: {
615
+ type: Object,
616
+ default() {
617
+ return {};
618
+ }
619
+ },
620
+ /**
621
+ * 是否允许配置界面
622
+ */
623
+ settingEnable: {
624
+ type: Boolean,
625
+ default: true
626
+ },
627
+ /**
628
+ * 自动加载
629
+ */
630
+ autoLoad: {
631
+ type: Boolean,
632
+ default: true
633
+ },
634
+ /**
635
+ * 是否允许选择
636
+ */
637
+ selectEnable: {
638
+ type: Boolean,
639
+ default: false
640
+ },
641
+ /**
642
+ * 是否允许树展开
643
+ */
644
+ treeEnable: {
645
+ type: Boolean,
646
+ default: false
647
+ },
648
+ /**
649
+ * 树展开动作
650
+ */
651
+ treeLoad: {
652
+ type: Function
653
+ },
654
+ /**
655
+ * 树包含子项
656
+ */
657
+ hasChildren: {
658
+ type: Function
659
+ },
660
+ /**
661
+ * 高度
662
+ */
663
+ height: {
664
+ type: Number,
665
+ default: null
666
+ },
667
+ /**
668
+ * 允许创建
669
+ */
670
+ createEnable: {
671
+ type: Boolean,
672
+ default: true
673
+ },
674
+ /**
675
+ * 允许编辑
676
+ */
677
+ editEnable: {
678
+ type: Boolean,
679
+ default: true
680
+ },
681
+ /**
682
+ * 允许删除
683
+ */
684
+ removeEnable: {
685
+ type: Boolean,
686
+ default: true
687
+ },
688
+ /**
689
+ * 允许拖动
690
+ */
691
+ draggable: {
692
+ type: Boolean,
693
+ default: false
694
+ },
695
+ /**
696
+ * 允许筛选栏
697
+ */
698
+ filterEnable: {
699
+ type: Boolean,
700
+ default: true
701
+ },
702
+ /**
703
+ * 允许分页
704
+ */
705
+ pageEnable: {
706
+ type: Boolean,
707
+ default: true
708
+ },
709
+ /**
710
+ * 禁用筛选
711
+ */
712
+ filterDisable: {
713
+ type: Boolean,
714
+ default: false
715
+ },
716
+ /**
717
+ * 查询方法
718
+ */
719
+ onSearch: {
720
+ type: Function
721
+ },
722
+ /**
723
+ * 合计方法
724
+ */
725
+ summaryMethod: {
726
+ type: Function
727
+ },
728
+ /**
729
+ * 每页条数切换的配置
730
+ */
731
+ pageSizeOpts: {
732
+ type: Array
733
+ }
734
+ },
735
+ computed: {
736
+ // 表格最大高度,固定表头
737
+ maxHeight() {
738
+ if (this.height == null) {
739
+ return document.body.offsetHeight - 400;
740
+ } else {
741
+ return this.height;
742
+ }
743
+ }
744
+ },
745
+ watch: {
746
+ // value() {
747
+ // if (this.embedded) {
748
+ // this.loadData(this.value);
749
+ // }
750
+ // //this.changed = false;
751
+ // }
752
+ // staticData() {
753
+ // // 设置选中项
754
+ // if (typeof this.selectFunc === 'function') {
755
+ // let selected = this.staticData.filter(this.selectFunc);
756
+ // this.setSelected(selected);
757
+ // }
758
+ // }
759
+ },
760
+ methods: {
761
+ ...mapActions('admin/dataView', { loadDataView: 'load' }),
762
+ /**
763
+ * 初始化
764
+ *
765
+ * @param {string} viewCode 视图代码
766
+ * @param {function} callback 完成后回调方法
767
+ * @param {function} onFail 失败后回调方法
768
+ * @public
769
+ */
770
+ async init(viewCode, callback, onFail) {
771
+ // 加载表格视图
772
+
773
+ let view = await this.loadDataView(viewCode);
774
+
775
+ if (view == null && viewCode.indexOf('_') >= 0) {
776
+ view = await this.loadDataView(viewCode.split('_')[0]);
777
+ }
778
+
779
+ if (view == null) {
780
+ if (typeof onFail === 'function') {
781
+ onFail();
782
+ } else {
783
+ this.error('视图代码不存在!' + viewCode);
784
+ }
785
+ return;
786
+ }
787
+
788
+ this.tableView = view.dataView;
789
+ this.tableView.columns = view.viewColumns;
790
+ this.tableView.filterColumns = view.filterColumns;
791
+ this.filterColumns = view.filterColumns;
792
+
793
+ // 操作栏按钮
794
+ if (!!(this.tableView.commandButton || '').trim()) {
795
+ this.commandButtons = JSON.parse(this.tableView.commandButton);
796
+ } else {
797
+ this.commandButtons = [];
798
+ }
799
+
800
+ /**
801
+ * 视图获取完成事件
802
+ * @property {object} tableView 表格视图
803
+ */
804
+ this.$emit('on-ready', this.tableView);
805
+
806
+ this.columns = view.viewColumns
807
+ .filter(item => {
808
+ return !(item.parentCode || '').trim();
809
+ })
810
+ .map(item => {
811
+ return getColumns(view, item);
812
+ });
813
+
814
+ if (this.tableView.snEnable) {
815
+ this.columns.unshift({
816
+ title: '序号',
817
+ slot: 'sn',
818
+ align: 'center',
819
+ width: 60
820
+ });
821
+ }
822
+
823
+ if (this.tableView.commandEnable) {
824
+ let column = {
825
+ title: ' ',
826
+ slot: 'command',
827
+ align: 'center',
828
+ width: this.embedded && !this.tableView.commandWidth ? 60 : this.tableView.commandWidth == null ? 90 : (this.tableView.commandWidth + 1) * 30,
829
+ fixed: 'right'
830
+ };
831
+
832
+ if (this.embedded && this.tableView.batchSelectEnable && this.createEnable && !this.readonly) {
833
+ column.renderHeader = h => {
834
+ return h('div', {}, [
835
+ h(resolveComponent('Button'), {
836
+ type: 'primary',
837
+ shape: 'circle',
838
+ icon: 'md-checkmark-circle-outline',
839
+ size: 'small',
840
+ style: {
841
+ height: '20px',
842
+ width: '20px'
843
+ },
844
+ onClick: () => {
845
+ this.openSelectItem();
846
+ }
847
+ })
848
+ ]);
849
+ };
850
+
851
+ this.itemSelectActive = true;
852
+
853
+ setTimeout(() => {
854
+ this.$refs.itemSelect.init(this.tableView.batchSelectDataModel + 'Source', this.tableView.batchSelectDataModel + 'Target');
855
+ });
856
+ } else if (this.embedded && this.tableView.createEnable && this.createEnable && !this.readonly) {
857
+ column.renderHeader = h => {
858
+ return h('div', {}, [
859
+ h(resolveComponent('Button'), {
860
+ type: 'primary',
861
+ shape: 'circle',
862
+ icon: 'md-add',
863
+ size: 'small',
864
+ style: {
865
+ height: '20px',
866
+ width: '20px'
867
+ },
868
+ onClick: () => {
869
+ this.addNew();
870
+ }
871
+ })
872
+ ]);
873
+ };
874
+ }
875
+
876
+ this.columns.push(column);
877
+ }
878
+
879
+ if (this.selectEnable) {
880
+ this.columns.unshift({
881
+ type: 'selection',
882
+ align: 'center',
883
+ width: 60
884
+ });
885
+ }
886
+ if (this.treeEnable) {
887
+ this.columns.unshift({
888
+ tree: true,
889
+ display: 'inline',
890
+ align: 'left',
891
+ width: 100
892
+ });
893
+ }
894
+
895
+ // 默认每页数据量
896
+ if (this.tableView.size) {
897
+ this.size = this.tableView.size;
898
+ } else if (this.tableView.pageEnable && this.pageEnable) {
899
+ this.size = 10;
900
+ } else {
901
+ this.size = 1000;
902
+ }
903
+
904
+ if (this.tableView.sorting) {
905
+ // 排序
906
+ let obj = JSON.parse(this.tableView.sorting);
907
+ let arr = [];
908
+ for (let key in obj) {
909
+ if (obj[key] === 'desc') {
910
+ arr.push('-' + key);
911
+ } else {
912
+ arr.push('+' + key);
913
+ }
914
+ }
915
+
916
+ this.orderBy = arr.join(',');
917
+ } else {
918
+ this.orderBy = null;
919
+ }
920
+
921
+ if (this.tableView.filtering) {
922
+ // 排序
923
+ let obj = JSON.parse(this.tableView.filtering);
924
+ for (let key in obj) {
925
+ this.viewFilter[key] = obj[key];
926
+ }
927
+ } else {
928
+ this.viewFilter = {};
929
+ }
930
+
931
+ if (this.tableView.keywordEnable && !!(this.tableView.keywordColumn || '').trim()) {
932
+ this.viewFilter['keywordColumns'] = this.tableView.keywordColumn;
933
+ } else {
934
+ this.viewFilter['keywordColumns'] = null;
935
+ }
936
+
937
+ // 清空数据
938
+ // if (this.static) {
939
+ // this.staticData = [];
940
+ // this.data = [];
941
+ // }
942
+
943
+ // 清空选择项
944
+ this.selectedData = [];
945
+
946
+ this.inited = true;
947
+
948
+ // 初始化触发规则
949
+ this.initTrigger();
950
+
951
+ setTimeout(() => {
952
+ if (typeof callback === 'function') {
953
+ callback();
954
+ }
955
+ });
956
+ },
957
+ /**
958
+ * 加载数据
959
+ *
960
+ * @param {array} staticData 静态数据
961
+ * @public
962
+ */
963
+ async loadData(staticData) {
964
+ if (!this.inited) {
965
+ await this.init(this.viewCode);
966
+
967
+ if (!this.inited) {
968
+ return;
969
+ }
970
+ }
971
+
972
+ if (staticData) {
973
+ this.staticData = this.copy(staticData);
974
+ }
975
+
976
+ if (this.static) {
977
+ // 筛选和排序
978
+ let data = this.getFilterResult();
979
+
980
+ this.total = data.length;
981
+
982
+ let offset = (this.current - 1) * this.size;
983
+ this.data = offset + this.size >= data.length ? data.slice(offset, data.length) : data.slice(offset, offset + this.size);
984
+ } else {
985
+ let data = {
986
+ ...this.getAllFilter(),
987
+ page: this.current,
988
+ per: this.size,
989
+ orderBy: this.orderBy
990
+ };
991
+
992
+ if (this.tableView.isGroupBy) {
993
+ data.isGroupBy = true;
994
+ data.groupColumn = JSON.parse(this.tableView.groupColumn);
995
+ data.groupMethod = JSON.parse(this.tableView.groupMethod);
996
+ }
997
+
998
+ if (this.tableView.isCustom) {
999
+ let res = await customModelApi.query(this.tableView.model, data);
1000
+
1001
+ this.total = res.totalCount;
1002
+ this.data = res.data;
1003
+ } else if (this.tableView.isDataSource) {
1004
+ let res = await dataSourceApi.query(this.tableView.dataSource, data);
1005
+
1006
+ this.total = res.totalCount;
1007
+ this.data = res.table;
1008
+ } else {
1009
+ let res = await modelApi.query(this.tableView.model, data, this.tableView.functionName, this.tableView.functionType);
1010
+
1011
+ this.total = res.totalCount;
1012
+ this.data = res.data;
1013
+ }
1014
+
1015
+ // 如果超出页码,设为最后一页
1016
+ if (this.current > Math.ceil(this.total / this.size)) {
1017
+ this.current = Math.ceil(this.total / this.size);
1018
+ }
1019
+
1020
+ // 最小为第一页
1021
+ if (this.current <= 0) {
1022
+ this.current = 1;
1023
+ }
1024
+
1025
+ // 设置选中项
1026
+ this.data.forEach(item => {
1027
+ item._checked = this.selectedData.some(i => {
1028
+ return item.id === i.id;
1029
+ });
1030
+ });
1031
+ // if (typeof this.selectFunc === 'function') {
1032
+ // let selected = this.data.filter(this.selectFunc);
1033
+ // this.setSelected(selected);
1034
+ // }
1035
+ }
1036
+
1037
+ // 如果这行数据有子集,需要添加展开加载方法
1038
+ if (this.treeEnable) {
1039
+ this.data.forEach(item => {
1040
+ if (this.hasChildren == null || this.hasChildren(item)) {
1041
+ item._loading = false;
1042
+ item.children = [];
1043
+ }
1044
+ });
1045
+
1046
+ this.data = this.copy(this.data);
1047
+ }
1048
+
1049
+ // 加载数据源
1050
+ this.initDataSource();
1051
+
1052
+ // 重新计算公式
1053
+ for (let i = 0; i < this.data.length; i++) {
1054
+ this.calc(this.data[i]);
1055
+ }
1056
+
1057
+ /**
1058
+ * 数据加载事件
1059
+ */
1060
+ this.$emit('on-load-data');
1061
+
1062
+ // 刷新表头控件
1063
+ if (this.$refs.tableFilter) {
1064
+ //this.$refs.tableFilter.$forceUpdate();
1065
+ }
1066
+ },
1067
+ /**
1068
+ * 创建新项
1069
+ *
1070
+ * @public
1071
+ */
1072
+ create() {
1073
+ /**
1074
+ * 创建事件
1075
+ */
1076
+ this.$emit('create');
1077
+ },
1078
+ /**
1079
+ * 编辑项
1080
+ *
1081
+ * @param {object} row 行对象
1082
+ * @param {int} index 行序号
1083
+ * @public
1084
+ */
1085
+ edit(row, index) {
1086
+ /**
1087
+ * 编辑事件
1088
+ * @property {object} args { row 行对象, index 行序号 }
1089
+ */
1090
+ this.$emit('edit', { row, index });
1091
+ },
1092
+ /**
1093
+ * 删除项
1094
+ *
1095
+ * @param {object} row 行对象
1096
+ * @param {int} index 行序号
1097
+ * @public
1098
+ */
1099
+ remove(row, index) {
1100
+ this.confirm('确定要删除该项吗?', async () => {
1101
+ if (this.embedded) {
1102
+ this.staticData.splice((this.current - 1) * this.size + index, 1);
1103
+ this.loadData();
1104
+ } else {
1105
+ if (this.tableView.isCustom) {
1106
+ await customModelApi.remove(this.tableView.model, row.id);
1107
+ } else {
1108
+ await modelApi.remove(this.tableView.model, row.id);
1109
+ }
1110
+
1111
+ this.success('操作成功!', () => {
1112
+ this.loadData();
1113
+ });
1114
+ }
1115
+ });
1116
+ },
1117
+ /**
1118
+ * 获取默认值
1119
+ *
1120
+ * @public
1121
+ */
1122
+ getDefaultData() {
1123
+ let data = {};
1124
+ this.columns.forEach(item => {
1125
+ if (item.defaultValue) {
1126
+ if (item.defaultValue == '{today}') {
1127
+ // 当前日期
1128
+ let date = new Date();
1129
+ let value = date.toISOString().replace(/T.*/, '');
1130
+ this.setData(data, item.code, new Date(value));
1131
+ } else if (item.defaultValue.startsWith('{today(') && item.defaultValue.endsWith(')}')) {
1132
+ // 当前时间转字符串
1133
+ let format = item.defaultValue.substr(7, item.defaultValue.length - 9);
1134
+ this.setData(data, item.code, dateFormat(new Date(), format));
1135
+ } else if (item.defaultValue == '{currentUser}') {
1136
+ // 当前用户
1137
+ this.setData(data, item.code, this.info.name);
1138
+ } else {
1139
+ if (item.dataType === 'Integer') {
1140
+ this.setData(data, item.code, parseInt(item.defaultValue));
1141
+ } else if (item.dataType === 'Decimal') {
1142
+ this.setData(data, item.code, parseFloat(item.defaultValue));
1143
+ } else if (item.dataType === 'Boolean' && item.defaultValue.toUpperCase == 'TRUE') {
1144
+ this.setData(data, item.code, true);
1145
+ } else if (item.dataType === 'Boolean' && item.defaultValue.toUpperCase == 'FALSE') {
1146
+ this.setData(data, item.code, false);
1147
+ } else {
1148
+ this.setData(data, item.code, item.defaultValue);
1149
+ }
1150
+ }
1151
+ } else {
1152
+ if (item.dataType === 'Boolean') {
1153
+ this.setData(data, item.code, false);
1154
+ } else {
1155
+ this.setData(data, item.code, null);
1156
+ }
1157
+ }
1158
+ });
1159
+
1160
+ return data;
1161
+ },
1162
+ /**
1163
+ * 添加新行
1164
+ *
1165
+ * @public
1166
+ */
1167
+ addNew() {
1168
+ this.staticData.push(this.getDefaultData());
1169
+ this.loadData();
1170
+ },
1171
+ /**
1172
+ * 获取选中项
1173
+ *
1174
+ * @public
1175
+ */
1176
+ getSelected() {
1177
+ return this.selectedData;
1178
+ },
1179
+ /**
1180
+ * 设置选中项
1181
+ *
1182
+ * @param {object} selected 选中项
1183
+ * @public
1184
+ */
1185
+ setSelected(selected) {
1186
+ this.selectedData = [];
1187
+ selected.forEach(item => {
1188
+ this.selectedData.push(item);
1189
+ });
1190
+
1191
+ if (this.static) {
1192
+ this.staticData.forEach(item => {
1193
+ item._checked = this.selectedData.some(i => {
1194
+ return item.id === i.id;
1195
+ });
1196
+ });
1197
+
1198
+ this.loadData();
1199
+ } else {
1200
+ this.data.forEach(item => {
1201
+ item._checked = this.selectedData.some(i => {
1202
+ return item.id === i.id;
1203
+ });
1204
+ });
1205
+ }
1206
+
1207
+ ////this.$forceUpdate();
1208
+
1209
+ this.data = this.copy(this.data);
1210
+ },
1211
+ /**
1212
+ * 必填验证
1213
+ *
1214
+ * @public
1215
+ */
1216
+ validate() {
1217
+ for (let i = 0; i < this.staticData.length; i++) {
1218
+ let row = this.staticData[i];
1219
+
1220
+ for (let j = 0; j < this.columns.length; j++) {
1221
+ let column = this.columns[j];
1222
+
1223
+ // 不显示的不验证
1224
+ if (row._isShow && row._isShow[column.code] == false) {
1225
+ continue;
1226
+ } else if (!column.isShow) {
1227
+ continue;
1228
+ }
1229
+
1230
+ let isRequired = column.isRequired;
1231
+
1232
+ // 动态判断是否必填
1233
+ if (!!(column.requiredJson || '').trim()) {
1234
+ let setting = JSON.parse(column.requiredJson);
1235
+
1236
+ if (setting.type == 'Condition' || setting.type == 'Expression') {
1237
+ isRequired = this.judgeCondition(setting, row);
1238
+ }
1239
+ }
1240
+
1241
+ if (isRequired) {
1242
+ let value = this.parseData(row, column.code);
1243
+
1244
+ if (value == null || !(String(value) || '').trim()) {
1245
+ this.error('第' + (i + 1) + '行 ' + column.name + ' 必须输入!');
1246
+ return false;
1247
+ }
1248
+ }
1249
+ }
1250
+ }
1251
+
1252
+ return true;
1253
+ },
1254
+ /**
1255
+ * 获取数据
1256
+ *
1257
+ * @public
1258
+ */
1259
+ getData() {
1260
+ let data = null;
1261
+ if (this.static) {
1262
+ data = this.copy(this.staticData);
1263
+ } else {
1264
+ data = this.copy(this.data);
1265
+ }
1266
+
1267
+ data.forEach(item => {
1268
+ delete item._checked;
1269
+ delete item._dataSource;
1270
+ delete item._needRefresh;
1271
+ delete item._needClear;
1272
+ delete item._rawData;
1273
+ });
1274
+
1275
+ return data;
1276
+ },
1277
+ /**
1278
+ * 重置筛选
1279
+ *
1280
+ * @public
1281
+ */
1282
+ resetFilter() {
1283
+ for (let key in this.filter) {
1284
+ delete this.filter[key];
1285
+ }
1286
+
1287
+ //this.$forceUpdate();
1288
+ },
1289
+ // 查询
1290
+ search() {
1291
+ if (typeof this.onSearch == 'function') {
1292
+ this.onSearch();
1293
+ } else {
1294
+ this.loadData();
1295
+ }
1296
+ },
1297
+ // 点击更多按钮
1298
+ async moreClick(name) {
1299
+ if (!this.inited) {
1300
+ await this.init(this.viewCode);
1301
+
1302
+ if (!this.inited) {
1303
+ return;
1304
+ }
1305
+ }
1306
+
1307
+ if (this.static) {
1308
+ if (name === 'exportExcel') {
1309
+ dataViewApi.exportExcel(
1310
+ this.tableView,
1311
+ this.staticData,
1312
+ this.columns.filter(item => {
1313
+ return item.slot == 'normal';
1314
+ })
1315
+ );
1316
+ } else if (name === 'exportPdf') {
1317
+ dataViewApi.exportPdf(
1318
+ this.tableView,
1319
+ this.staticData,
1320
+ this.columns.filter(item => {
1321
+ return item.slot == 'normal';
1322
+ })
1323
+ );
1324
+ } else if (name === 'print') {
1325
+ dataViewApi.print(
1326
+ this.tableView,
1327
+ this.staticData,
1328
+ this.columns.filter(item => {
1329
+ return item.slot == 'normal';
1330
+ })
1331
+ );
1332
+ } else if (name === 'batchEdit') {
1333
+ this.error('不支持此操作!');
1334
+ }
1335
+ } else {
1336
+ if (name === 'exportExcel') {
1337
+ this.exportExcel();
1338
+ } else if (name === 'exportPdf') {
1339
+ this.exportPdf();
1340
+ } else if (name === 'print') {
1341
+ this.print();
1342
+ } else if (name === 'batchEdit') {
1343
+ this.$refs.batchEditTable.init(this.tableView.batchEditView, async () => {
1344
+ let res;
1345
+ if (this.tableView.isCustom) {
1346
+ res = await customModelApi.query(this.tableView.model, {});
1347
+ } else {
1348
+ res = await modelApi.query(this.tableView.model, {});
1349
+ }
1350
+ this.$refs.batchEditTable.loadData(res.data);
1351
+ this.$refs.batchEditTable.open();
1352
+ });
1353
+ }
1354
+ }
1355
+ },
1356
+ // 导出Excel
1357
+ exportExcel() {
1358
+ let data = {
1359
+ ...this.getAllFilter(),
1360
+ orderBy: this.orderBy
1361
+ };
1362
+
1363
+ if (this.tableView.isCustom) {
1364
+ customModelApi.exportExcel(this.tableView, data);
1365
+ } else if (this.tableView.isDataSource) {
1366
+ dataSourceApi.exportExcel(this.tableView, data);
1367
+ } else {
1368
+ modelApi.exportExcel(this.tableView, data);
1369
+ }
1370
+ },
1371
+ // 导出PDF
1372
+ exportPdf() {
1373
+ let data = {
1374
+ ...this.getAllFilter(),
1375
+ orderBy: this.orderBy
1376
+ };
1377
+
1378
+ if (this.tableView.isCustom) {
1379
+ customModelApi.exportExcel(this.tableView, data);
1380
+ } else if (this.tableView.isDataSource) {
1381
+ dataSourceApi.exportPdf(this.tableView, data);
1382
+ } else {
1383
+ modelApi.exportPdf(this.tableView, data);
1384
+ }
1385
+ },
1386
+ // 打印
1387
+ print() {
1388
+ let data = {
1389
+ ...this.getAllFilter(),
1390
+ orderBy: this.orderBy
1391
+ };
1392
+
1393
+ if (this.tableView.isCustom) {
1394
+ customModelApi.exportExcel(this.tableView, data);
1395
+ } else if (this.tableView.isDataSource) {
1396
+ dataSourceApi.printList(this.tableView, data);
1397
+ } else {
1398
+ modelApi.printList(this.tableView, data);
1399
+ }
1400
+ },
1401
+ // 加载数据源
1402
+ initDataSource() {
1403
+ this.columns.forEach(column => {
1404
+ if (
1405
+ column.controlType == 'Select' ||
1406
+ column.controlType == 'SelectWithOther' ||
1407
+ column.controlType == 'ComboSelect' ||
1408
+ column.controlType == 'MultiSelect' ||
1409
+ column.controlType == 'Radio' ||
1410
+ column.controlType == 'CheckGroup'
1411
+ ) {
1412
+ if (column.isStaticItem) {
1413
+ // 固定数据源
1414
+ this.data.forEach(row => {
1415
+ if (!row._dataSource) {
1416
+ row._dataSource = {};
1417
+ row._rawData = {};
1418
+ row._needRefresh = {};
1419
+ row._needClear = {};
1420
+ } else if (row._dataSource[column.code]) {
1421
+ return;
1422
+ }
1423
+
1424
+ row._dataSource[column.code] = [];
1425
+ row._rawData[column.code] = [];
1426
+
1427
+ if (!!(column.itemData || '').trim()) {
1428
+ column.itemData.split(/[\n]/).forEach(item => {
1429
+ if (!!(item || '').trim()) {
1430
+ if (item.split(':').length > 1) {
1431
+ let key = item.split(':')[0];
1432
+ let value = item.split(':')[1];
1433
+ row._dataSource[column.code].push({
1434
+ id: key,
1435
+ name: value
1436
+ });
1437
+ } else {
1438
+ row._dataSource[column.code].push({
1439
+ id: item,
1440
+ name: item
1441
+ });
1442
+ }
1443
+ }
1444
+ });
1445
+ }
1446
+ });
1447
+
1448
+ //this.$forceUpdate();
1449
+ } else {
1450
+ if (!!(column.source || '').trim()) {
1451
+ this.data.forEach(row => {
1452
+ if (row._dataSource && row._dataSource[column.code]) {
1453
+ return;
1454
+ }
1455
+
1456
+ let param = this.getParam(row, column, this.parentData);
1457
+
1458
+ // 选择框、单选框组
1459
+ if (param != null) {
1460
+ this.fillDataSource(row, column, param);
1461
+ }
1462
+ });
1463
+ }
1464
+ }
1465
+ }
1466
+ });
1467
+ },
1468
+ // 初始化触发规则
1469
+ initTrigger() {
1470
+ // 触发规则
1471
+ this.columns.forEach(column => {
1472
+ column.triggers = [];
1473
+ });
1474
+
1475
+ // 数据源中包含变量需要刷新
1476
+ this.columns
1477
+ .filter(column => {
1478
+ return !column.isStaticItem && !!(column.source || '').trim() && !!(column.param || '').trim();
1479
+ })
1480
+ .forEach(column => {
1481
+ let param = JSON.parse(column.param);
1482
+ for (let key in param) {
1483
+ this.columns
1484
+ .filter(item => {
1485
+ return param[key] == item.code || param[key].split('.')[0] + 'ID' == item.code;
1486
+ })
1487
+ .forEach(item => {
1488
+ item.triggers.push(this.copy(column));
1489
+ });
1490
+ }
1491
+ });
1492
+ },
1493
+ // 填充数据源
1494
+ async fillDataSource(data, column, param) {
1495
+ if (!data._dataSource) {
1496
+ data._dataSource = {};
1497
+ data._rawData = {};
1498
+ data._needRefresh = {};
1499
+ data._needClear = {};
1500
+ }
1501
+
1502
+ // 参数完整,查询数据
1503
+ let res;
1504
+ if (column.isSourceCustom) {
1505
+ res = await customModelApi.query(column.source, param);
1506
+ } else {
1507
+ res = await modelApi.query(column.source, param);
1508
+ }
1509
+
1510
+ data._rawData[column.code] = res.data;
1511
+
1512
+ data._dataSource[column.code] = res.data.map(item => {
1513
+ return {
1514
+ id: !(column.sourceDataCode || '').trim() ? item.id : this.parseData(item, column.sourceDataCode),
1515
+ name: this.parseData(item, column.sourceDisplayCode)
1516
+ };
1517
+ });
1518
+
1519
+ // 默认第一项
1520
+ if (data) {
1521
+ if (this.parseData(data, column.code) == null && column.isDefaultFirst && res.data.length > 0) {
1522
+ this.setData(data, column.code, this.parseData(res.data[0], column.sourceDataCode));
1523
+
1524
+ if (column.sourceDataCode == 'id' && column.code.length > 2) {
1525
+ let code = column.code.substr(0, column.code.length - 2);
1526
+
1527
+ if (data._rawData && data._rawData[column.code]) {
1528
+ let model = data._rawData[column.code].find(item => {
1529
+ return item.id == this.parseData(data, column.code);
1530
+ });
1531
+
1532
+ this.setData(data, code, model);
1533
+ }
1534
+ }
1535
+ }
1536
+ }
1537
+
1538
+ // 更新data触发刷新
1539
+ this.data = this.data.map(item => {
1540
+ return item;
1541
+ });
1542
+
1543
+ // 触发
1544
+ this.onDataChange(data, column);
1545
+ },
1546
+ // 获取数据源
1547
+ getDataSource(data, column) {
1548
+ if (!column.isStaticItem && column.dataType.indexOf('Enum:') === 0) {
1549
+ // 枚举
1550
+ return this.getEnumList(column.dataType.split(':')[1]);
1551
+ } else if (data._dataSource != null && data._dataSource[column.code] != null) {
1552
+ return data._dataSource[column.code];
1553
+ }
1554
+ },
1555
+ // // 可筛选下拉框加载数据
1556
+ // loadOption(data, column, keyword) {
1557
+ // if (!data._dataSource) {
1558
+ // data._dataSource = {};
1559
+ // }
1560
+
1561
+ // let param = this.getParam(data, column, this.parentData);
1562
+
1563
+ // if (param != null) {
1564
+ // if (!(keyword || '').trim() && this.parseData(data, column.code) != null) {
1565
+ // param.id = this.parseData(data, column.code);
1566
+ // } else {
1567
+ // param.keyword = keyword;
1568
+ // }
1569
+ // param.per = 20;
1570
+
1571
+ // this.fillDataSource(data, column, param);
1572
+ // } else {
1573
+ // // 参数不完整,清空数据
1574
+ // data._dataSource[column.code] = [];
1575
+ // this.setData(data, column.code, null);
1576
+ // // column.displayValue = null;
1577
+
1578
+ // // 触发
1579
+ // column.triggers.forEach(item => {
1580
+ // item.needRefresh = true;
1581
+ // });
1582
+ // }
1583
+ // },
1584
+ // 每页数量切换
1585
+ pageSizeChange(size) {
1586
+ this.size = size;
1587
+ this.loadData();
1588
+ },
1589
+ // 排序切换
1590
+ sortChange({ key, order }) {
1591
+ let orderColumns = [];
1592
+ if (this.orderBy) {
1593
+ orderColumns = this.orderBy.split(',');
1594
+ }
1595
+
1596
+ orderColumns = orderColumns.filter(item => {
1597
+ return item.substring(1) !== key;
1598
+ });
1599
+
1600
+ // 添加排序字段
1601
+ if (order === 'asc') {
1602
+ orderColumns.unshift('+' + key);
1603
+ } else if (order === 'desc') {
1604
+ orderColumns.unshift('-' + key);
1605
+ }
1606
+
1607
+ this.orderBy = orderColumns.join(',');
1608
+
1609
+ this.loadData();
1610
+ },
1611
+ columnWidthResize(newWidth, oldWidth, column, event) {
1612
+ console.log('columnWidthResize', newWidth, oldWidth, column, event);
1613
+ },
1614
+ onSelectDataChange(data, sender, selected) {
1615
+ let code;
1616
+ if (sender.code.endsWith('ID')) {
1617
+ code = sender.code.substr(0, sender.code.length - 2);
1618
+ }
1619
+
1620
+ let model = null;
1621
+
1622
+ if (typeof selected == 'object') {
1623
+ if (selected instanceof Array) {
1624
+ model = [];
1625
+
1626
+ for (let item of selected) {
1627
+ if (typeof item == 'object') {
1628
+ model.push(item);
1629
+ } else {
1630
+ if (data._rawData && data._rawData[sender.code]) {
1631
+ model.push(
1632
+ data._rawData[sender.code].find(rawData => {
1633
+ return this.parseData(rawData, sender.sourceDataCode) == item;
1634
+ })
1635
+ );
1636
+ } else {
1637
+ model.push(item);
1638
+ }
1639
+ }
1640
+ }
1641
+ } else {
1642
+ model = selected;
1643
+ }
1644
+ } else {
1645
+ if (data._rawData && data._rawData[sender.code]) {
1646
+ model = data._rawData[sender.code].find(rawData => {
1647
+ return this.parseData(rawData, sender.sourceDataCode) == selected;
1648
+ });
1649
+ } else {
1650
+ model = selected;
1651
+ }
1652
+ }
1653
+
1654
+ if (code) {
1655
+ this.setData(data, code, model);
1656
+ }
1657
+
1658
+ this.onDataChange(data, sender, model);
1659
+ },
1660
+ // 数据变化事件
1661
+ onDataChange(data, sender, selected) {
1662
+ for (let column of this.columns) {
1663
+ // 判断是否需要显示
1664
+ if (!!(column.showJson || '').trim()) {
1665
+ if (data._isShow == null) {
1666
+ data._isShow = {};
1667
+ }
1668
+
1669
+ let setting = JSON.parse(column.showJson);
1670
+
1671
+ if (setting.type == 'Condition' || setting.type == 'Expression') {
1672
+ data._isShow[column.code] = this.judgeCondition(setting, data);
1673
+ }
1674
+ }
1675
+
1676
+ // 判断是否只读
1677
+ if (!!(column.readonlyJson || '').trim()) {
1678
+ if (data._isReadonly == null) {
1679
+ data._isReadonly = {};
1680
+ }
1681
+
1682
+ let setting = JSON.parse(column.readonlyJson);
1683
+
1684
+ if (setting.type == 'Condition' || setting.type == 'Expression') {
1685
+ data._isReadonly[column.code] = this.judgeCondition(setting, data);
1686
+ }
1687
+ }
1688
+ }
1689
+
1690
+ //this.$forceUpdate();
1691
+
1692
+ /**
1693
+ * 数据变化事件
1694
+ * @property {object} data 行对象
1695
+ * @property {object} sender 触发的列对象
1696
+ * @property {object} selected 选中对象(弹出选择框等有效)
1697
+ */
1698
+ this.$emit('on-change', data, sender, selected);
1699
+
1700
+ // 公式计算
1701
+ this.calc(data, sender);
1702
+
1703
+ // 计算需要刷新的字段
1704
+ if (sender == null || sender.triggers !== []) {
1705
+ this.columns.forEach(function (column) {
1706
+ if (
1707
+ !column.isStaticItem &&
1708
+ !!(column.source || '').trim() &&
1709
+ (sender == null ||
1710
+ sender.triggers.some(item => {
1711
+ return item.code == column.code;
1712
+ }))
1713
+ ) {
1714
+ if (data._needRefresh) {
1715
+ data._needRefresh[column.code] = true;
1716
+ }
1717
+ }
1718
+ });
1719
+ }
1720
+
1721
+ // 刷新数据源
1722
+ while (true) {
1723
+ let column = this.columns.filter(item => {
1724
+ return (data._needRefresh && data._needRefresh[item.code] == true) || (data._needClear && data._needClear[item.code] == true);
1725
+ })[0];
1726
+
1727
+ if (column == null) {
1728
+ // 没有需要刷新的字段
1729
+ break;
1730
+ }
1731
+
1732
+ // 重新加载数据源
1733
+ if (data._needClear[column.code] && this.parseData(data, column.code) != null) {
1734
+ this.setData(data, column.code, null);
1735
+ // 触发
1736
+ column.triggers.forEach(item => {
1737
+ data._needClear[item.code] = true;
1738
+ });
1739
+ } else if (data._needRefresh[column.code] && !!(column.source || '').trim()) {
1740
+ let param = this.getParam(data, column, this.parentData);
1741
+
1742
+ if (
1743
+ column.controlType === 'Select' ||
1744
+ column.controlType === 'SelectWithOther' ||
1745
+ column.controlType === 'ComboSelect' ||
1746
+ column.controlType === 'MulitSelect' ||
1747
+ column.controlType === 'Radio' ||
1748
+ column.controlType === 'CheckGroup'
1749
+ // column.controlType === 'AutoComplete'
1750
+ ) {
1751
+ // 选择框、单选框组
1752
+ if (param != null) {
1753
+ this.fillDataSource(data, column, param);
1754
+ } else {
1755
+ // 参数不完整,清空数据
1756
+ data._dataSource[column.code] = [];
1757
+ this.setData(data, column.code, null);
1758
+ // column.displayValue = null;
1759
+
1760
+ // 触发
1761
+ column.triggers.forEach(item => {
1762
+ data._needClear[item.code] = true;
1763
+ });
1764
+ }
1765
+ }
1766
+ }
1767
+
1768
+ // 重新加载公式
1769
+ // if (!!(column.calculate || '').trim()) {
1770
+ // let data = this.calculate(column.calculate, this.data);
1771
+ // this.setData(this.data, column.code, data);
1772
+ // }
1773
+
1774
+ data._needClear[column.code] = false;
1775
+ data._needRefresh[column.code] = false;
1776
+ }
1777
+ },
1778
+ // 公式计算
1779
+ calc(data, sender) {
1780
+ for (let i = 0; i < this.columns.length; i++) {
1781
+ let column = this.columns[i];
1782
+ if (!!(column.calculate || '').trim()) {
1783
+ let triggers = this.getTriggers(column.calculate);
1784
+ if (!sender || triggers.some(item => item == sender.code)) {
1785
+ // 包含在公式中,需要刷新
1786
+ let result = this.calculate(column.calculate, data);
1787
+
1788
+ // 保留小数
1789
+ if (column.digit != null) {
1790
+ result = this.keepDecimal(result, column.digit, column.fixedDigit);
1791
+ }
1792
+
1793
+ this.setData(data, column.code, result);
1794
+ }
1795
+ }
1796
+ }
1797
+ },
1798
+ // 输入框失去焦点事件
1799
+ onBlur(data, sender) {
1800
+ /**
1801
+ * 数据变化事件
1802
+ * @property {object} data 行对象
1803
+ * @property {object} sender 触发的列对象
1804
+ */
1805
+ this.$emit('on-blur', data, sender);
1806
+ },
1807
+ // 打开表格设置界面
1808
+ tableSettingOpen() {
1809
+ this.tableSettingActive = true;
1810
+
1811
+ setTimeout(() => {
1812
+ this.$refs.tableSetting.open(this.tableView, this.copy(this.tableView.columns));
1813
+ });
1814
+ },
1815
+ // 打开筛选设置界面
1816
+ filterSettingOpen() {
1817
+ this.filterSettingActive = true;
1818
+
1819
+ setTimeout(() => {
1820
+ this.$refs.filterSetting.open(this.tableView, this.copy(this.tableView.filterColumns));
1821
+ });
1822
+ },
1823
+ // 选中响应事件
1824
+ select(selection, row) {
1825
+ this.selectedData.push(row);
1826
+ /**
1827
+ * 选中项变化事件
1828
+ */
1829
+ this.$emit('on-select-change');
1830
+ },
1831
+ // 取消选中响应事件
1832
+ selectCancel(selection, row) {
1833
+ const index = this.selectedData.findIndex(item => item.id === row.id);
1834
+ this.selectedData.splice(index, 1);
1835
+ /**
1836
+ * 选中项变化事件
1837
+ */
1838
+ this.$emit('on-select-change');
1839
+ },
1840
+ // 全选响应事件
1841
+ selectAll() {
1842
+ if (this.static) {
1843
+ this.setSelected(this.staticData);
1844
+ } else {
1845
+ let selected = this.copy(this.selectedData);
1846
+
1847
+ this.data.forEach(item => {
1848
+ if (
1849
+ !selected.some(i => {
1850
+ return i.id == item.id;
1851
+ })
1852
+ ) {
1853
+ selected.push(item);
1854
+ }
1855
+ });
1856
+
1857
+ this.setSelected(selected);
1858
+ }
1859
+ /**
1860
+ * 选中项变化事件
1861
+ */
1862
+ this.$emit('on-select-change');
1863
+ },
1864
+ // 取消全选响应事件
1865
+ selectAllCancel() {
1866
+ if (this.static) {
1867
+ this.setSelected([]);
1868
+ } else {
1869
+ let selected = this.copy(this.selectedData);
1870
+
1871
+ this.data.forEach(item => {
1872
+ const index = selected.findIndex(i => {
1873
+ return i.id == item.id;
1874
+ });
1875
+
1876
+ if (index != -1) {
1877
+ selected.splice(index, 1);
1878
+ }
1879
+ });
1880
+
1881
+ this.setSelected(selected);
1882
+ }
1883
+
1884
+ /**
1885
+ * 选中项变化事件
1886
+ */
1887
+ this.$emit('on-select-change');
1888
+ },
1889
+ // 键盘事件
1890
+ onKeyup(e) {
1891
+ if (e) {
1892
+ var keycode = window.event ? e.keyCode : e.which;
1893
+
1894
+ if (!keycode) {
1895
+ return;
1896
+ }
1897
+
1898
+ if (keycode !== 0 && keycode !== 1 && keycode !== 13) {
1899
+ return;
1900
+ }
1901
+ }
1902
+
1903
+ this.loadData();
1904
+ },
1905
+ // 合并后最终的筛选项
1906
+ getAllFilter() {
1907
+ let filter = {
1908
+ ...this.viewFilter,
1909
+ ...this.filter
1910
+ };
1911
+
1912
+ for (let key in filter) {
1913
+ if (typeof filter[key] == 'object' && !(filter[key] instanceof Date)) {
1914
+ delete filter[key];
1915
+ }
1916
+ }
1917
+
1918
+ return filter;
1919
+ },
1920
+ // 静态数据筛选
1921
+ getFilterResult() {
1922
+ let data = this.staticData;
1923
+
1924
+ if (!this.filterDisable) {
1925
+ let filter = this.filter;
1926
+
1927
+ for (let key in filter) {
1928
+ let column = key;
1929
+ let value = filter[key];
1930
+ if (value == null || value == '') {
1931
+ continue;
1932
+ }
1933
+
1934
+ if (column == 'keywordColumns') {
1935
+ continue;
1936
+ }
1937
+
1938
+ data = data.filter(item => {
1939
+ if (column.startsWith('d_')) {
1940
+ column = column.substr(2);
1941
+ } else if (column.startsWith('m_')) {
1942
+ column = column.substr(2);
1943
+ } else if (column.startsWith('y_')) {
1944
+ column = column.substr(2);
1945
+ }
1946
+
1947
+ if (column == 'keyword') {
1948
+ // 关键词
1949
+ let columns = filter['keywordColumns'].split(',');
1950
+
1951
+ for (let i = 0; i < columns.length; i++) {
1952
+ let c = columns[i];
1953
+
1954
+ if (this.parseData(item, c) != null && this.parseData(item, c).indexOf(value) >= 0) {
1955
+ return true;
1956
+ }
1957
+ }
1958
+
1959
+ return false;
1960
+ } else if (column.endsWith('_g')) {
1961
+ // 大于
1962
+ let c = column.substr(0, column.length - 2);
1963
+ if (value instanceof Date) {
1964
+ return new Date(this.parseData(item, c)) > value;
1965
+ } else {
1966
+ return this.parseData(item, c) > value;
1967
+ }
1968
+ } else if (column.endsWith('_l')) {
1969
+ // 小于
1970
+ let c = column.substr(0, column.length - 2);
1971
+ if (value instanceof Date) {
1972
+ return new Date(this.parseData(item, c)) < value;
1973
+ } else {
1974
+ return this.parseData(item, c) < value;
1975
+ }
1976
+ } else if (column.endsWith('_ge')) {
1977
+ // 大于等于
1978
+ let c = column.substr(0, column.length - 3);
1979
+ if (value instanceof Date) {
1980
+ return new Date(this.parseData(item, c)) >= value;
1981
+ } else {
1982
+ return this.parseData(item, c) >= value;
1983
+ }
1984
+ } else if (column.endsWith('_le')) {
1985
+ // 小于等于
1986
+ let c = column.substr(0, column.length - 3);
1987
+ if (value instanceof Date) {
1988
+ return new Date(this.parseData(item, c)) <= value;
1989
+ } else {
1990
+ return this.parseData(item, c) <= value;
1991
+ }
1992
+ } else if (column.endsWith('_n')) {
1993
+ // 不等于
1994
+ let c = column.substr(0, column.length - 2);
1995
+ if (typeof value == 'string') {
1996
+ for (let i = 0; i < value.split(',').length; i++) {
1997
+ if (this.parseData(item, c) != value.split(',')[i]) {
1998
+ return true;
1999
+ }
2000
+ }
2001
+
2002
+ return false;
2003
+ } else if (value instanceof Date) {
2004
+ return new Date(this.parseData(item, c)) != value;
2005
+ } else {
2006
+ return this.parseData(item, c) != value;
2007
+ }
2008
+ } else if (column.endsWith('_c')) {
2009
+ // 文字包含
2010
+ let c = column.substr(0, column.length - 2);
2011
+ return this.parseData(item, c) != null && this.parseData(item, c).indexOf(value) >= 0;
2012
+ } else {
2013
+ // 相等
2014
+ let c = column;
2015
+ if (typeof value == 'string') {
2016
+ for (let i = 0; i < value.split(',').length; i++) {
2017
+ if (this.parseData(item, c) == value.split(',')[i]) {
2018
+ return true;
2019
+ }
2020
+ }
2021
+ return false;
2022
+ } else if (value instanceof Date) {
2023
+ return new Date(this.parseData(item, c)) == value;
2024
+ } else {
2025
+ return this.parseData(item, c) == value;
2026
+ }
2027
+ }
2028
+ });
2029
+ }
2030
+ }
2031
+
2032
+ if (!!(this.orderBy || '').trim()) {
2033
+ // 需要排序
2034
+ let orderBy = this.orderBy.split(',')[0];
2035
+
2036
+ let type = orderBy.substr(0, 1);
2037
+ let column = orderBy.substr(1);
2038
+
2039
+ data.sort((a, b) => {
2040
+ let dataA = this.parseData(a, column);
2041
+ let dataB = this.parseData(b, column);
2042
+
2043
+ if (dataA == dataB) {
2044
+ return 0;
2045
+ } else if (dataA > dataB || dataB == null) {
2046
+ return type == '+' ? 1 : -1;
2047
+ } else {
2048
+ return type == '+' ? -1 : 1;
2049
+ }
2050
+ });
2051
+ }
2052
+
2053
+ return data;
2054
+ },
2055
+ // 树展开动态查询
2056
+ async onLoadData(item, callback) {
2057
+ if (this.treeLoad != null) {
2058
+ let data = await this.treeLoad(item);
2059
+ data.forEach(item => {
2060
+ if (this.hasChildren == null || this.hasChildren(item)) {
2061
+ item._loading = false;
2062
+ item.children = [];
2063
+ }
2064
+ });
2065
+
2066
+ callback(data);
2067
+ }
2068
+ },
2069
+ // 拖动事件
2070
+ dragDrop(index1, index2) {
2071
+ /**
2072
+ * 拖动完成事件
2073
+ * @property {object} args { index1 来源行序号, index2 目标行序号 }
2074
+ */
2075
+ this.$emit('on-drag-drop', { index1, index2 });
2076
+ },
2077
+ // // 转换为日期类型
2078
+ // parseDateTime(value) {
2079
+ // if (value && typeof value === 'string') {
2080
+ // return new Date(value);
2081
+ // } else {
2082
+ // return value;
2083
+ // }
2084
+ // },
2085
+ // 打开选择内容
2086
+ openSelectItem() {
2087
+ let selected = [];
2088
+ let batchSelectDataCode = this.tableView.batchSelectDataCode;
2089
+ let key = batchSelectDataCode.substr(0, batchSelectDataCode.length - 2);
2090
+
2091
+ for (let i = 0; i < this.staticData.length; i++) {
2092
+ selected.push(this.staticData[i][key]);
2093
+ }
2094
+
2095
+ this.$refs.itemSelect.setSelected(selected);
2096
+
2097
+ this.$refs.itemSelect.open();
2098
+ },
2099
+ // 保存选择内容
2100
+ saveItemSelect() {
2101
+ let selected = this.$refs.itemSelect.getSelected();
2102
+ let batchSelectDataCode = this.tableView.batchSelectDataCode;
2103
+ let key = batchSelectDataCode.substr(0, batchSelectDataCode.length - 2);
2104
+
2105
+ this.staticData = this.staticData.filter(item => {
2106
+ return selected.some(i => {
2107
+ return i.id == item[batchSelectDataCode];
2108
+ });
2109
+ });
2110
+
2111
+ for (let i = 0; i < selected.length; i++) {
2112
+ if (
2113
+ !this.staticData.some(item => {
2114
+ return item[batchSelectDataCode] == selected[i].id;
2115
+ })
2116
+ ) {
2117
+ let item = {};
2118
+ item[batchSelectDataCode] = selected[i].id;
2119
+ item[key] = selected[i];
2120
+
2121
+ this.staticData.push(item);
2122
+ }
2123
+ }
2124
+
2125
+ this.loadData(this.staticData);
2126
+ this.$refs.itemSelect.close();
2127
+
2128
+ ////this.$forceUpdate();
2129
+ },
2130
+ // 操作栏按钮
2131
+ clickCommandButton(row, commandButton) {
2132
+ if (commandButton.viewType == 'TableView') {
2133
+ // 打开表格
2134
+ this.$refs.modalTable.init(commandButton.viewCode, async () => {
2135
+ let params = {};
2136
+
2137
+ if (!!(commandButton.params || '').trim()) {
2138
+ let commandButtonParams = JSON.parse(commandButton.params);
2139
+
2140
+ for (let i = 0; i < commandButtonParams.length; i++) {
2141
+ let value = this.parseData(row, commandButtonParams[i].value);
2142
+ params[commandButtonParams[i].param] = value;
2143
+ }
2144
+ }
2145
+
2146
+ this.$refs.modalTable.open(params);
2147
+ });
2148
+ } else {
2149
+ // 打开表单
2150
+ this.$refs.modalForm.init(commandButton.viewCode, async () => {
2151
+ this.$refs.modalForm.open(row);
2152
+ });
2153
+ }
2154
+ },
2155
+ // 预览
2156
+ previewImage(item) {
2157
+ this.imageUrl = item;
2158
+ this.preview = true;
2159
+ },
2160
+ // 合并单元格方法
2161
+ handleSpan({ row, column, rowIndex }) {
2162
+ if (column.mergeSame) {
2163
+ if (rowIndex != 0 && this.parseData(row, column.code) == this.parseData(this.data[rowIndex - 1], column.code)) {
2164
+ return [0, 0];
2165
+ }
2166
+
2167
+ let span = 0;
2168
+ for (let i = rowIndex; i < this.data.length; i++) {
2169
+ if (this.parseData(row, column.code) == this.parseData(this.data[i], column.code)) {
2170
+ span++;
2171
+ } else {
2172
+ return [span, 1];
2173
+ }
2174
+ }
2175
+
2176
+ return [span, 1];
2177
+ }
2178
+ },
2179
+ // 根据条件判断
2180
+ judge(enable, json, data) {
2181
+ // 判断是否只读
2182
+ if (!!(json || '').trim()) {
2183
+ let setting = JSON.parse(json);
2184
+
2185
+ if (setting.type == 'Condition' || setting.type == 'Expression') {
2186
+ return this.judgeCondition(setting, data);
2187
+ }
2188
+ }
2189
+
2190
+ return enable;
2191
+ },
2192
+ // 是否显示
2193
+ isShow(data, column) {
2194
+ if (data._isShow != null && data._isShow[column.code] != null) {
2195
+ return data._isShow[column.code];
2196
+ } else {
2197
+ return column.isShow;
2198
+ }
2199
+ },
2200
+ // 是否只读
2201
+ isReadonly(data, column) {
2202
+ if (this.readonly == true) {
2203
+ return true;
2204
+ } else if (data._isReadonly != null && data._isReadonly[column.code] != null) {
2205
+ return data._isReadonly[column.code];
2206
+ } else {
2207
+ return column.isReadonly;
2208
+ }
2209
+ },
2210
+ // 批量保存
2211
+ batchSave() {
2212
+ if (!this.$refs.batchEditTable.validate()) {
2213
+ return;
2214
+ }
2215
+
2216
+ this.confirm('确定要保存吗?', async () => {
2217
+ let data = this.$refs.batchEditTable.data;
2218
+
2219
+ if (this.tableView.isCustom) {
2220
+ await customModelApi.batchSave(this.tableView.model, data);
2221
+ } else {
2222
+ await modelApi.batchSave(this.tableView.model, data);
2223
+ }
2224
+
2225
+ this.success('操作成功!', () => {
2226
+ this.$refs.batchEditTable.close();
2227
+ this.loadData();
2228
+ });
2229
+ });
2230
+ },
2231
+ // 行数据
2232
+ rowData(row, index) {
2233
+ if (this.treeEnable) {
2234
+ return row;
2235
+ } else {
2236
+ return this.data[index];
2237
+ }
2238
+ }
2239
+ }
2240
+ };
2241
+ </script>
2242
+
2243
+ <style scoped>
2244
+ /* 图片 */
2245
+ .image-group {
2246
+ display: flex;
2247
+ }
2248
+
2249
+ .image-group .image {
2250
+ border: solid 1px #ccc;
2251
+ width: 75px;
2252
+ height: 75px;
2253
+ margin: 2px 1px 2px 1px;
2254
+ cursor: pointer;
2255
+ }
2256
+
2257
+ .image-group .image img {
2258
+ width: 75px;
2259
+ height: 75px;
2260
+ }
2261
+ </style>