CreateDialog.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. <template>
  2. <el-dialog
  3. v-el-drag-dialog
  4. :title="titleStr"
  5. :visible.sync="data.bSwitch"
  6. width="1200px"
  7. top="5vh"
  8. >
  9. <el-form ref="ruleForm" :model="ruleForm" :rules="rules" label-width="80px" class="demo-ruleForm">
  10. <el-row :gutter="16">
  11. <el-col :span="8">
  12. <el-form-item label="病历类型" prop="case_type">
  13. <el-select v-model="ruleForm.case_type" filterable clearable placeholder="请选择" style="width: 100%;">
  14. <el-option label="出院记录" value="出院记录" />
  15. <el-option label="入院记录" value="入院记录" />
  16. <el-option label="病程类" value="病程类" />
  17. <el-option label="手术类" value="手术类" />
  18. <el-option label="医嘱" value="医嘱" />
  19. <el-option label="费用" value="费用" />
  20. </el-select>
  21. </el-form-item>
  22. </el-col>
  23. <el-col :span="8">
  24. <el-form-item label="质控项目" prop="object">
  25. <el-cascader
  26. v-model="ruleForm.object"
  27. :options="objects"
  28. :props="{
  29. expandTrigger: 'hover',
  30. value: 'field_name',
  31. label: 'field_name',
  32. children: 'child'
  33. }"
  34. clearable
  35. filterable
  36. :show-all-levels="false"
  37. placeholder="请选择"
  38. style="width: 100%;"
  39. />
  40. </el-form-item>
  41. </el-col>
  42. <el-col :span="8">
  43. <el-form-item label="质控科室">
  44. <el-select
  45. v-model="ruleForm.department"
  46. multiple
  47. collapse-tags
  48. placeholder="请选择"
  49. style="width: 100%;"
  50. >
  51. <el-option
  52. v-for="item in departments"
  53. :key="item.id"
  54. :label="item.dep_name"
  55. :value="item.dep_id"
  56. />
  57. </el-select>
  58. </el-form-item>
  59. </el-col>
  60. <el-col :span="8">
  61. <el-form-item label="单项否决">
  62. <el-select v-model="ruleForm.is_not" filterable clearable placeholder="请选择" style="width: 100%;">
  63. <el-option label="是" :value="1" />
  64. <el-option label="否" :value="0" />
  65. </el-select>
  66. </el-form-item>
  67. </el-col>
  68. <el-col :span="8">
  69. <el-form-item label="质控状态" prop="status">
  70. <el-select v-model="ruleForm.status" filterable clearable placeholder="请选择" style="width: 100%;">
  71. <el-option label="开启" :value="1" />
  72. <el-option label="禁用" :value="2" />
  73. </el-select>
  74. </el-form-item>
  75. </el-col>
  76. <el-col :span="8">
  77. <el-form-item label="质控类型" prop="type">
  78. <el-select v-model="ruleForm.type" filterable clearable placeholder="请选择" style="width: 100%;">
  79. <el-option label="时效性" value="时效性" />
  80. <el-option label="完整性" value="完整性" />
  81. <el-option label="逻辑性" value="逻辑性" />
  82. <el-option label="内涵性" value="内涵性" />
  83. <el-option label="专病规则" value="专病规则" />
  84. <el-option label="专科规则" value="专科规则" />
  85. <el-option label="检查规则" value="检查规则" />
  86. <el-option label="检验规则" value="检验规则" />
  87. <el-option label="其他规则" value="其他规则" />
  88. </el-select>
  89. </el-form-item>
  90. </el-col>
  91. <el-col :span="8">
  92. <el-form-item label="质控场景" prop="changjing">
  93. <el-select v-model="ruleForm.changjing" multiple collapse-tags filterable clearable placeholder="请选择" style="width: 100%;">
  94. <el-option label="医生端" value="医生端" />
  95. <el-option label="编码员" value="编码员" />
  96. <el-option label="质控员" value="质控员" />
  97. <el-option label="国考" value="国考" />
  98. <el-option label="卫统" value="卫统" />
  99. <el-option label="医保" value="医保" />
  100. </el-select>
  101. </el-form-item>
  102. </el-col>
  103. <el-col :span="8">
  104. <el-form-item label="风险等级" prop="error_level">
  105. <el-select v-model="ruleForm.error_level" filterable clearable placeholder="请选择" style="width: 100%;">
  106. <el-option label="低风险" :value="1" />
  107. <el-option label="中风险" :value="2" />
  108. <el-option label="高风险" :value="3" />
  109. </el-select>
  110. </el-form-item>
  111. </el-col>
  112. <el-col :span="8">
  113. <el-form-item label="扣分分值" prop="score">
  114. <el-input-number v-model="ruleForm.score" :precision="1" :step="0.5" step-strictly :max="100" :min="0" controls-position="right" placeholder="请输入" style="width: 100%;" />
  115. </el-form-item>
  116. </el-col>
  117. <el-col :span="24">
  118. <el-form-item label="规则描述" prop="description">
  119. <el-input
  120. v-model="ruleForm.description"
  121. type="textarea"
  122. :autosize="{ minRows: 3 }"
  123. placeholder="请输入"
  124. />
  125. </el-form-item>
  126. </el-col>
  127. <el-col :span="24">
  128. <el-form-item label="质控规则">
  129. <el-col :span="5">
  130. <el-form-item label="规则模板" prop="rule_type">
  131. <el-select v-model="ruleForm.rule_type" filterable placeholder="请选择" style="width: 100%;">
  132. <el-option label="普通规则" value="普通规则" />
  133. <!-- <el-option label="时效性规则" value="时效性规则" />
  134. <el-option label="完整性规则" value="完整性规则" />
  135. <el-option label="知识库规则" value="知识库规则" />
  136. <el-option label="大模型规则" value="大模型规则" /> -->
  137. </el-select>
  138. </el-form-item>
  139. </el-col>
  140. <!-- 前置条件 -->
  141. <el-col :span="24" style="margin-bottom: 20px;">
  142. <el-button type="primary" plain icon="el-icon-plus" @click="onAddQZTJ">前置条件</el-button>
  143. </el-col>
  144. <el-col v-if="ruleForm.qztj.length" :span="24">
  145. <el-card v-for="(item, index) of ruleForm.qztj" :key="'qztj'+index" class="box-card" shadow="never">
  146. <div slot="header" class="clearfix box-card_header span">
  147. <span class="text">前置条件{{ index + 1 }}</span>
  148. <span class="ml40">
  149. <span>条件流向</span>
  150. <el-radio v-model="item.condition_type" :label="1" class="ml40">过滤</el-radio>
  151. <el-radio v-model="item.condition_type" :label="2">免审</el-radio>
  152. </span>
  153. <i class="el-icon-delete" style="float: right; margin-top: 13px; cursor: pointer;" @click="onDeleteQZTJ(index)" />
  154. </div>
  155. <div>
  156. <el-row v-for="(sItem, sIndex) of item.condition_content" :key="'tj'+sIndex" :gutter="12" class="mb12">
  157. <el-col :span="2">
  158. <div class="text-right">条件{{ sIndex + 1 }}</div>
  159. </el-col>
  160. <el-col :span="8">
  161. <el-cascader
  162. v-model="sItem.param1"
  163. :options="objects"
  164. :props="{
  165. expandTrigger: 'hover',
  166. value: 'field_name',
  167. label: 'field_name',
  168. children: 'child'
  169. }"
  170. clearable
  171. filterable
  172. :show-all-levels="false"
  173. placeholder="请选择"
  174. style="width: 100%;"
  175. />
  176. </el-col>
  177. <el-col :span="4">
  178. <el-select v-model="sItem.condition" filterable clearable placeholder="请选择" style="width: 100%;">
  179. <el-option label="包含" value="包含" />
  180. <el-option label="不包含" value="不包含" />
  181. <el-option label="大于" value="大于" />
  182. <el-option label="小于" value="小于" />
  183. <el-option label="等于" value="等于" />
  184. </el-select>
  185. </el-col>
  186. <el-col :span="6">
  187. <el-input v-model="sItem.param2" clearable placeholder="请输入" style="width: 100%;" />
  188. </el-col>
  189. <el-col :span="4">
  190. <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="onAddTJ(index, sIndex)" />
  191. <el-button v-if="item.condition_content.length !== 1" size="mini" type="primary" plain icon="el-icon-minus" @click="onDeleteTJ(index, sIndex)" />
  192. </el-col>
  193. </el-row>
  194. <div class="span">
  195. <span>条件之间的逻辑</span>
  196. <el-radio v-model="item.condition_relation" :label="1" class="ml40">且(满足所有条件)</el-radio>
  197. <el-radio v-model="item.condition_relation" :label="2">或(满足任意一条件)</el-radio>
  198. </div>
  199. </div>
  200. </el-card>
  201. </el-col>
  202. <!-- 质控逻辑 -->
  203. <el-col :span="24">
  204. <el-divider />
  205. <el-card v-for="(item, index) of ruleForm.rule" :key="'rule'+index" class="box-card" shadow="never">
  206. <div slot="header" class="clearfix box-card_header span">
  207. <span class="text">质控逻辑</span>
  208. </div>
  209. <div>
  210. <el-row v-for="(sItem, sIndex) of item.condition_content" :key="'tj'+sIndex" :gutter="12" class="mb12">
  211. <el-col :span="2">
  212. <div class="text-right">逻辑{{ sIndex + 1 }}</div>
  213. </el-col>
  214. <el-col :span="8">
  215. <el-cascader
  216. v-model="sItem.param1"
  217. :options="objects"
  218. :props="{
  219. expandTrigger: 'hover',
  220. value: 'field_name',
  221. label: 'field_name',
  222. children: 'child'
  223. }"
  224. clearable
  225. filterable
  226. :show-all-levels="false"
  227. placeholder="请选择"
  228. style="width: 100%;"
  229. />
  230. </el-col>
  231. <el-col :span="4">
  232. <el-select v-model="sItem.condition" filterable clearable placeholder="请选择" style="width: 100%;">
  233. <el-option label="包含" value="包含" />
  234. <el-option label="不包含" value="不包含" />
  235. <el-option label="大于" value="大于" />
  236. <el-option label="小于" value="小于" />
  237. <el-option label="等于" value="等于" />
  238. </el-select>
  239. </el-col>
  240. <el-col :span="6">
  241. <el-autocomplete
  242. v-model="sItem.param2"
  243. class="inline-input"
  244. value-key="name"
  245. :fetch-suggestions="querySearch"
  246. placeholder="请输入"
  247. style="width: 100%;"
  248. @select="handleSelect"
  249. />
  250. </el-col>
  251. <el-col :span="4">
  252. <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="onAddGZ(index, sIndex)" />
  253. <el-button v-if="item.condition_content.length !== 1" type="primary" size="mini" plain icon="el-icon-minus" @click="onDeleteGZ(index, sIndex)" />
  254. </el-col>
  255. </el-row>
  256. <div class="span">
  257. <span>规则之间的逻辑</span>
  258. <el-radio v-model="item.condition_relation" :label="1" class="ml40">且(满足所有条件)</el-radio>
  259. <el-radio v-model="item.condition_relation" :label="2">或(满足任意一条件)</el-radio>
  260. </div>
  261. </div>
  262. </el-card>
  263. </el-col>
  264. </el-form-item>
  265. </el-col>
  266. </el-row>
  267. </el-form>
  268. <span slot="footer" class="dialog-footer">
  269. <el-button type="primary" @click="submitForm('ruleForm')">提 交</el-button>
  270. <el-button @click="onTest">测试规则</el-button>
  271. </span>
  272. </el-dialog>
  273. </template>
  274. <script>
  275. import { add_rule } from '@/api/rule/config'
  276. import { get_all_word_map } from '@/api/dict'
  277. import { get_rule_detail } from '@/api/rule/config'
  278. export default {
  279. props: {
  280. data: {
  281. type: Object,
  282. default() {
  283. return {
  284. bSwitch: false,
  285. row: {}
  286. }
  287. }
  288. },
  289. objects: {
  290. type: Array,
  291. default() {
  292. return []
  293. }
  294. },
  295. departments: {
  296. type: Array,
  297. default() {
  298. return []
  299. }
  300. }
  301. },
  302. data() {
  303. return {
  304. qcData: [],
  305. ruleForm: {
  306. case_type: '',
  307. changjing: [],
  308. department: [],
  309. object: [],
  310. type: '',
  311. is_not: '',
  312. description: '',
  313. score: undefined,
  314. error_level: '',
  315. status: '',
  316. rule_type: '普通规则',
  317. rule: [
  318. // 质控逻辑只有一条
  319. {
  320. is_pre_condition: 0,
  321. condition_type: 1,
  322. condition_relation: 2,
  323. condition_content: [
  324. {
  325. param1: '',
  326. param2: '',
  327. condition: '包含'
  328. }
  329. ]
  330. }
  331. ],
  332. qztj: [
  333. // 前置条件默认只有一条
  334. {
  335. is_pre_condition: 1,
  336. condition_type: 1,
  337. condition_relation: 2,
  338. condition_content: [
  339. {
  340. param1: '',
  341. param2: '',
  342. condition: '包含'
  343. }
  344. ]
  345. }
  346. ]
  347. },
  348. rules: {
  349. description: [
  350. { required: true, message: '请输入', trigger: 'blur' }
  351. ],
  352. score: [
  353. { required: true, message: '请输入', trigger: 'blur' }
  354. ],
  355. case_type: [
  356. { required: true, message: '请选择', trigger: 'blur' }
  357. ],
  358. changjing: [
  359. { required: true, message: '请选择', trigger: 'blur' }
  360. ],
  361. department: [
  362. { required: true, message: '请选择', trigger: 'blur' }
  363. ],
  364. object: [
  365. { required: true, message: '请选择', trigger: 'blur' }
  366. ],
  367. type: [
  368. { required: true, message: '请选择', trigger: 'blur' }
  369. ],
  370. is_not: [
  371. { required: true, message: '请选择', trigger: 'blur' }
  372. ],
  373. error_level: [
  374. { required: true, message: '请选择', trigger: 'blur' }
  375. ],
  376. status: [
  377. { required: true, message: '请选择', trigger: 'blur' }
  378. ],
  379. rule_type: [
  380. { required: true, message: '请选择', trigger: 'blur' }
  381. ]
  382. }
  383. }
  384. },
  385. computed: {
  386. titleStr() {
  387. return this.data.row.id ? '编辑' : '新增'
  388. }
  389. },
  390. created() {
  391. this.getQcData()
  392. if (this.data.row.id) {
  393. this.getDetail(this.data.row.id)
  394. }
  395. },
  396. methods: {
  397. onTest() {
  398. this.$message.info('功能待开放...')
  399. },
  400. // 获取详情
  401. getDetail(id) {
  402. get_rule_detail({ id }).then(res => {
  403. const { p } = res
  404. const {
  405. case_type,
  406. changjing,
  407. department,
  408. object,
  409. type,
  410. is_not,
  411. description,
  412. score,
  413. error_level,
  414. status
  415. } = p.rule
  416. this.ruleForm.case_type = case_type
  417. this.ruleForm.changjing = changjing.split(',')
  418. this.ruleForm.department = this.toNumberArray(department)
  419. this.ruleForm.is_not = is_not
  420. this.ruleForm.status = status
  421. this.ruleForm.type = type
  422. this.ruleForm.error_level = error_level
  423. this.ruleForm.score = score
  424. this.ruleForm.description = description
  425. this.ruleForm.object = object.split(',')
  426. this.ruleForm.rule = this.getQcRule(p.rule_list)
  427. this.ruleForm.qztj = this.getPreRule(p.rule_list)
  428. })
  429. },
  430. // 找到前置条件
  431. getPreRule(list) {
  432. return list.filter(item => item.is_pre_condition)
  433. },
  434. // 找到质控逻辑
  435. getQcRule(list) {
  436. const rule = list.filter(item => !item.is_pre_condition)
  437. return rule
  438. },
  439. // string 数组 装 number 数组
  440. toNumberArray(slist) {
  441. const alist = []
  442. slist.map(item => {
  443. alist.push(Number(item))
  444. })
  445. return alist
  446. },
  447. // 搜索质控字典
  448. getQcData() {
  449. get_all_word_map({ status: 1 }).then(res => {
  450. const { p } = res
  451. this.qcData = Array.isArray(p) ? p : []
  452. })
  453. },
  454. querySearch(queryString, cb) {
  455. var qcData = this.qcData
  456. var results = queryString ? qcData.filter(this.createFilter(queryString)) : qcData
  457. // 调用 callback 返回建议列表的数据
  458. cb(results)
  459. },
  460. createFilter(queryString) {
  461. return (restaurant) => {
  462. return (restaurant.name.toLowerCase().indexOf(queryString.toLowerCase()) === 0)
  463. }
  464. },
  465. handleSelect(item) {
  466. console.log(item)
  467. },
  468. // 添加前置条件大框
  469. onAddQZTJ() {
  470. this.ruleForm.qztj.push({
  471. is_pre_condition: 1,
  472. condition_type: 1,
  473. condition_relation: 2,
  474. condition_content: [
  475. {
  476. param1: '',
  477. param2: '',
  478. condition: '包含'
  479. }
  480. ]
  481. })
  482. },
  483. // 删除前置条件大框
  484. onDeleteQZTJ(index) {
  485. this.ruleForm.qztj.splice(index, 1)
  486. },
  487. // 新增前置条件大框中_条件
  488. onAddTJ(index, sIndex) {
  489. this.ruleForm.qztj[index].condition_content.push({
  490. param1: '',
  491. param2: '',
  492. condition: '包含'
  493. })
  494. },
  495. // 删除前置条件大框中_条件
  496. onDeleteTJ(index, sIndex) {
  497. this.ruleForm.qztj[index].condition_content.splice(sIndex, 1)
  498. },
  499. // 新增质控逻辑大框中_逻辑
  500. onAddGZ(index, sIndex) {
  501. this.ruleForm.rule[index].condition_content.push({
  502. param1: '',
  503. param2: '',
  504. condition: '包含'
  505. })
  506. },
  507. // 删除质控逻辑大框中_逻辑
  508. onDeleteGZ(index, sIndex) {
  509. this.ruleForm.rule[index].condition_content.splice(sIndex, 1)
  510. },
  511. hasEmptyValues(obj) {
  512. return Object.values(obj).some(value => !value)
  513. },
  514. // 验证前置条件
  515. judgeQZTJ() {
  516. const { qztj } = this.ruleForm
  517. let result = true
  518. const e_index = []
  519. if (qztj.length) {
  520. for (let i = 0; i < qztj.length; i++) {
  521. qztj[i].condition_content.map(item => {
  522. if (this.hasEmptyValues(item)) {
  523. e_index.push(i + 1)
  524. }
  525. })
  526. }
  527. if (e_index.length) {
  528. this.$message.error(`请完善前置条件${e_index.join()}`)
  529. result = false
  530. }
  531. }
  532. return result
  533. },
  534. // 验证质控逻辑
  535. judgeRule() {
  536. const { rule } = this.ruleForm
  537. let result = true
  538. // 质控逻辑只有一条
  539. rule[0].condition_content.map(item => {
  540. if (this.hasEmptyValues(item)) {
  541. this.$message.error(`请完善质控逻辑`)
  542. result = false
  543. }
  544. })
  545. return result
  546. },
  547. submitForm(formName) {
  548. console.log(this.ruleForm.object)
  549. this.$refs[formName].validate(async(valid) => {
  550. const {
  551. case_type,
  552. changjing,
  553. department,
  554. object,
  555. type,
  556. is_not,
  557. description,
  558. score,
  559. error_level,
  560. status,
  561. rule_type,
  562. rule,
  563. qztj
  564. } = this.ruleForm
  565. if (valid) {
  566. if (this.judgeQZTJ() && this.judgeRule()) {
  567. const params = {
  568. case_type,
  569. changjing,
  570. department,
  571. object,
  572. type,
  573. is_not,
  574. description,
  575. score,
  576. error_level,
  577. status,
  578. rule_type,
  579. rule: [...rule, ...qztj]
  580. }
  581. if (this.data.row.id) {
  582. params.id = this.data.row.id
  583. }
  584. add_rule(params).then(res => {
  585. this.data.bSwitch = false
  586. this.$emit('refresh')
  587. this.$message.success(res.m || '操作成功')
  588. })
  589. }
  590. } else {
  591. return false
  592. }
  593. })
  594. }
  595. }
  596. }
  597. </script>
  598. <style lang="scss" scoped>
  599. ::v-deep .el-col-15 {
  600. .el-form-item__label {
  601. width: 160px !important;
  602. }
  603. }
  604. .box-card {
  605. margin-bottom: 16px;
  606. }
  607. ::v-deep .el-card__header {
  608. padding: 0;
  609. .box-card_header {
  610. background: #F7F7F8;
  611. padding: 0 20px;
  612. line-height: 40px;
  613. }
  614. }
  615. ::v-deep .el-card__body {
  616. padding: 20px 12px;
  617. }
  618. .text-right {
  619. text-align: right;
  620. }
  621. .ml40 {
  622. margin-left: 40px;
  623. }
  624. .mb12 {
  625. margin-bottom: 12px;
  626. }
  627. .span {
  628. padding-top: 40px;
  629. .text {
  630. color: #909399;
  631. }
  632. }
  633. </style>