GridBody.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  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. <Modal v-model:show="modal" :full="true">
  88. <ProcessReportResultPreview
  89. v-if="
  90. processReportResult != null &&
  91. (processReportResult.reportResults != null ||
  92. processReportResult.processResult != null)
  93. "
  94. :process-report-result="processReportResult"
  95. :pdf-only="false"
  96. :excel-only="false"
  97. />
  98. <template #header>
  99. {{ $t("lang.tabButton.executeResult") }}
  100. </template>
  101. </Modal>
  102. <Modal
  103. v-model:show="titleModal"
  104. :show-canel-button="false"
  105. :show-ok-button="false"
  106. >
  107. <template #header>
  108. {{ tabButtonModel.tipsTitle }}
  109. </template>
  110. {{ tabButtonModel.tipsContent }}
  111. <template #footer>
  112. <button type="button" class="btn btn-default" @click="titleModalClose">
  113. {{ $t("lang.tabButton.cancel") }}
  114. </button>
  115. <button type="primary" class="btn btn-default" @click="executeProcess">
  116. 确认
  117. </button>
  118. </template>
  119. </Modal>
  120. </template>
  121. <script>
  122. import WindowClientUtil from '../../resource/dictionary/WindowClientUtil.js';
  123. import FieldUtil from '../../resource/dictionary/FieldUtil.js';
  124. import CellItem from './CellItem.vue';
  125. import CellTextItem from './CellTextItem.vue';
  126. import Common from '../../common/Common.js';
  127. import Context from '../common/Context.js';
  128. import JsUtil from '../../common/JsUtil.js';
  129. import Language from '../../common/Language.js';
  130. import { Notify} from 'pc-component-v3';
  131. export default {
  132. components: {
  133. CellItem, CellTextItem,
  134. },
  135. props: {
  136. windowNo: {
  137. type: String,
  138. default: null,
  139. },
  140. tabIndex: {
  141. type: Number,
  142. default: null,
  143. },
  144. /** 表格标题字段 */
  145. tabGridTitleFields: {
  146. type: Array,
  147. default: function () {
  148. return null;
  149. },
  150. },
  151. /** 表格字段 */
  152. tabGridFields: {
  153. type: Array,
  154. default: function () {
  155. return null;
  156. },
  157. },
  158. modelData: {
  159. type: Object,
  160. default: function () {
  161. return null;
  162. },
  163. },
  164. parentModelData: {
  165. type: Object,
  166. default: function () {
  167. return null;
  168. },
  169. },
  170. className: {
  171. type: String,
  172. default: null,
  173. },
  174. isShowEdit: {
  175. type: Boolean,
  176. default: false,
  177. },
  178. scrollObject: {
  179. type: Object,
  180. default: null,
  181. },
  182. serialNumber: {
  183. type: Number,
  184. default: null,
  185. },
  186. jsUrl: {
  187. type: String,
  188. default: null,
  189. },
  190. simpleFilterParams: {
  191. type: String,
  192. default: null,
  193. },
  194. complexFilterParams: {
  195. type: Array,
  196. default: () => {
  197. return [];
  198. },
  199. },
  200. modelDatas: {
  201. type: Array,
  202. default: () => {
  203. return [];
  204. },
  205. },
  206. },
  207. emits: ['deleteRecord', 'editRecord', 'readRecord', 'clickModelData', 'executeCallout', 'valueChanged', 'refreshDatas'],
  208. data: function () {
  209. return {
  210. tabGridFields1: this.tabGridFields,
  211. lastClickTime: 0,
  212. fieldUtil: FieldUtil,
  213. Language: Language,
  214. processReportResult: {},
  215. modal: false,
  216. titleModal: false,
  217. tabButtonModel:{},
  218. };
  219. },
  220. computed: {
  221. modelDataCopy: function () {
  222. return JSON.parse(JSON.stringify(this.modelData));
  223. },
  224. isSelected: {
  225. get: function () {
  226. return this.modelData.select == true;
  227. },
  228. set: function () {
  229. },
  230. },
  231. /**
  232. * 获取报警颜色
  233. */
  234. warningColor: function () {
  235. if (this.modelData.data['warningColor'] != undefined && this.modelData.data['warningColor'].displayValue.length > 0) {
  236. return this.modelData.data['warningColor'].displayValue[0];
  237. } else {
  238. return 'none';
  239. }
  240. },
  241. /**
  242. * 是否显示编辑按钮
  243. */
  244. showEditButton: function () {
  245. if (this.isShowEdit == undefined || this.isShowEdit) {
  246. if (this.modelData != undefined
  247. && this.modelData.data != undefined
  248. && this.modelData.data['documentStatus'] != undefined
  249. && this.modelData.data['documentStatus'].displayValue != undefined
  250. && (this.modelData.data['documentStatus'].displayValue[0] == 'APPROVED'
  251. || this.modelData.data['documentStatus'].displayValue[0] == 'REJECTED'
  252. || this.modelData.data['documentStatus'].displayValue[0] == 'PROCESSING')) {
  253. return false;
  254. }
  255. return true;
  256. }
  257. return false;
  258. },
  259. /**
  260. * 是否显示标题行
  261. */
  262. showTabGridTitleFields: function () {
  263. if (this.tabGridTitleFields == null || this.tabGridTitleFields.length == 0) {
  264. return false;
  265. } else {
  266. return true;
  267. }
  268. },
  269. },
  270. watch: {
  271. 'parentModelData': {
  272. deep: true,
  273. handler(curVal, oldVal) {
  274. var _self = this;
  275. for (let index = 0; index < _self.tabGridFields.length; index++) {
  276. const tabGridField = _self.tabGridFields[index];
  277. let oldTabGridFieldString = JSON.stringify(tabGridField);
  278. const columnShowLogical = tabGridField.columnShowLogical;
  279. if (columnShowLogical != null && columnShowLogical.length > 0) {
  280. let functionName = tabGridField.fieldName.replace('.', '_') + '_showLogical';
  281. let executeFunction = function () {
  282. let parentCtx = new _self.getContext(_self.parentModelData);
  283. try {
  284. tabGridField.visible = _self[functionName](null, parentCtx.modelData);
  285. } catch (e) {
  286. console.error('js代码 %s 执行异常 %o', columnShowLogical, e);
  287. tabGridField.visible = true;
  288. }
  289. };
  290. if (_self[functionName] == null) {
  291. // 执行服务端的脚本
  292. const jsUrl = _self.jsUrl;
  293. if (jsUrl == null || jsUrl == undefined) {
  294. Notify.error('数据字典定义异常', '【' + tabGridField.fieldName + '】列显示逻辑的JS文件不存在,请联系管理员检查数据字典是否JS文件。', false);
  295. return;
  296. }
  297. let promise = JsUtil.dynamicLoadJsFunction(jsUrl, columnShowLogical);
  298. promise.then(dynamicFunction => {
  299. let targetFunction = dynamicFunction;
  300. if (targetFunction == null) {
  301. Notify.error('数据字典定义异常', '【' + tabGridField.fieldName + '】列显示逻辑定义异常,请联系管理员检查数据字典的定义。', false);
  302. return;
  303. }
  304. _self[functionName] = targetFunction;
  305. executeFunction();
  306. }, errorData => {
  307. console.error(errorData);
  308. });
  309. } else {
  310. executeFunction();
  311. }
  312. } else {
  313. tabGridField.visible = true;
  314. }
  315. let newTabGridFieldString = JSON.stringify(tabGridField);
  316. // bug fixed by jack 2022-01-17
  317. // 只有当数据发生改变以后,才重新设置数据,解决当子表数据量很打的时候,输入卡顿的问题。
  318. if (oldTabGridFieldString != newTabGridFieldString) {
  319. _self.tabGridFields[index] = tabGridField;
  320. }
  321. }
  322. console.log(_self.tabGridFields);
  323. },
  324. },
  325. },
  326. methods: {
  327. /**
  328. * 获取Context
  329. */
  330. getContext: Context,
  331. deleteRecord: function () {
  332. this.$emit('deleteRecord');
  333. },
  334. refreshDatas: function(){
  335. this.$emit('refreshDatas');
  336. },
  337. buttonClick: function(){
  338. Notify.error('提示', '暂不支持该组件', false);
  339. },
  340. // 改变表格行元素的编辑状态
  341. editRecord: function () {
  342. this.$emit('editRecord');
  343. },
  344. readRecord: function () {
  345. this.$emit('readRecord');
  346. },
  347. clickModelData: function () {
  348. this.$emit('clickModelData');
  349. },
  350. // 值发生改变
  351. valueChanged: function (newFieldValue, gridFieldItem) {
  352. var valueObject = {
  353. newFieldValue: newFieldValue,
  354. gridFieldItem: gridFieldItem,
  355. };
  356. this.$emit('valueChanged', valueObject);
  357. this.refreshSelectField(this.modelData, gridFieldItem.fieldName);
  358. },
  359. // 刷新下拉选择框keyValues
  360. refreshSelectField: function (modelData, valueChangedFieldName) {
  361. var _self = this;
  362. if (_self.tabGridFields1) {
  363. _self.tabGridFields1.forEach(function (item) {
  364. if (item.displayType == 'ListBoxEditor') {
  365. var name1 = ':' + valueChangedFieldName;
  366. var showLogical = item.showLogical;
  367. if (showLogical != undefined && showLogical.indexOf(name1) >= 0) {
  368. refresh(item);
  369. }
  370. }
  371. });
  372. }
  373. function refresh(item) {
  374. var obj = {
  375. fieldId: item.id,
  376. modelData: modelData,
  377. };
  378. console.log('GridBody RefreshField');
  379. $.ajax({
  380. url: Common.getApiURL('FieldResource/refreshField'),
  381. async: false,
  382. dataType: 'json',
  383. type: 'post',
  384. data: JSON.stringify(obj),
  385. contentType: 'application/json',
  386. beforeSend: function (request) {
  387. Common.addTokenToRequest(request);
  388. },
  389. success: function (data) {
  390. if (data != undefined) {
  391. item.keyValues = data.keyValues;
  392. }
  393. },
  394. error: function (XMLHttpRequest, textStatus, errorThrown) {
  395. Common.processException(XMLHttpRequest, textStatus, errorThrown);
  396. },
  397. });
  398. }
  399. },
  400. performValidate: function () {
  401. var validateResults = [];
  402. for (var i = 0; i < this.tabGridFields1.length; i++) {
  403. let cellId = 'cellItem' + i;
  404. if (this.$refs[cellId] && this.$refs[cellId][0]) {
  405. var result = this.$refs[cellId][0].performValidate();
  406. validateResults.push(result);
  407. }
  408. }
  409. return validateResults;
  410. },
  411. clickRecord: function () {
  412. var now = new Date().getTime();
  413. if (now - this.lastClickTime < 500) {
  414. this.readRecord();
  415. }
  416. this.lastClickTime = now;
  417. },
  418. /**
  419. * 执行Callout
  420. */
  421. executeCallout: function (gridFieldItem) {
  422. this.$emit('executeCallout', gridFieldItem);
  423. },
  424. /**
  425. * 获取字符串的哈希值
  426. * @param input
  427. */
  428. getHash: function (input) {
  429. let hash = 0;
  430. if (input.length === 0) {
  431. return hash;
  432. }
  433. for (let i = 0; i < input.length; i++) {
  434. const char = input.charCodeAt(i);
  435. hash = (hash << 5) - hash + char;
  436. hash = hash & hash; // 确保返回值是一个32位有符号整数
  437. }
  438. return Math.abs(hash).toString();
  439. },
  440. },
  441. };
  442. </script>
  443. <style scoped>
  444. .table-cell-text {
  445. overflow: hidden;
  446. text-overflow: ellipsis;
  447. white-space: nowrap;
  448. text-align: center;
  449. }
  450. /** 搜索框,自动提示表格, */
  451. .table-cell-searchwidget {
  452. position: relative;
  453. }
  454. .text-center {
  455. text-align: center;
  456. }
  457. .warning {
  458. background-color: #fcf8e3 !important;
  459. }
  460. .operation-delete {
  461. margin-left: 10px;
  462. margin-right: 5px;
  463. }
  464. .operation-edit {
  465. margin-left: 5px;
  466. margin-right: 10px;
  467. }
  468. /* 固定列 */
  469. .sticky-col {
  470. position: -webkit-sticky; /* Safari */
  471. position: sticky;
  472. left: 0;
  473. background: #fafafa;
  474. z-index: 1; /* 确保固定列在其他内容之上 */
  475. }
  476. </style>