TargetDictConfig.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. <template>
  2. <el-row :gutter="5">
  3. <el-col :span="8">
  4. <TargetTree v-if="isShowTree" :targetTreeData="targetTreeData" @treeNodeClick="treeNodeClick" />
  5. </el-col>
  6. <el-col :span="16">
  7. <PageLayer>
  8. <template #header class="hd-cl">
  9. <el-button type="primary" icon="Plus" @click="resetForm(ruleFormRef)"
  10. style="margin-left: 10px">新增</el-button>
  11. <el-button type="primary" icon="Edit" @click="editForm(ruleFormRef)"
  12. style="margin-left: 10px">编辑</el-button>
  13. <el-button type="primary" icon="Check" @click="submitForm(ruleFormRef)"
  14. style="margin-left: 10px">保存</el-button>
  15. <el-button type="primary" icon="Refresh" @click="resetForm(ruleFormRef)"
  16. style="margin-left: 10px">重置</el-button>
  17. </template>
  18. <template #main>
  19. <el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="120px" class="demo-ruleForm"
  20. :size="formSize" status-icon :disabled="isShowForm">
  21. <el-row>
  22. <el-col :span="12">
  23. <el-form-item label="指标名称" prop="name">
  24. <el-input v-model="ruleForm.name" />
  25. </el-form-item>
  26. </el-col>
  27. <el-col :span="6">
  28. <el-form-item label="指标编码" prop="id">
  29. <el-input v-model="ruleForm.id" />
  30. </el-form-item>
  31. </el-col>
  32. <el-col :span="6">
  33. <el-form-item label="父级编码" prop="pid">
  34. <el-input v-model="ruleForm.pid" />
  35. </el-form-item>
  36. </el-col>
  37. </el-row>
  38. <el-row>
  39. <el-col :span="6">
  40. <el-form-item label="指标序号" prop="sort">
  41. <el-input v-model="ruleForm.sort" />
  42. </el-form-item>
  43. </el-col>
  44. <el-col :span="6">
  45. <el-form-item label="总分" prop="score">
  46. <el-input v-model="ruleForm.score" />
  47. </el-form-item>
  48. </el-col>
  49. <el-col :span="6">
  50. <el-form-item label="所占比率" prop="ratio" :disabled="true">
  51. <el-input v-model="ruleForm.ratio" />
  52. </el-form-item>
  53. </el-col>
  54. <el-col :span="6">
  55. <el-form-item label="对接类型">
  56. <el-select v-model="ruleForm.type" placeholder="请选择类型">
  57. <el-option label="V1" value="0" />
  58. <el-option label="V2" value="1" />
  59. </el-select>
  60. </el-form-item>
  61. </el-col>
  62. </el-row>
  63. <el-row>
  64. <el-col :span="6">
  65. <el-form-item label="状态" prop="state">
  66. <el-select v-model="ruleForm.state" placeholder="请选择状态">
  67. <el-option label="开启" value="Y" />
  68. <el-option label="关闭" value="N" />
  69. </el-select>
  70. </el-form-item>
  71. </el-col>
  72. <el-col :span="6">
  73. <el-form-item label="启用时间">
  74. <el-form-item prop="openTime">
  75. <el-date-picker v-model="ruleForm.openTime" type="date" label="选择时间"
  76. placeholder="选择时间" style="width: 100%" />
  77. </el-form-item>
  78. </el-form-item>
  79. </el-col>
  80. <el-col :span="6">
  81. <el-form-item label="责任科室" prop="deptCode">
  82. <el-select-v2 ref="deptInfoRef" v-model="ruleForm.deptCode" clearable remote filterable
  83. :remote-method="deptMethod" :options="deptWardList" />
  84. </el-form-item>
  85. </el-col>
  86. <el-col :span="6">
  87. <el-form-item label="责任人" prop="opId">
  88. <el-select-v2 ref="opInfoRef" v-model="ruleForm.opId" clearable remote filterable
  89. :remote-method="empMethod" :options="empList" />
  90. </el-form-item>
  91. </el-col>
  92. </el-row>
  93. <el-form-item label="是否叶子节点" prop="isLeaf">
  94. <el-switch v-model="ruleForm.isLeaf" active-value="1" inactive-value="0" active-color="#13ce66"
  95. inactive-color="#ff4949" @change='changeNode(ruleFormRef)' />
  96. </el-form-item>
  97. <el-form-item label="指标定义" prop="definition">
  98. <el-input v-model="ruleForm.definition" type="textarea" />
  99. </el-form-item>
  100. <el-form-item label="评审方法" prop="method">
  101. <el-input v-model="ruleForm.method" type="textarea" />
  102. </el-form-item>
  103. <el-form-item label="计分细则" prop="scoreRule">
  104. <el-input v-model="ruleForm.scoreRule" type="textarea" />
  105. </el-form-item>
  106. <el-form-item label="数据来源" prop="source">
  107. <el-input v-model="ruleForm.source" type="textarea" />
  108. </el-form-item>
  109. <el-divider />
  110. <el-form ref="ruleFormRef" label-width="120px" :model="sqlForm" class="demo-ruleForm"
  111. :size="formSize">
  112. <el-row>
  113. <el-col :span="12">
  114. <el-form-item label="开始时间">
  115. <el-form-item prop="startTime">
  116. <el-date-picker v-model="sqlForm.startTime" type="date" label="选择时间"
  117. placeholder="选择时间" format="YYYYMMDD" value-format="YYYYMMDD" />
  118. </el-form-item>
  119. </el-form-item>
  120. </el-col>
  121. <el-col :span="12">
  122. <el-form-item label="结束时间">
  123. <el-form-item prop="endTime">
  124. <el-date-picker v-model="sqlForm.endTime" type="date" label="选择时间"
  125. placeholder="选择时间" format="YYYYMMDD" value-format="YYYYMMDD" />
  126. </el-form-item>
  127. </el-form-item>
  128. </el-col>
  129. </el-row>
  130. <el-row>
  131. <el-col :span="8">
  132. <el-form-item label="公式-分子结果" prop="childResult">
  133. <el-input v-model="sqlForm.childResult" type="textarea" />
  134. </el-form-item>
  135. </el-col>
  136. <el-col :span="8">
  137. <el-form-item label="公式-分母结果" prop="momResult">
  138. <el-input v-model="sqlForm.momResult" type="textarea" />
  139. </el-form-item>
  140. </el-col>
  141. <el-col :span="8">
  142. <el-form-item label="分子/分母-结果" prop="calcResult">
  143. <el-input v-model="sqlForm.calcResult" type="textarea" />
  144. </el-form-item>
  145. </el-col>
  146. </el-row>
  147. <el-row>
  148. <el-col :span="12">
  149. <el-form-item>
  150. <el-button type="primary" @click="sqlEdit(ruleFormRef)"> 指标sql编辑 </el-button>
  151. </el-form-item>
  152. </el-col>
  153. <el-col :span="12">
  154. <el-form-item>
  155. <el-button type="primary" @click="sqlExecute(ruleFormRef)"> 指标运行结果 </el-button>
  156. </el-form-item>
  157. </el-col>
  158. </el-row>
  159. </el-form>
  160. </el-form>
  161. </template>
  162. </PageLayer>
  163. </el-col>
  164. </el-row>
  165. <el-drawer :title="'Sql编辑'" v-model="isSqlEdit" size="80%" destroy-on-close>
  166. <SqlEditPage :sqlEditData="sqlEditData" />
  167. </el-drawer>
  168. </template>
  169. <script setup name="TargetDictConfig" lang="ts">
  170. import { ref, reactive, onMounted, nextTick } from 'vue'
  171. import TargetTree from '../target-comm/targetTree.vue'
  172. import SqlEditPage from '../target-comm/SqlEditPage.vue'
  173. import { ElMessage } from 'element-plus'
  174. import type { FormInstance, FormRules } from 'element-plus'
  175. import { formatDate } from '../../../utils/date'
  176. import { clone } from '../../../utils/clone'
  177. import PageLayer from '../../../layout/PageLayer.vue'
  178. import { queryDept } from '../../../api/public-api'
  179. import { selectTargetDict, selectTargetDictTree, saveTargetDict } from '../../../api/target-management/target-dict'
  180. import { employeeList } from "../../../api/zhu-yuan-yi-sheng/pat-info-query"
  181. import { targetSqlExecute } from '../../../api/target-management/target-sql'
  182. const targetTreeData = ref({
  183. data: [{}],
  184. height: 900,
  185. })
  186. const isShowTree = ref(false)
  187. const isShowForm = ref(false)
  188. const nowDay = new Date()
  189. const ds = formatDate(nowDay)
  190. const deptWardList = ref([])
  191. const empList = ref([])
  192. const deptInfoRef = ref()
  193. const opInfoRef = ref()
  194. const isSqlEdit = ref(false)
  195. let sqlEditData = ref({
  196. id: '', // 指标编码
  197. name: '', // 指标名称
  198. pid: '', // 父级编码
  199. sort: '', // 指标序号
  200. calcChild: '', // 计算分子sql
  201. calcMom: '', // 计算分母sql
  202. })
  203. const queryParam = reactive({
  204. id: '', // 指标编码
  205. name: '', // 指标名称
  206. pid: '', // 父级编码
  207. sort: '', // 指标序号
  208. type: '', // 对接类型
  209. state: '', // 状态
  210. openTime: '', // 启用时间
  211. deptId: '', // 责任科室id
  212. source: '', // 数据来源
  213. calcChild: '', // 计算分子sql
  214. calcMom: '', // 计算分母sql
  215. isLeaf: '', //是否叶子节点(0:否, 1:是)
  216. })
  217. onMounted(() => {
  218. nextTick(() => {
  219. qeryTargetDictTree()
  220. deptMethod('')
  221. empMethod('')
  222. })
  223. })
  224. const deptMethod = (val: string) => {
  225. queryDept(val).then((res: any) => {
  226. deptWardList.value = res
  227. })
  228. }
  229. const empMethod = (val: string) => {
  230. employeeList(val).then((res: any) => {
  231. empList.value = res
  232. })
  233. }
  234. // 查询指标字典树
  235. const qeryTargetDictTree = () => {
  236. isShowTree.value == true ? false : true
  237. queryParam.id = '';
  238. queryParam.pid = '';
  239. selectTargetDictTree(queryParam)
  240. .then((res: any) => {
  241. targetTreeData.value.data = res
  242. isShowTree.value = true
  243. });
  244. }
  245. // ------ 指标字典新增,修改保存表单开始 ------
  246. // ruleForm.value.name = '123'
  247. // ruleForm.name = '21312'
  248. let ruleForm = $ref({
  249. id: '', // 指标编码
  250. name: '', // 指标名称
  251. pid: '', // 父级编码
  252. sort: '', // 指标序号
  253. score: '', // 总分
  254. ratio: '', // 所占比率
  255. type: '0', // 对接类型
  256. state: 'Y', // 状态
  257. openTime: ds, // 启用时间
  258. dept: '', // 责任科室
  259. deptCode: '', // 责任科室id
  260. op: '', // 责任人
  261. opId: '', // 责任人id
  262. definition: '', // 指标定义
  263. method: '', // 评审方法
  264. scoreRule: '', // 计分细则
  265. source: '', // 数据来源
  266. isLeaf: '0', // 是否叶子节点(0:否, 1:是)
  267. calcChild: '', // 计算-分子
  268. calcMom: '', // 计算-分母
  269. })
  270. let sqlForm = $ref({
  271. id: '', // 指标编码
  272. pid: '', // 父级编码
  273. calcChild: '', // 计算分子sql
  274. calcMom: '', // 计算分母sql
  275. startTime: '', // 计算开始时间
  276. endTime: '', // 计算结束时间
  277. childResult: '', // 计算分子结果
  278. momResult: '', // 计算分母结果
  279. calcResult: '' // 计算结果
  280. })
  281. const formSize = ref('default')
  282. const ruleFormRef = ref<FormInstance>()
  283. const rules = $ref<FormRules>({
  284. name: [
  285. { required: true, message: '请填写指标名称', trigger: 'blur' },
  286. { min: 1, max: 256, message: '指标名称长度范围1-256个字符', trigger: 'blur' },
  287. ],
  288. id: [
  289. { required: true, message: '请填写指标id', trigger: 'blur' },
  290. { min: 1, max: 12, message: '指标id长度范围1-12个字符', trigger: 'blur' },
  291. ],
  292. pid: [
  293. { required: true, message: '请填写指标父id', trigger: 'blur' },
  294. { min: 1, max: 12, message: '指标父id长度范围1-12个字符', trigger: 'blur' },
  295. ],
  296. sort: [
  297. { min: 0, max: 12, message: '指标序号长度范围0-12个字符', trigger: 'blur' },
  298. ],
  299. score: [
  300. { required: true, message: '请填写指标总分', trigger: 'blur' },
  301. {
  302. validator: (rule: any, value: any, callback: any) => {
  303. if (/^(([1-9][0-9]*)|(([0]\.\d{1,2}|[1-9][0-9]*\.\d{1,2})))$/.test(value) == false) {
  304. callback(new Error("请输入正整数或两位小数"));
  305. } else {
  306. callback();
  307. }
  308. },
  309. trigger: "blur",
  310. }
  311. ],
  312. ratio: [
  313. { min: 0, max: 48, message: '指标所占比例长度范围0-48个字符', trigger: 'blur' },
  314. ],
  315. definition: [
  316. { required: false, message: '请填写指标定义', trigger: 'blur' },
  317. ],
  318. method: [
  319. { required: false, message: '请填写评审方法', trigger: 'blur' },
  320. ],
  321. scoreRule: [
  322. { required: false, message: '请填写计分细则', trigger: 'blur' },
  323. ]
  324. })
  325. // 需要添加的叶子节点的校验
  326. const leafRuleFields = ['definition', 'method', 'scoreRule']
  327. const submitForm = async (formEl: FormInstance | undefined) => {
  328. if (!formEl) return
  329. // 处理叶子节点验证
  330. await leafRulesChange(formEl)
  331. await formEl.validate((valid, fields) => {
  332. if (valid) {
  333. ruleForm.dept = deptInfoRef.value.states.selectedLabel
  334. ruleForm.op = opInfoRef.value.states.selectedLabel
  335. saveTargetDict(ruleForm).then((res: any) => {
  336. if (res) {
  337. nextTick(() => {
  338. qeryTargetDictTree()
  339. if (!isShowForm.value) {
  340. isShowForm.value = true
  341. }
  342. })
  343. } else {
  344. qeryTargetDictTree()
  345. return
  346. }
  347. });
  348. } else {
  349. return
  350. }
  351. })
  352. }
  353. const resetForm = (formEl: FormInstance | undefined) => {
  354. if (!formEl) return
  355. if (isShowForm.value) {
  356. isShowForm.value = false
  357. }
  358. formEl.resetFields()
  359. sqlForm.startTime = ''
  360. sqlForm.endTime = ''
  361. sqlForm.childResult = ''
  362. sqlForm.momResult = ''
  363. sqlForm.calcResult = ''
  364. }
  365. const changeNode = async (formEl: FormInstance | undefined) => {
  366. if (!formEl) return
  367. await leafRulesChange(formEl)
  368. }
  369. // 叶子节点校验
  370. const leafRulesChange = async (formEl: FormInstance | undefined) => {
  371. if (!formEl) return
  372. // 父节点
  373. if (ruleForm.isLeaf === '0') {
  374. // 取消叶子节点的字典值校验
  375. leafRuleFields.forEach(e => {
  376. if (rules[e]) {
  377. rules[e][0].required = false
  378. }
  379. })
  380. formEl.clearValidate(leafRuleFields)
  381. } else { // 叶子节点
  382. // 增加叶子节点的字典值校验
  383. leafRuleFields.forEach(e => {
  384. if (rules[e]) {
  385. rules[e][0].required = true
  386. }
  387. })
  388. }
  389. }
  390. const editForm = (formEl: FormInstance | undefined) => {
  391. if (!formEl) return
  392. if (isShowForm.value) {
  393. isShowForm.value = false
  394. if ('1' === ruleForm.isLeaf) {
  395. changeNode(formEl)
  396. }
  397. }
  398. }
  399. // ------ 指标字典新增,修改保存表单结束 ------
  400. // ------ 接收树页面传来的数据 -------
  401. const treeNodeClick = (data: any, node: any, obj: any) => {
  402. if (node.data) {
  403. sqlForm.startTime = ''
  404. sqlForm.endTime = ''
  405. sqlForm.childResult = ''
  406. sqlForm.momResult = ''
  407. sqlForm.calcResult = ''
  408. queryParam.id = node.data.id
  409. queryParam.pid = node.data.pid
  410. selectTargetDict(queryParam)
  411. .then((res: any) => {
  412. if (res) {
  413. nextTick(() => {
  414. isShowForm.value = true
  415. ruleForm = clone(res[0])
  416. ruleFormRef.value?.resetFields()
  417. ruleFormRef.value?.clearValidate()
  418. leafRulesChange(ruleFormRef.value)
  419. })
  420. }
  421. });
  422. }
  423. }
  424. // ------------------------- sql编辑 -----------------------
  425. const sqlEdit = (formEl: FormInstance | undefined) => {
  426. if (!formEl) return
  427. if (ruleForm.id === '') {
  428. ElMessage({
  429. type: "info",
  430. message: "指标信息不全,请确认!",
  431. duration: 2500,
  432. showClose: true,
  433. });
  434. return
  435. }
  436. if (ruleForm.isLeaf === '0') {
  437. ElMessage({
  438. type: "info",
  439. message: "不是基础指标,不需要编写sql,请确认!",
  440. duration: 2500,
  441. showClose: true,
  442. });
  443. return
  444. }
  445. isSqlEdit.value = true
  446. sqlEditData.value = ruleForm
  447. }
  448. // --------------- sql编写结束 ------------
  449. // --------------- sql运行 ----------------
  450. const sqlExecute = (formEl: FormInstance | undefined) => {
  451. if (!formEl) return
  452. // 验证是否填写完整
  453. if (ruleForm.id === '') {
  454. ElMessage({
  455. type: "info",
  456. message: "指标信息不全,请确认!",
  457. duration: 2500,
  458. showClose: true,
  459. });
  460. return
  461. }
  462. if (ruleForm.isLeaf === '0') {
  463. ElMessage({
  464. type: "info",
  465. message: "不是基础指标,不需要执行sql,请确认!",
  466. duration: 2500,
  467. showClose: true,
  468. });
  469. return
  470. }
  471. if (ruleForm.calcChild === '') {
  472. ElMessage({
  473. type: "info",
  474. message: "未编写sql,请联系管理员编写!",
  475. duration: 2500,
  476. showClose: true,
  477. });
  478. return
  479. }
  480. if (sqlForm.startTime === '' || sqlForm.endTime === '') {
  481. ElMessage({
  482. type: "info",
  483. message: "时间条件未选择,请确认!",
  484. duration: 2500,
  485. showClose: true,
  486. });
  487. return
  488. }
  489. sqlForm.id = ruleForm.id
  490. sqlForm.pid = ruleForm.pid
  491. sqlForm.calcChild = ruleForm.calcChild
  492. sqlForm.calcMom = ruleForm.calcMom
  493. targetSqlExecute(sqlForm)
  494. .then((res: any) => {
  495. let r = JSON.parse(JSON.stringify(res))
  496. sqlForm.childResult = r.r1
  497. sqlForm.momResult = r.r2
  498. sqlForm.calcResult = r.r3
  499. });
  500. }
  501. </script>
  502. <style lang="scss" scoped deep>
  503. .hd-cl {
  504. margin-bottom: 1px !important;
  505. }
  506. </style>