task-review.vue 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832
  1. <template>
  2. <hc-new-dialog v-model="isShow" is-table widths="96%" title="任务审核" @close="cancelClick">
  3. <template #header="{ titleId, titleClass }">
  4. <div class="hc-card-header flex items-center">
  5. <div :id="titleId" :class="titleClass">任务审核 【已开启电签】</div>
  6. </div>
  7. </template>
  8. <div v-loading="isLoading" class="relative h-full">
  9. <div class="hc-task-name relative">{{ rowInfo.taskName }} 审批信息</div>
  10. <div class="hc-task-body relative flex">
  11. <div class="hc-task-time">
  12. <hc-body class="hc-task-body-card" padding="10px" scrollbar>
  13. <el-timeline v-if="rowInfo.fixedFlowId == null" class="hc-time-line">
  14. <template v-for="(item, index) in flowList" :key="index">
  15. <el-timeline-item :class="item.status === '2' ? 'success' : 'primary'" size="large">
  16. <div class="timeline-item-icon">
  17. <hc-icon v-if="item.status === '2'" class="check-icon" name="check" />
  18. </div>
  19. <div class="reply-name">{{ item.name }}</div>
  20. <div class="reply-time">{{ item.date }}</div>
  21. <div class="reply-content" v-html="item.flowValue" />
  22. </el-timeline-item>
  23. </template>
  24. </el-timeline>
  25. <el-timeline v-else class="hc-time-line">
  26. <template v-for="(item, index) in flowListTask" :key="index">
  27. <el-timeline-item :class="item.status == '2' ? 'success' : 'primary'" size="large">
  28. <div class="timeline-item-icon">
  29. <hc-icon v-if="item.status == '2'" class="check-icon" name="check" />
  30. </div>
  31. <div v-if="!item.isTask" class="reply-name">{{ item.name }}</div>
  32. <div v-if="item.isTask">
  33. <div class="reply-name">
  34. {{ item.name }}
  35. <hc-icon v-if="item.type == 2" name="links" class="ml-2" />
  36. <hc-icon v-if="item.type == 1" name="exchange-2" class="ml-2" />
  37. <br>
  38. <el-tooltip placement="right" effect="light" :visible="item.taskDetailvisible">
  39. <template #content>
  40. <el-timeline class="hc-time-line">
  41. <template v-for="(item1, index1) in item.userList" :key="index1">
  42. <el-timeline-item :class="item1.status === '2' ? 'success' : 'primary'" size="large">
  43. <div class="timeline-item-icon">
  44. <hc-icon v-if="item1.status === '2'" class="check-icon" name="check" />
  45. </div>
  46. <div class="reply-name">{{ item1.name }}</div>
  47. <div class="reply-time">{{ item1.date }}</div>
  48. <div class="reply-content" v-html="item1.flowValue" />
  49. </el-timeline-item>
  50. </template>
  51. </el-timeline>
  52. </template>
  53. <el-link @click="getTaskDetail" @mouseenter="item.taskDetailvisible = true" @mouseleave="item.taskDetailvisible = false">点击查看详情</el-link>
  54. </el-tooltip>
  55. </div>
  56. </div>
  57. <div class="reply-time">{{ item.date }}</div>
  58. <div class="reply-content" v-html="item.flowValue" />
  59. </el-timeline-item>
  60. </template>
  61. </el-timeline>
  62. </hc-body>
  63. </div>
  64. <div :id="`hc_task_table_${uuid}`" class="hc-task-table">
  65. <hc-body class="hc-task-body-card" padding="10px">
  66. <div class="hc-task-body-table">
  67. <hc-tab-card :tabs="tabsData" :tab-key="tabKey" @change="tabsChange">
  68. <hc-table
  69. v-if="tabKey === '1'" ref="tableRef" :column="tableColumn" :datas="tableData"
  70. :is-stripe="false" is-new :index-style="{ width: 60 }" is-current-row
  71. @row-click="tableRowClick"
  72. >
  73. <template #action="{ row }">
  74. <div class="hc-task-table-action" :class="row.isComment === 1 ? 'is-cur' : ''" @click="rowRemarkClick(row)">
  75. <i class="i-iconoir-star-solid" />
  76. </div>
  77. </template>
  78. <template #state="{ row }">
  79. <div class="hc-task-table-state">
  80. <i v-if="row.status === 1" class="i-iconoir-check-circle-solid is-success" />
  81. <i v-else-if="row.status === 2" class="i-iconoir-xmark-circle-solid is-danger" />
  82. <span v-else-if="row.status === 3">审批结束</span>
  83. <i v-else class="i-iconoir-help-circle-solid" />
  84. </div>
  85. </template>
  86. </hc-table>
  87. <div v-if="tabKey === '2'" class="hc-task-body-table-form">
  88. <template v-if="rowInfo.meterType === 1 || rowInfo.meterType === 3">
  89. <div class="title-box">
  90. <div v-if="meterApproveOpinion1.projectName" class="title">{{ meterApproveOpinion1.projectName }}</div>
  91. <div class="text">审批意见</div>
  92. </div>
  93. <!--
  94. <div class="name">计量工程师意见:</div>
  95. <div v-if="meterApproveOpinion1.meterEngineer" class="text-box hc-bt-0">
  96. <div class="content">{{ meterApproveOpinion1.meterEngineer }}</div>
  97. <div v-if="meterApproveOpinion1.meterEngineerUserName" class="sign-name">
  98. <div class="user-name">工程部:{{ meterApproveOpinion1.meterEngineerUserName }}</div>
  99. <div class="user-time">{{ meterApproveOpinion1.meterEngineerTime }}</div>
  100. </div>
  101. </div>
  102. <div v-else class="input hc-bt-0">
  103. <el-input v-model="meterApproveOpinion2.meterEngineer" :autosize="{ minRows: 2, maxRows: 4 }" type="textarea" />
  104. </div>
  105. <div class="name hc-bt-0">项目经理意见:</div>
  106. <div v-if="meterApproveOpinion1.projectManager" class="text-box hc-bt-0">
  107. <div class="content">{{ meterApproveOpinion1.projectManager }}</div>
  108. <div v-if="meterApproveOpinion1.projectManagerUserName" class="sign-name">
  109. <div class="user-name">工程部:{{ meterApproveOpinion1.projectManagerUserName }}</div>
  110. <div class="user-time">{{ meterApproveOpinion1.projectManagerTime }}</div>
  111. </div>
  112. </div>
  113. <div v-else class="input hc-bt-0">
  114. <el-input v-model="meterApproveOpinion2.projectManager" :autosize="{ minRows: 2, maxRows: 4 }" type="textarea" />
  115. </div>
  116. <div class="name hc-bt-0">合同监理工程师意见:</div>
  117. <div v-if="meterApproveOpinion1.contractSupervisorEngineer" class="text-box hc-bt-0">
  118. <div class="content">{{ meterApproveOpinion1.contractSupervisorEngineer }}</div>
  119. <div v-if="meterApproveOpinion1.contractSupervisorEngineerUserName" class="sign-name">
  120. <div class="user-name">工程部:{{ meterApproveOpinion1.contractSupervisorEngineerUserName }}</div>
  121. <div class="user-time">{{ meterApproveOpinion1.contractSupervisorEngineerTime }}</div>
  122. </div>
  123. </div>
  124. <div v-else class="input hc-bt-0">
  125. <el-input v-model="meterApproveOpinion2.contractSupervisorEngineer" :autosize="{ minRows: 2, maxRows: 4 }" type="textarea" />
  126. </div>
  127. <div class="name hc-bt-0">业主代表意见:</div>
  128. <div v-if="meterApproveOpinion1.ownerDelegate" class="text-box hc-bt-0">
  129. <div class="content">{{ meterApproveOpinion1.ownerDelegate }}</div>
  130. <div v-if="meterApproveOpinion1.ownerDelegateUserName" class="sign-name">
  131. <div class="user-name">工程部:{{ meterApproveOpinion1.ownerDelegateUserName }}</div>
  132. <div class="user-time">{{ meterApproveOpinion1.ownerDelegateTime }}</div>
  133. </div>
  134. </div>
  135. <div v-else class="input hc-bt-0">
  136. <el-input v-model="meterApproveOpinion2.ownerDelegate" :autosize="{ minRows: 2, maxRows: 4 }" type="textarea" />
  137. </div>
  138. -->
  139. <div class="name">总监理工程师意见:</div>
  140. <div v-if="meterApproveOpinion1.chiefSupervisor" class="text-box hc-bt-0">
  141. <div class="content">{{ meterApproveOpinion1.chiefSupervisor }}</div>
  142. <div v-if="meterApproveOpinion1.chiefSupervisorUserName" class="sign-name">
  143. <div class="user-name">{{ meterApproveOpinion1.chiefSupervisorUserName }}</div>
  144. <div class="user-time">{{ meterApproveOpinion1.chiefSupervisorTime }}</div>
  145. </div>
  146. </div>
  147. <div v-else class="input hc-bt-0">
  148. <el-input v-model="meterApproveOpinion2.chiefSupervisor" :autosize="{ minRows: 2, maxRows: 4 }" type="textarea" />
  149. </div>
  150. <template v-if="rowInfo.meterType === 3">
  151. <div class="name hc-bt-0">监理审核意见:</div>
  152. <div v-if="meterApproveOpinion1.supervisorAudit" class="text-box hc-bt-0">
  153. <div class="content">{{ meterApproveOpinion1.supervisorAudit }}</div>
  154. <div v-if="meterApproveOpinion1.supervisorAuditUserName" class="sign-name">
  155. <div class="user-name">{{ meterApproveOpinion1.supervisorAuditUserName }}</div>
  156. <div class="user-time">{{ meterApproveOpinion1.supervisorAuditTime }}</div>
  157. </div>
  158. </div>
  159. <div v-else class="input hc-bt-0">
  160. <el-input v-model="meterApproveOpinion2.supervisorAudit" :autosize="{ minRows: 2, maxRows: 4 }" type="textarea" />
  161. </div>
  162. </template>
  163. <div class="input-box">
  164. <div class="box">
  165. <div class="name hc-bt-0">工程建设部意见:</div>
  166. <div v-if="meterApproveOpinion1.projectBuild" class="text-box hc-bt-0">
  167. <div class="content">{{ meterApproveOpinion1.projectBuild }}</div>
  168. <div v-if="meterApproveOpinion1.projectBuildUserName" class="sign-name">
  169. <div class="user-name">{{ meterApproveOpinion1.projectBuildUserName }}</div>
  170. <div class="user-time">{{ meterApproveOpinion1.projectBuildTime }}</div>
  171. </div>
  172. </div>
  173. <div v-else class="input hc-bt-0">
  174. <el-input v-model="meterApproveOpinion2.projectBuild" :autosize="{ minRows: 2, maxRows: 4 }" type="textarea" />
  175. </div>
  176. </div>
  177. <div class="box">
  178. <div class="name no-b hc-bt-0">分管领导意见:</div>
  179. <div v-if="meterApproveOpinion1.projectBuildLeader" class="text-box no-b hc-bt-0">
  180. <div class="content">{{ meterApproveOpinion1.projectBuildLeader }}</div>
  181. <div v-if="meterApproveOpinion1.projectBuildLeaderUserName" class="sign-name">
  182. <div class="user-name">{{ meterApproveOpinion1.projectBuildLeaderUserName }}</div>
  183. <div class="user-time">{{ meterApproveOpinion1.projectBuildLeaderTime }}</div>
  184. </div>
  185. </div>
  186. <div v-else class="input no-b hc-bt-0">
  187. <el-input v-model="meterApproveOpinion2.projectBuildLeader" :autosize="{ minRows: 2, maxRows: 4 }" type="textarea" />
  188. </div>
  189. </div>
  190. </div>
  191. <div v-if="rowInfo.meterType === 1" class="input-box">
  192. <div class="box">
  193. <div class="name hc-bt-0">安全管理部意见:</div>
  194. <div v-if="meterApproveOpinion1.safetyManager" class="text-box hc-bt-0">
  195. <div class="content">{{ meterApproveOpinion1.safetyManager }}</div>
  196. <div v-if="meterApproveOpinion1.safetyManagerUserName" class="sign-name">
  197. <div class="user-name">{{ meterApproveOpinion1.safetyManagerUserName }}</div>
  198. <div class="user-time">{{ meterApproveOpinion1.safetyManagerTime }}</div>
  199. </div>
  200. </div>
  201. <div v-else class="input hc-bt-0">
  202. <el-input v-model="meterApproveOpinion2.safetyManager" :autosize="{ minRows: 2, maxRows: 4 }" type="textarea" />
  203. </div>
  204. </div>
  205. <div class="box">
  206. <div class="name no-b hc-bt-0">分管领导意见:</div>
  207. <div v-if="meterApproveOpinion1.safetyManagerLeader" class="text-box no-b hc-bt-0">
  208. <div class="content">{{ meterApproveOpinion1.safetyManagerLeader }}</div>
  209. <div v-if="meterApproveOpinion1.safetyManagerLeaderUserName" class="sign-name">
  210. <div class="user-name">{{ meterApproveOpinion1.safetyManagerLeaderUserName }}</div>
  211. <div class="user-time">{{ meterApproveOpinion1.safetyManagerLeaderTime }}</div>
  212. </div>
  213. </div>
  214. <div v-else class="input no-b hc-bt-0">
  215. <el-input v-model="meterApproveOpinion2.safetyManagerLeader" :autosize="{ minRows: 2, maxRows: 4 }" type="textarea" />
  216. </div>
  217. </div>
  218. </div>
  219. <div class="input-box">
  220. <div class="box">
  221. <div class="name hc-bt-0">合同部意见:</div>
  222. <div v-if="meterApproveOpinion1.contractDept" class="text-box hc-bt-0">
  223. <div class="content">{{ meterApproveOpinion1.contractDept }}</div>
  224. <div v-if="meterApproveOpinion1.contractDeptUserName" class="sign-name">
  225. <div class="user-name">{{ meterApproveOpinion1.contractDeptUserName }}</div>
  226. <div class="user-time">{{ meterApproveOpinion1.contractDeptTime }}</div>
  227. </div>
  228. </div>
  229. <div v-else class="input hc-bt-0">
  230. <el-input v-model="meterApproveOpinion2.contractDept" :autosize="{ minRows: 2, maxRows: 4 }" type="textarea" />
  231. </div>
  232. </div>
  233. <div class="box">
  234. <div class="name no-b hc-bt-0">分管领导意见:</div>
  235. <div v-if="meterApproveOpinion1.contractDeptLeader" class="text-box no-b hc-bt-0">
  236. <div class="content">{{ meterApproveOpinion1.contractDeptLeader }}</div>
  237. <div v-if="meterApproveOpinion1.contractDeptLeaderUserName" class="sign-name">
  238. <div class="user-name">{{ meterApproveOpinion1.contractDeptLeaderUserName }}</div>
  239. <div class="user-time">{{ meterApproveOpinion1.contractDeptLeaderTime }}</div>
  240. </div>
  241. </div>
  242. <div v-else class="input no-b hc-bt-0">
  243. <el-input v-model="meterApproveOpinion2.contractDeptLeader" :autosize="{ minRows: 2, maxRows: 4 }" type="textarea" />
  244. </div>
  245. </div>
  246. </div>
  247. <div class="name hc-bt-0">总经理意见:</div>
  248. <div v-if="meterApproveOpinion1.generalManager" class="text-box no-b hc-bt-0">
  249. <div class="content">{{ meterApproveOpinion1.generalManager }}</div>
  250. <div v-if="meterApproveOpinion1.generalManagerUserName" class="sign-name">
  251. <div class="user-name">{{ meterApproveOpinion1.generalManagerUserName }}</div>
  252. <div class="user-time">{{ meterApproveOpinion1.generalManagerTime }}</div>
  253. </div>
  254. </div>
  255. <div v-else class="input hc-bt-0">
  256. <el-input v-model="meterApproveOpinion2.generalManager" :autosize="{ minRows: 2, maxRows: 4 }" type="textarea" />
  257. </div>
  258. <div class="name no-b hc-bt-0">董事长意见:</div>
  259. <div v-if="meterApproveOpinion1.chiefExecutive" class="text-box no-b hc-bt-0">
  260. <div class="content">{{ meterApproveOpinion1.chiefExecutive }}</div>
  261. <div v-if="meterApproveOpinion1.chiefExecutiveUserName" class="sign-name">
  262. <div class="user-name">{{ meterApproveOpinion1.chiefExecutiveUserName }}</div>
  263. <div class="user-time">{{ meterApproveOpinion1.chiefExecutiveTime }}</div>
  264. </div>
  265. </div>
  266. <div v-else class="input no-b hc-bt-0">
  267. <el-input v-model="meterApproveOpinion2.chiefExecutive" :autosize="{ minRows: 2, maxRows: 4 }" type="textarea" />
  268. </div>
  269. </template>
  270. <template v-else>
  271. <hc-empty />
  272. </template>
  273. </div>
  274. </hc-tab-card>
  275. </div>
  276. <div v-if="!isNullES(detailInfo.opinionType)" class="hc-task-body-tip hc-flex h-30px">
  277. <span class="mr-14px">上报总金额:{{ reportAllMoney }}元</span>
  278. <span v-if="detailInfo.opinionType != 4">本期审核进度款:{{ progressMoney }}元</span>
  279. </div>
  280. </hc-body>
  281. </div>
  282. <div :id="`hc_task_form_${uuid}`" class="hc-task-form" :class="`is-tab-${taskTabsKey}`">
  283. <hc-body class="hc-task-body-card" padding="10px" scrollbar>
  284. <HcTaskForm ref="htmlFormRef" :table="tableInfo" :info="rowInfo" :detail="detailInfo" :is-edit="tabsKey === 1" @finish="taskFormFinish" @tab-tap="taskTabsClick" />
  285. </hc-body>
  286. </div>
  287. </div>
  288. </div>
  289. <template #footer>
  290. <div class="hc-task-dialog-footer">
  291. <el-button :disabled="tabsKey !== 1" @click="rejectionClick">驳回审批</el-button>
  292. <el-button v-if="rowInfo.meterType > 0 && rowInfo.meterType <= 3" type="warning" :loading="rowViewLoading" @click="rowViewPdf">查看报表</el-button>
  293. <el-button type="primary" :loading="confirmLoading" :disabled="tabsKey !== 1" @click="confirmClick">同意审批</el-button>
  294. </div>
  295. </template>
  296. </hc-new-dialog>
  297. <!-- 批注 -->
  298. <HcTaskNotes v-model="isNotesShow" :table="tableNoteInfo" :info="rowInfo" :is-edit="tabsKey === 1" @finish="taskNotesFinish" />
  299. <!-- 驳回 -->
  300. <HcRepealForm v-model="isRepealShow" :info="rowInfo" @finish="taskRepealFinish" />
  301. <!-- 短信认证 -->
  302. <HcSmsAuth :loading="SMSAuthLoading" :show="SMSAuthShow" @cancel="SMSAuthCancel" @confirm="SMSAuthConfirm" />
  303. </template>
  304. <script setup>
  305. import { nextTick, ref, watch } from 'vue'
  306. import { useAppStore } from '~src/store'
  307. import { toPdfPage } from '~uti/btn-auth'
  308. import HcTaskForm from './task-form.vue'
  309. import HcTaskNotes from './task-notes.vue'
  310. import HcRepealForm from './repeal-form.vue'
  311. import { arrUnion, deepClone, getArrValue, getObjValue, getRandom, isNullES } from 'js-fast-way'
  312. import mainApi from '~api/tasks/hc-data'
  313. import dayjs from 'dayjs'
  314. const props = defineProps({
  315. tabs: {
  316. type: [String, Number],
  317. default: '',
  318. },
  319. row: {
  320. type: Object,
  321. default: () => ({}),
  322. },
  323. })
  324. //事件
  325. const emit = defineEmits(['finish', 'close'])
  326. const uuid = getRandom(4)
  327. const useAppState = useAppStore()
  328. const projectId = ref(useAppState.getProjectId || '')
  329. const contractId = ref(useAppState.getContractId || '')
  330. //双向绑定
  331. // eslint-disable-next-line no-undef
  332. const isShow = defineModel('modelValue', {
  333. default: false,
  334. })
  335. //监听
  336. const tableRef = ref(null)
  337. const tabsKey = ref(Number(props.tabs))
  338. const rowInfo = ref(props.row)
  339. watch(() => [props.tabs, props.row], ([key, row]) => {
  340. tabsKey.value = Number(key)
  341. rowInfo.value = row
  342. }, {
  343. immediate: true,
  344. deep: true,
  345. })
  346. //监听显示
  347. watch(isShow, (val) => {
  348. if (val) {
  349. checkSmsCode()
  350. setTaskInfo()
  351. setSplitRef()
  352. }
  353. })
  354. //初始化设置拖动分割线
  355. const setSplitRef = () => {
  356. //配置参考: https://split.js.org/#/?direction=vertical&snapOffset=0
  357. nextTick(() => {
  358. window.$split(['#hc_task_table_' + uuid, '#hc_task_form_' + uuid], {
  359. sizes: [50, 50],
  360. snapOffset: 0,
  361. minSize: [50, 500],
  362. })
  363. })
  364. }
  365. //设置任务信息
  366. const setTaskInfo = () => {
  367. //meterType:1中间,2材料,3开工,4变更令
  368. const { meterType } = rowInfo.value
  369. if (meterType === 1) {
  370. tableColumn.value = middlepayTableColumn.value
  371. } else if (meterType === 2) {
  372. tableColumn.value = materialTableColumn.value
  373. } else if (meterType === 3) {
  374. tableColumn.value = startWorkTableColumn.value
  375. } else if (meterType === 4) {
  376. tableColumn.value = alterTableColumn.value
  377. } else {
  378. tableColumn.value = []
  379. }
  380. getTableDetail()
  381. }
  382. //获取数据详情
  383. const detailInfo = ref({})
  384. const reportAllMoney = ref('0')
  385. const progressMoney = ref('0')
  386. const meterApproveOpinion1 = ref({})
  387. const meterApproveOpinion2 = ref({})
  388. const isLoading = ref(false)
  389. const getTableDetail = async () => {
  390. isLoading.value = true
  391. confirmLoading.value = true
  392. //获取数据
  393. const { data } = await mainApi.getDetail(rowInfo.value.id)
  394. const infoData = getObjValue(data)
  395. const { taskProcessInfo, taskCenterDataInfo } = infoData
  396. tableData.value = getArrValue(taskCenterDataInfo)
  397. flowList.value = getArrValue(taskProcessInfo)
  398. reportAllMoney.value = infoData.reportAllMoney
  399. progressMoney.value = infoData.progressMoney
  400. detailInfo.value = infoData
  401. if (rowInfo.value?.fixedFlowId) {
  402. const list = [...flowList.value]
  403. let firstarr = list.slice(0, 1)
  404. let taskList = list.slice(1, list.length)
  405. taskList.forEach((ele)=>{
  406. ele.name = ele.taskBranchName
  407. ele.status = ele.taskBranchStatus
  408. ele.type = ele.taskBranchType
  409. ele.isTask = true
  410. })
  411. flowListTask.value = arrUnion(firstarr, taskList)
  412. }
  413. //意见信息
  414. const meterRes = getObjValue(data.meterApproveOpinion)
  415. meterApproveOpinion2.value = deepClone(meterRes)
  416. meterApproveOpinion1.value = meterRes
  417. //默认选中第一行
  418. let info = {}
  419. if (tableData.value.length > 0) {
  420. info = tableData.value[0]
  421. }
  422. await nextTick(() => {
  423. tableInfo.value = info
  424. tableRef.value?.tableRef?.setCurrentRow(info)
  425. })
  426. //关闭加载状态
  427. isLoading.value = false
  428. confirmLoading.value = false
  429. }
  430. //流程信息,1待审批,2已审批
  431. const flowList = ref([])
  432. //type为1流程审批,type为2是平行审批
  433. const flowListTask = ref([
  434. { name: 'PCT', date: '2024-03-01 09:27:17', status: '2', flowValue: '上报', isTask:false },
  435. { name: '"222"', date: '', status: '2', flowValue: '', type:1, isTask:true },
  436. { name: '"111"', date: '', status: '1', flowValue: '', type:2, isTask:true },
  437. ])
  438. const taskDetailList = ref([])
  439. //中间计量单的表格数据
  440. const middlepayTableColumn = ref([
  441. { key: 'action', name: '批注', width: 45, align: 'center' },
  442. { key: 'meterNumber', name: '计量单编号' },
  443. { key: 'meterMoney', name: '计量金额', width: 100 },
  444. { key: 'engineerDivide', name: '工程划分' },
  445. { key: 'state', name: '审批状态', fixed: 'right', width: 70, align: 'center' },
  446. ])
  447. //开工预付款计量单的表格数据
  448. const startWorkTableColumn = ref([
  449. { key: 'action', name: '批注', width: 45, align: 'center' },
  450. { key: 'periodName', name: '计量期', minWidth: 100, align: 'center' },
  451. { key: 'businessDate', name: '业务日期', width: 160, align: 'center' },
  452. { key: 'meterMoney', name: '计量金额', width: 100, align: 'center' },
  453. { key: 'state', name: '审批状态', fixed: 'right', width: 70, align: 'center' },
  454. ])
  455. //变更令的表格数据
  456. const alterTableColumn = ref([
  457. { key: 'action', name: '批注', width: 45, align: 'center' },
  458. { key: 'changeNumber', name: '变更编号', minWidth: 120, align: 'center' },
  459. { key: 'changeName', name: '变更名称', minWidth: 120, align: 'center' },
  460. { key: 'changeMoney', name: '变更金额', width: 100, align: 'center' },
  461. { key: 'changeApprovalDate', name: '变更批复日期', width: 160, align: 'center' },
  462. { key: 'state', name: '审批状态', fixed: 'right', width: 70, align: 'center' },
  463. ])
  464. //材料计量单的表格数据
  465. const materialTableColumn = ref([
  466. { key: 'action', name: '批注', width: 45, align: 'center' },
  467. { key: 'periodName', name: '计量期', minWidth: 100, align: 'center' },
  468. { key: 'contractMaterialName', name: '合同材料', minWidth: 120, align: 'center' },
  469. { key: 'materialArriveNumber', name: '材料到场编号', width: 120, align: 'center' },
  470. { key: 'meterMoney', name: '计量金额', width: 100, align: 'center' },
  471. { key: 'state', name: '审批状态', fixed: 'right', width: 70, align: 'center' },
  472. ])
  473. //表格数据
  474. const tableColumn = ref([])
  475. const tableData = ref([])
  476. //表格行被点击
  477. const tableInfo = ref({})
  478. const tableRowClick = ({ row }) => {
  479. tableInfo.value = row
  480. }
  481. //批注, isComment 是否已批注,1=是,0=否
  482. const isNotesShow = ref(false)
  483. const tableNoteInfo = ref({})
  484. const rowRemarkClick = (row) => {
  485. tableNoteInfo.value = row
  486. nextTick(() => {
  487. isNotesShow.value = true
  488. })
  489. }
  490. //批注完成
  491. const taskNotesFinish = () => {
  492. getTableDetail()
  493. }
  494. //单条审批
  495. const taskFormFinish = () => {
  496. getTableDetail()
  497. }
  498. //确认审批
  499. const confirmLoading = ref(false)
  500. const confirmClick = () => {
  501. const ShowAuth = isCheckSmsCodeTime()
  502. SMSAuthShow.value = ShowAuth
  503. //免短信验证
  504. if (!ShowAuth) SMSAuthConfirm()
  505. }
  506. //驳回审批
  507. const isRepealShow = ref(false)
  508. const rejectionClick = async () => {
  509. isRepealShow.value = true
  510. }
  511. //驳回完成
  512. const taskRepealFinish = () => {
  513. emit('finish')
  514. cancelClick()
  515. }
  516. //取消审批
  517. const cancelClick = () => {
  518. isShow.value = false
  519. isLoading.value = false
  520. confirmLoading.value = false
  521. tableColumn.value = []
  522. tableData.value = []
  523. tableInfo.value = {}
  524. emit('close')
  525. }
  526. const taskDetailvisible = ref(false)
  527. const getTaskDetail = ()=>{
  528. taskDetailvisible.value = true
  529. }
  530. //短信验证有效期
  531. const smsCodeTime = ref('')
  532. const checkSmsCode = async () => {
  533. const { data } = await mainApi.checkSmsCode()
  534. smsCodeTime.value = data ? data : ''
  535. }
  536. //验证短信有效期
  537. const isCheckSmsCodeTime = () => {
  538. const smsTime = smsCodeTime.value
  539. if (isNullES(smsTime)) {
  540. return true
  541. } else {
  542. const toDayTime = dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss')
  543. return dayjs(smsTime).isBefore(toDayTime)
  544. }
  545. }
  546. //短信验证
  547. const SMSAuthLoading = ref(false)
  548. const SMSAuthShow = ref(false)
  549. const htmlFormRef = ref(null)
  550. const SMSAuthConfirm = async () => {
  551. confirmLoading.value = true
  552. const tableData = htmlFormRef.value?.getTableForm()
  553. const { error, code, msg } = await mainApi.taskApprove({
  554. tableData: tableData,
  555. taskId: rowInfo.value.id,
  556. projectId: projectId.value,
  557. contractId: contractId.value,
  558. meterApproveOpinion: meterApproveOpinion2.value,
  559. })
  560. if (!error && code === 200) {
  561. window.$message.success('审批成功')
  562. await checkSmsCode()
  563. confirmLoading.value = false
  564. emit('finish')
  565. SMSAuthCancel()
  566. cancelClick()
  567. } else {
  568. confirmLoading.value = false
  569. window.$message.error(msg ?? '审批失败')
  570. }
  571. }
  572. const SMSAuthCancel = () => {
  573. SMSAuthShow.value = false
  574. }
  575. //选项卡被切换
  576. const taskTabsKey = ref('key1')
  577. const taskTabsClick = (key) => {
  578. taskTabsKey.value = key
  579. }
  580. //查看报表
  581. const rowViewLoading = ref(false)
  582. const rowViewPdf = async () => {
  583. const { type, reportId } = detailInfo.value
  584. if (isNullES(reportId)) {
  585. window.$message.warning('参数异常')
  586. return
  587. }
  588. rowViewLoading.value = true
  589. const { code, msg, data } = await mainApi.taskMeterPdfInfo({
  590. reportId: reportId,
  591. type: type,
  592. taskType: 10,
  593. taskId: rowInfo.value.id,
  594. })
  595. rowViewLoading.value = false
  596. if (code === 200 && !isNullES(data)) {
  597. window.$message.success('操作成功')
  598. toPdfPage(data)
  599. } else {
  600. window.$message.error(msg ?? '操作失败')
  601. }
  602. }
  603. //选项卡
  604. const tabKey = ref('1')
  605. const tabsData = [
  606. { key: '2', name: '意见信息' },
  607. { key: '1', name: '计量单信息' },
  608. ]
  609. const tabsChange = ({ key }) => {
  610. tabKey.value = key
  611. }
  612. </script>
  613. <style lang="scss" scoped>
  614. .hc-task-name {
  615. font-weight: bold;
  616. color: #1A1a1a;
  617. padding-bottom: 10px;
  618. border-bottom: 1px solid #f5f5f5;
  619. }
  620. .hc-task-body {
  621. height: calc(100% - 27px);
  622. .hc-task-time {
  623. position: relative;
  624. height: 100%;
  625. flex-shrink: 0;
  626. width: 170px;
  627. }
  628. .hc-task-table, .hc-task-form {
  629. position: relative;
  630. height: 100%;
  631. flex: 1;
  632. flex-basis: auto;
  633. }
  634. .hc-task-table {
  635. border-left: 1px solid #e5e5e5;
  636. }
  637. }
  638. //表格图标
  639. .hc-task-table-action, .hc-task-table-state {
  640. position: relative;
  641. display: flex;
  642. justify-content: center;
  643. align-items: center;
  644. cursor: pointer;
  645. font-size: 20px;
  646. color: #929293;
  647. i {
  648. display: inline-flex;
  649. }
  650. }
  651. //表格批注
  652. .hc-task-table-action.is-cur {
  653. color: #F2B90B;
  654. }
  655. //表格状态
  656. .hc-task-table-state {
  657. .is-success {
  658. color: #25a62d;
  659. }
  660. .is-danger {
  661. color: #F5221D;
  662. }
  663. span {
  664. color: #1A1a1a;
  665. }
  666. }
  667. //弹窗底部
  668. .hc-task-dialog-footer {
  669. position: relative;
  670. text-align: center;
  671. }
  672. </style>
  673. <style lang="scss">
  674. .hc-task-body-card {
  675. background: #f7f7f7;
  676. .el-scrollbar__bar.is-vertical {
  677. right: -8px;
  678. }
  679. .hc-task-body-table {
  680. position: relative;
  681. height: calc(100% - 30px);
  682. .hc-task-body-table-form {
  683. position: relative;
  684. height: 100%;
  685. overflow: auto;
  686. .title-box {
  687. position: relative;
  688. text-align: center;
  689. margin-bottom: 10px;
  690. .title {
  691. font-size: 18px;
  692. margin-bottom: 20px;
  693. }
  694. .text {
  695. font-size: 15px;
  696. }
  697. }
  698. .text-box {
  699. position: relative;
  700. border: 1px solid #4b4b4b;
  701. padding: 8px 3px;
  702. display: flex;
  703. align-items: center;
  704. font-size: 12px;
  705. .content {
  706. position: relative;
  707. flex: 1;
  708. padding-right: 20px;
  709. }
  710. .sign-name {
  711. position: relative;
  712. .user-time {
  713. margin-top: 10px;
  714. }
  715. }
  716. }
  717. .name {
  718. position: relative;
  719. display: flex;
  720. align-items: center;
  721. font-size: 13px;
  722. border: 1px solid #4b4b4b;
  723. background: #eef3f7;
  724. padding: 8px 3px;
  725. }
  726. .input {
  727. position: relative;
  728. border: 1px solid #4b4b4b;
  729. padding: 2px;
  730. }
  731. .input-box {
  732. position: relative;
  733. display: flex;
  734. .box {
  735. position: relative;
  736. flex: 1;
  737. display: flex;
  738. flex-direction: column;
  739. .name {
  740. flex-shrink: 0;
  741. }
  742. .text-box {
  743. flex: 1;
  744. flex-basis: auto;
  745. }
  746. }
  747. .no-b {
  748. border-left: 0;
  749. }
  750. }
  751. .hc-bt-0 {
  752. border-top: 0;
  753. }
  754. .hc-bb-0 {
  755. border-bottom: 0;
  756. }
  757. }
  758. }
  759. .hc-task-body-tip {
  760. color: red;
  761. }
  762. }
  763. //html表单模式
  764. .hc-task-body .hc-task-form.is-tab-key3 .hc-task-body-card {
  765. .el-scrollbar__view {
  766. height: 100%;
  767. }
  768. .hc-task-form-body {
  769. height: 100%;
  770. .el-tabs {
  771. height: 100%;
  772. .el-tabs__content {
  773. height: calc(100% - 39px);
  774. #pane-key3 {
  775. height: 100%;
  776. }
  777. }
  778. }
  779. }
  780. .hc-task-html-form-body {
  781. height: 100%;
  782. .hc-table-form-data-item .el-scrollbar__view {
  783. height: auto;
  784. }
  785. }
  786. }
  787. </style>