addModal.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. <template>
  2. <hc-new-dialog is-table widths="90%" :show="isShow" :title="`变更令${dataId ? '修改' : '新增'}`" @save="addModalSave" @close="addModalClose">
  3. <div class="relative h-full flex">
  4. <div id="hc_add_dialog_tree_card">
  5. <hc-card-item title="工程部位" scrollbar>
  6. <template #extra>
  7. <el-link type="primary" @click="addChangeNode">添加</el-link>
  8. </template>
  9. <hc-lazy-tree show-checkbox tree-key="id" :h-props="treeProps" @load="treeLoadNode" @check="treeNodeCheck" />
  10. </hc-card-item>
  11. </div>
  12. <div id="hc_add_dialog_table_card">
  13. <el-scrollbar>
  14. <!-- 基础表单 -->
  15. <hc-card-item title="基础表单">
  16. <el-form ref="baseFormRef" :model="baseForm" :rules="baseFormRules" label-position="left" label-width="auto">
  17. <el-row :gutter="20">
  18. <el-col :span="8">
  19. <el-form-item label="变更令编号:" prop="changeNumber">
  20. <el-input v-model="baseForm.changeNumber" />
  21. </el-form-item>
  22. </el-col>
  23. <el-col :span="8">
  24. <el-form-item label="变更令名称:" prop="changeName">
  25. <el-input v-model="baseForm.changeName" />
  26. </el-form-item>
  27. </el-col>
  28. <el-col :span="8">
  29. <el-form-item label="变更发起单位:">
  30. <el-input v-model="baseForm.changeUnit" />
  31. </el-form-item>
  32. </el-col>
  33. <el-col :span="8">
  34. <el-form-item label="业务日期:" prop="businessDate">
  35. <el-date-picker v-model="baseForm.businessDate" class="block" format="YYYY-MM-DD" type="date" value-format="YYYY-MM-DD" />
  36. </el-form-item>
  37. </el-col>
  38. <el-col :span="8">
  39. <el-form-item label="变更类型:">
  40. <el-select v-model="baseForm.changeType" filterable block>
  41. <el-option v-for="item in typeData" :key="item.value" :label="item.label" :value="item.value" />
  42. </el-select>
  43. </el-form-item>
  44. </el-col>
  45. <el-col :span="8">
  46. <el-form-item label="延长工期:">
  47. <el-input v-model="baseForm.lengthenDays" />
  48. </el-form-item>
  49. </el-col>
  50. <el-col :span="8">
  51. <el-form-item label="变更申请金额:">
  52. <el-input v-model="baseForm.changeMoney" disabled />
  53. </el-form-item>
  54. </el-col>
  55. <el-col :span="8">
  56. <el-form-item label="设计完成时间:" prop="designDate">
  57. <el-date-picker v-model="baseForm.designDate" class="block" format="YYYY-MM-DD" type="date" value-format="YYYY-MM-DD" />
  58. </el-form-item>
  59. </el-col>
  60. <el-col :span="8">
  61. <el-form-item label="实际变更桩号:">
  62. <el-input v-model="baseForm.realityChangeNumber" />
  63. </el-form-item>
  64. </el-col>
  65. <el-col :span="8">
  66. <el-form-item label="变更归类:">
  67. <el-select v-model="baseForm.changeClassify" filterable block>
  68. <el-option v-for="item in classifyData" :key="item.value" :label="item.label" :value="item.value" />
  69. </el-select>
  70. </el-form-item>
  71. </el-col>
  72. <el-col :span="8">
  73. <el-form-item label="变更批复文号:">
  74. <el-input v-model="baseForm.changeApprovalNumber" />
  75. </el-form-item>
  76. </el-col>
  77. <el-col :span="8">
  78. <el-form-item label="变更批复日期:" prop="changeApprovalDate">
  79. <el-date-picker v-model="baseForm.changeApprovalDate" class="block" format="YYYY-MM-DD" type="date" value-format="YYYY-MM-DD" />
  80. </el-form-item>
  81. </el-col>
  82. <!-- el-col :span="24">
  83. <el-form-item class="input-link-item" label="引用预变更:">
  84. <el-input v-model="baseForm.key6" disabled />
  85. <el-link type="primary" @click="quoteClick">引用</el-link>
  86. <el-link type="danger">删除引用</el-link>
  87. </el-form-item>
  88. </el-col -->
  89. <el-col :span="24">
  90. <el-form-item label="变更原因:">
  91. <el-input v-model="baseForm.changeCause" :autosize="{ minRows: 4, maxRows: 8 }" type="textarea" />
  92. </el-form-item>
  93. </el-col>
  94. </el-row>
  95. </el-form>
  96. </hc-card-item>
  97. <!-- 变更申请部位 -->
  98. <hc-card-item title="变更申请部位" class="mt-3">
  99. <hc-table :column="tableColumn" :datas="tableData" is-new is-current-row :index-style="{ width: 60 }" @row-click="rowChangeNodeClick">
  100. <template #contractPicture="{ row }">
  101. <hc-table-input v-model="row.contractPicture" />
  102. </template>
  103. <template #action="{ index }">
  104. <el-link type="danger" @click="delChangeNode(index)">删除</el-link>
  105. </template>
  106. </hc-table>
  107. </hc-card-item>
  108. <!-- 变更申请清单 -->
  109. <hc-card-item title="变更申请清单" class="mt-3">
  110. <template #extra>
  111. <el-link type="primary" @click="changeShowClick">添加</el-link>
  112. </template>
  113. <div class="no-border hc-table-ref-box">
  114. <el-table class="w-full" :data="tableData[tableIndex]?.formList" row-key="id" height="100%" highlight-current-row border>
  115. <el-table-column type="index" label="序号" />
  116. <el-table-column prop="formNumber" label="清单编号" />
  117. <el-table-column prop="formName" label="清单名称" />
  118. <el-table-column prop="currentPrice" label="单价" />
  119. <el-table-column label="数量" align="center">
  120. <el-table-column prop="contractTotal" label="变更前" />
  121. <el-table-column prop="currentChangeTotal" label="变更增减">
  122. <template #default="{ row }">
  123. <hc-table-input v-model="row.currentChangeTotal" @blur="currentChangeTotalBlur(row)" />
  124. </template>
  125. </el-table-column>
  126. <el-table-column prop="changeTotal" label="变更后" />
  127. </el-table-column>
  128. <el-table-column label="金额" align="center">
  129. <el-table-column prop="contractMoney" label="变更前" />
  130. <el-table-column prop="currentChangeMoney" label="变更增减" />
  131. <el-table-column prop="changeMoney" label="变更后" />
  132. </el-table-column>
  133. <el-table-column prop="action" label="操作" width="80" align="center">
  134. <template #default="scope">
  135. <el-link type="danger" @click="tableFormListDel(scope.$index)">删除</el-link>
  136. </template>
  137. </el-table-column>
  138. </el-table>
  139. </div>
  140. </hc-card-item>
  141. <!-- 附件列表 -->
  142. <hc-card-item class="mt-3" title="附件列表">
  143. <template #extra>
  144. <span class="text-orange font-400">可上传 图片(png、jpg、jpeg)、Excel(xls、xlsx)、PDF、Word(doc、docx)文件</span>
  145. </template>
  146. <el-form :model="baseForm" label-position="left" label-width="auto">
  147. <el-form-item label="上传附件">
  148. <hc-form-upload
  149. v-model="baseForm.fileList"
  150. is-res
  151. :options="{
  152. type: 'list',
  153. props: uploadFormProps,
  154. isArr: true,
  155. num: 0,
  156. preview: false,
  157. }"
  158. :upload="{ options: { multiple: false } }"
  159. @item="uploadFileItem"
  160. @success="uploadFileSuccess"
  161. />
  162. </el-form-item>
  163. </el-form>
  164. </hc-card-item>
  165. </el-scrollbar>
  166. </div>
  167. </div>
  168. <!-- 变更申请清单 -->
  169. <ChangeRequest v-model="isChangeShow" :ids="changeIds" :tree-id="changeNodeItem.id" :contract-id="contractId" @finish="changeNodeFinish" />
  170. </hc-new-dialog>
  171. </template>
  172. <script setup>
  173. import { nextTick, ref, watch } from 'vue'
  174. import { useAppStore } from '~src/store'
  175. import { toPdfPage } from '~uti/btn-auth'
  176. import { getDictionaryData, isNumberReg } from '~uti/tools'
  177. import { arrIndex, arrToKey, formValidate, getArrValue, getObjValue, isArray, isNullES } from 'js-fast-way'
  178. import ChangeRequest from './changeRequest.vue'
  179. import unitApi from '~api/project/debit/contract/unit'
  180. import mainApi from '~api/alter/admin/order'
  181. import BigNumber from 'bignumber.js'
  182. const props = defineProps({
  183. ids: {
  184. type: [String, Number],
  185. default: '',
  186. },
  187. })
  188. //事件
  189. const emit = defineEmits(['finish', 'close'])
  190. const useAppState = useAppStore()
  191. const projectId = ref(useAppState.getProjectId || '')
  192. const contractId = ref(useAppState.getContractId || '')
  193. //双向绑定
  194. // eslint-disable-next-line no-undef
  195. const isShow = defineModel('modelValue', {
  196. default: false,
  197. })
  198. //监听
  199. const dataId = ref(props.ids)
  200. watch(() => props.ids, (ids) => {
  201. dataId.value = ids
  202. }, { immediate: true })
  203. //监听
  204. watch(isShow, (val) => {
  205. if (val) {
  206. getMeterChangeClassify()
  207. getMeterChangeType()
  208. getTableDetail()
  209. nextTick(() => {
  210. setSplitRef()
  211. })
  212. }
  213. })
  214. //初始化设置拖动分割线
  215. const setSplitRef = () => {
  216. //配置参考: https://split.js.org/#/?direction=vertical&snapOffset=0
  217. try {
  218. window.$split(['#hc_add_dialog_tree_card', '#hc_add_dialog_table_card'], {
  219. sizes: [20, 80],
  220. snapOffset: 0,
  221. minSize: [100, 400],
  222. })
  223. } catch (error) {
  224. console.log(error)
  225. }
  226. }
  227. //计量变更归类
  228. const classifyData = ref([])
  229. const getMeterChangeClassify = async () => {
  230. classifyData.value = await getDictionaryData('meter_change_classify')
  231. }
  232. //计量变更类型
  233. const typeData = ref([])
  234. const getMeterChangeType = async () => {
  235. typeData.value = await getDictionaryData('meter_change_type')
  236. }
  237. //获取详情
  238. const getTableDetail = async () => {
  239. if (isNullES(dataId.value)) return
  240. const { data } = await mainApi.getDetail({ id: dataId.value })
  241. const info = getObjValue(data)
  242. baseForm.value = info
  243. tableData.value = getArrValue(info.nodeList)
  244. }
  245. //数据格式
  246. const treeProps = {
  247. label: 'nodeName',
  248. children: 'children',
  249. isLeaf: 'notExsitChild',
  250. }
  251. //懒加载的数据
  252. const treeLoadNode = async ({ item, level }, resolve) => {
  253. let id = 0
  254. if (level !== 0) {
  255. const nodeData = getObjValue(item)
  256. id = nodeData?.id || ''
  257. }
  258. //获取数据
  259. const { data } = await unitApi.lazyTree({
  260. contractId: contractId.value,
  261. id: id,
  262. })
  263. resolve(getArrValue(data))
  264. }
  265. //节点树被点击
  266. const treeCheckKeys = ref('')
  267. const treeNodeCheck = (_, { checkedKeys }) => {
  268. treeCheckKeys.value = checkedKeys?.join() ?? ''
  269. }
  270. //基础表单
  271. const baseFormRef = ref(null)
  272. const baseForm = ref({ fileList: [] })
  273. const baseFormRules = {
  274. changeNumber: {
  275. required: true,
  276. trigger: 'blur',
  277. message: '请输入变更令编号',
  278. },
  279. changeName: {
  280. required: true,
  281. trigger: 'blur',
  282. message: '请输入变更令名称',
  283. },
  284. businessDate: {
  285. required: true,
  286. trigger: 'blur',
  287. message: '请选择业务日期',
  288. },
  289. designDate: {
  290. required: true,
  291. trigger: 'blur',
  292. message: '请选择设计完成时间',
  293. },
  294. changeApprovalDate: {
  295. required: true,
  296. trigger: 'blur',
  297. message: '请选择变更批复日期',
  298. },
  299. }
  300. //变更申请部位列表
  301. const tableColumn = ref([
  302. { key: 'nodeName', name: '工程名称' },
  303. { key: 'nodeUrl', name: '节点路径' },
  304. { key: 'contractPicture', name: '合同图号' },
  305. { key: 'changeMoney', name: '变更后金额(元)' },
  306. { key: 'isSupplementName', name: '是否增补' },
  307. { key: 'action', name: '操作', width: 80, align: 'center' },
  308. ])
  309. const tableData = ref([])
  310. const addChangeNode = async () => {
  311. const nodeId = treeCheckKeys.value ?? ''
  312. if (isNullES(nodeId)) {
  313. window.$message.warning('请先选择节点')
  314. return
  315. }
  316. const { data } = await mainApi.getChangeNode({
  317. projectId: projectId.value,
  318. contractId: contractId.value,
  319. changeIds: tableData.value.map((item) => item.id).join(),
  320. ids: nodeId,
  321. })
  322. const newArr = getArrValue(data)
  323. tableData.value.push(...newArr)
  324. }
  325. //删除变更申请部位
  326. const delChangeNode = (index) => {
  327. tableData.value.splice(index, 1)
  328. tableIndex.value = -1
  329. }
  330. //变更申请部位 行被点击
  331. const changeNodeItem = ref({})
  332. const tableIndex = ref(-1)
  333. const rowChangeNodeClick = ({ row }) => {
  334. const index = arrIndex(tableData.value, 'id', row.id)
  335. if (!isArray(row.formList)) {
  336. tableData.value[index].formList = []
  337. }
  338. // tableIndex.value = index
  339. tableIndex.value = index
  340. changeNodeItem.value = row
  341. }
  342. //删除变更申请清单
  343. const tableFormListDel = (index) => {
  344. tableData.value[tableIndex.value].formList.splice(index, 1)
  345. getFormList()
  346. }
  347. //变更清单的添加弹窗
  348. const isChangeShow = ref(false)
  349. const changeIds = ref('')
  350. const changeShowClick = () => {
  351. if (isNullES(changeNodeItem.value['id'])) {
  352. window.$message.warning('请先选择变更申请部位')
  353. return false
  354. }
  355. changeIds.value = arrToKey(tableData.value[tableIndex.value].formList, 'id')
  356. isChangeShow.value = true
  357. }
  358. //确认选择完成
  359. const changeNodeFinish = (data) => {
  360. tableData.value[tableIndex.value].formList.push(...data)
  361. getFormList()
  362. }
  363. //变更清单增减
  364. const currentChangeTotalBlur = (row) => {
  365. //如果为空
  366. let val = row.currentChangeTotal
  367. const isMeter = isNumberReg(val)
  368. if (isNullES(val) || !isMeter) {
  369. val = 0
  370. }
  371. const changeNum = (BigNumber(row.contractTotal).plus(val)).toString()
  372. if (changeNum < 0) {
  373. window.$message.warning('变更增减数量不能小于变更前数量')
  374. const contract = '-' + row.contractTotal
  375. nextTick(() => {
  376. //设置数量
  377. row.currentChangeTotal = contract
  378. row.changeTotal = 0
  379. //计算金额
  380. row.currentChangeMoney = (BigNumber(contract).multipliedBy(row.currentPrice)).toString()
  381. row.changeMoney = 0
  382. getFormList()
  383. })
  384. } else {
  385. nextTick(() => {
  386. //设置数量
  387. row.changeTotal = changeNum
  388. row.currentChangeTotal = val
  389. //计算金额
  390. row.currentChangeMoney = (BigNumber(val).multipliedBy(row.currentPrice)).toString()
  391. row.changeMoney = (BigNumber(changeNum).multipliedBy(row.currentPrice)).toString()
  392. getFormList()
  393. })
  394. }
  395. }
  396. //获取变更清单总额
  397. const getFormList = () => {
  398. let total = 0, table = tableData.value
  399. for (let i = 0; i < table.length; i++) {
  400. const item = table[i]
  401. if (!isArray(item.formList)) {
  402. item.formList = []
  403. }
  404. let changeMoney = 0
  405. for (let j = 0; j < item.formList.length; j++) {
  406. const form = item.formList[j]
  407. total = (BigNumber(total).plus(form.currentChangeMoney)).toString()
  408. //变更后的金额统计
  409. changeMoney = (BigNumber(changeMoney).plus(form.changeMoney)).toString()
  410. }
  411. item.changeMoney = changeMoney
  412. }
  413. //更新数据
  414. nextTick(() => {
  415. tableData.value = table
  416. baseForm.value.changeMoney = total
  417. })
  418. }
  419. //附件上传
  420. const uploadFormProps = {
  421. url: 'filePdfUrl',
  422. name: 'fileName',
  423. }
  424. // 文件上传成功的回调
  425. const uploadFileSuccess = ({ res }, resolve) => {
  426. const { link, pdfUrl, originalName } = getObjValue(res.data)
  427. if (isNullES(pdfUrl)) {
  428. window.$message.warning('该文件不能生成pdf,请更换文件上传')
  429. resolve()
  430. return
  431. }
  432. resolve({
  433. contractId: contractId.value,
  434. fileName: originalName ?? '',
  435. filePdfUrl: pdfUrl ?? '',
  436. fileUrl: link ?? '',
  437. })
  438. }
  439. //文件被点击
  440. const uploadFileItem = ({ file }) => {
  441. const { pdfUrl } = getObjValue(file)
  442. if (isNullES(pdfUrl)) return
  443. toPdfPage(pdfUrl)
  444. }
  445. //保存
  446. const addModalSave = async () => {
  447. const isValidate = await formValidate(baseFormRef.value)
  448. if (!isValidate) return false
  449. const form = baseForm.value, table = tableData.value
  450. if (table.length <= 0) {
  451. window.$message.warning('请先添加变更申请部位')
  452. return false
  453. }
  454. form.nodeList = table
  455. form.projectId = projectId.value
  456. form.contractId = contractId.value
  457. //发起请求
  458. let res = {}
  459. if (isNullES(dataId.value)) {
  460. //新增
  461. res = await mainApi.add(form)
  462. } else {
  463. //修改
  464. res = await mainApi.edit(form)
  465. }
  466. //处理数据
  467. const { code, msg } = res
  468. if (code === 200) {
  469. window.$message.success('保存成功')
  470. addModalClose()
  471. emit('finish')
  472. } else {
  473. window.$message.error(msg ?? '保存失败')
  474. }
  475. }
  476. //关闭弹窗
  477. const addModalClose = () => {
  478. isShow.value = false
  479. baseForm.value = { fileList: [] }
  480. tableData.value = []
  481. tableIndex.value = -1
  482. emit('close')
  483. }
  484. </script>