noteFormModal.vue 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. <template>
  2. <BasicModal
  3. width="800px"
  4. v-bind="$attrs"
  5. destroyOnClose
  6. @register="registerModal"
  7. :title="getTitle"
  8. @ok="handleSubmit"
  9. >
  10. <Row>
  11. <Col :span="16">
  12. <BasicForm @register="registerForm">
  13. <template #contextSlot="{ model, field }">
  14. <InputGroup compact>
  15. <Textarea
  16. type="textarea"
  17. :rows="4"
  18. v-model:value="model[field]"
  19. @focus="treeDis = false"
  20. id="contexts"
  21. />
  22. <span class="context-tip"
  23. >例:患者今日常规透析,预设超滤{V值}。透前称重测血压{透前血压}。</span
  24. >
  25. <Button size="mini" type="primary" shape="round" class="per-btn" @click="handlePer"
  26. >内容预览</Button
  27. >
  28. <!-- @blur="treeDis = true" -->
  29. </InputGroup>
  30. </template>
  31. <template #previewSlot="{ model, field }"> {{ model[field] }} </template>
  32. </BasicForm>
  33. </Col>
  34. <Col :span="8">
  35. <a-tree
  36. :disabled="treeDis"
  37. :tree-data="noteFieldList"
  38. v-model:expanded-keys="expandedKeys"
  39. @select="handleSel"
  40. :field-names="{ children: 'children', title: 'fieldName', key: 'fieldName' }"
  41. />
  42. </Col>
  43. </Row>
  44. </BasicModal>
  45. </template>
  46. <script lang="ts" setup>
  47. import { Row, Col, InputGroup, Button, Textarea } from 'ant-design-vue';
  48. import { ref, computed, unref } from 'vue';
  49. import { BasicModal, useModalInner } from '/@/components/Modal';
  50. import { BasicForm, useForm } from '/@/components/Form';
  51. import { useMessage } from '/@/hooks/web/useMessage';
  52. import { FormSchema } from '/@/components/Table';
  53. import { getNoteFieldList } from '/@/api/biz/management/complication';
  54. import {
  55. addComplicationExplain,
  56. editComplicationExplain,
  57. getComplicationExplainById,
  58. perComplicationExplain,
  59. } from '/@/api/biz/management/complication';
  60. const emit = defineEmits(['success', 'register']);
  61. const getTitle = computed(() => (!unref(isUpdate) ? '新增说明模板' : '编辑说明模板'));
  62. const isUpdate = ref(false);
  63. const rowId = ref();
  64. const noteFieldList = ref([]);
  65. const expandedKeys = ref([]);
  66. const treeDis = ref(true);
  67. const noteFormSchema: FormSchema[] = [
  68. {
  69. label: '并发症ID',
  70. field: 'complicationId',
  71. component: 'Input',
  72. show: false,
  73. },
  74. {
  75. label: '模版名称',
  76. field: 'name',
  77. required: true,
  78. component: 'Input',
  79. componentProps: {
  80. placeholder: '请输入模版名称',
  81. onFocus: function () {
  82. treeDis.value = true;
  83. },
  84. },
  85. },
  86. {
  87. label: '排序',
  88. field: 'sort',
  89. required: true,
  90. component: 'InputNumber',
  91. componentProps: {
  92. placeholder: '请输入排序',
  93. min: 0,
  94. onFocus: function () {
  95. treeDis.value = true;
  96. },
  97. },
  98. },
  99. {
  100. label: '模版内容',
  101. field: 'context',
  102. required: true,
  103. slot: 'contextSlot',
  104. component: 'Input',
  105. },
  106. {
  107. label: '预览内容',
  108. field: 'preview',
  109. slot: 'previewSlot',
  110. component: 'InputTextArea',
  111. },
  112. ];
  113. const { createMessage } = useMessage();
  114. const [registerForm, { resetFields, validate, setFieldsValue, getFieldsValue }] = useForm({
  115. layout: 'vertical',
  116. showResetButton: true,
  117. labelWidth: 100,
  118. schemas: noteFormSchema,
  119. showActionButtonGroup: false,
  120. actionColOptions: {
  121. span: 23,
  122. },
  123. });
  124. const [registerModal, { setModalProps, closeModal }] = useModalInner(async data => {
  125. await resetFields();
  126. getNoteFieldLists();
  127. setModalProps({ confirmLoading: false });
  128. isUpdate.value = !!data?.isUpdate;
  129. if (unref(isUpdate)) {
  130. rowId.value = data.record.id;
  131. const resData = await getComplicationExplainById(data.record.id);
  132. await setFieldsValue({
  133. ...resData,
  134. });
  135. } else {
  136. await setFieldsValue({
  137. complicationId: data.id,
  138. });
  139. }
  140. });
  141. //获取说明模板字段
  142. async function getNoteFieldLists() {
  143. const lists = await getNoteFieldList();
  144. noteFieldList.value = [];
  145. expandedKeys.value = Object.keys(lists);
  146. Object.keys(lists).forEach((item, index) => {
  147. lists[item].forEach((cItem, cIndex) => {
  148. cItem.key = index * 1000 + cIndex;
  149. });
  150. noteFieldList.value.push({
  151. fieldName: item,
  152. key: index,
  153. children: lists[item],
  154. });
  155. });
  156. }
  157. // 提交按钮事件
  158. async function handleSubmit() {
  159. try {
  160. const values = await validate();
  161. setModalProps({ confirmLoading: true });
  162. !unref(isUpdate)
  163. ? await addComplicationExplain({ ...values })
  164. : await editComplicationExplain({ ...values, id: rowId.value });
  165. !unref(isUpdate) ? createMessage.success('新增成功!') : createMessage.success('编辑成功!');
  166. closeModal();
  167. emit('success', { isUpdate: unref(isUpdate), values: { ...values, id: rowId.value } });
  168. } finally {
  169. setModalProps({ confirmLoading: false, canFullscreen: false });
  170. }
  171. }
  172. // 预览按钮事件
  173. async function handlePer() {
  174. const formVal = getFieldsValue();
  175. if (formVal && formVal.context) {
  176. const perVal = await perComplicationExplain(formVal.context);
  177. await setFieldsValue({
  178. ...formVal,
  179. preview: perVal,
  180. });
  181. } else {
  182. createMessage.error('请输入模板内容后进行预览');
  183. }
  184. }
  185. // 选择说明模板字段事件
  186. function handleSel(selectedKeys, { selectedNodes }) {
  187. // selected, selectedNodes, node, event
  188. treeDis.value = false;
  189. insertAtCursor(selectedNodes[0].fieldName);
  190. selectedKeys = [];
  191. }
  192. // 在鼠标光标处插入对应说明模板字段
  193. async function insertAtCursor(myValue: any) {
  194. let res = '';
  195. let frontString = '';
  196. let afterString = '';
  197. const fieldsValue = getFieldsValue();
  198. const position = document.getElementById('contexts');
  199. const pos = getPositionForTextArea(position);
  200. const y = fieldsValue.context ? fieldsValue.context : '';
  201. frontString = y.substring(0, pos);
  202. afterString = y.substring(pos, fieldsValue.context?.length);
  203. res = frontString + '{' + myValue + '}' + afterString;
  204. await setFieldsValue({
  205. ...fieldsValue,
  206. context: res,
  207. });
  208. }
  209. // 获取鼠标光标位置
  210. function getPositionForTextArea(ctrl) {
  211. let CaretPos = 0;
  212. if (ctrl.selectionStart || ctrl.selectionStart == '0') {
  213. CaretPos = ctrl.selectionStart;
  214. }
  215. return CaretPos;
  216. }
  217. </script>
  218. <style lang="less" scoped>
  219. .per-btn {
  220. margin-top: 6px;
  221. margin-right: 6px;
  222. border-radius: 12px !important;
  223. float: right;
  224. }
  225. .context-tip {
  226. font-size: 12px;
  227. font-weight: 400;
  228. color: #c3cdd8;
  229. }
  230. </style>