projectDetail.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. <template>
  2. <div class="_ProjectDetail">
  3. <div class="detailHeader">
  4. <div>
  5. <div>
  6. <h2>
  7. {{ projectDetail?.['xmmc'] ?? '' }}
  8. <span class="subTitle" v-show="projectDetail?.['xmbh']"
  9. >({{ projectDetail?.['xmbh'] ?? '' }})</span
  10. >
  11. <span class="statu" v-if="projectDetail?.['xmzt'] === 0">立项申请中</span>
  12. <span class="statu" v-else-if="projectDetail?.['xmzt'] === 1">进行中</span>
  13. <span class="statu" v-else-if="projectDetail?.['xmzt'] === 2">已结项</span>
  14. <span class="statu" v-else-if="projectDetail?.['xmzt'] === 3">中止</span>
  15. <span class="statu" v-else-if="projectDetail?.['xmzt'] === 4">已验收</span>
  16. </h2>
  17. </div>
  18. <ul>
  19. <li
  20. v-if="projectPermis.projectPermisState.all || projectPermis.projectPermisState.xmLeader"
  21. v-show="currentIndex === 0 && ![2].includes(projectDetail?.['xmzt'])"
  22. @click="editorProject"
  23. >{{ !isEditorProject ? '编辑' : '保存' }}
  24. </li>
  25. <template v-if="projectDetail?.['isSign'] === 1">
  26. <template
  27. v-if="
  28. (projectPermis.projectPermisState.all ||
  29. projectPermis.projectPermisState.xsLeader ||
  30. projectPermis.projectPermisState.projectMember) &&
  31. !signContract.flowStatus &&
  32. isShowSign
  33. "
  34. >
  35. <dialog-confirm
  36. title="是否发起合同签订流程?"
  37. v-if="!signContract?.exist"
  38. @confirm="handleStartContractSign"
  39. >
  40. <template #reference>
  41. <li>合同签订</li>
  42. </template>
  43. </dialog-confirm>
  44. <li
  45. v-else-if="signContract.flowStatus === 1"
  46. @click="processLookHandle(signContract.instanceId)"
  47. >
  48. 合同签订
  49. </li>
  50. </template>
  51. </template>
  52. <!-- <li
  53. v-if="projectPermis.projectPermisState.all || projectPermis.projectPermisState.xmLeader"
  54. v-show="currentIndex === 0 && ![2, 3].includes(projectDetail?.['xmzt'])"
  55. @click="addSubProject"
  56. >
  57. 添加子项目
  58. </li> -->
  59. <li
  60. v-if="projectPermis.projectPermisState.all || projectPermis.projectPermisState.xmLeader"
  61. v-show="projectDetail?.['xmzt'] === 1"
  62. @click="projectStatusAndProcessHandler('ys')"
  63. >
  64. 验收
  65. </li>
  66. <dialog-confirm
  67. :title="`是否中止项目【${projectDetail?.['xmbh']}】?`"
  68. v-if="projectPermis.projectPermisState.all || projectPermis.projectPermisState.xmLeader"
  69. @confirm="projectTerminateHandler"
  70. >
  71. <template #reference>
  72. <li v-show="projectDetail?.['xmzt'] === 1"> 中止 </li>
  73. </template>
  74. </dialog-confirm>
  75. <dialog-confirm
  76. :title="`是否恢复项目【${projectDetail?.['xmbh']}】?`"
  77. width="280px"
  78. v-if="projectPermis.projectPermisState.all || projectPermis.projectPermisState.xmLeader"
  79. @confirm="projectRecoverHandler"
  80. >
  81. <template #reference>
  82. <li v-show="projectDetail?.['xmzt'] === 3"> 恢复中止 </li>
  83. </template>
  84. </dialog-confirm>
  85. <li
  86. v-if="projectPermis.projectPermisState.all || projectPermis.projectPermisState.xmLeader"
  87. v-show="projectDetail?.['xmzt'] === 4"
  88. @click="projectStatusAndProcessHandler('jx')"
  89. >
  90. 结项
  91. </li>
  92. <li @click="processLookHandle(projectDetail.instanceId)">查看流程</li>
  93. </ul>
  94. </div>
  95. <div>
  96. <ul>
  97. <li @click="switchComponent(XmxxComp, 0)" :class="currentIndex === 0 ? 'active' : ''">
  98. <div><i class="icon"></i>项目信息</div>
  99. </li>
  100. <li
  101. v-show="
  102. signContract.exist && signContract.isvalid == 1 && signContract.flowStatus === 90
  103. "
  104. @click="switchComponent(XmhtComp, 1)"
  105. :class="currentIndex === 1 ? 'active' : ''"
  106. >
  107. <div><i class="icon"></i>项目合同</div>
  108. </li>
  109. <li @click="switchComponent(XmcbComp, 2)" :class="currentIndex === 2 ? 'active' : ''">
  110. <div><i class="icon"></i>项目成本</div>
  111. </li>
  112. <li @click="switchComponent(FjclComp, 3)" :class="currentIndex === 3 ? 'active' : ''">
  113. <div><i class="icon"></i>附件材料</div>
  114. </li>
  115. </ul>
  116. <div class="projectInfo">
  117. <template v-if="projectDetail?.['isSign'] === 0">
  118. <p style="margin-right: 0">该项目不签合同</p>
  119. </template>
  120. <template v-else-if="!signContract.exist">
  121. <p style="margin-right: 0">该项目待签合同</p>
  122. </template>
  123. <template
  124. v-else-if="
  125. signContract.exist && signContract.isvalid == 1 && signContract.flowStatus != 90
  126. "
  127. >
  128. <p style="margin-right: 0">合同签订过程中</p>
  129. </template>
  130. <template v-else>
  131. <p>
  132. <span class="title">合同额(元):</span>
  133. <span class="value">{{ projectDetail?.['contractAmount'] ?? '' }}</span>
  134. </p>
  135. <p>
  136. <span class="title">应收款(元):</span>
  137. <span class="value">{{ projectDetail?.['receivableAmount'] ?? '' }}</span>
  138. </p>
  139. <p>
  140. <span class="title">已回款(元):</span>
  141. <span class="value">{{ projectDetail?.['returnAmount'] ?? '0' }}</span>
  142. </p>
  143. <p>
  144. <span class="title">合同余额(元):</span>
  145. <span class="value">{{ projectDetail?.['contractBalance'] ?? '' }}</span>
  146. </p>
  147. </template>
  148. </div>
  149. </div>
  150. </div>
  151. <div class="detailContent">
  152. <component
  153. :is="currentComponent"
  154. ref="dynamicRef"
  155. :editor="isEditorProject"
  156. :isContract="signContract.exist"
  157. :isEstimateAmount="
  158. signContract.exist &&
  159. signContract.isvalid == 1 &&
  160. (signContract.flowStatus == 90 || signContract.flowStatus == 1)
  161. "
  162. />
  163. </div>
  164. </div>
  165. </template>
  166. <script setup lang="ts">
  167. import { type Component } from 'vue'
  168. import { useRoute } from 'vue-router'
  169. import { useProjectPermis } from '@/store/modules/projectPermis'
  170. import {
  171. isProjectContractExist,
  172. getContractsByProject,
  173. startContractSign
  174. } from '@/service/contract'
  175. import subscribe from '@/utils/Subscribe'
  176. import { openFlow, openProcessFlow } from '@/utils/flow'
  177. import { useMutation } from '@tanstack/vue-query'
  178. import { ProjectId } from '@/interface/project'
  179. import { Contract } from '@/interface/contract'
  180. import {
  181. getProjectWithChildrenById,
  182. projectStatusAndProcess,
  183. projectTerminate,
  184. projectRecover
  185. } from '@/service/project'
  186. import XmxxComp from './components/xmxx/index.vue'
  187. import XmhtComp from './components/xmht/index.vue'
  188. import XmcbComp from './components/xmcb/index.vue'
  189. import FjclComp from './components/fjcl/index.vue'
  190. const router = useRouter()
  191. defineOptions({ name: 'ProjectDetail' })
  192. const message = useMessage()
  193. const dynamicRef = shallowRef<Component>()
  194. const { query } = useRoute()
  195. const { id: projectId, contractId } = query
  196. const currentIndex = ref<number>(0)
  197. const currentComponent = shallowRef<Component>(XmxxComp)
  198. const switchComponent: (c: Component, i: number) => void = (c: Component, i: number) => {
  199. currentComponent.value = c
  200. currentIndex.value = i
  201. }
  202. const projectPermis = useProjectPermis()
  203. projectPermis.initProjectPermis(projectId as string)
  204. /***
  205. * 初始化项目中是否存在合同
  206. */
  207. const signContract = ref<{
  208. exist: boolean //判断是否存在合同
  209. contractId: string
  210. instanceId: string
  211. isvalid: number //判断有没有作废 0 已作废 1 未作废
  212. flowStatus: number //0|null 未开始 1 进行中 90 已完成
  213. }>({
  214. exist: false,
  215. contractId: '',
  216. instanceId: '',
  217. isvalid: 0,
  218. flowStatus: 0
  219. })
  220. const queryProjectContractExist = async (projectId: string) => {
  221. const result: any = await isProjectContractExist(projectId)
  222. if (result) {
  223. signContract.value = result
  224. }
  225. }
  226. // queryProjectContractExist(query?.id as string)
  227. /***
  228. * 查询项目详情
  229. * **/
  230. const projectDetail = ref()
  231. provide('projectDetail', projectDetail)
  232. const queryProjectByDetail = async (projectId: string) => {
  233. const result = await getProjectWithChildrenById(projectId)
  234. if (result) {
  235. projectDetail.value = result
  236. queryProjectContractExist(projectDetail.value.id)
  237. }
  238. }
  239. queryProjectByDetail(query?.id as string)
  240. subscribe.on('mainContractRefetch', () => {
  241. queryProjectByDetail(query?.id as string)
  242. })
  243. /**
  244. * 添加子项目
  245. * **/
  246. const addSubProject: () => void = () => {
  247. dynamicRef.value?.handleAddSubProject()
  248. }
  249. /**
  250. * 项目中止
  251. */
  252. const projectTerminateHandler = async () => {
  253. const id = projectDetail.value.id
  254. if (!id) {
  255. console.error('项目ID不存在!')
  256. return
  257. }
  258. await projectTerminate(id as string)
  259. message.success('中止成功')
  260. queryProjectByDetail(query?.id as string)
  261. }
  262. /**
  263. * 项目恢复
  264. */
  265. const projectRecoverHandler = async () => {
  266. const id = projectDetail.value.id
  267. if (!id) {
  268. console.error('项目ID不存在!')
  269. return
  270. }
  271. await projectRecover(id as string)
  272. message.success('中止成功')
  273. queryProjectByDetail(query?.id as string)
  274. }
  275. /**
  276. * 发起项目验收或结项
  277. */
  278. const sfysType: Ref<string> = ref('')
  279. const { mutate: startProjectStatusAndProcess } = useMutation(projectStatusAndProcess, {
  280. onSuccess: (data) => {
  281. const subTitle: string =
  282. sfysType.value === 'ys'
  283. ? '验收'
  284. : sfysType.value === 'jx'
  285. ? '结项'
  286. : sfysType.value === 'zz'
  287. ? '中止'
  288. : ''
  289. openFlow(router, data, `项目${subTitle}`)
  290. }
  291. })
  292. const projectStatusAndProcessHandler = (sfys: string) => {
  293. if (!sfys) {
  294. console.warn('sfys字段值不能为空!')
  295. return
  296. }
  297. sfysType.value = sfys
  298. startProjectStatusAndProcess({
  299. projectId: projectId as ProjectId,
  300. sfys
  301. })
  302. }
  303. /**
  304. * 流程查看
  305. */
  306. const processLookHandle = (instanceId: string) => {
  307. openProcessFlow(router, instanceId)
  308. }
  309. /***
  310. * 查询合同数据:存在多主合同情况
  311. * **/
  312. const contractDatas = ref<Contract[]>([])
  313. const queryContractsByProject = async (projectId: string) => {
  314. const tData: Contract[] = await getContractsByProject(projectId)
  315. contractDatas.value = tData
  316. if (contractDatas.value.length > 0 && contractId) {
  317. switchComponent(XmhtComp, 1)
  318. }
  319. }
  320. queryContractsByProject(query?.id as string)
  321. /**
  322. * 项目编辑
  323. * **/
  324. const isEditorProject = ref<boolean>(false)
  325. const editorProject: () => void = (): void => {
  326. isEditorProject.value = !isEditorProject.value
  327. if (isEditorProject.value) return
  328. //@ts-ignore
  329. dynamicRef.value.saveProjectHandle(0)
  330. }
  331. /**
  332. * 发起合同签订
  333. */
  334. const isShowSign = ref<boolean>(true)
  335. const { mutate: startContractSignMutate } = useMutation(startContractSign, {
  336. onSuccess: (data) => openFlow(router, data, '合同签订')
  337. })
  338. const handleStartContractSign = () => {
  339. isShowSign.value = false
  340. startContractSignMutate(projectId as ProjectId)
  341. }
  342. </script>
  343. <style lang="scss" scoped>
  344. @import url('./projectDetail.scss');
  345. </style>