audit-manage-model.vue 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080
  1. <template>
  2. <a-card ref="allHeight" :class="$style.financial">
  3. <!-- 组织机构筛选 -->
  4. <!-- 报告类型 年报月报,如果是年报则年筛选器 否则月-->
  5. <!-- 时间筛选 -->
  6. <a-form-model ref="search" :model="searchForm" v-bind="formItemLayout" :class="$style.form">
  7. <a-row>
  8. <a-col :span="6">
  9. <a-form-model-item label="组织机构">
  10. <!-- <audit-company-select
  11. ref="cRelSelect"
  12. v-model="orgList"
  13. :read-only="false"
  14. :single="true"
  15. @change="changecompany"
  16. /> -->
  17. <SdGroupPicker
  18. ref="cRelSelect"
  19. :key="orgKeys"
  20. v-model="orgList"
  21. :read-only="false"
  22. :root-node="userNodeTree"
  23. :single="true"
  24. @change="changecompany"
  25. />
  26. </a-form-model-item>
  27. </a-col>
  28. <a-col :span="6">
  29. <a-form-model-item label="年份">
  30. <AuditYearTime v-model="searchForm.year" />
  31. </a-form-model-item>
  32. </a-col>
  33. <!-- 指标选择 -->
  34. <a-col :span="6">
  35. <a-form-model-item label="指标选择">
  36. <a-select
  37. ref="zb"
  38. v-model="targetKeysList"
  39. mode="multiple"
  40. :open="false"
  41. :max-tag-count="3"
  42. @change="selectZbChange"
  43. @focus="focusZb"
  44. >
  45. <template slot="maxTagPlaceholder">
  46. ...
  47. </template>
  48. <a-select-option v-for="(item, i) in mockData" :key="i" :value="item.key">
  49. {{ item.title }}
  50. </a-select-option>
  51. </a-select>
  52. </a-form-model-item>
  53. </a-col>
  54. <!-- 搜索重置 -->
  55. <a-col :span="6">
  56. <a-form-model-item>
  57. <a-button style="margin-left: 15px" type="primary" @click="handlerSearch">
  58. 搜索
  59. </a-button>
  60. <a-button style="margin-left: 10px" @click="resetSearch">
  61. 重置
  62. </a-button>
  63. </a-form-model-item>
  64. </a-col>
  65. </a-row>
  66. <a-row> </a-row>
  67. </a-form-model>
  68. <div :class="$style.tableContent">
  69. <div :class="$style.titleContent">
  70. <span>数据来源:{{ manageType }}报表</span>
  71. <span>{{ nowYear }}更新</span>
  72. </div>
  73. <vxe-table
  74. ref="xTable"
  75. :key="tableKey"
  76. border
  77. :loading="tableLoading"
  78. :column-config="{ resizable: true }"
  79. :data="tableData"
  80. align="center"
  81. :height="tableHeight"
  82. :tree-config="{}"
  83. >
  84. <!-- <vxe-column field="name" title="Name"></vxe-column> -->
  85. <template v-for="(item, i) in columns">
  86. <!-- 如果有children 则显示colgroup -->
  87. <vxe-colgroup
  88. v-if="item?.children?.length > 0"
  89. :key="i"
  90. :title="item.title"
  91. :field="item.dataIndex"
  92. align="center"
  93. :fixed="fixedType(i)"
  94. >
  95. <template v-for="(item1, i1) in item.children">
  96. <!-- 如果有children 则显示colgroup -->
  97. <vxe-colgroup
  98. v-if="item1?.children?.length > 0"
  99. :key="i1"
  100. :title="item1.title"
  101. :field="item1.dataIndex"
  102. align="center"
  103. >
  104. <template v-for="(item2, i2) in item1.children">
  105. <vxe-column
  106. :key="i2"
  107. :tree-node="i2 === 0 && i1 === 0 && i === 0"
  108. :field="item2.dataIndex"
  109. :title="item2.title"
  110. align="center"
  111. min-width="180"
  112. >
  113. <!-- 如果大于9则赋予宽度 -->
  114. </vxe-column>
  115. </template>
  116. </vxe-colgroup>
  117. <vxe-column
  118. v-else
  119. :key="i1"
  120. :field="item1.dataIndex"
  121. :title="item1.title"
  122. align="center"
  123. width="180px"
  124. >
  125. <template v-if="item1.title === '操作'" v-slot="{ row }">
  126. <!-- 隐藏,可视化,对比 -->
  127. <a :style="{ color: '#1890ff', cursor: 'pointer' }" @click="onUnShow(row)">
  128. 隐藏
  129. </a>
  130. <a
  131. :style="{ color: '#1890ff', cursor: 'pointer', marginLeft: '10px' }"
  132. @click="showEcharts(row)"
  133. >
  134. 可视化
  135. </a>
  136. <!-- 对比 -->
  137. <a
  138. :style="{ color: '#1890ff', cursor: 'pointer', marginLeft: '10px' }"
  139. @click="onDiffFinancial(row)"
  140. >
  141. 对比
  142. </a>
  143. </template>
  144. </vxe-column>
  145. </template>
  146. </vxe-colgroup>
  147. <vxe-column
  148. v-else
  149. :key="i"
  150. :field="item.dataIndex"
  151. :title="item.title"
  152. align="center"
  153. width="180px"
  154. >
  155. </vxe-column>
  156. </template>
  157. </vxe-table>
  158. </div>
  159. <a-modal v-model="echartsShow" :title="manageType">
  160. <div :class="$style.modalBody">
  161. <div :class="$style.echartsUtil">
  162. <div :class="$style.echartsType">
  163. <a-icon
  164. type="bar-chart"
  165. :style="{
  166. fontSize: '26px',
  167. color: action === 1 ? '#1890ff' : '',
  168. marginRight: '10px',
  169. }"
  170. @click="onTypeChange(1)"
  171. />
  172. <a-icon
  173. type="line-chart"
  174. :style="{ fontSize: '26px', color: action === 2 ? '#1890ff' : '' }"
  175. @click="onTypeChange(2)"
  176. />
  177. </div>
  178. <div :class="$style.echartsContent">
  179. <div id="echartsContent" :class="$style.content"></div>
  180. </div>
  181. </div>
  182. </div>
  183. </a-modal>
  184. <!-- 差选报表选择 -->
  185. <a-modal v-model="visibleGs" title="公司选择" @ok="gsOk">
  186. <!-- 单选 -->
  187. <sd-table
  188. :row-selection="{
  189. selectedRowKeys: selectedRowKeys,
  190. onChange: onSelectChange,
  191. type: 'radio',
  192. }"
  193. :row-key="(record, i) => i"
  194. :columns="columnsGs"
  195. :data-source="tableDataGs"
  196. />
  197. </a-modal>
  198. <!-- 指标选择 使用穿梭框 -->
  199. <a-modal v-model="visibleZb" title="指标选择" @ok="zbOk">
  200. <a-transfer
  201. :data-source="mockData"
  202. :list-style="{
  203. width: '400px',
  204. height: '500px',
  205. }"
  206. :target-keys="targetKeys"
  207. :render="(item) => item.title"
  208. @change="handleChangeZb"
  209. >
  210. <template
  211. slot="children"
  212. slot-scope="{ props: { direction, selectedKeys }, on: { itemSelect } }"
  213. >
  214. <a-tree
  215. v-if="direction === 'left'"
  216. block-node
  217. checkable
  218. check-strictly
  219. default-expand-all
  220. :checked-keys="[...selectedKeys, ...targetKeys]"
  221. :tree-data="treeData"
  222. @check="
  223. (_, props) => {
  224. onChecked(_, props, [...selectedKeys, ...targetKeys], itemSelect)
  225. }
  226. "
  227. @select="
  228. (_, props) => {
  229. onChecked(_, props, [...selectedKeys, ...targetKeys], itemSelect)
  230. }
  231. "
  232. />
  233. </template>
  234. </a-transfer>
  235. </a-modal>
  236. </a-card>
  237. </template>
  238. <script>
  239. import components from './_import-components/audit-financial-detail-import'
  240. import SdGroupPicker from '../report/audit-company-select.vue'
  241. import echarts from 'echarts'
  242. import AuditYearTime from './audit-year-time.vue'
  243. import auditPortraitService from './audit-portrait-service'
  244. import { message } from 'ant-design-vue'
  245. import { getUserInfo } from '@/common/store-mixin'
  246. import auditMaintainService from '../dataUphold/data-config'
  247. import sdTable from '@/common/components/sd-table.vue'
  248. import VXETable from 'vxe-table'
  249. import 'vxe-table/lib/style.css'
  250. import Vue from 'vue'
  251. Vue.use(VXETable)
  252. function isChecked(selectedKeys, eventKey) {
  253. return selectedKeys.indexOf(eventKey) !== -1
  254. }
  255. export default {
  256. name: 'AuditManageModel',
  257. components: {
  258. ...components,
  259. SdGroupPicker,
  260. AuditYearTime,
  261. sdTable,
  262. },
  263. props: {
  264. manageType: {
  265. type: String,
  266. default: '财务管理',
  267. },
  268. },
  269. data() {
  270. return {
  271. tableKey: 1,
  272. tableLoading: true,
  273. companyUnit: [],
  274. searchForm: {
  275. // 组织机构
  276. orgId: '',
  277. orgName: '',
  278. onOrgCode: '',
  279. // 时间范围
  280. year: [],
  281. month: '',
  282. // 报告类型
  283. reportType: '1',
  284. },
  285. defaultValue: [],
  286. // 指标穿梭框
  287. showTable: true,
  288. visibleZb: false,
  289. mockData: [],
  290. treeData: [],
  291. targetKeys: [],
  292. // 临时存储组织机构
  293. targetKeysList: [],
  294. // 组织机构
  295. orgList: [],
  296. visibleGs: false,
  297. columnsGs: [
  298. {
  299. title: '公司名称',
  300. dataIndex: 'org_name',
  301. },
  302. ],
  303. tableDataGs: [],
  304. selectedRowKeys: [],
  305. selectedRows: [],
  306. // 报告类型 年报月报
  307. reportList: [
  308. { label: '年报', value: '1' },
  309. { label: '月报', value: '2' },
  310. ],
  311. formItemLayout: {
  312. labelCol: { span: 7 },
  313. wrapperCol: { span: 17 },
  314. },
  315. // 表格数据
  316. tableData: [],
  317. expandedRowKeys: [1, 3],
  318. columnsInit: [
  319. {
  320. children: [
  321. {
  322. children: [
  323. // 指标分类
  324. {
  325. title: '指标分类',
  326. dataIndex: 'zbClassName',
  327. align: 'center',
  328. width: '180px',
  329. },
  330. // 指标名称
  331. {
  332. title: '指标名称',
  333. dataIndex: 'zbName',
  334. width: '140px',
  335. // 自定义渲染 如果超长则显示tooltip
  336. },
  337. ],
  338. },
  339. ],
  340. },
  341. ],
  342. columns: [],
  343. // 显示echarts
  344. action: 1,
  345. echartsShow: false,
  346. myChart: null,
  347. // 年份 当前年份前后一百年
  348. allYear: Array.from({ length: 200 }, (v, k) => k + 1900).reverse(),
  349. // 当前时间 2024.1.11以此形式
  350. nowYear:
  351. new Date().getFullYear() + '.' + (new Date().getMonth() + 1) + '.' + new Date().getDate(),
  352. onRecord: {},
  353. userNodeTree: [],
  354. isJt: false,
  355. orgKeys: 1,
  356. // iamFinancialIndex
  357. tableHeight: 600,
  358. }
  359. },
  360. watch: {
  361. targetKeys: {
  362. handler(val) {
  363. // 置灰 和取消置灰
  364. this.treeData.forEach((item) => {
  365. item.children.forEach((item2) => {
  366. if (val.includes(item2.key)) {
  367. item2.disabled = true
  368. } else {
  369. item2.disabled = false
  370. }
  371. })
  372. })
  373. },
  374. deep: true,
  375. },
  376. },
  377. created() {
  378. this.initUserUnit()
  379. this.initUserCompany()
  380. },
  381. mounted() {
  382. this.$nextTick(() => {
  383. this.tableHeight = this.$refs.allHeight.$el.clientHeight - 150
  384. })
  385. },
  386. methods: {
  387. // 初始化个人公司
  388. initUserCompany() {
  389. const userInfo = getUserInfo()
  390. auditMaintainService.getCompany(userInfo.account).then((res) => {
  391. // 100000和100001
  392. const roleCompany = ['100000', '100001']
  393. this.userNodeTree.push({
  394. code: res.data.id,
  395. name: res.data.name,
  396. orgCode: res.data.code,
  397. type: 'Group',
  398. })
  399. this.companyUnit = [
  400. {
  401. code: res.data.id,
  402. name: res.data.name,
  403. orgCode: res.data.code,
  404. },
  405. ]
  406. if (roleCompany.includes(res.data.code)) {
  407. this.isJt = true
  408. this.userNodeTree = [
  409. {
  410. code: '28951',
  411. name: '国家电力投资集团有限公司',
  412. orgCode: '100000',
  413. },
  414. ]
  415. this.companyUnit = [
  416. {
  417. code: '28951',
  418. name: '国家电力投资集团有限公司',
  419. orgCode: '100000',
  420. },
  421. ]
  422. }
  423. })
  424. },
  425. selectZbChange(val) {
  426. this.targetKeysList = val
  427. this.targetKeys = val
  428. },
  429. fixedType(i) {
  430. if (i === 0) return 'left'
  431. if (this.columns.length - 1 === i) return 'right'
  432. },
  433. initUserUnit() {
  434. const userInfo = getUserInfo()
  435. const grop = ['100001', '100000']
  436. // 年份为当前年份和前两年
  437. this.searchForm.year = [2020, 2021, 2022]
  438. auditMaintainService.getCompany(userInfo.account).then((res) => {
  439. if (grop.includes(res.data.code)) this.isJt = true
  440. this.orgList = [
  441. {
  442. code: res.data.id,
  443. name: res.data.name,
  444. orgCode: res.data.code,
  445. },
  446. ]
  447. // if (this.isJt) {
  448. // this.orgList = [
  449. // {
  450. // code: 29711,
  451. // name: '上海发电设备成套设计研究院有限责任公司',
  452. // orgCode: '100550',
  453. // },
  454. // ]
  455. // }
  456. this.searchForm.orgId = this.orgList[0].orgCode
  457. this.searchForm.orgName = this.orgList[0].name
  458. this.orgKeys += 1
  459. // this.$refs.cRelSelect.initTreeData()
  460. const params = {
  461. columns:
  462. 'sortNumber,firstClassify,secondClassify,indexName,indexNameEn,indexMeasure,price,systemSource,remark',
  463. maxResults: 1000,
  464. startPosition: 0,
  465. expressions: [
  466. {
  467. dataType: 'str',
  468. name: 'firstClassify',
  469. op: 'eq',
  470. stringValue: this.manageType,
  471. },
  472. ],
  473. buttonExpressions: [],
  474. formId: 'iamFinancialIndex',
  475. }
  476. auditPortraitService.getBusinessList(params).then((res) => {
  477. const data = res.data.data.filter((item) => item.firstClassify === this.manageType)
  478. // 所有二级分类
  479. const secondClassify = Array.from(new Set(data.map((item) => item.secondClassify)))
  480. this.mockData = data.map((item) => ({
  481. key: item.indexNameEn,
  482. title: item.indexName,
  483. description: item.indexName,
  484. }))
  485. // 生成树 并且所有二级分类不可选
  486. this.treeData = secondClassify.map((item) => ({
  487. title: item,
  488. key: item,
  489. disabled: true,
  490. children: data
  491. .filter((item2) => item2.secondClassify === item)
  492. .map((item3) => ({
  493. title: item3.indexName,
  494. key: item3.indexNameEn,
  495. })),
  496. }))
  497. this.targetKeysList = this.mockData.map((item) => item.key)
  498. this.targetKeys = this.mockData.map((item) => item.key)
  499. // 如果已经选中则遍历treeData置灰
  500. this.targetKeysList.forEach((item) => {
  501. this.treeData.forEach((item2) => {
  502. item2.children.forEach((item3) => {
  503. if (item3.key === item) {
  504. item3.disabled = true
  505. }
  506. })
  507. })
  508. })
  509. this.$nextTick(() => {
  510. this.initTable()
  511. })
  512. })
  513. })
  514. },
  515. //
  516. changecompany(val) {
  517. this.orgList = val
  518. if (val.length > 0) {
  519. this.searchForm.orgId = val[0].orgCode
  520. this.searchForm.orgName = val[0].name
  521. }
  522. },
  523. handleChangeZb(nextTargetKeys, direction, moveKeys) {
  524. this.targetKeys = nextTargetKeys
  525. // 如果是从左边到右边则取消置灰
  526. this.treeData.forEach((item) => {
  527. item.children.forEach((item2) => {
  528. if (moveKeys.includes(item2.key)) {
  529. item2.disabled = false
  530. }
  531. if (nextTargetKeys.includes(item2.key)) {
  532. item2.disabled = true
  533. }
  534. })
  535. })
  536. },
  537. onChecked(_, e, checkedKeys, itemSelect) {
  538. const { eventKey } = e.node
  539. itemSelect(eventKey, !isChecked(checkedKeys, eventKey))
  540. },
  541. handlerSearch() {
  542. this.initTable()
  543. // 请选择组织机构
  544. // if (this.orgList.length === 0) {
  545. // message.error('请选择组织机构')
  546. // return
  547. // }
  548. // if (this.searchForm.year.length === 0) {
  549. // message.error('请选择年份')
  550. // return
  551. // }
  552. // // todo
  553. // const params = { mdg_orgCode: this.searchForm.orgId }
  554. // // const params = { mdg_orgCode: '190848' }
  555. // // 190848
  556. // auditPortraitService.getCompanyList(params).then((res) => {
  557. // this.visibleGs = true
  558. // this.tableDataGs = res.data.data
  559. // })
  560. },
  561. onSelectChange(selectedRowKeys, selectedRows) {
  562. this.selectedRowKeys = selectedRowKeys
  563. this.selectedRows = selectedRows
  564. },
  565. gsOk() {
  566. // 确定是否选择了公司
  567. if (this.tableDataGs.length !== 0 && this.selectedRows.length === 0) {
  568. message.error('请选择公司')
  569. return
  570. }
  571. // 请选择年份
  572. this.visibleGs = false
  573. if (this.selectedRows.length > 0) {
  574. this.searchForm.onOrgCode = this.selectedRows[0].org_code || ''
  575. } else {
  576. this.searchForm.onOrgCode = ''
  577. }
  578. this.selectedRowKeys = []
  579. this.selectedRows = []
  580. this.initTable()
  581. },
  582. // 获得指标
  583. focusZb() {
  584. this.visibleZb = true
  585. this.$refs.zb.blur()
  586. },
  587. zbOk() {
  588. this.visibleZb = false
  589. this.searchForm.zb = this.targetKeys
  590. this.targetKeysList = this.targetKeys
  591. },
  592. // 重置
  593. resetSearch() {
  594. this.searchForm = {
  595. // 组织机构
  596. orgId: '',
  597. orgName: '',
  598. // 时间范围
  599. year: [],
  600. month: '',
  601. // 报告类型
  602. reportType: '1',
  603. onOrgCode: '',
  604. }
  605. this.orgList = []
  606. this.targetKeysList = []
  607. this.targetKeys = []
  608. this.showTable = true
  609. },
  610. // 替换icons
  611. // 展开图标
  612. expandIcon(props) {
  613. // 判断当有子级时添加图标
  614. if (props.record.children?.length > 0) {
  615. // 有数据-展开时候图标
  616. if (props.expanded) {
  617. // 这里的margin-right是为了让图标和字体有一点间距
  618. return (
  619. <span
  620. style='margin-right:10px;user-select:none'
  621. onClick={(e) => {
  622. props.onExpand(props.record, e)
  623. }}
  624. >
  625. <a-icon type='caret-down' />
  626. </span>
  627. )
  628. // 无数据时-关闭的图标
  629. } else {
  630. return (
  631. <span
  632. style='margin-right:10px;user-select:none'
  633. onClick={(e) => {
  634. props.onExpand(props.record, e)
  635. }}
  636. >
  637. <a-icon type='caret-right' />
  638. </span>
  639. )
  640. }
  641. } else {
  642. // 这里是为了让无图标子级的父元素也给了个margin-right,让它跟有子级的父元素在同一竖线上
  643. return <span style='margin-right:19px'></span>
  644. }
  645. },
  646. onexpand(expanded, record) {
  647. // this.expandedRowKeys = expanded ? [record.key] : []
  648. // 如果有key则删除
  649. if (expanded) {
  650. this.expandedRowKeys.push(record.key)
  651. } else {
  652. this.expandedRowKeys = this.expandedRowKeys.filter((item) => item !== record.key)
  653. }
  654. },
  655. initTable() {
  656. this.tableData = []
  657. this.columns = []
  658. this.tableLoading = true
  659. const params = {
  660. mdg_orgCode: this.searchForm.orgId,
  661. year: this.searchForm.year.map((item) => item + ''),
  662. metricNameCn: this.targetKeysList,
  663. }
  664. auditPortraitService
  665. .getReportList(params)
  666. .then((res) => {
  667. const allData = res.data.data
  668. if (allData.length === 0) {
  669. this.showTable = false
  670. return
  671. }
  672. const orColumns = allData.map((val, i) => ({
  673. title: val.org_name,
  674. align: 'center',
  675. children: val.index_value.map((val1, j) => ({
  676. // 年份
  677. title: val1.year,
  678. width: '180px',
  679. align: 'center',
  680. children: [
  681. // 指标值
  682. {
  683. width: '180px',
  684. align: 'center',
  685. title: '指标值',
  686. dataIndex: 'colValue' + val.org_code + '' + val1.year,
  687. },
  688. ],
  689. })),
  690. }))
  691. // 汇总所有指标分类
  692. // 遍历allData内所有index_value数组内对象下data内有值得,遇到优质数据则返回
  693. const onlyZbClass =
  694. allData.map((item) => item.index_value.filter((val) => val.data?.length > 0))[0][0] ||
  695. {}
  696. // todo 筛选有效数据
  697. let zbClassArr = onlyZbClass.data?.map((item) => item.secondClassify) || []
  698. // 去重
  699. zbClassArr = Array.from(new Set(zbClassArr))
  700. // 遍历数据进行分级
  701. const orgNameList = allData.map((item) => item.org_name)
  702. const tableData = zbClassArr.map((val, i) => {
  703. const children = onlyZbClass.data
  704. .filter((item) => val === item.secondClassify)
  705. .map((val2, j) => {
  706. return {
  707. zbClassName: '',
  708. zbName: val2.metric_name_cn,
  709. zbCode: val2.metric_name,
  710. orgNameList: orgNameList,
  711. orgCode: val2.org_code,
  712. zbDw: val2.indexMeasure,
  713. key: i + '' + j,
  714. }
  715. })
  716. const onData = children[0] || []
  717. // 删除第一个
  718. // children.shift()
  719. const obj = {
  720. zbClassName: val,
  721. zbCode: onData.zbCode,
  722. zbName: onData.zbName,
  723. orgNameList: orgNameList,
  724. orgCode: onData.orgCode,
  725. key: 'zb' + i,
  726. zbDw: onData.zbDw,
  727. name: val,
  728. children,
  729. }
  730. // 展开的key
  731. return obj
  732. })
  733. this.expandedRowKeys = tableData.map((item) => item.key)
  734. // 遍历 allData向 tableData中添加数据
  735. allData.forEach((item, i) => {
  736. item.index_value.forEach((item2, j) => {
  737. tableData.forEach((item3) => {
  738. item3.children.forEach((item4) => {
  739. const itemData2 = item2.data || []
  740. itemData2.forEach((item5) => {
  741. // 指标相同
  742. if (item5.metric_name === item4.zbCode) {
  743. // 如果指标名称最后一位是率则 小数点后两位 并且乘以100 如果是空 则是空
  744. const isType = item4.zbName.includes('率')
  745. let isValue = ''
  746. // 如果当前值
  747. // 99999.99999
  748. // 88888.88888
  749. // 77777.77777
  750. const filterValue = ['99999.99999', '88888.88888', '77777.77777']
  751. // 如果 item5.index_value 为99999.99999 88888.88888 77777.77777 则为null
  752. if (isType) {
  753. isValue = item5.index_value
  754. ? (item5.index_value * 100).toFixed(2) || ''
  755. : ''
  756. } else {
  757. isValue = item5.index_value ? (item5.index_value * 1).toFixed(2) || '' : ''
  758. }
  759. if (filterValue.includes(item5.index_value + '')) {
  760. isValue = ''
  761. }
  762. // 如果是NaN则保留原值
  763. if (isNaN(isValue)) {
  764. isValue = item5.index_value
  765. }
  766. item4['colValue' + item.org_code + '' + item2.year] = isValue
  767. item4 = JSON.parse(JSON.stringify(item4 || {}))
  768. }
  769. })
  770. })
  771. })
  772. })
  773. })
  774. // 再次遍历tableData将children首位code zbName 添加到上层 并是删除children首位
  775. tableData.forEach((item) => {
  776. item.children.forEach((item2, i) => {
  777. const obj = JSON.parse(JSON.stringify(item2 || {}))
  778. if (i === 0) {
  779. item.children.shift()
  780. }
  781. // 删除所有非colValue开头的
  782. Object.keys(obj).forEach((key) => {
  783. if (!key.includes('colValue')) {
  784. delete obj[key]
  785. }
  786. })
  787. item = JSON.parse(JSON.stringify(Object.assign(item, obj)))
  788. })
  789. })
  790. this.columns = [
  791. ...this.columnsInit,
  792. ...orColumns, // 操作插槽
  793. {
  794. children: [
  795. {
  796. align: 'center',
  797. title: '操作',
  798. dataIndex: 'key',
  799. width: '180px',
  800. // 动态渲染
  801. customRender: (text, record) => {
  802. // 隐藏对比可视化
  803. // 阻止穿透
  804. return (
  805. <div style='width:180px;'>
  806. <a
  807. style='margin:0 10px'
  808. onClick={(e) => {
  809. e.stopPropagation()
  810. this.onUnShow(record)
  811. }}
  812. >
  813. 隐藏
  814. </a>
  815. <a
  816. style='margin-right:10px'
  817. onClick={(e) => {
  818. e.stopPropagation()
  819. this.showEcharts(record)
  820. }}
  821. >
  822. 可视化
  823. </a>
  824. <a
  825. type='link'
  826. onClick={(e) => {
  827. e.stopPropagation()
  828. this.onDiffFinancial(record)
  829. }}
  830. >
  831. 对比
  832. </a>
  833. </div>
  834. )
  835. },
  836. },
  837. ],
  838. },
  839. ]
  840. this.tableData = tableData
  841. this.tableKey++
  842. })
  843. .finally(() => {
  844. this.tableLoading = false
  845. })
  846. },
  847. onUnShow(record) {
  848. const zbCode = record.zbCode
  849. // 在指标选择器删除当前对应的指标名称,必须使用删除方法
  850. const onKeys = JSON.parse(
  851. JSON.stringify(this.targetKeysList.filter((item) => item !== zbCode))
  852. )
  853. this.targetKeysList = onKeys
  854. this.targetKeys = onKeys
  855. this.initTable()
  856. // 并且重新刷新数据
  857. // this.echartsShow = false
  858. // this.tagetKeysList = this.targetKeysList.filter((item) => item !== record.colTitle)
  859. },
  860. onDiffFinancial(record) {
  861. // 跳转对比
  862. const params = {
  863. mdg_orgCode: this.searchForm.orgId,
  864. year: this.searchForm.year || [],
  865. orgList: this.orgList || [],
  866. zbName: record.zbName || '',
  867. zbCode: record.zbCode || '',
  868. // 指标名称 指标code
  869. }
  870. window.open('#/audit-contrast-view?params=' + JSON.stringify(params))
  871. },
  872. showEcharts(record) {
  873. this.onRecord = record
  874. this.echartsShow = true
  875. this.$nextTick(() => {
  876. this.initEcharts(record)
  877. })
  878. },
  879. initEcharts(record) {
  880. record = this.onRecord
  881. // 过滤所有不以colValue开头的
  882. const allDataArr = Object.keys(record).filter((item) => item.includes('colValue'))
  883. // 年份
  884. let allYear = allDataArr.map((item) => item.slice(-4))
  885. // 每年的指标值
  886. allYear = Array.from(new Set(allYear))
  887. // 单位 CNY 如果colTitle含率则单位为%
  888. const dw = this.onRecord.zbDw
  889. // 指标值
  890. const seriesList = allYear.map((item, i) => {
  891. return {
  892. name: item,
  893. data: allDataArr.filter((val) => val.includes(item)).map((item2) => record[item2] || ''),
  894. type: this.action === 1 ? 'bar' : 'line',
  895. // 柱子宽度
  896. barMaxWidth: 50,
  897. // 柱状图颜色
  898. itemStyle: {
  899. color: i % 2 === 0 ? '#1890ff' : '#E76F00',
  900. },
  901. }
  902. })
  903. // {
  904. // name: this.onRecord.colTitle,
  905. // data: allDataArr,
  906. // type: this.action === 1 ? 'bar' : 'line',
  907. // // 柱子宽度
  908. // barMaxWidth: 50,
  909. // // 柱状图颜色
  910. // itemStyle: {
  911. // color: '#1890ff',
  912. // },
  913. // },
  914. this.myChart = echarts.init(document.getElementById('echartsContent'))
  915. const option = {
  916. title: {
  917. text: this.onRecord.zbName,
  918. textStyle: {
  919. rich: {
  920. a: {
  921. fontSize: 16,
  922. fontWeight: 600,
  923. },
  924. },
  925. },
  926. top: '0%',
  927. left: '45%',
  928. },
  929. tooltip: {
  930. trigger: 'item',
  931. // 带单位
  932. formatter: '{a} <br/>{b} : {c}' + dw,
  933. },
  934. grid: {
  935. left: '5%', // grid布局设置适当调整避免X轴文字只能部分显示
  936. right: '10%', // grid布局设置适当调整避免X轴文字只能部分显示
  937. bottom: '10%',
  938. containLabel: true,
  939. },
  940. xAxis: {
  941. type: 'category',
  942. data: record.orgNameList,
  943. axisLabel: {
  944. show: true, // 是否显示刻度标签,默认显示
  945. interval: 0, // 坐标轴刻度标签的显示间隔,在类目轴中有效;默认会采用标签不重叠的策略间隔显示标签;可以设置成0强制显示所有标签;如果设置为1,表示『隔一个标签显示一个标签』,如果值为2,表示隔两个标签显示一个标签,以此类推。
  946. inside: false, // 刻度标签是否朝内,默认朝外
  947. margin: 6, // 刻度标签与轴线之间的距离
  948. // formatter: '{value}', // 刻度标签的内容格式器
  949. // 旋转30度
  950. rotate: -15,
  951. },
  952. },
  953. yAxis: {
  954. name: dw,
  955. type: 'value',
  956. minInterval: 1,
  957. splitLine: {
  958. lineStyle: {
  959. type: 'dashed',
  960. color: '#111',
  961. },
  962. },
  963. },
  964. dataZoom: [
  965. {
  966. type: 'slider',
  967. show: true,
  968. xAxisIndex: [0],
  969. startValue: 0, // 起始值
  970. endValue: 5, // 结束值
  971. // 滑动条
  972. // 最多显示五条数据
  973. },
  974. {
  975. type: 'inside',
  976. xAxisIndex: [0],
  977. start: 0,
  978. end: 10,
  979. },
  980. // 最多显示五条数据
  981. ],
  982. // 图例
  983. legend: {
  984. data: [this.onRecord.colTitle],
  985. textStyle: {
  986. align: 'right',
  987. },
  988. top: '2%',
  989. right: '2%',
  990. },
  991. series: seriesList,
  992. }
  993. this.myChart.setOption(option)
  994. },
  995. onTypeChange(type) {
  996. this.action = type
  997. // 折线图
  998. this.initEcharts()
  999. },
  1000. },
  1001. }
  1002. </script>
  1003. <style module lang="scss">
  1004. @use '@/common/design' as *;
  1005. .table-sapn {
  1006. display: inline-block;
  1007. width: 100px;
  1008. margin: 0 15px;
  1009. }
  1010. .form {
  1011. margin-bottom: 20px;
  1012. }
  1013. .echarts-util {
  1014. display: flex;
  1015. flex-direction: column;
  1016. height: 100%;
  1017. .echarts-type {
  1018. display: flex;
  1019. justify-content: flex-start;
  1020. padding: 10px;
  1021. margin-bottom: 20px;
  1022. border-bottom: 1px solid #e8e8e8;
  1023. }
  1024. }
  1025. .echarts-content {
  1026. width: 100%;
  1027. }
  1028. .content {
  1029. width: 100%;
  1030. min-height: 500px;
  1031. }
  1032. .table-content {
  1033. .title-content {
  1034. display: flex;
  1035. justify-content: flex-end;
  1036. padding-right: 10px;
  1037. margin-bottom: 20px;
  1038. span {
  1039. margin-left: 20px;
  1040. }
  1041. }
  1042. }
  1043. </style>
  1044. <style lang="scss" scoped>
  1045. @use '@/common/design' as *;
  1046. ::v-deep .col-header {
  1047. font-weight: 600;
  1048. color: $table-header-color !important;
  1049. background: #fafafa;
  1050. }
  1051. ::v-deep .ant-table-scroll table .ant-table-fixed-columns-in-body:not([colspan]) > * {
  1052. visibility: visible;
  1053. }
  1054. </style>