xm-paper-child-table.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. <template>
  2. <div :class="[$style.wrapper, $style.sdFormforxmchild]">
  3. <div v-if="captionvisiable" :class="[$style.caption]">
  4. {{ label }}
  5. <div v-if="!readOnly" :class="$style.header">
  6. <a-button v-if="findtable" type="link" :class="$style.batchselect" @click="creatnewfind">
  7. <a-icon type="plus-circle" :theme="'filled'" />
  8. 添加
  9. </a-button>
  10. <a-button
  11. v-if="evidencetable"
  12. type="link"
  13. :class="$style.btnmuban"
  14. icon="sd-plus-square"
  15. @click="createvidence"
  16. >选择
  17. </a-button>
  18. <a-button v-if="addbuttonvisiable" type="link" @click="add">
  19. <a-icon type="plus-circle" :theme="'filled'" />
  20. 添加
  21. </a-button>
  22. <a-button
  23. v-if="findtable"
  24. type="link"
  25. :disabled="selectedRowKeys.length === 0"
  26. @click="deletefindremove(selectedRowKeys)"
  27. >
  28. <a-icon type="minus-circle" :theme="'filled'" />
  29. 删除
  30. </a-button>
  31. <a-button
  32. v-if="!findtable"
  33. type="link"
  34. :disabled="selectedRowKeys.length === 0"
  35. @click="remove(selectedRowKeys)"
  36. ><a-icon type="minus-circle" :theme="'filled'" />
  37. 删除
  38. </a-button>
  39. <AuditAdvancedImport
  40. :v-if="true"
  41. :config-id="'41'"
  42. :import-fun="ImportFun"
  43. ></AuditAdvancedImport>
  44. </div>
  45. </div>
  46. <sd-table
  47. size="middle"
  48. :columns="_columns"
  49. :width="width"
  50. sortable
  51. :data-source="value"
  52. :row-key="(record, index) => index"
  53. :pagination="false"
  54. :row-selection="
  55. readOnly
  56. ? null
  57. : {
  58. getCheckboxProps(record) {
  59. return {
  60. props: { disabled: !showSelection(record) },
  61. }
  62. },
  63. selectedRowKeys: selectedRowKeys,
  64. onChange: onSelectChange,
  65. }
  66. "
  67. :custom-row="
  68. (record, index) => {
  69. return {
  70. on: {
  71. click: () => {
  72. edit(index)
  73. },
  74. },
  75. }
  76. }
  77. "
  78. @update:data-source="($event) => $emit('change', $event)"
  79. >
  80. <div slot="sd_opt" slot-scope="text, record, index" :class="$style.operatecol">
  81. <span v-if="value[index].editable">
  82. <a-button
  83. v-for="(bt, indexbt) in buttonsfortable"
  84. :key="indexbt"
  85. type="link"
  86. size="small"
  87. @click="optbuttonClick(bt.id, record, index)"
  88. >{{ bt.label }}
  89. </a-button> </span
  90. ><span v-else>
  91. <a-button
  92. v-for="(bt, indexbt) in buttonssavefortable"
  93. :key="indexbt"
  94. type="link"
  95. size="small"
  96. @click="optbuttonClick(bt.id, record, index)"
  97. >{{ bt.label }}
  98. </a-button>
  99. </span>
  100. </div>
  101. <div slot="islink" slot-scope="text, record">
  102. <a :title="text" @click="rowClick(record)">{{ text }}</a>
  103. </div>
  104. <div slot="suggestionType" slot-scope="text, record">
  105. {{
  106. fields.filter((item) => item.name === 'suggestionType').length > 0
  107. ? fields
  108. .filter((item) => item.name === 'suggestionType')[0]
  109. .attr.selectListItem.filter((item) => item.value === text)[0].label
  110. : text
  111. }}
  112. </div>
  113. </sd-table>
  114. </div>
  115. </template>
  116. <script>
  117. import { Modal } from 'ant-design-vue'
  118. import crossWindowWatcher from '@/common/services/cross-window-watcher'
  119. import { getComponentSpec } from '@/common/components/sd-form'
  120. import moment from 'moment'
  121. import AuditAdvancedImport from '../../../components/audit-advanced-import'
  122. import components from './_import-components/xm-paper-child-table-import'
  123. // Vue.use(DatePicker)
  124. // Vue.use(TimePicker)
  125. /**
  126. * 主子表、动态表格字段
  127. * @displayName XmChildTable 主子表
  128. */
  129. export default {
  130. name: 'XmPaperChildTable',
  131. components: {
  132. ...components,
  133. AuditAdvancedImport,
  134. },
  135. model: {
  136. prop: 'value',
  137. event: 'change',
  138. },
  139. props: {
  140. mode: {
  141. type: String,
  142. default: '',
  143. },
  144. projectId: {
  145. type: String,
  146. default: '',
  147. },
  148. /**
  149. * 字表的值,{key:value}的格式
  150. */
  151. value: {
  152. type: Array,
  153. default: () => [],
  154. },
  155. /**
  156. * 字表的字段属性
  157. */
  158. fields: {
  159. type: Array,
  160. default: () => [],
  161. },
  162. /**
  163. * 是否只读
  164. */
  165. readOnly: {
  166. type: Boolean,
  167. default: false,
  168. },
  169. /**
  170. * 标签名
  171. */
  172. label: {
  173. type: String,
  174. default: '',
  175. },
  176. /**
  177. * 自定义子表列属性,如[{dataIndex:'shuxingmingzi15',width:'120px'}],8.0.4及以后版本支持
  178. */
  179. columns: {
  180. type: Array,
  181. default: () => [],
  182. },
  183. /**
  184. * 某行是否可选
  185. * @since 8.0.11
  186. */
  187. showSelection: {
  188. type: Function,
  189. default: () => true,
  190. },
  191. width: {
  192. type: Number,
  193. default: 100,
  194. },
  195. datachange: {
  196. type: Function,
  197. default: null,
  198. },
  199. dzcl: {
  200. type: Boolean,
  201. default: false,
  202. },
  203. addfun: {
  204. type: Function,
  205. default: null,
  206. },
  207. captionvisiable: {
  208. type: Boolean,
  209. default: true,
  210. },
  211. addbuttonvisiable: {
  212. type: Boolean,
  213. default: false,
  214. },
  215. creatnewfind: {
  216. type: Function,
  217. default: null,
  218. },
  219. findtable: {
  220. type: Boolean,
  221. default: false,
  222. },
  223. createvidence: {
  224. type: Function,
  225. default: null,
  226. },
  227. evidencetable: {
  228. type: Boolean,
  229. default: false,
  230. },
  231. deletefind: {
  232. type: Function,
  233. default: null,
  234. },
  235. },
  236. data() {
  237. return {
  238. selectedRowKeys: [],
  239. visible: false,
  240. editRecord: [], // 待修改或编辑的记录
  241. attkeys: {}, // 附件组件的key,行编辑了就修改对应的附件key,强制更新附件列表
  242. savevisible: true,
  243. adddataxm: {},
  244. }
  245. },
  246. computed: {
  247. _columns() {
  248. const fields = JSON.parse(JSON.stringify(this.fields))
  249. return fields
  250. .filter((item) => item.dataType !== 'id')
  251. .map((item) => {
  252. const t = {
  253. dataIndex: item.name,
  254. key: item.name,
  255. title: item.caption,
  256. scopedSlots: { customRender: 'sd_' + item.name },
  257. editable: false,
  258. width: item.width || '40',
  259. }
  260. const column = this.columns.find((c) => c.dataIndex === item.name)
  261. if (column) Object.assign(t, column)
  262. return t
  263. })
  264. .filter((item) => item.sdHidden !== true)
  265. },
  266. },
  267. mounted() {
  268. if (this.datachange) {
  269. this.datachange()
  270. }
  271. },
  272. destroyed() {
  273. const data = this.value || [] // 兼容初始值是null的情况
  274. const index = data.findIndex((item) => item.editable === true)
  275. if (index !== -1) {
  276. this.optbuttonClick('delete', [], index)
  277. }
  278. },
  279. methods: {
  280. moment,
  281. getDisplayVaule(field, text) {
  282. if (getComponentSpec(field).getDisplayValue) {
  283. if (typeof text !== 'undefined' && text !== null) {
  284. const value = getComponentSpec(field).parseBackendValue?.(text) || text
  285. return getComponentSpec(field).getDisplayValue(value)
  286. } else {
  287. return ''
  288. }
  289. }
  290. return text
  291. },
  292. add() {
  293. this.action = 'add'
  294. const data = this.value || [] // 兼容初始值是null的情况
  295. // 判断当前动态表格中是否有已打开编辑的行,如果有则需要保存后才能再新增
  296. const editrow = data.find((c) => c.editable === true)
  297. if (editrow !== undefined) {
  298. Modal.warning({
  299. title: '提示',
  300. content: '请先保存动态表格中内容!!',
  301. })
  302. } else {
  303. this.editRecord = this.fields
  304. const attachobj = this.fields.find((obj) => obj.dataType === 'attachment')
  305. const d1 = { mainId: 0, editable: true }
  306. if (attachobj !== undefined) {
  307. d1[attachobj.name] =
  308. '{"value":"' + Math.round(Math.random() * 100000000000000000).toString() + '"}'
  309. }
  310. if (this.addfun) {
  311. this.addfun(d1).then((res) => {
  312. data.push(res)
  313. this.adddataxm = d1
  314. this.$emit('change', data)
  315. })
  316. } else {
  317. data.push(d1)
  318. this.adddataxm = d1
  319. this.$emit('change', data)
  320. }
  321. }
  322. },
  323. edit(index) {
  324. // const data = this.value || [] // 兼容初始值是null的情况
  325. // if (data[index].editable === undefined) {
  326. // this.optbuttonClick(event, 'edit', [], index)
  327. // }
  328. },
  329. save() {
  330. if (this.readOnly || !this.visible) {
  331. // 判断visable为false时,modal没有是为了防止快速重复点击确定
  332. this.visible = false
  333. }
  334. this.$refs.form.validateFields().then(() => {
  335. const value = {}
  336. this.$refs.form.getBackendValues().forEach((item) => {
  337. value[item.name] = item.value
  338. })
  339. const data = this.value || [] // 兼容初始值是null的情况
  340. if (this.action === 'add') {
  341. // 新增
  342. data.push(value)
  343. }
  344. if (!isNaN(this.action)) {
  345. // 修改
  346. this.attkeys[this.action] = Math.random()
  347. data[this.action] = value
  348. }
  349. /**
  350. * 动态表格值变化时触发
  351. * @property {Object} data 子表的值
  352. */
  353. this.$emit('change', [...data])
  354. this.visible = false
  355. })
  356. },
  357. onSelectChange(selectedRowKeys) {
  358. this.selectedRowKeys = selectedRowKeys
  359. },
  360. remove(keys) {
  361. // 用的序号作key,从大往小删,防止串了
  362. const removeKeys = keys.sort((a, b) => b - a)
  363. removeKeys.forEach((key) => {
  364. this.value.splice(key, 1)
  365. })
  366. this.selectedRowKeys = []
  367. this.$emit('change', this.value)
  368. },
  369. deletefindremove(keys) {
  370. // 用的序号作key,从大往小删,防止串了
  371. const removeKeys = keys.sort((a, b) => b - a)
  372. const valueid = []
  373. removeKeys.forEach((key) => {
  374. valueid.push(this.value[key].id)
  375. this.value.splice(key, 1)
  376. })
  377. this.selectedRowKeys = []
  378. this.$emit('change', this.value)
  379. this.deletefind(valueid)
  380. },
  381. optbuttonClick(val, record, i) {
  382. let value = {}
  383. const data = this.value || [] // 兼容初始值是null的情况
  384. const adddata = this.adddataxm || {}
  385. let index = 0
  386. const qqcs = this._columns.length - 2
  387. const editrow = data.find((c) => c.editable === true)
  388. switch (val) {
  389. case 'save':
  390. value = data[i]
  391. this.fields.forEach((item) => {
  392. const refname = item.name
  393. const dataType = item.dataType
  394. if (this.$refs[refname]) {
  395. this.$refs[refname][0].validateFields().then(() => {
  396. this.$refs[refname][0].getBackendValues().forEach((item) => {
  397. if (item.name === refname) {
  398. if (dataType === 'attachment') {
  399. if (adddata[refname] !== undefined) {
  400. var obj = JSON.parse(adddata[refname])
  401. value[item.name] = '{"value":"' + obj.value + '"}'
  402. } else {
  403. value[item.name] = item.value
  404. }
  405. } else {
  406. value[item.name] = item.value
  407. }
  408. }
  409. })
  410. index = index + 1
  411. if (index === qqcs) {
  412. this.attkeys[0] = Math.random()
  413. value.editable = false
  414. data.splice(i, 1)
  415. data.splice(i, 0, value)
  416. this.$emit('change', data)
  417. }
  418. })
  419. }
  420. })
  421. this.adddataxm = {}
  422. // event.stopPropagation()
  423. break
  424. case 'delete':
  425. data.splice(i, 1)
  426. this.$emit('change', data)
  427. this.adddataxm = {}
  428. break
  429. case 'edit':
  430. // 判断当前动态表格中是否有已打开编辑的行,如果有则需要保存后才能再新增
  431. if (editrow !== undefined) {
  432. Modal.warning({
  433. title: '提示',
  434. content: '请先保存动态表格中内容!',
  435. })
  436. return false
  437. }
  438. if (data[i].editable === undefined) {
  439. data[i].editable = true
  440. const value = data[i]
  441. data.splice(i, 1)
  442. data.splice(i, 0, value)
  443. this.$emit('change', data)
  444. this.editRecord = JSON.parse(JSON.stringify(this.fields))
  445. this.editRecord[0].editable = true
  446. this.editRecord.forEach((item) => {
  447. // 把值放到字段信息fields里
  448. item.value = value[item.name]
  449. if (item.attr.controlType === 'DictType') {
  450. if (item.attr.selectListItem.find((t) => t.value === item.value) !== undefined) {
  451. item.attr.displayValue = item.attr.selectListItem.find(
  452. (t) => t.value === item.value
  453. ).label
  454. }
  455. }
  456. })
  457. this.adddataxm = value
  458. }
  459. break
  460. }
  461. },
  462. savesdform() {
  463. console.log('保存')
  464. },
  465. ImportFun(params) {
  466. params.projectId = this.projectId
  467. return params
  468. },
  469. rowClick(record) {
  470. const url = '/audit-externalProject-find-form?record=' + record.id + '&mode=' + this.mode // 新页面要打开的路由地址
  471. crossWindowWatcher.waitForChanged(url).then((refreshFlag) => {
  472. if (refreshFlag) {
  473. this.refresh()
  474. }
  475. })
  476. },
  477. },
  478. }
  479. </script>
  480. <style module lang="scss">
  481. @use '@/common/design' as *;
  482. @use "@/common/components/sd-web-print.scss" as print;
  483. .header {
  484. position: absolute;
  485. top: 0;
  486. right: 0;
  487. :global .ant-input-search {
  488. width: 200px;
  489. }
  490. :global .ant-btn {
  491. margin: 5px;
  492. }
  493. }
  494. .caption {
  495. position: absolute;
  496. width: 100%;
  497. min-height: 40px;
  498. margin: 3px 0;
  499. text-align: center;
  500. }
  501. .wrapper {
  502. :global(.ant-table-tbody) {
  503. .clickable-cell {
  504. color: $primary-color;
  505. cursor: pointer;
  506. &:hover {
  507. color: $primary-5;
  508. }
  509. &:active {
  510. color: $primary-7;
  511. }
  512. }
  513. }
  514. }
  515. // 打印状态下 子表上选择列的按钮
  516. @include print.wrapper-for-printer {
  517. .wrapper {
  518. :global(.ant-table-thead .anticon) {
  519. display: none;
  520. }
  521. }
  522. }
  523. .operatecol {
  524. // display: flex;
  525. // flex-wrap: wrap;
  526. justify-content: flex-end;
  527. width: 100px;
  528. :global(.ant-btn-sm) {
  529. padding: 0 0;
  530. }
  531. :global(.menu_sd-table-header_common) {
  532. display: none;
  533. }
  534. }
  535. .sdFormforxmchild {
  536. :global(.ant-upload.ant-upload-drag p.ant-upload-drag-icon) {
  537. margin-bottom: 0;
  538. }
  539. :global(.ant-upload-text) {
  540. display: none !important;
  541. }
  542. :global(.ant-upload.ant-upload-drag .ant-upload) {
  543. padding: 0 0;
  544. }
  545. :global(.ant-form-item) {
  546. margin-bottom: 6px;
  547. }
  548. :global(.actionlist_sd-attachment_common > span) {
  549. overflow: hidden;
  550. text-overflow: ellipsis;
  551. white-space: nowrap;
  552. }
  553. :global(.actionlist_sd-attachment_common > span :hover) {
  554. white-space: normal;
  555. // overflow: auto;
  556. }
  557. :global(.ant-upload.ant-upload-drag) {
  558. text-align: left;
  559. background: none;
  560. border: none;
  561. }
  562. :global(.ant-upload.ant-upload-drag p.ant-upload-drag-icon .anticon) {
  563. font-size: 28px;
  564. }
  565. :global(.form_sd-form_common > .ant-form-item > .ant-form-item-control-wrapper) {
  566. width: 100%;
  567. }
  568. }
  569. </style>