riskV2.vue 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241
  1. <template>
  2. <el-dialog
  3. v-loading="loading"
  4. :title="title"
  5. :visible.sync="dialogVisible"
  6. :close-on-click-modal="false"
  7. :close-on-press-escape="false"
  8. :show-close="false"
  9. append-to-body
  10. fullscreen
  11. class="dialog paper-detail-dialog"
  12. top="0"
  13. >
  14. <div slot="title" class="dialog-title">
  15. <span class="dialogtitle">{{ title }}</span>
  16. <div>
  17. <ibps-toolbar :actions="toolbars" @action-event="handleActionEvent" />
  18. </div>
  19. </div>
  20. <div class="container">
  21. <div class="left" :style="{ width: initWidth }">
  22. <el-descriptions
  23. title=""
  24. direction="vertical"
  25. :column="5"
  26. border
  27. size="mini"
  28. class="risk-fx-form-desc"
  29. >
  30. <el-descriptions-item label="年度" class="aaaa">
  31. <div class="desc-field-cell">
  32. <span class="required-star">*</span>
  33. <el-date-picker
  34. v-model="infoFxssbData.nian_du_"
  35. type="year"
  36. placeholder="选择年"
  37. :disabled="readonly"
  38. value-format="yyyy"
  39. size="mini"
  40. />
  41. </div>
  42. </el-descriptions-item>
  43. <el-descriptions-item label="编制部门">
  44. <div class="desc-field-cell">
  45. <span class="required-star">*</span>
  46. <ibps-user-selector
  47. v-model="infoFxssbData.bian_zhi_bu_men_"
  48. type="position"
  49. readonly-text="text"
  50. :disabled="readonly"
  51. :multiple="false"
  52. size="mini"
  53. style="width: 100%"
  54. :filter="filter"
  55. filtrate
  56. />
  57. </div>
  58. </el-descriptions-item>
  59. <el-descriptions-item label="编制人">
  60. <ibps-user-selector
  61. type="user"
  62. :value="infoFxssbData.bian_zhi_ren_"
  63. readonly-text="text"
  64. :disabled="true"
  65. :multiple="true"
  66. size="mini"
  67. style="width: 100%"
  68. />
  69. </el-descriptions-item>
  70. <el-descriptions-item label="编制时间">
  71. <div class="desc-field-cell">
  72. <span class="required-star">*</span>
  73. <el-date-picker
  74. v-model="infoFxssbData.bian_zhi_shi_jian"
  75. type="datetime"
  76. placeholder="选择日期时间"
  77. :disabled="readonly"
  78. value-format="yyyy-MM-dd HH:mm:ss"
  79. size="mini"
  80. />
  81. </div>
  82. </el-descriptions-item>
  83. <el-descriptions-item label="评估编号">
  84. {{ infoFxssbData.ji_hua_bian_hao_ }}
  85. </el-descriptions-item>
  86. <el-descriptions-item label="评估开始时间">
  87. <div class="desc-field-cell">
  88. <span class="required-star">*</span>
  89. <el-date-picker
  90. v-model="infoFxssbData.kai_shi_ri_qi_"
  91. type="date"
  92. placeholder="选择日期"
  93. :disabled="readonly"
  94. value-format="yyyy-MM-dd"
  95. size="mini"
  96. />
  97. </div>
  98. </el-descriptions-item>
  99. <el-descriptions-item label="评估结束时间">
  100. <div class="desc-field-cell">
  101. <span class="required-star">*</span>
  102. <el-date-picker
  103. v-model="infoFxssbData.jie_shu_ri_qi_"
  104. type="date"
  105. placeholder="选择日期"
  106. :disabled="readonly"
  107. value-format="yyyy-MM-dd"
  108. size="mini"
  109. />
  110. </div>
  111. </el-descriptions-item>
  112. <el-descriptions-item label="报告完成时间">
  113. <div class="desc-field-cell">
  114. <span class="required-star">*</span>
  115. <el-date-picker
  116. v-model="infoFxssbData.bao_gao_shi_jian_"
  117. type="date"
  118. placeholder="选择日期"
  119. :disabled="readonly"
  120. value-format="yyyy-MM-dd"
  121. size="mini"
  122. />
  123. </div>
  124. </el-descriptions-item>
  125. <el-descriptions-item label="评估时机" :span="1">
  126. <el-select
  127. v-model="infoFxssbData.shi_ji_"
  128. :disabled="readonly"
  129. placeholder="请选择"
  130. size="mini"
  131. style="width: 100%"
  132. >
  133. <el-option
  134. v-for="item in shiJiOptions"
  135. :key="item"
  136. :label="item"
  137. :value="item"
  138. />
  139. </el-select>
  140. </el-descriptions-item>
  141. <el-descriptions-item label="其他">
  142. <div class="desc-field-cell">
  143. <span v-if="isShiJiQiTa" class="required-star">*</span>
  144. <el-input
  145. v-model="infoFxssbData.qi_ta_"
  146. :disabled="readonly || !isShiJiQiTa"
  147. size="mini"
  148. :placeholder="
  149. isShiJiQiTa
  150. ? '请填写其他评估时机说明'
  151. : '请先选择评估时机为「其他」'
  152. "
  153. />
  154. </div>
  155. </el-descriptions-item>
  156. <el-descriptions-item label="评估负责人">
  157. <ibps-user-selector
  158. type="user"
  159. :value="infoFxssbData.zu_chang_id_"
  160. readonly-text="text"
  161. :disabled="true"
  162. :multiple="true"
  163. size="mini"
  164. style="width: 100%"
  165. :filter="filter"
  166. filtrate
  167. />
  168. </el-descriptions-item>
  169. <el-descriptions-item label="评估范围" :span="onlyoneWay ? 2 : 1">
  170. <el-input
  171. v-model="infoFxssbData.fan_wei_"
  172. :disabled="readonly"
  173. size="mini"
  174. />
  175. </el-descriptions-item>
  176. <el-descriptions-item label="评估方法" :span="onlyoneWay ? 2 : 1">
  177. <el-select
  178. v-model="infoFxssbData.fang_fa_"
  179. size="mini"
  180. style="width: 100%"
  181. :disabled="readonly"
  182. filterable
  183. allow-create
  184. clearable
  185. placeholder="请选择评估方法"
  186. >
  187. <el-option
  188. v-for="item in fangFaOptions"
  189. :key="item.value"
  190. :label="item.label"
  191. :value="item.value"
  192. />
  193. </el-select>
  194. </el-descriptions-item>
  195. <el-descriptions-item
  196. v-if="!onlyoneWay"
  197. label="风险系数计算方式"
  198. :span="2"
  199. >
  200. <span class="required-star">*</span>
  201. <el-radio
  202. v-for="(v, k) in culWays"
  203. :key="k"
  204. v-model="infoFxssbData.ji_suan_fang_shi_"
  205. :label="k"
  206. size="mini"
  207. :disabled="isEdit"
  208. >{{ v }}
  209. </el-radio>
  210. </el-descriptions-item>
  211. <el-descriptions-item label="评估目的" :span="5">
  212. <el-input
  213. v-model="infoFxssbData.mu_di_"
  214. :disabled="readonly"
  215. size="mini"
  216. />
  217. </el-descriptions-item>
  218. <el-descriptions-item label="评估依据文件" :span="5">
  219. <!-- 模版弹窗 -->
  220. <ibps-custom-dialog
  221. v-if="!readonly"
  222. v-model="infoFxssbData.yi_ju_wen_jian_id"
  223. template-key="nsyjwjxz"
  224. multiple
  225. type="dialog"
  226. class="custom-dialog"
  227. placeholder="请选择评估依据文件"
  228. size="mini"
  229. icon="el-icon-search"
  230. />
  231. <pre style="margin: 0">{{ infoFxssbData.yi_ju_wen_jian_ }}</pre>
  232. </el-descriptions-item>
  233. <el-descriptions-item label="首次会议时间" :span="1">
  234. <el-date-picker
  235. v-model="infoFxssbData.hui_yi_shi_jian_"
  236. type="datetime"
  237. placeholder="选择日期时间"
  238. default-time="12:00:00"
  239. :disabled="readonly"
  240. value-format="yyyy-MM-dd HH:mm"
  241. size="mini"
  242. style="width: 100%"
  243. />
  244. </el-descriptions-item>
  245. <el-descriptions-item label="参会人员" :span="4">
  246. <div class="desc-field-cell">
  247. <ibps-user-selector
  248. v-model="infoFxssbData.can_hui_ren_yuan_"
  249. style="width: 100%"
  250. type="user"
  251. readonly-text="text"
  252. :disabled="readonly"
  253. :multiple="true"
  254. size="mini"
  255. :filter="filter"
  256. filtrate
  257. />
  258. </div>
  259. </el-descriptions-item>
  260. <el-descriptions-item label="会议附件" :span="5">
  261. <ibps-attachment
  262. v-model="infoFxssbData.hui_yi_fu_jian_"
  263. :download="true"
  264. multiple
  265. accept="*"
  266. :readonly="readonly"
  267. size="mini"
  268. />
  269. </el-descriptions-item>
  270. <el-descriptions-item label="事务说明 " :span="5">
  271. <el-input
  272. v-model="infoFxssbData.shi_wu_shuo_ming_"
  273. :disabled="readonly"
  274. size="mini"
  275. /></el-descriptions-item>
  276. <el-descriptions-item label="评估小组成员" :span="5">
  277. <div class="desc-field-cell">
  278. <span class="required-star">*</span>
  279. <ibps-user-selector
  280. v-model="infoFxssbData.ping_gu_ren_yuan_"
  281. type="user"
  282. style="width: 100%"
  283. readonly-text="text"
  284. :disabled="readonly"
  285. :multiple="true"
  286. size="mini"
  287. :filter="filter"
  288. filtrate
  289. />
  290. </div>
  291. </el-descriptions-item>
  292. </el-descriptions>
  293. <div v-if="isEdit" style="margin-top: 20px">
  294. <el-alert
  295. title="根据评估小组成员选定的风险识别项给每个措施制定人推送风险改进流程"
  296. type="success"
  297. :closable="false"
  298. />
  299. <RiskPeopleTable
  300. ref="RiskPeopleTableRef"
  301. :params="params"
  302. :people-ids="infoFxssbData.ping_gu_ren_yuan_"
  303. :cul-ways="culWays"
  304. @goBack="goRefresh"
  305. />
  306. </div>
  307. </div>
  308. </div>
  309. <!-- <data-template-formrender-dialog
  310. :visible="DialogVisible"
  311. form-key="fxbg"
  312. :pk-value="pkValue"
  313. :readonly="readonly"
  314. @close="visible => DialogVisible = visible"
  315. /> -->
  316. <RiskDetail ref="RiskDetailRef" :cul-ways="culWays" @close="goRefresh" />
  317. <el-image-viewer
  318. v-if="showViewer"
  319. :on-close="closeViewer"
  320. :url-list="[FlowPic]"
  321. />
  322. </el-dialog>
  323. </template>
  324. <script>
  325. import { getSetting } from '@/utils/query'
  326. import dayjs from 'dayjs'
  327. import RiskPeopleTable from './riskPeopleTable.vue'
  328. import ibpsUserSelector from '@/business/platform/org/selector'
  329. import RiskDetail from './riskDetail.vue'
  330. import IbpsAttachment from '@/business/platform/file/attachment/selector'
  331. import DataFormrender from '@/business/platform/data/templaterender/form'
  332. import DataTemplateFormrenderDialog from '@/business/platform/data/templaterender/form/dialog.vue'
  333. import ElImageViewer from 'element-ui/packages/image/src/image-viewer'
  334. import FlowPic from '@/assets/images/risk/file-read-18951.png'
  335. export default {
  336. components: {
  337. ElImageViewer,
  338. RiskDetail,
  339. RiskPeopleTable,
  340. ibpsUserSelector,
  341. IbpsAttachment,
  342. DataFormrender,
  343. DataTemplateFormrenderDialog,
  344. IbpsCustomDialog: () =>
  345. import('@/business/platform/data/templaterender/custom-dialog')
  346. },
  347. props: {
  348. params: {
  349. type: Object,
  350. default: function () {
  351. return {}
  352. }
  353. }
  354. },
  355. data() {
  356. const { userId, position, level } = this.$store.getters
  357. return {
  358. FlowPic: FlowPic,
  359. showViewer: false,
  360. filter: [
  361. {
  362. descVal: '1',
  363. includeSub: true,
  364. old: 'position',
  365. partyId: this.$store.getters.userInfo.employee.positions,
  366. partyName: '',
  367. scriptContent: '',
  368. type: 'user',
  369. userType: 'position'
  370. }
  371. ],
  372. isFirst: true,
  373. userId: userId,
  374. position: position,
  375. level: level.second || level.first,
  376. pkValue: '',
  377. readonly: true,
  378. DialogVisible: false,
  379. loading: false,
  380. dialogVisible: true,
  381. title: '风险评估与措施',
  382. toolbars: [
  383. { key: 'openFlowPic', label: '流程图', icon: 'ibps-icon-image' },
  384. {
  385. key: 'refresh',
  386. label: '刷新',
  387. hidden: () => {
  388. return !this.isZuZhang || !this.isEdit || this.isFinished
  389. }
  390. },
  391. {
  392. key: 'save',
  393. label: '保存',
  394. hidden: () => {
  395. return !this.isZuZhang || this.isFinished
  396. }
  397. },
  398. // { key: 'sendMsg', label: '提醒评估人', icon: 'el-icon-bell', hidden: () => { return !this.isZuZhang || !this.isEdit || this.isFinished } },
  399. // { key: 'peizhifengxian', label: '更新风险库', type: 'info', icon: 'el-icon-setting', hidden: () => { return !this.isZuZhang || !this.isEdit } },
  400. {
  401. key: 'submit',
  402. label: '提交',
  403. icon: 'el-icon-finished',
  404. hidden: () => {
  405. return !this.isZuZhang || !this.isEdit || this.isFinished
  406. }
  407. },
  408. {
  409. key: 'cancel',
  410. label: '退出',
  411. type: 'danger',
  412. icon: 'ibps-icon-close'
  413. }
  414. ],
  415. infoFxssbData: {
  416. nian_du_: '',
  417. bian_zhi_bu_men_: '',
  418. bian_zhi_ren_: '',
  419. bian_zhi_shi_jian: '',
  420. zu_chang_: '',
  421. zu_chang_id_: '',
  422. kai_shi_ri_qi_: '',
  423. jie_shu_ri_qi_: '',
  424. bao_gao_shi_jian_: '',
  425. feng_xian_lei_xin: '质量',
  426. qi_ta_: '',
  427. shi_ji_: '',
  428. fan_wei_: '',
  429. fang_fa_: '',
  430. mu_di_: '',
  431. yi_ju_wen_jian_id: '',
  432. yi_ju_wen_jian_: '',
  433. hui_yi_shi_jian_: '',
  434. can_hui_ren_yuan_: '',
  435. hui_yi_fu_jian_: '',
  436. shi_wu_shuo_ming_: '',
  437. ping_gu_ren_yuan_: '',
  438. ji_hua_bian_hao_: '',
  439. ji_suan_fang_shi_: ''
  440. },
  441. initWidth: '1280px',
  442. isEdit: false,
  443. isPingGuRen: false,
  444. isZuZhang: true,
  445. isFinished: false,
  446. preParams: {},
  447. Ids: [],
  448. culWays: { 1: '风险矩阵法', 2: 'FMEA法' },
  449. shiJiOptions: [
  450. '定期评估',
  451. '业务变化',
  452. '主要仪器设备变化',
  453. '设施环境变化',
  454. '其他'
  455. ],
  456. fangFaOptions: [
  457. { value: '定量风险评估法', label: '定量风险评估法' },
  458. { value: '风险矩阵', label: '风险矩阵' },
  459. {
  460. value: '头脑风暴法(集体讨论法)',
  461. label: '头脑风暴法(集体讨论法)'
  462. },
  463. { value: '德尔菲法(专家调查法)', label: '德尔菲法(专家调查法)' },
  464. { value: '情景分析', label: '情景分析' },
  465. { value: '检查表', label: '检查表' },
  466. { value: '故障树分析', label: '故障树分析' },
  467. { value: '蒙特卡罗模拟分析法', label: '蒙特卡罗模拟分析法' },
  468. { value: '贝叶斯统计及贝叶斯网络', label: '贝叶斯统计及贝叶斯网络' }
  469. ]
  470. }
  471. },
  472. computed: {
  473. onlyoneWay() {
  474. const keys = Object.keys(this.culWays)
  475. return keys.length === 1
  476. },
  477. isShiJiQiTa() {
  478. return this.infoFxssbData.shi_ji_ === '其他'
  479. }
  480. },
  481. watch: {
  482. 'infoFxssbData.yi_ju_wen_jian_id': {
  483. handler(val) {
  484. // const sql = `select * from yijuwenjianxuanze where find_in_set(id_, '${val}') order by id_`
  485. this.$common
  486. .request('query', {
  487. key: 'getRiskFileInfo',
  488. params: [val]
  489. })
  490. .then((response) => {
  491. const conts = response.variables.data
  492. let fileName = ''
  493. let num = 1
  494. conts.forEach((item, index) => {
  495. fileName += `${num}、${item.name_}\n`
  496. num = num + 1
  497. })
  498. this.infoFxssbData.yi_ju_wen_jian_ = fileName
  499. })
  500. },
  501. immediate: true
  502. },
  503. 'infoFxssbData.zu_chang_id_': {
  504. handler(val) {
  505. if (val) {
  506. const userList = this.$store.getters.userList
  507. const bianzhiUserid = userList.find((i) => i.userId === val)
  508. if (bianzhiUserid) {
  509. this.infoFxssbData.zu_chang_ = bianzhiUserid.userName
  510. }
  511. }
  512. }
  513. },
  514. 'infoFxssbData.feng_xian_lei_xin': {
  515. handler(val) {
  516. if (val) {
  517. if (this.isFirst) {
  518. this.isFirst = false
  519. } else {
  520. this.infoFxssbData.fan_wei_ = `本实验室与${val}相关所有活动`
  521. this.infoFxssbData.mu_di_ = `通过对实验室(${val}活动)进行风险评估,识别实验室在(${val}活动)方面存在的潜在风险,评估风险影响程度,制定风险管理策略,减少不利后果发生的概率和影响程度。`
  522. this.infoFxssbData.shi_wu_shuo_ming_ = `年度:${this.infoFxssbData.nian_du_};评估负责人:${this.infoFxssbData.zu_chang_};评估开始日期:${this.infoFxssbData.kai_shi_ri_qi_}`
  523. }
  524. }
  525. }
  526. },
  527. 'infoFxssbData.shi_ji_': {
  528. handler(val) {
  529. if (val !== '其他') {
  530. this.infoFxssbData.qi_ta_ = ''
  531. }
  532. }
  533. }
  534. },
  535. async mounted() {
  536. const culWays = await getSetting('risk', 'culWays')
  537. if (this.$utils.isNotEmpty(culWays)) {
  538. this.culWays = culWays
  539. }
  540. this.init()
  541. },
  542. beforeDestroy() {
  543. if (this.msg) {
  544. this.msg.close()
  545. }
  546. },
  547. methods: {
  548. // 获取最新数据
  549. async getNewData() {
  550. // const sql = `select * from t_fxpgjlb2 where id_='${this.params.id_}'`
  551. const {
  552. variables: { data }
  553. } = await this.$common.request('query', {
  554. key: 'getFxpgjlb2ById',
  555. params: [this.params.id_]
  556. })
  557. return data
  558. },
  559. // 判断是否已完成
  560. async getIsFinish() {
  561. const data = await this.getNewData()
  562. if (data.length > 0 && data[0].shi_fou_guo_shen_ === '已完成') {
  563. throw new Error('已结束,不可操作!')
  564. }
  565. },
  566. // 快照URL
  567. getReportParams(path, selection, data) {
  568. const { level } = this.$store.getters
  569. const str = `org_=${level.first}&second_=${level.second}&id_=`
  570. const arr = path.split('&')
  571. if (arr.length === 2) {
  572. const fieldArr = arr[1].split('=')
  573. return str + `${data[fieldArr[1]]}`
  574. } else {
  575. // 如果是没有传参,还是原报表路径
  576. return str + `${selection}`
  577. }
  578. },
  579. // 提交
  580. async goSubmit() {
  581. try {
  582. this.$confirm('提交后不可修改,是否确认保存并提交?', '提示', {
  583. confirmButtonText: '继续',
  584. cancelButtonText: '取消',
  585. type: 'warning'
  586. })
  587. .then(async () => {
  588. // 提交前自动保存
  589. await this.goSave()
  590. // 判断每个评估人是否已完成识别项
  591. const pinGuRenNum = this.Ids.length
  592. // const sql = `select * from t_fxsbpgb2 where parent_id_='${this.params.id_}'`
  593. const {
  594. variables: { data }
  595. } = await this.$common.request('query', {
  596. key: 'getFxsbpgb2ByPid',
  597. params: [this.params.id_]
  598. })
  599. const submitNum = new Set(data.map((item) => item.bian_zhi_ren_))
  600. .size
  601. if (
  602. submitNum === pinGuRenNum &&
  603. data.every((item) => item.shi_fou_guo_shen_ === '已完成')
  604. ) {
  605. // 1.修改状态为已完成
  606. const updateParamsRecord = {
  607. tableName: 't_fxpgjlb2',
  608. updList: [
  609. {
  610. where: {
  611. id_: this.params.id_
  612. },
  613. param: {
  614. shi_fou_guo_shen_: '已完成'
  615. }
  616. }
  617. ]
  618. }
  619. await this.$common.request('update', updateParamsRecord)
  620. // console.log(data)
  621. // 2.推送给措施制定人下一个流程
  622. const addParams = {
  623. tableName: 't_fxkzcsb2',
  624. paramWhere: data
  625. .map((item) => {
  626. if (
  627. item.feng_xian_ying_du !== '风险接受' &&
  628. item.zhi_ding_ren_
  629. ) {
  630. return {
  631. di_dian_: this.level,
  632. shi_fou_guo_shen_: '待制定',
  633. bian_zhi_ren_: item.zhi_ding_ren_,
  634. bian_zhi_bu_men_: this.getPersonPosition(
  635. item.zhi_ding_ren_.split(',')[0]
  636. ),
  637. bian_zhi_shi_jian: dayjs().format(
  638. 'YYYY-MM-DD HH:mm:ss'
  639. ),
  640. gai_jin_bian_hao_: '',
  641. yao_su_tiao_kuan_: item.yao_su_tiao_kuan_,
  642. gong_zuo_huan_jie: item.gong_zuo_huan_jie,
  643. // gong_zuo_miao_shu: item.gong_zuo_miao_shu,
  644. feng_xian_miao_sh: item.feng_xian_miao_sh,
  645. zu_chang_: this.infoFxssbData.zu_chang_,
  646. zu_chang_id_: this.infoFxssbData.zu_chang_id_,
  647. shi_wu_shuo_ming_: this.infoFxssbData.shi_wu_shuo_ming_,
  648. yuan_zhi_shu_: item.feng_xian_zhi_shu,
  649. kong_zhi_fang_fa_: item.xian_xing_kong_zh,
  650. feng_xian_lei_xin: this.infoFxssbData.feng_xian_lei_xin,
  651. qian_fu_jian_: this.infoFxssbData.yi_ju_wen_jian_id,
  652. ji_hua_bian_hao_: this.infoFxssbData.ji_hua_bian_hao_,
  653. ni_cai_qu_kong_zh: item.ni_cai_qu_cuo_shi,
  654. qian_zai_yuan_yin: item.qian_zai_yuan_yin,
  655. ji_suan_fang_shi_: this.infoFxssbData.ji_suan_fang_shi_,
  656. yuan_feng_xian_de: item.feng_xian_deng_ji,
  657. yuan_feng_xian_yi: item.feng_xian_ying_du,
  658. parent_id_: item.id_ || ''
  659. }
  660. }
  661. })
  662. .filter((i) => i !== undefined),
  663. formKey: 'fxcscsbV2',
  664. defKey: 'Process_1li9h0n'
  665. }
  666. this.loading = true
  667. for (let i = 0; i < addParams.paramWhere.length; i++) {
  668. const item = addParams.paramWhere[i]
  669. item.gai_jin_bian_hao_ = await this.getNextAlias('gjjllsh')
  670. }
  671. if (addParams.paramWhere.length) {
  672. // 预防推送流程数据过多,做切片处理
  673. await this.processInBatches(addParams.paramWhere)
  674. .then(() => {})
  675. .catch(() => {
  676. this.loading = false
  677. })
  678. console.log('改进流程推送成功')
  679. } else {
  680. console.log('无需推送')
  681. }
  682. // 3.推送给评估负责人 评估报告流程
  683. const addParams2 = {
  684. tableName: 't_fxkzbg',
  685. paramWhere: [
  686. {
  687. di_dian_: this.level,
  688. shi_fou_guo_shen_: '待编制',
  689. bian_zhi_ren_: this.infoFxssbData.zu_chang_id_,
  690. bian_zhi_bu_men_: this.getPersonPosition(
  691. this.infoFxssbData.zu_chang_id_
  692. ),
  693. bian_zhi_shi_jian: dayjs().format('YYYY-MM-DD HH:mm'),
  694. zu_chang_: this.infoFxssbData.zu_chang_,
  695. zu_chang_id_: this.infoFxssbData.zu_chang_id_,
  696. feng_xian_lei_xin: this.infoFxssbData.feng_xian_lei_xin,
  697. kai_shi_ri_qi_: this.infoFxssbData.kai_shi_ri_qi_,
  698. jie_shu_ri_qi_: this.infoFxssbData.jie_shu_ri_qi_,
  699. wan_cheng_ri_qi_: this.infoFxssbData.bao_gao_shi_jian_,
  700. shi_wu_shuo_ming_: this.infoFxssbData.shi_wu_shuo_ming_,
  701. ji_hua_bian_hao_: this.infoFxssbData.ji_hua_bian_hao_,
  702. hui_yi_wen_jian_: this.infoFxssbData.hui_yi_fu_jian_
  703. }
  704. ],
  705. formKey: 'fxbg',
  706. defKey: 'Process_0mrlsj7'
  707. }
  708. console.log('报告流程推送成功')
  709. await this.$common.request('add', addParams2)
  710. this.$message.success('提交成功')
  711. // 提醒用户推送信息
  712. this.$alert(
  713. `需要改进项${addParams.paramWhere.length}条,已向其中的每位措施制定人推送风险改进流程,同时向评估负责人 ${this.infoFxssbData.zu_chang_} 推送风险报告流程!`,
  714. '提交成功',
  715. {
  716. confirmButtonText: '确定',
  717. callback: (action) => {
  718. this.closeDialog(true)
  719. }
  720. }
  721. )
  722. } else {
  723. this.$message.warning(
  724. '存在未完成风险识别项的评估小组成员,无法提交!'
  725. )
  726. return
  727. }
  728. })
  729. .catch(() => {})
  730. } catch (error) {
  731. this.$message.warning(error.message)
  732. }
  733. },
  734. async processInBatches(array, batchSize = 20) {
  735. for (let i = 0; i < array.length; i += batchSize) {
  736. const batch = array.slice(i, i + batchSize)
  737. try {
  738. const addParams = {
  739. tableName: 't_fxkzcsb2',
  740. paramWhere: batch,
  741. formKey: 'fxcscsbV2',
  742. defKey: 'Process_1li9h0n'
  743. }
  744. await this.$common.request('add', addParams)
  745. } catch (error) {
  746. console.error('处理批次时出错:', error)
  747. // 可以添加重试逻辑或错误处理
  748. }
  749. }
  750. console.log('所有数据处理完成')
  751. },
  752. // id 转 姓名
  753. switchIdtoUserName(id) {
  754. const { userList } = this.$store.getters
  755. const user = userList.find((item) => item.userId === id)
  756. return user ? user.userName : ''
  757. },
  758. goPeizhifengxian() {
  759. const buttons = document.querySelector('button[name="peizhifengxian"]')
  760. if (buttons) {
  761. buttons.click()
  762. }
  763. },
  764. handleActionEvent({ key }) {
  765. switch (key) {
  766. case 'cancel':
  767. this.closeDialog(true)
  768. break
  769. case 'record':
  770. this.goRecord()
  771. break
  772. case 'save':
  773. this.goSave('close')
  774. break
  775. case 'submit':
  776. this.goSubmit()
  777. break
  778. case 'refresh':
  779. this.goRefresh()
  780. break
  781. case 'sendMsg':
  782. this.goSendMsg()
  783. break
  784. case 'peizhifengxian':
  785. this.goPeizhifengxian()
  786. break
  787. case 'openFlowPic':
  788. this.showViewer = true
  789. break
  790. default:
  791. break
  792. }
  793. },
  794. // 关闭大图预览
  795. closeViewer() {
  796. this.showViewer = false
  797. },
  798. // 推送消息给评估人
  799. async goSendMsg() {
  800. // const sql2 = `select * from t_fxpgjlb2 where id_='${this.params.id_}'`
  801. const {
  802. variables: { data: data2 }
  803. } = await this.$common.request('query', {
  804. key: 'getFxpgjlb2ById',
  805. params: [this.params.id_]
  806. })
  807. if (data2.length > 0 && data2[0].shi_fou_guo_shen_ === '已完成') {
  808. return this.$message('已结束,不可推送消息!')
  809. }
  810. if (!data2[0].ping_gu_ren_yuan_) {
  811. return this.$message.warning('请先指定评估人!')
  812. }
  813. this.$confirm('此操作将通知所有评估人,是否继续?', '提示', {
  814. confirmButtonText: '确定',
  815. cancelButtonText: '取消',
  816. type: 'warning'
  817. })
  818. .then(() => {
  819. // console.log(this.Ids)
  820. const allRequests = []
  821. this.Ids.forEach((item) => {
  822. allRequests.push(
  823. this.$common.sendMsg({
  824. subject: '风险识别项待填写提醒',
  825. content: `您有一份风险识别项待填写,请前往-风险控制-风险评估与措施页面填写,计划编号:${this.infoFxssbData.ji_hua_bian_hao_},评估负责人:${this.infoFxssbData.zu_chang_}。如已提交请忽略。`,
  826. receiverId: item,
  827. canreplay: '0',
  828. skipTypeMsg: JSON.stringify({
  829. skipType: 3,
  830. pathInfo: '/tygl/fxkzV2/fxpgycslb' // 路由
  831. })
  832. })
  833. )
  834. })
  835. Promise.all(allRequests)
  836. .then(() => {
  837. this.$message({
  838. type: 'success',
  839. message: '推送成功!'
  840. })
  841. })
  842. .catch(() => {
  843. this.$message({
  844. type: 'warning',
  845. message: '推送失败!'
  846. })
  847. })
  848. })
  849. .catch(() => {})
  850. },
  851. // 获取人员部门
  852. getPersonPosition(id) {
  853. const userList = this.$store.getters.userList
  854. const bianzhiUserid = userList.find((i) => i.userId === id)
  855. if (bianzhiUserid) {
  856. return bianzhiUserid.positionId.split(',')[0]
  857. }
  858. },
  859. checkRequired() {
  860. if (!this.infoFxssbData.nian_du_) {
  861. throw new Error('请填写年度!')
  862. }
  863. if (!this.infoFxssbData.kai_shi_ri_qi_) {
  864. throw new Error('请填写评估开始日期!')
  865. }
  866. if (!this.infoFxssbData.jie_shu_ri_qi_) {
  867. throw new Error('请填写评估结束日期!')
  868. }
  869. if (!this.infoFxssbData.bao_gao_shi_jian_) {
  870. throw new Error('请填写报告完成时间!')
  871. }
  872. // if (!this.infoFxssbData.hui_yi_shi_jian_) {
  873. // throw new Error('请填写首次会议时间!')
  874. // }
  875. // if (!this.infoFxssbData.can_hui_ren_yuan_) {
  876. // throw new Error('请填写参会人员!')
  877. // }
  878. if (!this.infoFxssbData.ping_gu_ren_yuan_) {
  879. throw new Error('请填写评估小组成员!')
  880. }
  881. if (!this.infoFxssbData.bian_zhi_shi_jian) {
  882. throw new Error('请选择编制时间!')
  883. }
  884. if (!this.infoFxssbData.bian_zhi_bu_men_) {
  885. throw new Error('请选择编制部门!')
  886. }
  887. if (!this.infoFxssbData.ji_suan_fang_shi_) {
  888. throw new Error('请选择风险系数计算方式!')
  889. }
  890. if (
  891. this.infoFxssbData.shi_ji_ === '其他' &&
  892. !this.infoFxssbData.qi_ta_?.trim()
  893. ) {
  894. throw new Error('评估时机为「其他」时请填写其他说明!')
  895. }
  896. },
  897. async goAdd() {
  898. try {
  899. const addParamsRecord = {
  900. tableName: 't_fxpgjlb2',
  901. paramWhere: [this.infoFxssbData]
  902. }
  903. const {
  904. variables: { cont }
  905. } = await this.$common.request('add', addParamsRecord)
  906. if (cont.length) {
  907. this.$message.success('添加成功')
  908. this.closeDialog(true)
  909. }
  910. } catch (error) {
  911. console.log(error)
  912. this.$message.warning('添加失败')
  913. }
  914. },
  915. async goEdit(flag) {
  916. try {
  917. // 先检查状态
  918. await this.getIsFinish()
  919. // 更新主表
  920. const updateParamsRecord = {
  921. tableName: 't_fxpgjlb2',
  922. updList: [
  923. {
  924. where: {
  925. id_: this.params.id_
  926. },
  927. param: this.infoFxssbData
  928. }
  929. ]
  930. }
  931. updateParamsRecord.updList.forEach((item) => {
  932. Object.keys(item.param).forEach((key) => {
  933. if (key.endsWith('_label_value')) {
  934. delete item.param[key]
  935. }
  936. })
  937. })
  938. console.log('updateParamsRecord', updateParamsRecord)
  939. await this.$common.request('update', updateParamsRecord)
  940. // 当前人员数组
  941. const curIds = this.infoFxssbData.ping_gu_ren_yuan_.split(',')
  942. // 计算需要增加项
  943. const addedIds = curIds.filter((item) => !this.Ids.includes(item))
  944. // 计算需要更新项
  945. const updatedIds = curIds.filter((item) => this.Ids.includes(item))
  946. // 计算需要删除项
  947. const deletedIds = this.Ids.filter((id) => !curIds.includes(id))
  948. console.log(addedIds, updatedIds, deletedIds)
  949. // 删除
  950. if (deletedIds.length > 0) {
  951. const ids = deletedIds.map((id) => id).join(',')
  952. // const sql3 = `select *from t_fxsbpgb2 where parent_id_='${this.params.id_}' and find_in_set(bian_zhi_ren_, '${ids}')`
  953. const {
  954. variables: { data: data3 }
  955. } = await this.$common.request('query', {
  956. key: 'getFxsbpgb2ByUid',
  957. params: [this.params.id_, ids]
  958. })
  959. // console.log(data3)
  960. if (data3.length > 0) {
  961. const params = {
  962. tableName: 't_fxsbpgb2',
  963. paramWhere: {
  964. id_: data3.map((item) => item.id_).join(',')
  965. }
  966. }
  967. console.log(params)
  968. await this.$common.request('delete', params)
  969. console.log('删除成功')
  970. }
  971. }
  972. if (flag === 'close') {
  973. this.closeDialog(true)
  974. this.$message.success('修改成功')
  975. } else {
  976. await this.goRefresh() // 修改之后刷新
  977. }
  978. } catch (error) {
  979. this.$message.warning(error.message)
  980. throw new Error(error.message)
  981. }
  982. },
  983. async goSave(flag) {
  984. try {
  985. this.checkRequired()
  986. if (this.isEdit) {
  987. await this.goEdit(flag)
  988. } else {
  989. this.$confirm(
  990. `${
  991. this.onlyoneWay
  992. ? '是否继续保存?'
  993. : '风险系数计算公式保存后不可再修改,是否继续?'
  994. }`,
  995. '提示',
  996. {
  997. confirmButtonText: '继续',
  998. cancelButtonText: '取消',
  999. type: 'warning'
  1000. }
  1001. )
  1002. .then(async () => {
  1003. await this.goAdd()
  1004. })
  1005. .catch(() => {})
  1006. }
  1007. } catch (error) {
  1008. this.$message.warning(error.message)
  1009. throw new Error(error.message)
  1010. }
  1011. },
  1012. // 刷新
  1013. async goRefresh() {
  1014. this.loading = true
  1015. if (this.msg) {
  1016. this.msg.close()
  1017. }
  1018. await this.init()
  1019. if (this.$refs.RiskPeopleTableRef) {
  1020. await this.$refs.RiskPeopleTableRef.getPeopleList()
  1021. }
  1022. this.loading = false
  1023. },
  1024. // 关闭当前窗口
  1025. closeDialog(needRefresh) {
  1026. this.dialogVisible = false
  1027. if (needRefresh) {
  1028. this.$emit('close')
  1029. }
  1030. if (this.msg) {
  1031. this.msg.close()
  1032. }
  1033. },
  1034. // 弹出提醒
  1035. async showAlert() {
  1036. if (!this.isPingGuRen || this.isFinished) return
  1037. // 判断是否已经填写风险识别项
  1038. // const sql = `select * from t_fxsbpgb2 where parent_id_='${this.params.id_}' and find_in_set(bian_zhi_ren_, '${this.userId}')`
  1039. const {
  1040. variables: { data }
  1041. } = await this.$common.request('query', {
  1042. key: 'getFxsbpgb2ByUid',
  1043. params: [this.params.id_, this.userId]
  1044. })
  1045. let status = '填写'
  1046. let type = 'warning'
  1047. if (data.length > 0) {
  1048. if (data.every((item) => item.shi_fou_guo_shen_ === '已完成')) {
  1049. return
  1050. } else {
  1051. status = '提交'
  1052. type = 'success'
  1053. }
  1054. }
  1055. this.msg = this.$notify({
  1056. offset: 50,
  1057. type: type,
  1058. title: `您有一份风险识别评估表待${status}!`,
  1059. message: `点击前去${status}`,
  1060. showClose: false,
  1061. duration: 0,
  1062. onClick: () => {
  1063. this.$refs.RiskDetailRef.open(this.params)
  1064. }
  1065. })
  1066. },
  1067. getNextAlias(alias) {
  1068. return new Promise((resolve, reject) => {
  1069. this.$common
  1070. .getNextIdByAlias({
  1071. alias
  1072. })
  1073. .then((response) => {
  1074. resolve(response.data)
  1075. })
  1076. .catch((error) => {
  1077. reject(error)
  1078. })
  1079. })
  1080. },
  1081. async init() {
  1082. this.isEdit = !!(this.params && this.params.id_)
  1083. if (this.isEdit) {
  1084. this.infoFxssbData = this.params
  1085. if (!this.infoFxssbData.feng_xian_lei_xin) {
  1086. this.infoFxssbData.feng_xian_lei_xin = '质量'
  1087. }
  1088. console.log('infoFxssbData', this.infoFxssbData)
  1089. this.preParams = JSON.parse(JSON.stringify(this.params))
  1090. this.isPingGuRen =
  1091. this.params.ping_gu_ren_yuan_.indexOf(this.userId) >= 0
  1092. this.isZuZhang = this.userId === this.infoFxssbData.zu_chang_id_
  1093. this.isFinished =
  1094. this.params && this.params.shi_fou_guo_shen_ === '已完成'
  1095. this.readonly = !!(!this.isZuZhang || this.isFinished)
  1096. if (this.params.ping_gu_ren_yuan_) {
  1097. this.Ids = this.params.ping_gu_ren_yuan_.split(',')
  1098. } else {
  1099. this.Ids = []
  1100. }
  1101. await this.showAlert()
  1102. } else {
  1103. const { positions } = this.$store.getters.userInfo
  1104. // 默认编制部门是主部门,没有主部门默认第一个部门
  1105. const mainPost =
  1106. positions.find((item) => item.isMainPost === 'Y')?.id ||
  1107. positions[0].id
  1108. this.readonly = false
  1109. this.infoFxssbData.di_dian_ = this.level
  1110. this.infoFxssbData.ji_hua_bian_hao_ = await this.getNextAlias('fxjhlsh')
  1111. this.infoFxssbData.nian_du_ = dayjs().format('YYYY')
  1112. this.infoFxssbData.bian_zhi_bu_men_ = mainPost
  1113. this.infoFxssbData.bian_zhi_ren_ = this.userId
  1114. this.infoFxssbData.bian_zhi_shi_jian = dayjs().format(
  1115. 'YYYY-MM-DD HH:mm:ss'
  1116. )
  1117. this.infoFxssbData.zu_chang_id_ = this.userId
  1118. this.infoFxssbData.kai_shi_ri_qi_ = dayjs().format('YYYY-MM-DD')
  1119. this.infoFxssbData.jie_shu_ri_qi_ = dayjs().format('YYYY-MM-DD')
  1120. this.infoFxssbData.feng_xian_lei_xin = '质量'
  1121. this.infoFxssbData.shi_ji_ = '定期评估'
  1122. this.infoFxssbData.fan_wei_ = '本实验室与质量相关所有活动'
  1123. this.infoFxssbData.fang_fa_ = '定量风险评估法'
  1124. this.infoFxssbData.mu_di_ =
  1125. '通过对实验室(质量活动)进行风险评估,识别实验室在(质量活动)方面存在的潜在风险,评估风险影响程度,制定风险管理策略,减少不利后果发生的概率和影响程度。'
  1126. this.infoFxssbData.hui_yi_shi_jian_ = dayjs().format('YYYY-MM-DD HH:mm')
  1127. this.$nextTick(() => {
  1128. this.infoFxssbData.shi_wu_shuo_ming_ = `年度:${this.infoFxssbData.nian_du_};评估负责人:${this.infoFxssbData.zu_chang_};评估开始日期:${this.infoFxssbData.kai_shi_ri_qi_}`
  1129. })
  1130. // this.onlyoneWay &&
  1131. // (
  1132. this.infoFxssbData.ji_suan_fang_shi_ = Object.keys(this.culWays)[0]
  1133. // )
  1134. }
  1135. }
  1136. }
  1137. }
  1138. </script>
  1139. <style lang="scss" scoped>
  1140. .paper-detail-dialog {
  1141. ::v-deep {
  1142. .el-dialog__header {
  1143. text-align: center;
  1144. }
  1145. }
  1146. .container {
  1147. display: flex;
  1148. width: 100%;
  1149. justify-content: center;
  1150. .left {
  1151. height: calc(100vh - 100px);
  1152. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  1153. padding: 10px;
  1154. overflow-y: auto;
  1155. ::v-deep .risk-fx-form-desc {
  1156. .el-descriptions__table {
  1157. table-layout: fixed;
  1158. width: 100%;
  1159. }
  1160. .el-descriptions-item__content {
  1161. width: 100%;
  1162. }
  1163. .el-date-editor.el-input,
  1164. .el-select,
  1165. .el-input {
  1166. width: 100%;
  1167. }
  1168. }
  1169. }
  1170. .right {
  1171. height: calc(100vh - 100px);
  1172. flex: 1;
  1173. padding: 10px;
  1174. .text {
  1175. line-height: 1.5;
  1176. }
  1177. overflow-y: auto;
  1178. }
  1179. }
  1180. }
  1181. .required-star {
  1182. color: red;
  1183. margin-right: 4px;
  1184. flex-shrink: 0;
  1185. }
  1186. .desc-field-cell {
  1187. display: flex;
  1188. align-items: center;
  1189. width: 100%;
  1190. min-width: 0;
  1191. ::v-deep .el-date-editor,
  1192. ::v-deep .el-select,
  1193. ::v-deep .el-input,
  1194. ::v-deep .ibps-user-selector {
  1195. flex: 1;
  1196. width: 100%;
  1197. min-width: 0;
  1198. }
  1199. }
  1200. .dialog-title {
  1201. display: flex;
  1202. align-items: center;
  1203. justify-content: center;
  1204. div {
  1205. position: absolute;
  1206. right: 8vw;
  1207. }
  1208. .dialogtitle {
  1209. font-size: 22px;
  1210. font-family: SimHei;
  1211. font-weight: bold;
  1212. color: #222;
  1213. }
  1214. }
  1215. .el-image-viewer__wrapper {
  1216. z-index: 9999 !important;
  1217. }
  1218. </style>