SubTabGridEdit.vue 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404
  1. <template>
  2. <div class="panel panel-default">
  3. <div class="panel-heading" @click="collapse = !collapse">
  4. {{ Language.getNameTrl($i18n.locale, tab) }}
  5. </div>
  6. <div v-if="!collapse" class="panel-body">
  7. <div
  8. class="grid-container"
  9. :style="{ 'padding-right': showComplexFilterPanel == true ? '360px' : '0px' }"
  10. >
  11. <div class="grid-item-row1">
  12. <SimpleFilterPanel
  13. v-model:searchText="searchText"
  14. :disabled="showComplexFilterPanel == true"
  15. :window-no="windowNo"
  16. :tab-index="tabIndex"
  17. :filter-schema="tab.filterSchema"
  18. class="m-row"
  19. @simple-search="simpleSearch"
  20. @show-complex-filter-panel="showComplexFilterPanel = true"
  21. />
  22. </div>
  23. <div class="grid-item-row2">
  24. <div class="row m-row">
  25. <div class="col-md-12 table-toolbar">
  26. <div class="btn-group toolbar-button-group-left" role="group">
  27. <button
  28. v-if="canEdit"
  29. type="button"
  30. class="btn btn-primary"
  31. @click="newModelData"
  32. >
  33. {{ $t("lang.subTabGridEdit.create") }}
  34. </button>
  35. <button
  36. v-if="canEdit"
  37. type="button"
  38. class="btn btn-danger"
  39. @click="deleteRecords(true)"
  40. >
  41. {{ $t("lang.subTabGridEdit.remove") }}
  42. </button>
  43. <button
  44. v-if="canEdit"
  45. type="button"
  46. class="btn btn-info"
  47. @click="queryGridData"
  48. >
  49. {{ $t("lang.subTabGridEdit.revert") }}
  50. </button>
  51. <button
  52. v-if="canEdit"
  53. type="button"
  54. class="btn btn-primary"
  55. @click="editAllTabData"
  56. >
  57. {{ $t("lang.subTabGridEdit.editAll") }}
  58. </button>
  59. <button type="button" class="btn btn-default" @click="queryGridData">
  60. {{ $t("lang.subTabGridEdit.refresh") }}
  61. </button>
  62. <TabButton
  63. :show-tab-dto="tab"
  64. :model-datas="modelDatas"
  65. :parent-model-data="parentModelData"
  66. :uuid="uuid"
  67. :view-type="'Grid'"
  68. :tab-buttons="tab.tabGridView ? tab.tabGridView.tabButtons : null"
  69. @save-view="$emit('saveView')"
  70. @process-execute-finish="refreshParent"
  71. />
  72. <GridColumnDef
  73. :tab-grid-fields="tabGridFields"
  74. :window-no="windowNo"
  75. :tab-index="tabIndex"
  76. @property-changed="propertyChanged($event)"
  77. />
  78. </div>
  79. </div>
  80. </div>
  81. </div>
  82. <div class="grid-item-row3-column1">
  83. <div class="row">
  84. <div
  85. :id="scrollObject.tableOutDivUuid1"
  86. ref="tableContainer1"
  87. class="col-md-12"
  88. >
  89. <div :id="scrollObject.tableOutDivUuid2" ref="tableContainer2">
  90. <table
  91. id="fixedTbody"
  92. class="fixed-table table-striped table-bordered float-table"
  93. :width="tableWidth"
  94. >
  95. <thead>
  96. <GridHeader
  97. :is-show-edit="canEdit"
  98. :tab-grid-fields="tabGridFields"
  99. :window-no="windowNo"
  100. :tab-index="tabIndex"
  101. :parent-model-data="parentModelDataClone"
  102. :is-chinese-english="isChineseEnglish"
  103. height="40px"
  104. @on-sort="onSort($event)"
  105. @property-changed="propertyChanged($event)"
  106. @select-all="selectAll($event)"
  107. @multiple-select="changeSelectMode($event)"
  108. />
  109. </thead>
  110. <tfoot>
  111. <GridFooter
  112. v-for="index in [1, 2, 3]"
  113. :key="'footer' + index"
  114. :tab-grid-fields="tabGridFields"
  115. :is-show-edit="canEdit"
  116. height="40px"
  117. />
  118. </tfoot>
  119. <tbody>
  120. <template v-for="(modelData, index) in modelDatas">
  121. <GridBody
  122. v-if="modelData.deleted != true && modelData.visible == true"
  123. ref="gridBody1"
  124. :key="modelData.id + '_' + index"
  125. :is-show-edit="canEdit"
  126. :serial-number="
  127. index + 1 + (pagination.current_page - 1) * pagination.per_page
  128. "
  129. :window-no="windowNo"
  130. :tab-index="tabIndex"
  131. :tab-grid-fields="tabGridFields"
  132. :model-data="modelData"
  133. :parent-model-data="parentModelDataClone"
  134. height="40px"
  135. :class-name="tab.tabDataSource.className"
  136. :scroll-object="scrollObject"
  137. :js-url="jsUrl"
  138. @delete-record="deleteRecord(modelData, true)"
  139. @edit-record="editRecord(modelData, tabGridFields)"
  140. @click-model-data="clickModelData(modelData)"
  141. @value-changed="valueChanged($event, modelData, index)"
  142. @execute-callout="executeCallout($event, modelData, index)"
  143. />
  144. </template>
  145. </tbody>
  146. </table>
  147. </div>
  148. </div>
  149. </div>
  150. </div>
  151. <div
  152. v-if="tab != null && tab.filterSchema != null"
  153. class="grid-item-row3-column2"
  154. >
  155. <div
  156. style="
  157. position: relative;
  158. top: 50%;
  159. transform: translateY(-50%);
  160. cursor: pointer;
  161. user-select: none;
  162. "
  163. @click="showComplexFilterPanel = !showComplexFilterPanel"
  164. >
  165. <span
  166. class="glyphicon glyphicon-chevron-left"
  167. :class="{
  168. 'glyphicon-chevron-left': showComplexFilterPanel == false,
  169. 'glyphicon-chevron-right': showComplexFilterPanel == true,
  170. }"
  171. aria-hidden="true"
  172. />
  173. </div>
  174. </div>
  175. <a-drawer
  176. v-model:visible="showComplexFilterPanel"
  177. :title="$t('lang.subTabGridEdit.advancedSearch')"
  178. :width="400"
  179. :footer-style="{ textAlign: 'right' }"
  180. :mask="false"
  181. :mask-closable="false"
  182. @close="showComplexFilterPanel = false"
  183. >
  184. <ComplexFilterPanel
  185. ref="complexFilterPanel"
  186. :key="'complex-filter-panel-' + windowNo + '-' + tabIndex"
  187. :window-no="windowNo"
  188. :tab-index="tabIndex"
  189. :filter-schema="tab.filterSchema"
  190. @complex-search="advancedSearchOk"
  191. />
  192. </a-drawer>
  193. <div class="grid-item-row4">
  194. <div class="row" style="margin-top: 10px">
  195. <div class="col-md-12">
  196. <div class="pull-left">
  197. <span>{{ $t("lang.subTabGridEdit.the") }}
  198. <a class="a-audit" @click="auditData">{{ (pagination.current_page - 1) * pagination.per_page + 1 }}-{{
  199. pagination.current_page * pagination.per_page
  200. }}</a>
  201. {{ $t("lang.subTabGridEdit.strip") }},{{ $t("lang.subTabGridEdit.total") }}
  202. {{ pagination.total }} {{ $t("lang.subTabGridEdit.strip") }},{{ $t("lang.subTabGridEdit.displayOnEachPage") }}</span>
  203. <PageSizeSelect @page-size-changed="gridSizeSelect" />
  204. <span>{{ $t("lang.subTabGridEdit.strip") }}</span>
  205. </div>
  206. <div class="pull-right">
  207. <VueBootstrapPagination
  208. :pagination="pagination"
  209. :callback="queryGridData"
  210. />
  211. </div>
  212. </div>
  213. </div>
  214. </div>
  215. </div>
  216. <template v-if="tab.subTabs != undefined">
  217. <div v-for="(subTab, index) in tab.subTabs" :key="'sub-tab-' + index" class="row">
  218. <div class="col-md-12">
  219. <SubTabGridEdit
  220. :ref="'subTab' + subTab.tabIndex"
  221. :is-show-edit="canEdit"
  222. :tab="subTab"
  223. :parent-model-data="selectModelData"
  224. :parent-tab="tab"
  225. :window-no="windowNo"
  226. :tab-index="subTab.tabIndex"
  227. @save-view="$emit('saveView')"
  228. @save-record-event="saveRecordEvent"
  229. @refresh-parent="refreshParent"
  230. @property-changed="propertyChanged"
  231. />
  232. </div>
  233. </div>
  234. </template>
  235. <Modal v-model:show="modal" @ok="saveRecord" @cancel="discardChildChangedData">
  236. <template #header> 请选择 </template>
  237. <div>您修改了子表格的数据,请先‘保存’数据,或者点击‘取消’按钮。</div>
  238. </Modal>
  239. <Modal v-model:show="modal1">
  240. <template #header> 无父页签/父表格的数据 </template>
  241. <div>请先选择父页签/父表格的数据</div>
  242. </Modal>
  243. <Modal v-model:show="modal3">
  244. <template #header> 数据校验失败 </template>
  245. <div>子表格的数据存在必填字段没有填写</div>
  246. </Modal>
  247. </div>
  248. <Modal
  249. v-model:show="modal2"
  250. :large="true"
  251. @ok="showAuditPanel = false"
  252. @cancel="showAuditPanel = false"
  253. >
  254. <template #header>
  255. 记录信息{{ currIndex }}/{{ pagination.total }} - {{ tab.name }}
  256. </template>
  257. <TabAudit v-if="showAuditPanel" :tab="tab" :model-data="auditModelData" />
  258. </Modal>
  259. <Loading v-if="loading" />
  260. </div>
  261. </template>
  262. <script>
  263. import Common from '../../common/Common.js';
  264. import FieldUtil from '../../resource/dictionary/FieldUtil.js';
  265. import WindowClientUtil from '../../resource/dictionary/WindowClientUtil.js';
  266. import WindowServerUtil from '../../resource/dictionary/WindowServerUtil.js';
  267. import ProcessReportResource from '../../api/dic/ProcessReportResource.js';
  268. import CurdWindowEditResource from '../../api/dic/CurdWindowEditResource.js';
  269. import Context from '../common/Context.js';
  270. import Language from '../../common/Language.js';
  271. import SimpleFilterPanel from '../filter/SimpleFilterPanel.vue';
  272. import GridHeader from '../tabGridView/GridHeader.vue';
  273. import GridBody from '../tabGridView/GridBody.vue';
  274. import GridFooter from '../tabGridView/GridFooter.vue';
  275. import GridColumnDef from '../tabGridView/GridColumnDef.vue';
  276. import GridColumnDefUtil from '../tabGridView/GridColumnDef.js';
  277. import TabButton from '../tabView/TabButton.vue';
  278. import TabAudit from '../tabView/TabAudit.vue';
  279. import ComplexFilterPanel from '../filter/ComplexFilterPanel.vue';
  280. import JsUtil from '../../common/JsUtil.js';
  281. import { Notify, Uuid } from 'pc-component-v3';
  282. export default {
  283. name: 'SubTabGridEdit',
  284. components: {
  285. TabButton,
  286. GridHeader,
  287. GridBody,
  288. GridFooter,
  289. GridColumnDef,
  290. TabAudit,
  291. SimpleFilterPanel,
  292. ComplexFilterPanel,
  293. },
  294. props: {
  295. windowNo: {
  296. type: String,
  297. default: null,
  298. },
  299. tabIndex: {
  300. type: Number,
  301. default: null,
  302. },
  303. tab: {
  304. type: Object,
  305. default: function () {
  306. return null;
  307. },
  308. },
  309. parentTab: {
  310. type: Object,
  311. default: function () {
  312. return null;
  313. },
  314. },
  315. parentModelData: {
  316. type: Object,
  317. default: function () {
  318. return null;
  319. },
  320. },
  321. isShowEdit: {
  322. type: Boolean,
  323. default: null,
  324. },
  325. jsUrl: {
  326. type: String,
  327. default: null,
  328. },
  329. isChineseEnglish: {
  330. type: Boolean,
  331. default: null,
  332. },
  333. },
  334. emits: ['saveView', 'changeRootParentModelData', 'saveRecordEvent', 'propertyChanged'],
  335. data: function () {
  336. this.Language = Language;
  337. return {
  338. tabGridFields: WindowClientUtil.getGridField(this.tab), //字段
  339. modelDatas: [],
  340. collapse: false,
  341. pagination: {
  342. total: 0,
  343. per_page: Common.pageSize, // required
  344. current_page: 1, // required
  345. last_page: 5, // required
  346. },
  347. sortStr: '', // 排序
  348. selectModelData: {}, // 当前选择的ModelData
  349. prepareSelectModelData: {}, // 选中ModelData,未生效前的数据
  350. sortStyle: ' ASC', //排列方式
  351. uuid: Uuid.createUUID(), // 创建UUID
  352. scrollObject: {
  353. // 表格滚动
  354. tableOutDivUuid1: Uuid.createUUID(), // table 的 uuid
  355. tableOutDivUuid2: Uuid.createUUID(), // table 外部 DIV 的 uuid
  356. },
  357. multipleSelect: true,
  358. showAuditPanel: false,
  359. auditModelData: {},
  360. currIndex: 0,
  361. showComplexFilterPanel: false, // 是否显示复杂查询面板
  362. parentModelDataClone: null,
  363. loading: false,
  364. modal: false,
  365. modal1: false,
  366. modal2: false,
  367. modal3: false,
  368. searchText: '', // 简单过滤条件
  369. };
  370. },
  371. computed: {
  372. tableWidth: function () {
  373. // 第一列和第二列
  374. var totalWidth = 30 + 95;
  375. if (this.tabGridFields != null && this.tabGridFields.length != 0) {
  376. this.tabGridFields.forEach(function (gridFieldItem) {
  377. // 列显示的时候才计算宽度
  378. if (gridFieldItem.visible) {
  379. totalWidth += Number(gridFieldItem.width);
  380. }
  381. });
  382. }
  383. return totalWidth + 'px';
  384. },
  385. /**
  386. * 表格是否可编辑
  387. * @return
  388. */
  389. canEdit: function () {
  390. if (this.isShowEdit == false) {
  391. return false;
  392. }
  393. if (
  394. this.tab != undefined &&
  395. this.tab.tabDataSource != null &&
  396. this.tab.tabDataSource.readOnly == false
  397. ) {
  398. return true;
  399. }
  400. return false;
  401. },
  402. parentModelDataStringCopy() {
  403. return JSON.stringify(this.parentModelData);
  404. },
  405. },
  406. watch: {
  407. parentModelDataStringCopy: {
  408. handler: function (newValue, oldValue) {
  409. if (newValue != oldValue) {
  410. this.parentModelDataClone = JSON.parse(newValue);
  411. }
  412. },
  413. deep: true,
  414. },
  415. // 监控父页签的数据,如果父页签的数据发生改变,则更新列表
  416. parentModelData: {
  417. handler: function (newValue, oldValue) {
  418. let needQuery = true;
  419. console.log(newValue);
  420. if (newValue != null && newValue.restore == true) {
  421. needQuery = false;
  422. }
  423. if (needQuery) {
  424. this.$nextTick(function () {
  425. this.queryGridData();
  426. });
  427. }
  428. },
  429. immediate: true,
  430. },
  431. showComplexFilterPanel: function (newValue, oldValue) {
  432. localStorage.setItem('showComplexFilterPanel', newValue ? 'true' : 'false');
  433. },
  434. },
  435. mounted: function () {
  436. var _self = this;
  437. console.log('SubTabGridEdit mounted.');
  438. this.tabGridFields = WindowClientUtil.getGridField(this.tab);
  439. GridColumnDefUtil.restoreTabGridFieldDef(
  440. this.windowNo,
  441. this.tabIndex,
  442. this.tabGridFields,
  443. );
  444. _self.showComplexFilterPanel =
  445. localStorage.getItem('showComplexFilterPanel') == 'true';
  446. },
  447. methods: {
  448. getContext: Context,
  449. auditData: function () {
  450. var _self = this;
  451. var selectedDatas = [];
  452. _self.modelDatas.forEach(function (modelData) {
  453. if (modelData.select == true) {
  454. selectedDatas.push(modelData);
  455. }
  456. });
  457. if (selectedDatas.length == 0 || selectedDatas.length > 1) {
  458. Notify.error(_self.$t('lang.Notify.error'), _self.$t('lang.subTabGridEdit.describe1'), true);
  459. } else {
  460. _self.auditModelData = selectedDatas[0];
  461. var index = _self.modelDatas.indexOf(_self.auditModelData);
  462. if (index < 0) {
  463. index = 1;
  464. }
  465. _self.currIndex =
  466. (_self.pagination.current_page - 1) * _self.pagination.per_page + 1 + index;
  467. _self.showAuditPanel = true;
  468. _self.modal2 = true;
  469. }
  470. },
  471. // 改变多选/单选
  472. changeSelectMode: function (val) {
  473. this.multipleSelect = val;
  474. },
  475. newModelData: function () {
  476. var _self = this;
  477. // 如果 parentModelData 无数据,则不允许新建
  478. if (this.parentModelData == undefined || this.parentModelData.id == undefined) {
  479. this.modal1 = true;
  480. } else {
  481. _self.loading = true;
  482. WindowServerUtil.newModelData(
  483. _self.windowNo,
  484. _self.tabIndex,
  485. function (modelData) {
  486. modelData.editMode = true;
  487. modelData.visible = true;
  488. modelData.tabIndex = _self.tabIndex;
  489. modelData.changed = true;
  490. _self.loading = false;
  491. _self.modelDatas[_self.modelDatas.length] = modelData;
  492. },
  493. function () {
  494. _self.loading = false;
  495. },
  496. );
  497. }
  498. },
  499. /**
  500. * 将fieldValue添加到新的modelData中
  501. * @param {Object} fieldName
  502. * @param {Object} fieldValue
  503. */
  504. newModelDataFieldValue: function (fieldName, fieldValue) {
  505. var _self = this;
  506. // 如果 parentModelData 无数据,则不允许新建
  507. if (this.parentModelData == undefined || this.parentModelData.id == undefined) {
  508. this.modal1 = true;
  509. } else {
  510. _self.loading = true;
  511. WindowServerUtil.newModelData(
  512. _self.windowNo,
  513. _self.tabIndex,
  514. function (modelData) {
  515. modelData.editMode = true;
  516. modelData.visible = true;
  517. modelData.tabIndex = _self.tabIndex;
  518. modelData.data[fieldName] = fieldValue;
  519. _self.loading = false;
  520. _self.modelDatas[_self.modelDatas.length] = modelData;
  521. },
  522. function () {
  523. _self.loading = false;
  524. },
  525. );
  526. }
  527. },
  528. gridSizeSelect: function (newPageSize) {
  529. this.pagination.per_page = newPageSize;
  530. this.pagination.current_page = 1;
  531. // 刷新界面
  532. // this.queryGridData();
  533. },
  534. // 改变表格行元素的编辑状态
  535. editRecord: function (modelData, fieldItems) {
  536. if (modelData.visible == null) {
  537. modelData.visible = true;
  538. }
  539. if (modelData.editMode == undefined) {
  540. modelData.editMode = true;
  541. } else {
  542. var flag = true;
  543. if (modelData.editMode == true && fieldItems) {
  544. fieldItems.forEach(function (fieldItem) {
  545. if (fieldItem.mandatory == true) {
  546. if (
  547. FieldUtil.isSelectType(fieldItem) ||
  548. FieldUtil.isSearchType(fieldItem)
  549. ) {
  550. var idValue =
  551. modelData.data == undefined ||
  552. modelData.data[fieldItem.fieldName] == undefined
  553. ? undefined
  554. : modelData.data[fieldItem.fieldName].id;
  555. if (idValue == undefined || idValue == '' || idValue < 1) {
  556. flag = false;
  557. }
  558. } else {
  559. var stringValue =
  560. modelData.data == undefined ||
  561. modelData.data[fieldItem.fieldName] == undefined
  562. ? ''
  563. : modelData.data[fieldItem.fieldName].displayValue[0];
  564. if (stringValue == undefined || stringValue === '') {
  565. flag = false;
  566. }
  567. }
  568. }
  569. });
  570. if (!flag) {
  571. this.modal3 = true;
  572. return;
  573. }
  574. }
  575. modelData.editMode = !modelData.editMode;
  576. }
  577. modelData.changed = true;
  578. var index = this.modelDatas.indexOf(modelData);
  579. if (index != -1) {
  580. this.modelDatas[index] = modelData;
  581. }
  582. },
  583. // 值改变事件
  584. valueChanged: function (event, modelData, index) {
  585. var _self = this;
  586. var gridFieldItem = event.gridFieldItem;
  587. var newFieldValue = event.newFieldValue;
  588. var oldFieldValue = modelData.data[gridFieldItem.fieldName];
  589. if (FieldUtil.isFieldValueEqual(newFieldValue, oldFieldValue) == false) {
  590. modelData.data[gridFieldItem.fieldName] = newFieldValue;
  591. // modelData.data[gridFieldItem.fieldName] = newFieldValue;
  592. if (
  593. gridFieldItem.calloutProcessReportNo != undefined &&
  594. gridFieldItem.calloutProcessReportNo != null
  595. ) {
  596. _self.callout(gridFieldItem.calloutProcessReportNo, modelData, index);
  597. }
  598. if (
  599. gridFieldItem.calloutLogical != undefined &&
  600. gridFieldItem.calloutLogical != null &&
  601. gridFieldItem.calloutLogical != ''
  602. ) {
  603. _self.executeCalloutJs(gridFieldItem, gridFieldItem.calloutLogical, modelData);
  604. }
  605. // 遍历所有的字段,判断是否有动态约束
  606. // 如果有关联的动态约束,则清空字段
  607. var fieldName0 = gridFieldItem.fieldName;
  608. _self.tabGridFields.forEach(function (item) {
  609. var fieldName1 = item.fieldName;
  610. var dynamicValidFields = item.dynamicValidFields;
  611. if (
  612. fieldName0 != fieldName1 &&
  613. dynamicValidFields != undefined &&
  614. dynamicValidFields.indexOf(fieldName0) >= 0
  615. ) {
  616. modelData.data[fieldName1].id = undefined;
  617. if (modelData.data[fieldName1].displayValue != undefined) {
  618. modelData.data[fieldName1].displayValue.splice(
  619. 0,
  620. modelData.data[fieldName1].displayValue.length,
  621. );
  622. } else {
  623. modelData.data[fieldName1].displayValue = [];
  624. }
  625. _self.modelDatas[index] = modelData;
  626. }
  627. });
  628. }
  629. },
  630. /**
  631. * 执行JS Callout
  632. */
  633. executeCalloutJs: function (gridFieldItem, scriptText, modelData) {
  634. var _self = this;
  635. let functionName = gridFieldItem.fieldName.replace('.', '_') + '_calloutjs';
  636. let exeuteFunction = function(){
  637. let actions = {
  638. changeParentModelData: _self.changeParentModelData,
  639. modelDatas: _self.modelDatas,
  640. };
  641. let context = new _self.getContext(modelData, actions);
  642. try {
  643. _self[functionName](context);
  644. } catch (error) {
  645. console.error(error);
  646. Notify.error(
  647. '数据字典定义异常',
  648. '【' +
  649. scriptText +
  650. '】Callout前端逻辑定义异常,请联系管理员检查数据字典的定义。',
  651. false,
  652. );
  653. }
  654. };
  655. if (_self[functionName] == null) {
  656. // 执行服务端的脚本
  657. const jsUrl = _self.jsUrl;
  658. if (jsUrl == null || jsUrl == undefined) {
  659. Notify.error(
  660. '数据字典定义异常',
  661. '【' +
  662. scriptText +
  663. '】Callout前端逻辑的JS文件不存在,请联系管理员检查数据字典是否存在JS文件。',
  664. false,
  665. );
  666. return;
  667. }
  668. let promise = JsUtil.dynamicLoadJsFunction(jsUrl, scriptText);
  669. promise.then(
  670. targetFunction => {
  671. if (targetFunction == null) {
  672. Notify.error(
  673. '数据字典定义异常',
  674. '【' +
  675. scriptText +
  676. '】Callout前端逻辑定义异常,请联系管理员检查数据字典的定义。',
  677. false,
  678. );
  679. return;
  680. }
  681. _self[functionName] = targetFunction;
  682. exeuteFunction();
  683. },
  684. errorData => {
  685. console.error(errorData);
  686. },
  687. );
  688. } else {
  689. exeuteFunction();
  690. }
  691. },
  692. /**
  693. * 修改父页签的数据
  694. */
  695. changeParentModelData: function (fieldName, fieldValue) {
  696. let param = {
  697. fieldName: fieldName,
  698. fieldValue: fieldValue,
  699. };
  700. this.$emit('changeRootParentModelData', param);
  701. },
  702. /**
  703. * callout
  704. * @param {[type]} calloutProcessReportNo [description]
  705. * @return {[type]} [description]
  706. */
  707. callout: function (calloutProcessReportNo, modelData, index) {
  708. var _self = this;
  709. _self.loading = true;
  710. // 查询流程和报表的定义
  711. ProcessReportResource.uniqueByNo(calloutProcessReportNo).then(
  712. successData => {
  713. if (successData == null) {
  714. return;
  715. }
  716. // 执行服务端的脚本
  717. ProcessReportResource.runCallout(calloutProcessReportNo, modelData).then(
  718. successData => {
  719. if (successData && successData.modelData) {
  720. var newModelData = successData.modelData;
  721. newModelData.editMode = modelData.editMode;
  722. newModelData.visible = modelData.visible;
  723. _self.modelDatas[index] = newModelData;
  724. }
  725. _self.loading = false;
  726. },
  727. errorData => {
  728. _self.loading = false;
  729. Common.processException(errorData);
  730. },
  731. );
  732. },
  733. errorData => {
  734. _self.loading = false;
  735. Common.processException(errorData);
  736. },
  737. );
  738. },
  739. /**
  740. * 获取子页签所有的数据
  741. */
  742. getAllModelData: function () {
  743. var _self = this;
  744. // 发生改变的modelData
  745. var allModelDatas = [];
  746. this.modelDatas.forEach(function (tempModelData) {
  747. allModelDatas.push(tempModelData);
  748. });
  749. return allModelDatas;
  750. },
  751. // 获取发生改变的数据
  752. getChangedModelData: function () {
  753. var _self = this;
  754. // 发生改变的modelData
  755. var changedModelDatas = [];
  756. this.modelDatas.forEach(function (tempModelData) {
  757. if (tempModelData === _self.selectModelData) {
  758. var subTabChangedData = _self.getSubTabChangedData();
  759. if (subTabChangedData.length > 0) {
  760. tempModelData.changed = true;
  761. tempModelData.saveDatas = subTabChangedData;
  762. } else {
  763. tempModelData.saveDatas = null;
  764. }
  765. }
  766. if (tempModelData.changed == true) {
  767. changedModelDatas.push(tempModelData);
  768. }
  769. });
  770. return changedModelDatas;
  771. },
  772. // 获取子页签发生改变的数据
  773. getSubTabChangedData: function () {
  774. var subTabChangedRecords = [];
  775. if (this.tab.subTabs != undefined) {
  776. for (var index = 0; index < this.tab.subTabs.length; index++) {
  777. var subTabId = 'subTab' + this.tab.subTabs[index].tabIndex;
  778. var modelDatas = this.$refs[subTabId][0].getChangedModelData();
  779. if (modelDatas != undefined && modelDatas.length > 0) {
  780. modelDatas.forEach(function (modelData) {
  781. subTabChangedRecords.push(modelData);
  782. });
  783. }
  784. }
  785. }
  786. return subTabChangedRecords;
  787. },
  788. // 删除数据
  789. deleteRecord: function (modelData, isAlert) {
  790. var _self = this;
  791. var index = this.modelDatas.indexOf(modelData);
  792. if (index == -1) {
  793. return;
  794. }
  795. if (isAlert) {
  796. // 获取数据改动的数量
  797. var changedCount = 0;
  798. for (var i = 0, len = _self.modelDatas.length; i < len; i++) {
  799. if (_self.modelDatas[i].changed == true) {
  800. changedCount++;
  801. }
  802. }
  803. var message = '';
  804. if (changedCount > 0) {
  805. message = _self.$t('lang.subTabGridEdit.describe2',{changedCount:changedCount});
  806. }
  807. message =
  808. message +
  809. _self.$t('lang.subTabGridEdit.someWhatThree');
  810. Notify.show({
  811. title:_self.$t('lang.subTabGridEdit.deleteConfirmation'),
  812. message: message,
  813. buttons: [
  814. {
  815. label: _self.$t('lang.subTabGridEdit.determine'),
  816. cssClass: 'btn-primary',
  817. action: function (dialogItself) {
  818. dialogItself.close();
  819. _self.deleteRecord(modelData, false);
  820. },
  821. },
  822. {
  823. label: _self.$t('lang.subTabGridEdit.cancel'),
  824. action: function (dialogItself) {
  825. dialogItself.close();
  826. },
  827. },
  828. ],
  829. });
  830. return;
  831. }
  832. if (modelData.id < 0) {
  833. this.modelDatas.splice(index, 1);
  834. return;
  835. }
  836. modelData.deleted = true;
  837. modelData.changed = true;
  838. },
  839. // 删除选择的数据(多删)
  840. deleteRecords: function (isAlert) {
  841. var _self = this;
  842. // 待删除的数据集合
  843. var dataPrepareDelete = [];
  844. _self.modelDatas.forEach(function (modelData) {
  845. if (modelData.select == true) {
  846. dataPrepareDelete.push(modelData);
  847. }
  848. });
  849. if (dataPrepareDelete.length == 0) {
  850. Notify.error(_self.$t('lang.subTabGridEdit.noDataSelected'), _self.$t('lang.subTabGridEdit.describe3'), false);
  851. return;
  852. }
  853. if (isAlert) {
  854. Notify.show({
  855. title: _self.$t('lang.subTabGridEdit.deleteConfirmation'),
  856. message:
  857. _self.$t('lang.subTabGridEdit.someWhatOne') +
  858. dataPrepareDelete.length +
  859. _self.$t('lang.subTabGridEdit.someWhatTwo'),
  860. buttons: [
  861. {
  862. label:_self.$t('lang.subTabGridEdit.determine'),
  863. cssClass: 'btn-primary',
  864. action: function (dialogItself) {
  865. dialogItself.close();
  866. _self.deleteRecords(false);
  867. },
  868. },
  869. {
  870. label: _self.$t('lang.subTabGridEdit.cancel'),
  871. action: function (dialogItself) {
  872. dialogItself.close();
  873. },
  874. },
  875. ],
  876. });
  877. return;
  878. }
  879. for (var index = 0; index < dataPrepareDelete.length; index++) {
  880. if (dataPrepareDelete[index].id < 0) {
  881. var index1 = _self.modelDatas.indexOf(dataPrepareDelete[index]);
  882. if (index1 >= 0) {
  883. _self.modelDatas.splice(index1, 1);
  884. }
  885. } else {
  886. dataPrepareDelete[index].deleted = true;
  887. dataPrepareDelete[index].changed = true;
  888. }
  889. }
  890. },
  891. /**
  892. * 子页签触发父页签刷新
  893. * @return {[type]} [description]
  894. */
  895. refreshParent: function () {
  896. var _self = this;
  897. // _self.queryGridData();
  898. _self.$emit('processExecuteFinish');
  899. },
  900. // 根据查询参数获取数据模型
  901. queryGridData: function () {
  902. var _self = this;
  903. // 如果没有父页签的数据,则清空界面
  904. if (_self.parentModelData == undefined || _self.parentModelData.id == undefined) {
  905. _self.modelDatas.splice(0, _self.modelDatas.length);
  906. _self.selectModelData = {};
  907. return;
  908. }
  909. // 简单过滤条件
  910. // 简单过滤条件
  911. let simpleFilterCondition = null;
  912. let filterParams = null;
  913. if (_self.showComplexFilterPanel == true) {
  914. if (_self.$refs.complexFilterPanel != null) {
  915. filterParams = _self.$refs.complexFilterPanel.getFilterParams();
  916. }
  917. } else {
  918. simpleFilterCondition = _self.searchText;
  919. }
  920. // 首先判断是否有未保存的数据
  921. // 如果有未保存的数据,则不能从服务器上进行查询
  922. for (let row = 0, len = _self.modelDatas.length; row < len; row++) {
  923. let rowData = _self.modelDatas[row];
  924. if (rowData.id < 0 && rowData.deleted != true) {
  925. // 数据未保存,且未删除
  926. let rowDataStr = JSON.stringify(rowData);
  927. if (rowDataStr.indexOf(simpleFilterCondition) >= 0) {
  928. rowData.visible = true;
  929. } else {
  930. rowData.visible = false;
  931. }
  932. }
  933. // 如果表格数据已经保存过了,那么直接移除掉。
  934. if (rowData.id > 0) {
  935. _self.modelDatas.splice(row, 1);
  936. row--;
  937. len--;
  938. }
  939. }
  940. var tabQueryParam = {
  941. range: {
  942. start: (_self.pagination.current_page - 1) * _self.pagination.per_page,
  943. length: _self.pagination.per_page,
  944. },
  945. windowNo: _self.windowNo,
  946. tabIndex: _self.tabIndex,
  947. parentColumnId:
  948. _self.parentModelData == undefined ? undefined : _self.parentModelData.id,
  949. filterParams: filterParams,
  950. simpleFilterCondition: simpleFilterCondition,
  951. sortStr: _self.sortStr,
  952. isHasWorkflow: true,
  953. };
  954. $.ajax({
  955. url: Common.getApiURL('CurdWindowResource/tabData'),
  956. type: 'post',
  957. contentType: 'application/json',
  958. data: JSON.stringify(tabQueryParam),
  959. beforeSend: function (request) {
  960. Common.addTokenToRequest(request);
  961. },
  962. success: function (data) {
  963. var modelDatas = data.dataList;
  964. WindowClientUtil.setViewDisplayAttribute(modelDatas, 'editMode', false);
  965. WindowClientUtil.setViewDisplayAttribute(modelDatas, 'select', false);
  966. WindowClientUtil.setViewDisplayAttribute(modelDatas, 'visible', true);
  967. //绑定数据模型信息
  968. //绑定数据模型信息
  969. modelDatas.forEach(function (modelDataItem) {
  970. _self.modelDatas.push(modelDataItem);
  971. });
  972. _self.pagination.total = data.totalSize;
  973. _self.pagination.last_page = Math.ceil(data.totalSize / data.range.length);
  974. // 恢复选定的数据
  975. if (modelDatas == undefined || modelDatas.length == 0) {
  976. _self.selectModelData = {};
  977. } else {
  978. if (
  979. _self.selectModelData != undefined &&
  980. _self.selectModelData.id != undefined
  981. ) {
  982. var lastSelectedId = _self.selectModelData.id;
  983. modelDatas.forEach(function (tempData) {
  984. if (tempData.id == lastSelectedId) {
  985. _self.selectModelData = tempData;
  986. _self.selectModelData.select = true;
  987. }
  988. });
  989. }
  990. }
  991. },
  992. error: function (XMLHttpRequest, textStatus, errorThrown) {
  993. Common.processException(XMLHttpRequest, textStatus, errorThrown);
  994. },
  995. });
  996. },
  997. // 点击了ModelData属性
  998. clickModelData: function (modelData) {
  999. var _self = this;
  1000. var currentIsSelect = modelData.select;
  1001. if (!_self.multipleSelect) {
  1002. _self.modelDatas.forEach(function (item) {
  1003. item.select = false;
  1004. });
  1005. }
  1006. _self.prepareSelectModelData = modelData;
  1007. _self.prepareSelectModelData.select = currentIsSelect;
  1008. _self.checkChildrenTabIsChanged();
  1009. },
  1010. // 检查子页签数据是否发生改变
  1011. checkChildrenTabIsChanged: function () {
  1012. // 获取子页签的数据
  1013. var changedModelDatas = this.getSubTabChangedData();
  1014. if (changedModelDatas != undefined && changedModelDatas.length > 0) {
  1015. // 弹出对话框,是否保存数据,或者放弃
  1016. // 如果点击保存数据,则触发父页签保存数据
  1017. this.modal = true;
  1018. // 如果点击放弃,则放弃页签改变的数据
  1019. } else {
  1020. // 无改变的数据
  1021. this.discardChildChangedData();
  1022. }
  1023. },
  1024. // 冒泡传递保存事件
  1025. saveRecord: function () {
  1026. this.prepareSelectModelData.changed = true;
  1027. this.prepareSelectModelData = {};
  1028. this.$emit('saveRecordEvent', this.parentModelData);
  1029. },
  1030. onSort: function (gridFieldItem) {
  1031. var _self = this;
  1032. var hasChangedModelData = _self.hasChangedModelData();
  1033. // 存在未保存的数据
  1034. if (hasChangedModelData == true) {
  1035. Notify.error(_self.$t('lang.subTabGridEdit.describe4'), _self.$t('lang.subTabGridEdit.describe5'), false);
  1036. return;
  1037. }
  1038. if (
  1039. gridFieldItem.entityFieldNames != undefined &&
  1040. gridFieldItem.entityFieldNames.length > 0
  1041. ) {
  1042. _self.sortStr =
  1043. gridFieldItem.fieldName +
  1044. '.' +
  1045. gridFieldItem.entityFieldNames[gridFieldItem.entityFieldIndex] +
  1046. _self.sortStyle;
  1047. } else {
  1048. _self.sortStr = gridFieldItem.fieldName + _self.sortStyle;
  1049. }
  1050. _self.queryGridData();
  1051. _self.sortStyle = _self.sortStyle == ' ASC' ? ' DESC' : ' ASC';
  1052. },
  1053. /**
  1054. * 判断是否存在未保存的数据
  1055. * @return {Boolean} [description]
  1056. */
  1057. hasChangedModelData: function () {
  1058. var _self = this;
  1059. // 检查是否存在未保存的数据
  1060. var hasChangedModelData = false;
  1061. for (var i = 0, len = _self.modelDatas.length; i < len; i++) {
  1062. if (_self.modelDatas[i].changed == true) {
  1063. hasChangedModelData = true;
  1064. break;
  1065. }
  1066. if (_self.modelDatas[i].id < 0) {
  1067. hasChangedModelData = true;
  1068. break;
  1069. }
  1070. }
  1071. return hasChangedModelData;
  1072. },
  1073. saveRecordEvent: function (modelData) {
  1074. modelData.changed = true;
  1075. this.$emit('saveRecordEvent', this.parentModelData);
  1076. },
  1077. // 放弃子页签修改的数据
  1078. discardChildChangedData: function () {
  1079. this.prepareSelectModelData.select = !this.prepareSelectModelData.select;
  1080. if (this.prepareSelectModelData.select) {
  1081. this.selectModelData = this.prepareSelectModelData;
  1082. } else {
  1083. this.selectModelData = {};
  1084. }
  1085. this.prepareSelectModelData = {};
  1086. },
  1087. // 显示状态发生改变
  1088. propertyChanged: function (gridFieldItem) {
  1089. GridColumnDefUtil.saveGridFieldDef(this.windowNo, this.tabIndex, gridFieldItem);
  1090. GridColumnDefUtil.restoreTabGridFieldDef(
  1091. this.windowNo,
  1092. this.tabIndex,
  1093. this.tabGridFields,
  1094. );
  1095. this.$emit('propertyChanged', gridFieldItem);
  1096. /* WindowClientUtil.gridFieldItemPropertyChanged(gridFieldItem);
  1097. this.tabGridFields.forEach(function (item) {
  1098. WindowClientUtil.restoreGridFieldItemAttr(item);
  1099. });*/
  1100. },
  1101. performValidate: function () {
  1102. var _self = this;
  1103. var validateResults = [];
  1104. if (this.$refs.gridBody1 != undefined) {
  1105. for (var i = 0; i < this.$refs.gridBody1.length; i++) {
  1106. if (_self.modelDatas[i].changed == true) {
  1107. var validateResults1 = this.$refs.gridBody1[i].performValidate();
  1108. validateResults = validateResults.concat(validateResults1);
  1109. }
  1110. }
  1111. var validateResults2 = this.getSubTabValidePromise();
  1112. validateResults = validateResults.concat(validateResults2);
  1113. }
  1114. return validateResults;
  1115. },
  1116. // 获取子页签发生改变的数据
  1117. getSubTabValidePromise: function () {
  1118. var validateResults = [];
  1119. if (this.tab.subTabs != undefined) {
  1120. for (var index = 0; index < this.tab.subTabs.length; index++) {
  1121. var subTabId = 'subTab' + this.tab.subTabs[index].tabIndex;
  1122. var validatePromises = this.$refs[subTabId][0].performValidate();
  1123. validateResults = validateResults.concat(validatePromises);
  1124. }
  1125. }
  1126. return validateResults;
  1127. },
  1128. // 添加 modelData
  1129. addModelData: function (modelData) {
  1130. // 如果 parentModelData 无数据,则不允许新建
  1131. this.modelDatas[this.modelDatas.length] = modelData;
  1132. if (modelData.saveDatas != undefined && modelData.saveDatas.length > 0) {
  1133. modelData.saveDatas.forEach(function (saveData) {
  1134. // 恢复子页签的数据
  1135. var subTabId = 'subTab' + saveData.tabIndex;
  1136. this.$refs[subTabId][0].addModelData(saveData);
  1137. });
  1138. }
  1139. },
  1140. /**
  1141. * 替换modeldatas数据
  1142. */
  1143. replaceModelDatas: function (modelDatas) {
  1144. let _self = this;
  1145. this.modelDatas.splice(0, this.modelDatas.length);
  1146. modelDatas.forEach(modelData => {
  1147. _self.addModelData(modelData);
  1148. });
  1149. },
  1150. /**
  1151. * 全选/取消全选
  1152. * @param {Boolean} val 状态
  1153. * @return {void}
  1154. */
  1155. selectAll: function (val) {
  1156. var _self = this;
  1157. if (_self.multipleSelect) {
  1158. _self.modelDatas.forEach(function (item) {
  1159. item.select = val;
  1160. });
  1161. }
  1162. },
  1163. /**
  1164. * 点击编辑全部按钮
  1165. */
  1166. editAllTabData: function () {
  1167. var _self = this;
  1168. _self.modelDatas.forEach(function (item) {
  1169. item.editMode = true;
  1170. item.changed = true;
  1171. item.visible = true;
  1172. });
  1173. },
  1174. /**
  1175. * 简单搜索
  1176. */
  1177. simpleSearch: function (filterParams) {
  1178. var _self = this;
  1179. _self.pagination.current_page = 1;
  1180. _self.queryGridData();
  1181. },
  1182. /**
  1183. * 高级搜索
  1184. */
  1185. advancedSearchOk: function () {
  1186. var _self = this;
  1187. _self.pagination.current_page = 1;
  1188. _self.queryGridData();
  1189. },
  1190. /**
  1191. * 执行Callout
  1192. */
  1193. executeCallout: function (gridFieldItem, modelData, index) {
  1194. var _self = this;
  1195. if (gridFieldItem.calloutProcessReportNo != null) {
  1196. _self.callout(gridFieldItem.calloutProcessReportNo, modelData, index);
  1197. }
  1198. },
  1199. /**
  1200. * 修改根ModelData的字段数据
  1201. * @param { String } fieldName 字段名称
  1202. * @param { com.leanwo.prodog.restful.base.model.FieldValue } fieldValue 字段的值
  1203. * @author YangZhiJie 20211012
  1204. *
  1205. */
  1206. changeRootParentModelData: function (fieldName, fieldValue) {
  1207. this.$emit('changeRootParentModelData', {
  1208. fieldName: fieldName,
  1209. fieldValue: fieldValue,
  1210. });
  1211. },
  1212. },
  1213. };
  1214. </script>
  1215. <style scoped>
  1216. .fixed-table {
  1217. table-layout: fixed;
  1218. }
  1219. .toolbar-button-group-left {
  1220. float: left;
  1221. }
  1222. .toolbar-button-group-right {
  1223. float: right;
  1224. }
  1225. .table-tr-eidt {
  1226. height: 38px;
  1227. }
  1228. .table-toolbar {
  1229. width: 100%;
  1230. }
  1231. .m-row {
  1232. margin-bottom: 15px;
  1233. }
  1234. .a-audit {
  1235. cursor: pointer;
  1236. }
  1237. th {
  1238. background-color: #f7f7f7;
  1239. }
  1240. </style>
  1241. <style scoped>
  1242. .grid-container {
  1243. margin-top: 10px;
  1244. display: grid;
  1245. grid-template-columns: auto 17px 0px;
  1246. grid-template-rows: 40px 40px auto 40px;
  1247. gap: 5px;
  1248. justify-items: stretch;
  1249. align-items: stretch;
  1250. }
  1251. .grid-item-row1 {
  1252. grid-row-start: 1;
  1253. grid-row-end: 2;
  1254. grid-column-start: 1;
  1255. grid-column-end: 4;
  1256. }
  1257. .grid-item-row2 {
  1258. grid-row-start: 2;
  1259. grid-row-end: 3;
  1260. grid-column-start: 1;
  1261. grid-column-end: 4;
  1262. }
  1263. .grid-item-row3-column1 {
  1264. grid-row-start: 3;
  1265. grid-row-end: 4;
  1266. grid-column-start: 1;
  1267. grid-column-end: 2;
  1268. overflow: auto;
  1269. }
  1270. .grid-item-row3-column2 {
  1271. grid-row-start: 3;
  1272. grid-row-end: 4;
  1273. grid-column-start: 2;
  1274. grid-column-end: 3;
  1275. overflow: hidden;
  1276. border: 1px solid #ddd;
  1277. border-radius: 4px;
  1278. }
  1279. .grid-item-row4 {
  1280. grid-row-start: 4;
  1281. grid-row-end: 5;
  1282. grid-column-start: 1;
  1283. grid-column-end: 4;
  1284. }
  1285. </style>