GridBody.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. <template>
  2. <tr v-if="showTabGridTitleFields" height="40px" :style="{ 'background-color': warningColor }" :class="{ 'warning': isSelected }">
  3. <td rowspan="2" class="sticky-col">{{ serialNumber }}</td>
  4. <td rowspan="2" class="text-center sticky-col" style="left:50px">
  5. <input v-model="isSelected" autocomplete="off" type="checkbox" @click="clickModelData(modelData)" />
  6. </td>
  7. <td v-if="isShowEdit == undefined || isShowEdit" rowspan="2" class="sticky-col" style="left:80px">
  8. <template v-if="showEditButton">
  9. <span class="operation-delete" aria-hidden="true" @click="editRecord">
  10. <i class="fa" :class="{ 'fa-pencil': !modelData.editMode, 'fa-check': modelData.editMode }" />
  11. </span>
  12. <span class="operation-edit" aria-hidden="true" @click="deleteRecord">
  13. <i class="fa fa-remove" />
  14. </span>
  15. </template>
  16. </td>
  17. <td :colspan="tabGridFields.length + 1" style="text-align: left; padding-left: 2rem;">
  18. <a-space align="center">
  19. <div v-for="tabGridTitleField in tabGridTitleFields" :key="tabGridTitleField.fieldName" @click="clickRecord">
  20. <a-space align="center">
  21. <span style="font-weight: normal;">{{ Language.getDisplayNameTrl($i18n.locale, tabGridTitleField) }}</span>
  22. <CellTextItem
  23. v-if="!modelData.editMode" :grid-field-item="tabGridTitleField" :model-data="modelData"
  24. :class-name="className" style="display: inline-block; font-weight: normal; padding-top: 3px;"
  25. @execute-callout="executeCallout(tabGridTitleField)"
  26. />
  27. <CellItem
  28. v-else :ref="'cellItem' + index" :scroll-object="scrollObject" :field-item="tabGridTitleField"
  29. :model-data="modelData" :parent-model-data="parentModelData" :class-name="className" :window-no="windowNo"
  30. :tab-index="tabIndex" style="display: inline-block; min-width: 200px;"
  31. :class="{ 'table-cell-searchwidget': fieldUtil.isSearchType(tabGridTitleField) }"
  32. @value-changed="valueChanged($event, tabGridTitleField)"
  33. @execute-callout="executeCallout(tabGridTitleField)"
  34. />
  35. </a-space>
  36. </div>
  37. </a-space>
  38. </td>
  39. </tr>
  40. <tr :style="{ 'background-color': warningColor }" :class="{ 'warning': isSelected }" height="40px">
  41. <template v-if="!showTabGridTitleFields">
  42. <td class="sticky-col">{{ serialNumber }}</td>
  43. <td class="text-center sticky-col" style="left:50px">
  44. <input v-model="isSelected" autocomplete="off" type="checkbox" @click="clickModelData(modelData)" />
  45. </td>
  46. <td v-if="isShowEdit == undefined || isShowEdit" class="sticky-col" style="left:80px">
  47. <template v-if="showEditButton">
  48. <span class="operation-delete" aria-hidden="true" @click="editRecord">
  49. <i class="fa" :class="{ 'fa-pencil': !modelData.editMode, 'fa-check': modelData.editMode }" />
  50. </span>
  51. <span class="operation-edit" aria-hidden="true" @click="deleteRecord">
  52. <i class="fa fa-remove" />
  53. </span>
  54. </template>
  55. </td>
  56. </template>
  57. <template
  58. v-for="(gridFieldItem, index) in tabGridFields"
  59. :key="'TabGridField_' + gridFieldItem.fieldName + '_' + index"
  60. >
  61. <td v-if="!modelData.editMode" v-show="gridFieldItem.visible" @click="clickRecord">
  62. <div>
  63. <CellTextItem
  64. ref="cellTextItem"
  65. :grid-field-item="gridFieldItem" :model-data="modelData" :class-name="className"
  66. :simple-filter-params="simpleFilterParams" :complex-filter-params="complexFilterParams"
  67. :model-datas="modelDatas" :js-url="jsUrl"
  68. @execute-callout="executeCallout(gridFieldItem)" @delete-record="deleteRecord" @refresh-datas="refreshDatas"
  69. @edit-record="editRecord"
  70. @read-record="readRecord"
  71. />
  72. </div>
  73. </td>
  74. <td
  75. v-else v-show="gridFieldItem.visible"
  76. :class="{ 'table-cell-searchwidget': fieldUtil.isSearchType(gridFieldItem) }" @click="clickRecord"
  77. >
  78. <CellItem
  79. :ref="'cellItem' + index" :scroll-object="scrollObject" :field-item="gridFieldItem"
  80. :model-data="modelData" :parent-model-data="parentModelData" :class-name="className" :window-no="windowNo"
  81. :tab-index="tabIndex" @value-changed="valueChanged($event, gridFieldItem)"
  82. @execute-callout="executeCallout(gridFieldItem)"
  83. />
  84. </td>
  85. </template>
  86. </tr>
  87. </template>
  88. <script>
  89. import WindowClientUtil from '../../resource/dictionary/WindowClientUtil.js';
  90. import FieldUtil from '../../resource/dictionary/FieldUtil.js';
  91. import CellItem from './CellItem.vue';
  92. import CellTextItem from './CellTextItem.vue';
  93. import Common from '../../common/Common.js';
  94. import Context from '../common/Context.js';
  95. import JsUtil from '../../common/JsUtil.js';
  96. import Language from '../../common/Language.js';
  97. import { Notify} from 'pc-component-v3';
  98. export default {
  99. components: {
  100. CellItem, CellTextItem,
  101. },
  102. props: {
  103. windowNo: {
  104. type: String,
  105. default: null,
  106. },
  107. tabIndex: {
  108. type: Number,
  109. default: null,
  110. },
  111. /** 表格标题字段 */
  112. tabGridTitleFields: {
  113. type: Array,
  114. default: function () {
  115. return null;
  116. },
  117. },
  118. /** 表格字段 */
  119. tabGridFields: {
  120. type: Array,
  121. default: function () {
  122. return null;
  123. },
  124. },
  125. modelData: {
  126. type: Object,
  127. default: function () {
  128. return null;
  129. },
  130. },
  131. parentModelData: {
  132. type: Object,
  133. default: function () {
  134. return null;
  135. },
  136. },
  137. className: {
  138. type: String,
  139. default: null,
  140. },
  141. isShowEdit: {
  142. type: Boolean,
  143. default: false,
  144. },
  145. scrollObject: {
  146. type: Object,
  147. default: null,
  148. },
  149. serialNumber: {
  150. type: Number,
  151. default: null,
  152. },
  153. jsUrl: {
  154. type: String,
  155. default: null,
  156. },
  157. simpleFilterParams: {
  158. type: String,
  159. default: null,
  160. },
  161. complexFilterParams: {
  162. type: Array,
  163. default: () => {
  164. return [];
  165. },
  166. },
  167. modelDatas: {
  168. type: Array,
  169. default: () => {
  170. return [];
  171. },
  172. },
  173. },
  174. emits: ['deleteRecord', 'editRecord', 'readRecord', 'clickModelData', 'executeCallout', 'valueChanged', 'refreshDatas'],
  175. data: function () {
  176. return {
  177. tabGridFields1: this.tabGridFields,
  178. lastClickTime: 0,
  179. fieldUtil: FieldUtil,
  180. Language: Language,
  181. modal1Open: false,
  182. modal1Component: null,
  183. processReportResult: {},
  184. modal: false,
  185. titleModal: false,
  186. tabButtonModel:{},
  187. };
  188. },
  189. computed: {
  190. modelDataCopy: function () {
  191. return JSON.parse(JSON.stringify(this.modelData));
  192. },
  193. isSelected: {
  194. get: function () {
  195. return this.modelData.select == true;
  196. },
  197. set: function () {
  198. },
  199. },
  200. /**
  201. * 获取报警颜色
  202. */
  203. warningColor: function () {
  204. if (this.modelData.data['warningColor'] != undefined && this.modelData.data['warningColor'].displayValue.length > 0) {
  205. return this.modelData.data['warningColor'].displayValue[0];
  206. } else {
  207. return 'none';
  208. }
  209. },
  210. /**
  211. * 是否显示编辑按钮
  212. */
  213. showEditButton: function () {
  214. if (this.isShowEdit == undefined || this.isShowEdit) {
  215. if (this.modelData != undefined
  216. && this.modelData.data != undefined
  217. && this.modelData.data['documentStatus'] != undefined
  218. && this.modelData.data['documentStatus'].displayValue != undefined
  219. && (this.modelData.data['documentStatus'].displayValue[0] == 'APPROVED'
  220. || this.modelData.data['documentStatus'].displayValue[0] == 'REJECTED'
  221. || this.modelData.data['documentStatus'].displayValue[0] == 'PROCESSING')) {
  222. return false;
  223. }
  224. return true;
  225. }
  226. return false;
  227. },
  228. /**
  229. * 是否显示标题行
  230. */
  231. showTabGridTitleFields: function () {
  232. if (this.tabGridTitleFields == null || this.tabGridTitleFields.length == 0) {
  233. return false;
  234. } else {
  235. return true;
  236. }
  237. },
  238. },
  239. watch: {
  240. 'parentModelData': {
  241. deep: true,
  242. handler(curVal, oldVal) {
  243. var _self = this;
  244. for (let index = 0; index < _self.tabGridFields.length; index++) {
  245. const tabGridField = _self.tabGridFields[index];
  246. let oldTabGridFieldString = JSON.stringify(tabGridField);
  247. const columnShowLogical = tabGridField.columnShowLogical;
  248. if (columnShowLogical != null && columnShowLogical.length > 0) {
  249. let functionName = tabGridField.fieldName.replace('.', '_') + '_showLogical';
  250. let executeFunction = function () {
  251. let parentCtx = new _self.getContext(_self.parentModelData);
  252. try {
  253. tabGridField.visible = _self[functionName](null, parentCtx.modelData);
  254. } catch (e) {
  255. console.error('js代码 %s 执行异常 %o', columnShowLogical, e);
  256. tabGridField.visible = true;
  257. }
  258. };
  259. if (_self[functionName] == null) {
  260. // 执行服务端的脚本
  261. const jsUrl = _self.jsUrl;
  262. if (jsUrl == null || jsUrl == undefined) {
  263. Notify.error('数据字典定义异常', '【' + tabGridField.fieldName + '】列显示逻辑的JS文件不存在,请联系管理员检查数据字典是否JS文件。', false);
  264. return;
  265. }
  266. let promise = JsUtil.dynamicLoadJsFunction(jsUrl, columnShowLogical);
  267. promise.then(dynamicFunction => {
  268. let targetFunction = dynamicFunction;
  269. if (targetFunction == null) {
  270. Notify.error('数据字典定义异常', '【' + tabGridField.fieldName + '】列显示逻辑定义异常,请联系管理员检查数据字典的定义。', false);
  271. return;
  272. }
  273. _self[functionName] = targetFunction;
  274. executeFunction();
  275. }, errorData => {
  276. console.error(errorData);
  277. });
  278. } else {
  279. executeFunction();
  280. }
  281. } else {
  282. tabGridField.visible = true;
  283. }
  284. let newTabGridFieldString = JSON.stringify(tabGridField);
  285. // bug fixed by jack 2022-01-17
  286. // 只有当数据发生改变以后,才重新设置数据,解决当子表数据量很打的时候,输入卡顿的问题。
  287. if (oldTabGridFieldString != newTabGridFieldString) {
  288. _self.tabGridFields[index] = tabGridField;
  289. }
  290. }
  291. console.log(_self.tabGridFields);
  292. },
  293. },
  294. },
  295. methods: {
  296. /**
  297. * 获取Context
  298. */
  299. getContext: Context,
  300. deleteRecord: function () {
  301. this.$emit('deleteRecord');
  302. },
  303. refreshDatas: function(){
  304. this.$emit('refreshDatas');
  305. },
  306. buttonClick: function(){
  307. Notify.error('提示', '暂不支持该组件', false);
  308. },
  309. closeModal: function(){
  310. var _self = this;
  311. _self.modal1Open.value = false;
  312. },
  313. // 改变表格行元素的编辑状态
  314. editRecord: function () {
  315. this.$emit('editRecord');
  316. },
  317. readRecord: function () {
  318. this.$emit('readRecord');
  319. },
  320. clickModelData: function () {
  321. this.$emit('clickModelData');
  322. },
  323. // 值发生改变
  324. valueChanged: function (newFieldValue, gridFieldItem) {
  325. var valueObject = {
  326. newFieldValue: newFieldValue,
  327. gridFieldItem: gridFieldItem,
  328. };
  329. this.$emit('valueChanged', valueObject);
  330. this.refreshSelectField(this.modelData, gridFieldItem.fieldName);
  331. },
  332. // 刷新下拉选择框keyValues
  333. refreshSelectField: function (modelData, valueChangedFieldName) {
  334. var _self = this;
  335. if (_self.tabGridFields1) {
  336. _self.tabGridFields1.forEach(function (item) {
  337. if (item.displayType == 'ListBoxEditor') {
  338. var name1 = ':' + valueChangedFieldName;
  339. var showLogical = item.showLogical;
  340. if (showLogical != undefined && showLogical.indexOf(name1) >= 0) {
  341. refresh(item);
  342. }
  343. }
  344. });
  345. }
  346. function refresh(item) {
  347. var obj = {
  348. fieldId: item.id,
  349. modelData: modelData,
  350. };
  351. console.log('GridBody RefreshField');
  352. $.ajax({
  353. url: Common.getApiURL('FieldResource/refreshField'),
  354. async: false,
  355. dataType: 'json',
  356. type: 'post',
  357. data: JSON.stringify(obj),
  358. contentType: 'application/json',
  359. beforeSend: function (request) {
  360. Common.addTokenToRequest(request);
  361. },
  362. success: function (data) {
  363. if (data != undefined) {
  364. item.keyValues = data.keyValues;
  365. }
  366. },
  367. error: function (XMLHttpRequest, textStatus, errorThrown) {
  368. Common.processException(XMLHttpRequest, textStatus, errorThrown);
  369. },
  370. });
  371. }
  372. },
  373. performValidate: function () {
  374. var validateResults = [];
  375. for (var i = 0; i < this.tabGridFields1.length; i++) {
  376. let cellId = 'cellItem' + i;
  377. if (this.$refs[cellId] && this.$refs[cellId][0]) {
  378. var result = this.$refs[cellId][0].performValidate();
  379. validateResults.push(result);
  380. }
  381. }
  382. return validateResults;
  383. },
  384. clickRecord: function () {
  385. var now = new Date().getTime();
  386. if (now - this.lastClickTime < 500) {
  387. this.readRecord();
  388. }
  389. this.lastClickTime = now;
  390. },
  391. /**
  392. * 执行Callout
  393. */
  394. executeCallout: function (gridFieldItem) {
  395. this.$emit('executeCallout', gridFieldItem);
  396. },
  397. /**
  398. * 获取字符串的哈希值
  399. * @param input
  400. */
  401. getHash: function (input) {
  402. let hash = 0;
  403. if (input.length === 0) {
  404. return hash;
  405. }
  406. for (let i = 0; i < input.length; i++) {
  407. const char = input.charCodeAt(i);
  408. hash = (hash << 5) - hash + char;
  409. hash = hash & hash; // 确保返回值是一个32位有符号整数
  410. }
  411. return Math.abs(hash).toString();
  412. },
  413. },
  414. };
  415. </script>
  416. <style scoped>
  417. .table-cell-text {
  418. overflow: hidden;
  419. text-overflow: ellipsis;
  420. white-space: nowrap;
  421. text-align: center;
  422. }
  423. /** 搜索框,自动提示表格, */
  424. .table-cell-searchwidget {
  425. position: relative;
  426. }
  427. .text-center {
  428. text-align: center;
  429. }
  430. .warning {
  431. background-color: #fcf8e3 !important;
  432. }
  433. .operation-delete {
  434. margin-left: 10px;
  435. margin-right: 5px;
  436. }
  437. .operation-edit {
  438. margin-left: 5px;
  439. margin-right: 10px;
  440. }
  441. /* 固定列 */
  442. .sticky-col {
  443. position: -webkit-sticky; /* Safari */
  444. position: sticky;
  445. left: 0;
  446. background: #fafafa;
  447. z-index: 1; /* 确保固定列在其他内容之上 */
  448. }
  449. </style>