partitionTargetList.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. <template>
  2. <div>
  3. <a-card size="small" :bordered="false" class="partitionTargetList-wrap searchBoxNormal">
  4. <!-- 搜索条件 -->
  5. <div class="table-page-search-wrapper" ref="tableSearch">
  6. <a-form-model
  7. id="partitionTargetList-form"
  8. ref="ruleForm"
  9. class="form-model-con"
  10. layout="inline"
  11. :model="queryParam"
  12. :rules="rules">
  13. <a-row :gutter="15">
  14. <a-col :md="5" :sm="24">
  15. <a-form-model-item label="年份" prop="confYear">
  16. <a-select
  17. id="partitionTargetList-confYear"
  18. style="width: 100%"
  19. placeholder="请选择年份"
  20. :value="queryParam.confYear"
  21. @change="changeYear">
  22. <a-select-option :id="'partitionTargetList-'+item" v-for="item in years" :value="item" :key="item">
  23. {{ item }}
  24. </a-select-option>
  25. </a-select>
  26. </a-form-model-item>
  27. </a-col>
  28. <a-col :md="4" :sm="24">
  29. <a-button
  30. type="primary"
  31. @click="handleSearch"
  32. :disabled="disabled"
  33. id="partitionTargetList-refresh">查询</a-button>
  34. <a-button
  35. style="margin-left: 8px"
  36. @click="resetSearchForm"
  37. :disabled="disabled"
  38. id="partitionTargetList-reset">重置</a-button>
  39. </a-col>
  40. </a-row>
  41. </a-form-model>
  42. </div>
  43. </a-card>
  44. <a-card size="small" :bordered="false">
  45. <a-spin :spinning="spinning" tip="Loading...">
  46. <!-- 列表 -->
  47. <s-table
  48. class="sTable fixPagination"
  49. ref="table"
  50. size="small"
  51. :rowKey="(record) => record.no"
  52. rowKeyName="no"
  53. :style="{ height: tableHeight+70+'px' }"
  54. :columns="columns"
  55. :data="loadData"
  56. :rowClassName="(record, index) => record.subareaAreaName ==='合计' ? 'last-row':''"
  57. :scroll="{ y: tableHeight}"
  58. :showPagination="false"
  59. :defaultLoadData="false"
  60. bordered>
  61. <!-- 1月~12月 -->
  62. <template
  63. v-for="col in 12"
  64. :slot="'month'+col"
  65. slot-scope="text, record"
  66. >
  67. <div :key="col">
  68. <a-input-number
  69. style="width:100%;"
  70. v-if="record.editable"
  71. size="small"
  72. :min="0"
  73. :max="999999999.99"
  74. placeholder="请输入"
  75. :precision="2"
  76. :value="text"
  77. :id="'partitionTargetList-input-'+record.id"
  78. @blur="e => handleChange(e.target.value,record, col)"/>
  79. <template v-else>
  80. {{ text?toThousands(text):'0.00' }}
  81. </template>
  82. </div>
  83. </template>
  84. <!-- 操作 -->
  85. <template slot="action" slot-scope="text, record">
  86. <span v-if="record.editable">
  87. <a-button
  88. size="small"
  89. type="link"
  90. class="button-info"
  91. @click="handleSave(record)"
  92. :id="'partitionTargetList-save-btn'+record.id"
  93. >
  94. 保存
  95. </a-button>
  96. <a-popconfirm title="确定取消吗?" :id="'partitionTargetList-cancel-btn'+record.id" @confirm="() => handleCancel(record)">
  97. <a>取消</a>
  98. </a-popconfirm>
  99. </span>
  100. <a-button
  101. size="small"
  102. type="link"
  103. v-else-if="$hasPermissions('B_dailyReportSettings_edit')&&!record.editable &&record.subareaAreaName!='合计'"
  104. class="button-info"
  105. :disabled="editingKey !== ''"
  106. @click="handleEdit(record)"
  107. :id="'partitionTargetList-edit-btn'+record.id"
  108. >
  109. 编辑
  110. </a-button>
  111. <span v-else>--</span>
  112. </template>
  113. </s-table>
  114. </a-spin>
  115. </a-card>
  116. </div>
  117. </template>
  118. <script>
  119. import { commonMixin } from '@/utils/mixin'
  120. // 组件
  121. import { STable } from '@/components'
  122. // 接口
  123. import { reportDailyConfList, dailyReportConfSave } from '@/api/reportDailyConf'
  124. export default {
  125. name: 'PartitionTargetList',
  126. mixins: [commonMixin],
  127. components: { STable },
  128. props: {
  129. pageType: { // 弹框显示状态
  130. type: String,
  131. default: ''
  132. }
  133. },
  134. data () {
  135. return {
  136. spinning: false,
  137. disabled: false, // 查询、重置按钮是否可操作
  138. tableHeight: 0, // 表格高度
  139. toYears: new Date().getFullYear(), // 今年
  140. editingKey: '', // 按钮是否禁用
  141. // 查询条件
  142. queryParam: {
  143. confType: undefined, // 页面类型
  144. confYear: new Date().getFullYear() // 年份
  145. },
  146. rules: {
  147. confYear: [{ required: true, message: '请选择年份', trigger: 'change' }]
  148. },
  149. dataSources: null, // 表格数据
  150. // 加载数据方法 必须为 Promise 对象
  151. loadData: parameter => {
  152. this.disabled = true
  153. this.spinning = true
  154. // 获取列表数据 wu分页
  155. this.queryParam.confType = this.pageType
  156. const params = Object.assign(parameter, this.queryParam)
  157. return reportDailyConfList(params).then(res => {
  158. let data
  159. if (res.status == 200) {
  160. data = res.data
  161. // 计算表格序号
  162. for (var i = 0; i < data.length; i++) {
  163. data[i].no = i + 1
  164. data[i].editable = false
  165. }
  166. }
  167. this.disabled = false
  168. this.spinning = false
  169. this.dataSources = data
  170. return data
  171. })
  172. }
  173. }
  174. },
  175. computed: {
  176. // 获取年份数据
  177. years () {
  178. const years = []
  179. const lens = (this.toYears - 2023) + 1
  180. for (let i = 0; i < lens; i++) {
  181. years.push(this.toYears - i)
  182. }
  183. return years
  184. },
  185. columns () {
  186. const _this = this
  187. const arr = [
  188. { title: '分区',
  189. dataIndex: 'subareaAreaName',
  190. width: '12%',
  191. align: 'center',
  192. ellipsis: true,
  193. customRender: (text, record, index) => {
  194. const isLastRow = record.no == this.dataSources.length
  195. return {
  196. children: text,
  197. attrs: {
  198. colSpan: isLastRow ? 2 : 1// 合并前两列
  199. }
  200. }
  201. } },
  202. { title: '区域负责人',
  203. dataIndex: 'userName',
  204. width: '12%',
  205. align: 'center',
  206. customRender: (text, record, index) => {
  207. const isLastRow = record.no == this.dataSources.length
  208. return {
  209. children: text || '--',
  210. attrs: {
  211. colSpan: isLastRow ? 0 : 1// 合并前两列
  212. }
  213. }
  214. },
  215. ellipsis: true },
  216. { title: '1月', dataIndex: 'value01', width: '8%', align: 'right', scopedSlots: { customRender: 'month1' } },
  217. { title: '2月', dataIndex: 'value02', width: '8%', align: 'right', scopedSlots: { customRender: 'month2' } },
  218. { title: '3月', dataIndex: 'value03', width: '8%', align: 'right', scopedSlots: { customRender: 'month3' } },
  219. { title: '4月', dataIndex: 'value04', width: '8%', align: 'right', scopedSlots: { customRender: 'month4' } },
  220. { title: '5月', dataIndex: 'value05', width: '8%', align: 'right', scopedSlots: { customRender: 'month5' } },
  221. { title: '6月', dataIndex: 'value06', width: '8%', align: 'right', scopedSlots: { customRender: 'month6' } },
  222. { title: '7月', dataIndex: 'value07', width: '8%', align: 'right', scopedSlots: { customRender: 'month7' } },
  223. { title: '8月', dataIndex: 'value08', width: '8%', align: 'right', scopedSlots: { customRender: 'month8' } },
  224. { title: '9月', dataIndex: 'value09', width: '8%', align: 'right', scopedSlots: { customRender: 'month9' } },
  225. { title: '10月', dataIndex: 'value10', width: '8%', align: 'right', scopedSlots: { customRender: 'month10' } },
  226. { title: '11月', dataIndex: 'value11', width: '8%', align: 'right', scopedSlots: { customRender: 'month11' } },
  227. { title: '12月', dataIndex: 'value12', width: '8%', align: 'right', scopedSlots: { customRender: 'month12' } },
  228. { title: '合计', dataIndex: 'summation', width: '11%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
  229. { title: '操作', scopedSlots: { customRender: 'action' }, width: '11%', align: 'center' }
  230. ]
  231. return arr
  232. }
  233. },
  234. methods: {
  235. // 添加数据处理方法
  236. processData (data, field) {
  237. let count = 0
  238. data.forEach((item, index) => {
  239. if (index === 0 || item[field] !== data[index - 1][field]) {
  240. count = 1
  241. // 向后查找相同项
  242. for (let i = index + 1; i < data.length; i++) {
  243. if (item[field] === data[i][field]) count++
  244. else break
  245. }
  246. item.rowSpan = count // 设置合并行数
  247. } else {
  248. item.rowSpan = 0 // 后续相同项设置为0(不渲染)
  249. }
  250. })
  251. return data
  252. },
  253. // 查询
  254. handleSearch () {
  255. this.$refs.ruleForm.validate(valid => {
  256. if (valid) {
  257. this.editingKey = ''
  258. this.$refs.table.refresh(true)
  259. } else {
  260. this.$message.error('请选择年份')
  261. return false
  262. }
  263. })
  264. },
  265. // 选择查询年份 change
  266. changeYear (val) {
  267. this.editingKey = ''
  268. if (!val) {
  269. this.queryParam.confYear = void 0
  270. } else {
  271. this.queryParam.confYear = val
  272. }
  273. },
  274. // 编辑
  275. handleEdit (row) {
  276. this.editingKey = row.no
  277. row.editable = true
  278. },
  279. // 保存
  280. handleSave (row) {
  281. row.confYear = this.queryParam.confYear
  282. dailyReportConfSave(row).then(res => {
  283. if (res.status == 200) {
  284. this.$message.success(res.message)
  285. row.editable = false
  286. this.editingKey = ''
  287. this.$refs.table.refresh(true)
  288. }
  289. })
  290. },
  291. // 取消
  292. handleCancel (row) {
  293. row.editable = false
  294. this.editingKey = ''
  295. this.$refs.table.refresh(true)
  296. },
  297. // input change事件
  298. handleChange (val, row, column) {
  299. const _this = this
  300. const newColumn = _this.padZero(column)
  301. row['value' + newColumn] = val || 0
  302. row.summation = _this.calculateTotal(row)
  303. // _this.dataSources[column * 1 - 1] = row
  304. },
  305. // 补零方法
  306. padZero (num) {
  307. return String(num).padStart(2, '0')
  308. },
  309. // 计算合计
  310. calculateTotal (rowData) {
  311. const keys = Array.from({ length: 12 }, (_, i) => 'value' + this.padZero(i + 1))
  312. const totalNum = keys.reduce((sum, key) => sum + (Number(rowData[key]) || 0), 0)
  313. console.log('sdsdsd:', totalNum)
  314. return totalNum
  315. },
  316. // 重置
  317. resetSearchForm () {
  318. this.editingKey = ''
  319. this.queryParam.confType = undefined
  320. this.queryParam.confYear = new Date().getFullYear()
  321. this.$refs.ruleForm.resetFields()
  322. this.$refs.table.refresh(true)
  323. },
  324. // 初始化
  325. pageInit () {
  326. this.$nextTick(() => { // 页面渲染完成后的回调
  327. this.setTableH()
  328. })
  329. this.resetSearchForm()
  330. },
  331. // 计算表格高度
  332. setTableH () {
  333. const tableSearchH = this.$refs.tableSearch.offsetHeight
  334. this.tableHeight = window.innerHeight - tableSearchH - 280
  335. }
  336. },
  337. mounted () {
  338. this.pageInit()
  339. }
  340. }
  341. </script>
  342. <style lang="less" scoped>
  343. .button-info[disabled] {
  344. color: gray;
  345. }
  346. /* 最后一行样式 */
  347. /deep/.last-row {
  348. background: #fafafa !important; /* 灰色背景 */
  349. /* 固定定位 */
  350. position: sticky;
  351. bottom: 0;
  352. z-index: 2;
  353. }
  354. /deep/.ant-input-number-handler-wrap {
  355. display: none;
  356. }
  357. </style>